diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0a76c10 --- /dev/null +++ b/.env.example @@ -0,0 +1,45 @@ +# Control Center - Environment Variables +# ====================================== + +# ── Backend Variables ─────────────────────────────────────────────────── +# Server configuration +PORT=8080 +CORS_ORIGIN=http://localhost:3000 +LOG_LEVEL=info +ENVIRONMENT=development + +# Database connection (PostgreSQL DSN) +# Format: postgresql://user:password@host:port/database?sslmode=disable +DATABASE_URL=postgresql://controlcenter:controlcenter@localhost:5432/controlcenter?sslmode=disable + +# Gateway (OpenClaw) connection +# URL to the OpenClaw gateway API for polling agent states +GATEWAY_URL=http://localhost:18789/api/agents +# Polling interval for agent state updates +GATEWAY_POLL_INTERVAL=5s + +# ── Frontend Variables (via Vite) ─────────────────────────────────────── +# The Vite config exposes these as import.meta.env.VITE_* +# Set via environment variable when building: VITE_API_URL +# VITE_API_URL=http://localhost:8080 + +# ── Docker Compose Specific ───────────────────────────────────────────── +# When using docker-compose, these are set in the services section +# See docker-compose.yml for service-specific environment variables + +# ── Database Configuration ───────────────────────────────────────────── +# Set in the db service environment section of docker-compose.yml +# POSTGRES_USER=controlcenter +# POSTGRES_PASSWORD=controlcenter +# POSTGRES_DB=controlcenter + +# ── Development Notes ─────────────────────────────────────────────────── +# For local development without Docker: +# 1. Start PostgreSQL locally +# 2. Run: go run ./cmd/server/main.go +# 3. Run: npm run dev in frontend/ +# +# For Docker deployment: +# 1. Copy .env.example to .env (backend only) +# 2. Run: docker compose up -d +# 3. Access frontend at http://localhost:3000 diff --git a/README-deployment.md b/README-deployment.md new file mode 100644 index 0000000..9a25cbc --- /dev/null +++ b/README-deployment.md @@ -0,0 +1,268 @@ +# Control Center Deployment Guide + +This document covers the Docker Compose deployment and kiosk configuration for the Control Center Go + React application. + +## Quick Start + +```bash +# Start all services (backend, frontend, database) +docker compose up -d + +# View logs +docker compose logs -f + +# Stop all services +docker compose down + +# Stop and remove volumes (database data) +docker compose down -v +``` + +## Architecture + +``` +┌─────────────────┐ +│ Frontend │ Port 3000 (host) → 80 (container) +│ React + nginx │ Serves SPA, proxies /api/ to backend +└────────┬────────┘ + │ + │ HTTP + │ +┌────────▼────────┐ +│ Backend │ Port 8080 (host) → 8080 (container) +│ Go HTTP API │ PostgreSQL-backed REST API +└────────┬────────┘ + │ + │ PostgreSQL + │ +┌────────▼────────┐ +│ PostgreSQL │ Port 5432 (internal only) +│ Database │ Persistent volume at /var/lib/postgresql/data +└─────────────────┘ +``` + +## Services + +### Backend (`go-backend`) + +- **Image**: Custom `alpine:latest` with Go binary +- **Port**: 8080 +- **Build**: Multi-stage from `go-backend/Dockerfile` +- **Environment Variables**: + - `PORT` (default: 8080) + - `DATABASE_URL` (PostgreSQL DSN) + - `CORS_ORIGIN` (default: `*`) + - `LOG_LEVEL` (default: `info`) + - `ENVIRONMENT` (default: `development`) + - `GATEWAY_URL` (OpenClaw gateway endpoint) + +### Frontend (`frontend`) + +- **Image**: `nginx:1.27-alpine` +- **Port**: 80 (internal) → 3000 (host) +- **Build**: Multi-stage from `frontend/Dockerfile` + - Node 22 for build + - Nginx 1.27 for serving +- **Config**: Custom nginx config in `frontend/nginx.conf` +- **Environment Variables**: + - `VITE_API_URL` (passed at build time via Vite config) + +### Database (`db`) + +- **Image**: `postgres:16-alpine` +- **Port**: 5432 (internal only) +- **Volume**: `postgres-data:/var/lib/postgresql/data` +- **Environment Variables**: + - `POSTGRES_USER` (default: `controlcenter`) + - `POSTGRES_PASSWORD` (default: `controlcenter`) + - `POSTGRES_DB` (default: `controlcenter`) + +## Kiosk Mode + +For dedicated display installations (e.g., control center dashboard), Chromium can run in kiosk mode. + +### Installation + +1. **Install the systemd service** (on Debian/Ubuntu with systemd): + +```bash +sudo cp kiosk/control-center-kiosk.service /etc/systemd/system/ +sudo systemctl daemon-reload +``` + +2. **Enable auto-start**: + +```bash +sudo systemctl enable control-center-kiosk +``` + +3. **Start the service**: + +```bash +sudo systemctl start control-center-kiosk +``` + +4. **Check status and logs**: + +```bash +sudo systemctl status control-center-kiosk +sudo journalctl -u control-center-kiosk -f +``` + +### Manual Launch + +```bash +# From project root +./kiosk/start-kiosk.sh http://localhost:3000 +``` + +### Uninstall + +```bash +# Stop and disable service +sudo systemctl stop control-center-kiosk +sudo systemctl disable control-center-kiosk +sudo rm /etc/systemd/system/control-center-kiosk.service +sudo systemctl daemon-reload +``` + +### Kiosk Requirements + +- **Browser**: `chromium-browser` (install via `apt-get install chromium`) +- **Display**: X11 session with `DISPLAY=:0` +- **User**: Must run as a user with X11 access (typically `overseer`) +- **Permissions**: Read access to the project directory + +## Environment Variables Reference + +### Backend (`go-backend/.env`) + +```bash +PORT=8080 +DATABASE_URL=postgresql://controlcenter:controlcenter@localhost:5432/controlcenter?sslmode=disable +CORS_ORIGIN=* +LOG_LEVEL=info +ENVIRONMENT=development +GATEWAY_URL=http://localhost:18789/api/agents +GATEWAY_POLL_INTERVAL=5s +``` + +### Frontend (build-time) + +```bash +VITE_API_URL=http://localhost:8080 +``` + +### Docker Compose + +Set via `services..environment` in `docker-compose.yml`: + +```yaml +services: + backend: + environment: + - DATABASE_URL=... + frontend: + environment: + - VITE_API_URL=... + db: + environment: + - POSTGRES_USER=... + - POSTGRES_PASSWORD=... + - POSTGRES_DB=... +``` + +## Development + +### Local Development (non-Docker) + +```bash +# Backend +cd go-backend +go run ./cmd/server/main.go + +# Frontend +cd frontend +npm install +npm run dev +``` + +### Database Migrations + +```bash +# If using pgx/migrate or similar +# The database is created automatically on first connection if it doesn't exist +``` + +## Troubleshooting + +### Backend won't connect to database + +```bash +# Check database container status +docker compose ps + +# View database logs +docker compose logs db + +# Test database connectivity from backend +docker compose exec backend ping db +``` + +### Frontend can't reach backend + +```bash +# Check network connectivity +docker compose exec frontend ping backend + +# Verify backend is running +docker compose logs backend +``` + +### Kiosk browser won't start + +```bash +# Check Chromium installation +which chromium-browser + +# Check X11 forwarding +echo $DISPLAY + +# Manual launch for debugging +./kiosk/start-kiosk.sh http://localhost:3000 +``` + +### Port conflicts + +If ports 8080, 3000, or 5432 are already in use, modify `docker-compose.yml`: + +```yaml +services: + backend: + ports: + - "8081:8080" # Change host port + frontend: + ports: + - "3001:80" # Change host port +``` + +## Production Considerations + +1. **HTTPS**: Add a reverse proxy (nginx/Traefik) for SSL termination +2. **Database security**: Use strong passwords, enable SSL +3. **CORS**: Restrict `CORS_ORIGIN` to production domain +4. **Logs**: Configure log aggregation (e.g., ELK, Loki) +5. **Backups**: Regular PostgreSQL volume backups +6. **Monitoring**: Add health checks and alerting + +## Files + +| File/Directory | Purpose | +|----------------|---------| +| `docker-compose.yml` | Service definitions and configuration | +| `.env.example` | Environment variable template | +| `go-backend/Dockerfile` | Backend build definition | +| `frontend/Dockerfile` | Frontend build definition | +| `frontend/nginx.conf` | Nginx config for SPA routing | +| `kiosk/start-kiosk.sh` | Kiosk browser startup script | +| `kiosk/control-center-kiosk.service` | Systemd unit for auto-start | diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2e3c5bb --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,72 @@ +# Control Center - Go + React + PostgreSQL Deployment +# ============================================================ + +services: + # ── Backend Service (Go) ─────────────────────────────────────────────── + backend: + build: + context: ./go-backend + dockerfile: Dockerfile + ports: + - "8080:8080" + environment: + - DATABASE_URL=postgresql://controlcenter:controlcenter@db:5432/controlcenter?sslmode=disable + - CORS_ORIGIN=http://localhost:3000 + - LOG_LEVEL=info + - ENVIRONMENT=production + - PORT=8080 + - GATEWAY_URL=http://host.docker.internal:18789/api/agents + depends_on: + db: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:8080/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + networks: + - control-center-network + restart: unless-stopped + + # ── Frontend Service (React) ─────────────────────────────────────────── + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + ports: + - "3000:80" + depends_on: + - backend + environment: + - VITE_API_URL=http://localhost:8080 + networks: + - control-center-network + restart: unless-stopped + + # ── Database Service (PostgreSQL 16) ─────────────────────────────────── + db: + image: postgres:16-alpine + container_name: control-center-db + environment: + - POSTGRES_USER=controlcenter + - POSTGRES_PASSWORD=controlcenter + - POSTGRES_DB=controlcenter + volumes: + - postgres-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U controlcenter -d controlcenter"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + networks: + - control-center-network + restart: unless-stopped + +networks: + control-center-network: + driver: bridge + +volumes: + postgres-data: diff --git a/kiosk/control-center-kiosk.service b/kiosk/control-center-kiosk.service new file mode 100644 index 0000000..79b961c --- /dev/null +++ b/kiosk/control-center-kiosk.service @@ -0,0 +1,42 @@ +# Control Center Kiosk Service +# ============================= +# Systemd unit file for auto-starting the Control Center kiosk on boot +# +# Install: sudo cp control-center-kiosk.service /etc/systemd/system/ +# Enable: sudo systemctl enable control-center-kiosk +# Start: sudo systemctl start control-center-kiosk +# Status: sudo systemctl status control-center-kiosk +# Logs: sudo journalctl -u control-center-kiosk -f + +[Unit] +Description=Control Center Kiosk - Chrome Browser Dashboard +Documentation=https://code.cubecraftcreations.com/CubeCraft-Creations/Control-Center +After=graphical-session.target network-online.target +Wants=network-online.target +PartOf=graphical-session.target + +[Service] +Type=simple +ExecStart=/home/overseer/projects/Control-Center/kiosk/start-kiosk.sh http://localhost:3000 +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=5 +Environment=DISPLAY=:0 +Environment=XAUTHORITY=/home/overseer/.Xauthority +WorkingDirectory=/home/overseer/projects/Control-Center +User=overseer +Group=overseer +StandardOutput=journal +StandardError=journal +SyslogIdentifier=control-center-kiosk + +# Security hardening +NoNewPrivileges=true +ProtectSystem=strict +ProtectHome=true +PrivateTmp=true +ReadWritePaths=/home/overseer/.config/chromium +ReadWritePaths=/var/log/journal + +[Install] +WantedBy=graphical-session.target diff --git a/kiosk/start-kiosk.sh b/kiosk/start-kiosk.sh new file mode 100755 index 0000000..26aee7b --- /dev/null +++ b/kiosk/start-kiosk.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# Control Center Kiosk Startup Script +# ==================================== +# This script launches Chromium in kiosk mode for the Control Center dashboard +# Usage: ./start-kiosk.sh [frontend-url] + +set -e + +FRONTEND_URL="${1:-http://localhost:3000}" +BROWSER_WINDOW="chromium-browser" + +# ── Functions ──────────────────────────────────────────────────────────── + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" +} + +cleanup() { + log "Stopping kiosk browser..." + pkill -f "chromium-browser.*--kiosk" || true +} + +trap cleanup SIGINT SIGTERM + +# ── Check prerequisites ────────────────────────────────────────────────── + +check_browser() { + if ! command -v chromium-browser &> /dev/null; then + log "ERROR: chromium-browser not found" + log "Install with: sudo apt-get install chromium" + exit 1 + fi +} + +check_x_server() { + if [ -z "$DISPLAY" ]; then + log "ERROR: DISPLAY environment variable not set" + log "This script requires an X server session" + exit 1 + fi +} + +# ── Main ──────────────────────────────────────────────────────────────── + +main() { + log "Starting Control Center Kiosk..." + log "Frontend URL: $FRONTEND_URL" + + check_browser + check_x_server + + # Clean up any existing browser instances + cleanup + + # Launch Chromium in kiosk mode + # --kiosk: Fullscreen without browser UI + # --incognito: Clean session + # --noerrdialogs: Suppress error dialogs + # --disable-notifications: Disable notifications + # --disable-extensions: Disable extensions + # --disable-plugins-discovery: Disable plugins + # --disable-sync: Disable sync + # --disable-web-security: Allow CORS (needed for local API calls) + # --ignore-certificate-errors: Ignore SSL errors (for local dev) + # --gpu: Enable GPU acceleration + # --start-fullscreen: Start in fullscreen mode + chromium-browser \ + --kiosk \ + --incognito \ + --noerrdialogs \ + --disable-notifications \ + --disable-extensions \ + --disable-plugins-discovery \ + --disable-sync \ + --disable-web-security \ + --ignore-certificate-errors \ + --gpu \ + --start-fullscreen \ + "$FRONTEND_URL" & + + KIOSK_PID=$! + log "Kiosk browser started (PID: $KIOSK_PID)" + + # Wait for browser to exit + wait $KIOSK_PID +} + +main "$@"