Complete Application Examples
This page provides complete, production-ready examples for different application types.
Node.js Express API
A complete REST API with database, caching, and AI integration.
Project Structure
my-api/
├── Dockerfile
├── strongly.manifest.yaml
├── package.json
├── .dockerignore
├── src/
│ ├── server.js
│ ├── routes/
│ │ ├── users.js
│ │ └── health.js
│ ├── services/
│ │ ├── database.js
│ │ └── ai.js
│ └── utils/
│ └── logger.js
Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy source code
COPY . .
# Production stage
FROM node:18-alpine
WORKDIR /app
# Copy from builder
COPY /app/node_modules ./node_modules
COPY /app/src ./src
COPY /app/package.json ./
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
USER nodejs
EXPOSE 3000
CMD ["node", "src/server.js"]
strongly.manifest.yaml
version: "1.0"
type: nodejs
name: user-api
description: REST API for user management with AI features
author: Acme Corp
tags:
- nodejs
- api
- backend
ports:
- port: 3000
name: http
expose: true
env:
- name: NODE_ENV
value: "production"
required: true
- name: LOG_LEVEL
value: "info"
description: Logging level (debug, info, warn, error)
- name: DATABASE_URL
value: ""
required: true
secret: true
description: PostgreSQL connection string
- name: REDIS_URL
value: ""
required: true
secret: true
description: Redis cache connection string
- name: JWT_SECRET
value: ""
required: true
secret: true
description: Secret for JWT token signing
health_check:
path: /health
port: 3000
initial_delay: 15
period: 30
timeout: 3
proxy:
websocket: false
timeout: 60
resources:
cpu_request: "200m"
memory_request: "512Mi"
cpu_limit: "1000m"
memory_limit: "1Gi"
package.json
{
"name": "user-api",
"version": "1.0.0",
"description": "User management API",
"main": "src/server.js",
"scripts": {
"start": "node src/server.js"
},
"dependencies": {
"express": "^4.18.2",
"pg": "^8.11.3",
"redis": "^4.6.10",
"winston": "^3.11.0",
"jsonwebtoken": "^9.0.2"
}
}
src/server.js
const express = require('express');
const logger = require('./utils/logger');
const healthRoutes = require('./routes/health');
const userRoutes = require('./routes/users');
const { initDatabase } = require('./services/database');
const { initAI } = require('./services/ai');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware
app.use(express.json());
app.use((req, res, next) => {
logger.info('Request received', {
method: req.method,
path: req.path,
ip: req.ip
});
next();
});
// Routes
app.use('/health', healthRoutes);
app.use('/api/users', userRoutes);
// Error handling
app.use((err, req, res, next) => {
logger.error('Error occurred', {
error: err.message,
stack: err.stack,
path: req.path
});
res.status(500).json({
error: 'Internal server error',
message: err.message
});
});
// Start server
async function start() {
try {
// Initialize services
await initDatabase();
await initAI();
app.listen(PORT, () => {
logger.info(`Server started on port ${PORT}`);
});
} catch (err) {
logger.error('Failed to start server', { error: err.message });
process.exit(1);
}
}
start();
src/services/database.js
const { Pool } = require('pg');
const logger = require('../utils/logger');
let pool = null;
async function initDatabase() {
const services = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
// Try to get PostgreSQL from addons first, then datasources
let dbConfig = null;
// Check addons
const pgAddon = Object.values(services.addons || {}).find(
addon => addon.type === 'postgresql'
);
if (pgAddon) {
pool = new Pool({ connectionString: pgAddon.connectionString });
} else if (process.env.DATABASE_URL) {
// Fallback to environment variable
pool = new Pool({ connectionString: process.env.DATABASE_URL });
} else {
throw new Error('No database configuration found');
}
// Test connection
const client = await pool.connect();
await client.query('SELECT NOW()');
client.release();
logger.info('Database connected successfully');
}
function getPool() {
if (!pool) {
throw new Error('Database not initialized');
}
return pool;
}
module.exports = { initDatabase, getPool };
src/services/ai.js
const logger = require('../utils/logger');
let aiModel = null;
async function initAI() {
const services = JSON.parse(process.env.STRONGLY_SERVICES || '{}');
// Get first available AI model
const models = Object.values(services.aiModels || {});
if (models.length === 0) {
logger.warn('No AI models configured');
return;
}
aiModel = models[0];
logger.info('AI model initialized', { model: aiModel.name });
}
async function generateText(prompt) {
if (!aiModel) {
throw new Error('AI model not initialized');
}
const response = await fetch(`${aiModel.endpoint}/chat/completions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${aiModel.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: aiModel.model,
messages: [{ role: 'user', content: prompt }],
max_tokens: 500
})
});
const data = await response.json();
return data.choices[0].message.content;
}
module.exports = { initAI, generateText };
src/routes/health.js
const express = require('express');
const { getPool } = require('../services/database');
const router = express.Router();
router.get('/', async (req, res) => {
try {
// Check database
const pool = getPool();
const client = await pool.connect();
await client.query('SELECT 1');
client.release();
res.status(200).json({
status: 'ok',
timestamp: new Date().toISOString(),
checks: {
database: 'ok'
}
});
} catch (err) {
res.status(503).json({
status: 'error',
timestamp: new Date().toISOString(),
error: err.message
});
}
});
module.exports = router;
.dockerignore
node_modules
npm-debug.log
.git
.env
.DS_Store
*.md
coverage
.vscode
.idea
test/
React SPA with Runtime Config
A production-ready React single-page application.
Project Structure
my-react-app/
├── Dockerfile
├── strongly.manifest.yaml
├── nginx.conf
├── package.json
├── .dockerignore
├── public/
│ ├── index.html
│ └── config.js
└── src/
├── App.js
├── config.js
└── index.js
Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy source code
COPY . .
# Build arguments
ARG REACT_APP_VERSION
ARG NODE_ENV
ENV REACT_APP_VERSION=${REACT_APP_VERSION}
ENV NODE_ENV=${NODE_ENV}
# Build app
RUN npm run build
# Production stage
FROM nginx:1.25-alpine
# Copy nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy built app
COPY /app/build /usr/share/nginx/html
# Copy config template
COPY public/config.js /usr/share/nginx/html/config.js
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
strongly.manifest.yaml
version: "1.0"
type: react
name: admin-dashboard
description: Admin dashboard with runtime configuration
author: Acme Corp
tags:
- react
- frontend
- dashboard
ports:
- port: 80
name: http
expose: true
static:
root: /usr/share/nginx/html
index: index.html
spa: true
config_file: /usr/share/nginx/html/config.js
config_placeholder: __APP_CONFIG__
build:
args:
NODE_ENV: production
REACT_APP_VERSION: "1.0.0"
output_dir: /app/build
env:
- name: REACT_APP_API_URL
value: "https://api.acme.com"
description: Backend API endpoint
- name: REACT_APP_VERSION
value: "1.0.0"
buildtime: true
description: Application version
health_check:
path: /
port: 80
initial_delay: 5
period: 30
resources:
cpu_request: "50m"
memory_request: "128Mi"
cpu_limit: "200m"
memory_limit: "256Mi"
nginx.conf
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
# SPA routing - fallback to index.html
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
}
public/config.js
// Runtime configuration injected by platform
window.__APP_CONFIG__ = __APP_CONFIG__;
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Admin Dashboard</title>
<!-- Load runtime config -->
<script src="%PUBLIC_URL%/config.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
src/config.js
// Access runtime configuration
const config = window.__APP_CONFIG__ || {
REACT_APP_API_URL: 'http://localhost:3000'
};
export const API_URL = config.REACT_APP_API_URL;
export const APP_VERSION = config.REACT_APP_VERSION || '1.0.0';
export default config;
src/App.js
import React, { useEffect, useState } from 'react';
import { API_URL, APP_VERSION } from './config';
function App() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(`${API_URL}/api/users`)
.then(res => res.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(err => {
console.error('Failed to fetch users:', err);
setLoading(false);
});
}, []);
return (
<div className="App">
<h1>Admin Dashboard</h1>
<p>Version: {APP_VERSION}</p>
<p>API: {API_URL}</p>
{loading ? (
<p>Loading...</p>
) : (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
</div>
);
}
export default App;
Python Flask API
A Flask API with PostgreSQL and AI integration.
Project Structure
my-flask-api/
├── Dockerfile
├── strongly.manifest.yaml
├── requirements.txt
├── .dockerignore
├── app.py
├── config.py
├── services/
│ ├── database.py
│ └── ai.py
└── routes/
├── health.py
└── users.py
Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gcc \
postgresql-client && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Copy requirements
COPY requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create non-root user
RUN useradd -m -u 1001 appuser && \
chown -R appuser:appuser /app
USER appuser
EXPOSE 5000
# Use gunicorn for production
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "--timeout", "60", "app:app"]
strongly.manifest.yaml
version: "1.0"
type: flask
name: ml-api
description: Machine learning inference API
author: Data Team
tags:
- python
- flask
- ml
ports:
- port: 5000
name: http
expose: true
env:
- name: FLASK_ENV
value: "production"
required: true
- name: LOG_LEVEL
value: "INFO"
description: Python logging level
- name: DATABASE_URL
value: ""
required: true
secret: true
description: PostgreSQL connection string
health_check:
path: /health
port: 5000
initial_delay: 20
period: 30
timeout: 5
resources:
cpu_request: "500m"
memory_request: "1Gi"
cpu_limit: "2000m"
memory_limit: "2Gi"
requirements.txt
Flask==3.0.0
gunicorn==21.2.0
psycopg2-binary==2.9.9
python-dotenv==1.0.0
requests==2.31.0
app.py
import os
import logging
from flask import Flask, jsonify
from config import Config
from services.database import init_db, get_db
from services.ai import init_ai
from routes.health import health_bp
from routes.users import users_bp
# Configure logging
logging.basicConfig(
level=os.environ.get('LOG_LEVEL', 'INFO'),
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Create Flask app
app = Flask(__name__)
app.config.from_object(Config)
# Initialize services
@app.before_first_request
def initialize():
try:
init_db()
init_ai()
logger.info('Services initialized successfully')
except Exception as e:
logger.error(f'Failed to initialize services: {e}')
raise
# Register blueprints
app.register_blueprint(health_bp, url_prefix='/health')
app.register_blueprint(users_bp, url_prefix='/api/users')
# Error handlers
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Not found'}), 404
@app.errorhandler(500)
def internal_error(error):
logger.error(f'Internal error: {error}')
return jsonify({'error': 'Internal server error'}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
services/database.py
import os
import json
import psycopg2
from psycopg2 import pool
import logging
logger = logging.getLogger(__name__)
connection_pool = None
def init_db():
global connection_pool
# Parse STRONGLY_SERVICES
services = json.loads(os.environ.get('STRONGLY_SERVICES', '{}'))
# Get PostgreSQL configuration
pg_addon = None
for addon in services.get('addons', {}).values():
if addon.get('type') == 'postgresql':
pg_addon = addon
break
if pg_addon:
db_url = pg_addon['connectionString']
else:
db_url = os.environ.get('DATABASE_URL')
if not db_url:
raise ValueError('No database configuration found')
# Create connection pool
connection_pool = pool.SimpleConnectionPool(
1, # min connections
20, # max connections
db_url
)
logger.info('Database connection pool created')
def get_db():
if not connection_pool:
raise RuntimeError('Database not initialized')
return connection_pool.getconn()
def release_db(conn):
if connection_pool:
connection_pool.putconn(conn)
routes/health.py
from flask import Blueprint, jsonify
from services.database import get_db, release_db
import logging
logger = logging.getLogger(__name__)
health_bp = Blueprint('health', __name__)
@health_bp.route('/', methods=['GET'])
def health():
try:
# Check database
conn = get_db()
cursor = conn.cursor()
cursor.execute('SELECT 1')
cursor.close()
release_db(conn)
return jsonify({
'status': 'ok',
'checks': {
'database': 'ok'
}
}), 200
except Exception as e:
logger.error(f'Health check failed: {e}')
return jsonify({
'status': 'error',
'error': str(e)
}), 503
Deployment Commands
For all examples above:
# 1. Create project archive
tar -czf app.tar.gz .
# 2. Upload via platform UI or CLI
# Navigate to Apps → Deploy App
# Upload app.tar.gz
# 3. Configure environment
# Select resource tier
# Connect services (databases, AI models)
# Set environment variables
# 4. Deploy
# Click "Deploy" button
# Monitor build progress
# 5. View application
# Click "View App" once deployed