commit 95c13a841f23c589162747607bba8e539a0529ed Author: ryan.gogo Date: Sat Feb 14 05:52:41 2026 +0100 Initial commit: Template site for Start an AI Company deployment - Node.js Express application with modern white UI - PostgreSQL and Redis integration - Docker Compose configuration without host port mappings - Traefik-ready with proper labels - Health check endpoint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9f10876 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +node_modules +npm-debug.log +.git +.gitignore +README.md +.env diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6562f2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +npm-debug.log +.env +.DS_Store +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8380370 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:18-alpine + +WORKDIR /app + +COPY package*.json ./ + +RUN npm install --production + +COPY . . + +EXPOSE 3000 + +CMD ["node", "server.js"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..c228d05 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# Template 001 - Start an AI Company Deployment Template + +This is a template site demonstrating how to deploy applications on Start an AI Company servers using Docker Compose and Traefik. + +## Features + +- Node.js Express application +- PostgreSQL database +- Redis caching +- Docker Compose configuration +- Traefik-ready (no host port mappings) +- Modern, clean white UI + +## Architecture + +- **App**: Node.js Express server running on port 3000 (internal) +- **Database**: PostgreSQL 15 +- **Cache**: Redis 7 +- **Routing**: Traefik handles external routing and SSL + +## Deployment + +Deploy using the SAAC command: + +```bash +saac create application +``` + +This will deploy the application to https://template-001.startanaicompany.com + +## Local Development + +```bash +npm install +npm run dev +``` + +## Docker Deployment + +```bash +docker-compose up -d +``` + +## Environment Variables + +- `PORT`: Application port (default: 3000) +- `POSTGRES_HOST`: PostgreSQL host +- `POSTGRES_PORT`: PostgreSQL port +- `POSTGRES_USER`: PostgreSQL user +- `POSTGRES_PASSWORD`: PostgreSQL password +- `POSTGRES_DB`: PostgreSQL database name +- `REDIS_HOST`: Redis host +- `REDIS_PORT`: Redis port + +## Health Check + +Visit `/health` endpoint to check service status. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6585e7e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,68 @@ +version: '3.8' + +services: + app: + build: . + container_name: template-001-app + restart: unless-stopped + environment: + - NODE_ENV=production + - PORT=3000 + - POSTGRES_HOST=postgres + - POSTGRES_PORT=5432 + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - POSTGRES_DB=template_db + - REDIS_HOST=redis + - REDIS_PORT=6379 + depends_on: + - postgres + - redis + networks: + - app-network + expose: + - "3000" + labels: + - "traefik.enable=true" + - "traefik.http.routers.template-001.rule=Host(`template-001.startanaicompany.com`)" + - "traefik.http.routers.template-001.entrypoints=websecure" + - "traefik.http.routers.template-001.tls=true" + - "traefik.http.routers.template-001.tls.certresolver=letsencrypt" + - "traefik.http.services.template-001.loadbalancer.server.port=3000" + + postgres: + image: postgres:15-alpine + container_name: template-001-postgres + restart: unless-stopped + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=postgres + - POSTGRES_DB=template_db + volumes: + - postgres-data:/var/lib/postgresql/data + networks: + - app-network + expose: + - "5432" + + redis: + image: redis:7-alpine + container_name: template-001-redis + restart: unless-stopped + command: redis-server --appendonly yes + volumes: + - redis-data:/data + networks: + - app-network + expose: + - "6379" + +volumes: + postgres-data: + driver: local + redis-data: + driver: local + +networks: + app-network: + driver: bridge diff --git a/package.json b/package.json new file mode 100644 index 0000000..7182ac2 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "template-001", + "version": "1.0.0", + "description": "Template site for Start an AI Company deployment", + "main": "server.js", + "scripts": { + "start": "node server.js", + "dev": "nodemon server.js" + }, + "dependencies": { + "express": "^4.18.2", + "pg": "^8.11.3", + "redis": "^4.6.12" + }, + "devDependencies": { + "nodemon": "^3.0.2" + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..7c3bc62 --- /dev/null +++ b/public/index.html @@ -0,0 +1,166 @@ + + + + + + Template Site - Start an AI Company + + + +
+ +

This site is a template site on how to deploy on Start an AI Company servers

+

A modern, scalable deployment template featuring Docker Compose, PostgreSQL, Redis, and Traefik integration.

+ +
+
+
🐳
+
Docker Ready
+

Containerized with Docker Compose

+
+
+
🗄️
+
PostgreSQL
+

Robust database solution

+
+
+
+
Redis Cache
+

High-performance caching

+
+
+
🚀
+
Traefik Ready
+

Automatic routing & SSL

+
+
+ + +
+ + diff --git a/server.js b/server.js new file mode 100644 index 0000000..da7d414 --- /dev/null +++ b/server.js @@ -0,0 +1,75 @@ +const express = require('express'); +const { Pool } = require('pg'); +const redis = require('redis'); +const path = require('path'); + +const app = express(); +const PORT = process.env.PORT || 3000; + +// PostgreSQL connection +const pool = new Pool({ + host: process.env.POSTGRES_HOST || 'postgres', + port: process.env.POSTGRES_PORT || 5432, + user: process.env.POSTGRES_USER || 'postgres', + password: process.env.POSTGRES_PASSWORD || 'postgres', + database: process.env.POSTGRES_DB || 'template_db' +}); + +// Redis connection +const redisClient = redis.createClient({ + socket: { + host: process.env.REDIS_HOST || 'redis', + port: process.env.REDIS_PORT || 6379 + } +}); + +// Connect to Redis +redisClient.connect().catch(console.error); + +// Test database connections +pool.query('SELECT NOW()', (err, res) => { + if (err) { + console.error('PostgreSQL connection error:', err); + } else { + console.log('PostgreSQL connected successfully at:', res.rows[0].now); + } +}); + +redisClient.on('connect', () => { + console.log('Redis connected successfully'); +}); + +redisClient.on('error', (err) => { + console.error('Redis connection error:', err); +}); + +// Serve static files +app.use(express.static('public')); + +// Health check endpoint +app.get('/health', async (req, res) => { + try { + const pgResult = await pool.query('SELECT NOW()'); + await redisClient.ping(); + res.json({ + status: 'healthy', + postgres: 'connected', + redis: 'connected', + timestamp: pgResult.rows[0].now + }); + } catch (error) { + res.status(500).json({ + status: 'unhealthy', + error: error.message + }); + } +}); + +// Main route +app.get('/', (req, res) => { + res.sendFile(path.join(__dirname, 'public', 'index.html')); +}); + +app.listen(PORT, '0.0.0.0', () => { + console.log(`Server running on port ${PORT}`); +});