Compare commits

...

10 Commits

Author SHA1 Message Date
Joshua King 49b959aee5 Add CI Docker image with Go 1.23 + Node 22 pre-installed, update workflow to use go-react label
Dev Build & Deploy / test-and-build (push) Has been cancelled
Dev Build & Deploy / docker-build-push (push) Has been cancelled
2026-05-20 08:47:16 -04:00
Joshua King ae37d79aa8 Switch to ubuntu-dotnet runner label to bypass /var/run symlink issue
Dev Build & Deploy / test-and-build (push) Has been cancelled
Dev Build & Deploy / docker-build-push (push) Has been cancelled
2026-05-20 08:39:05 -04:00
Joshua King 8fb4183abe Add container spec to fix /var/run symlink path escape error
Dev Build & Deploy / test-and-build (push) Failing after 7s
Dev Build & Deploy / docker-build-push (push) Has been skipped
2026-05-20 08:30:49 -04:00
Joshua King ee6ad10db9 Replace setup-go/setup-node actions with manual install for Gitea runner compatibility
Dev Build & Deploy / test-and-build (push) Failing after 14m18s
Dev Build & Deploy / docker-build-push (push) Has been cancelled
2026-05-20 08:10:13 -04:00
Joshua King 5f42a3be18 Rename GITEA_TOKEN secret to ACCESS_TOKEN
Dev Build & Deploy / test-and-build (push) Failing after 4s
Dev Build & Deploy / docker-build-push (push) Has been skipped
2026-05-20 08:08:21 -04:00
Joshua King 0e452941dd Remove deploy-dev job - deployment handled via docker-compose
Dev Build & Deploy / test-and-build (push) Failing after 0s
Dev Build & Deploy / docker-build-push (push) Has been skipped
2026-05-20 08:06:52 -04:00
Joshua King 87cb517623 Update CI workflow to match Go+React stack with Docker registry push
Dev Build & Deploy / test-and-build (push) Failing after 1s
Dev Build & Deploy / docker-build-push (push) Has been skipped
Dev Build & Deploy / deploy-dev (push) Has been skipped
2026-05-20 08:04:50 -04:00
Joshua King 0ac4898027 Updates
Dev Build / deploy-dev (push) Has been cancelled
Dev Build / build-test (push) Has been cancelled
2026-05-20 07:27:31 -04:00
Otto 519e872027 Merge pull request 'CUB-126: Update Control Center deployment for Go + React' (#40) from agent/pip/CUB-126-deployment-go-react into dev
Dev Build / build-test (push) Successful in 1m26s
2026-05-14 05:33:37 -04:00
overseer 2b4b9b3e96 CUB-126: Update Control Center deployment for Go + React
Dev Build / build-test (pull_request) Successful in 1m33s
- Updated docker-compose.yml for Go + React + PostgreSQL
- Go backend multi-stage Dockerfile (already existed)
- React frontend multi-stage Dockerfile with nginx SPA config (already existed)
- Kiosk start script and systemd unit
- Deployment README
- .env.example for environment variables
2026-05-14 05:32:23 -04:00
7 changed files with 579 additions and 22 deletions
+45
View File
@@ -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
+53 -22
View File
@@ -1,4 +1,4 @@
name: Dev Build name: Dev Build & Deploy
on: on:
pull_request: pull_request:
@@ -6,39 +6,70 @@ on:
push: push:
branches: [dev] branches: [dev]
env:
REGISTRY: code.cubecraftcreations.com
BACKEND_IMAGE: ${{ gitea.repository }}/backend
FRONTEND_IMAGE: ${{ gitea.repository }}/frontend
jobs: jobs:
build-test: test-and-build:
runs-on: ubuntu-latest runs-on: go-react
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Setup .NET - name: Run backend tests
uses: actions/setup-dotnet@v4 run: go test ./...
with: working-directory: ./go-backend
dotnet-version: '9.0.x'
- name: Restore backend
run: dotnet restore
working-directory: ./backend
- name: Build backend - name: Build backend
run: dotnet build --no-restore --configuration Release run: go build -ldflags="-w -s" -o /tmp/server ./cmd/server
working-directory: ./backend working-directory: ./go-backend
- name: Test backend
run: dotnet test --no-build --configuration Release
working-directory: ./backend
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "24"
- name: Install frontend deps - name: Install frontend deps
run: npm ci run: npm ci
working-directory: ./frontend working-directory: ./frontend
- name: Lint frontend
run: npm run lint
working-directory: ./frontend
- name: Build frontend - name: Build frontend
run: npm run build run: npm run build
working-directory: ./frontend working-directory: ./frontend
docker-build-push:
needs: test-and-build
if: gitea.event_name == 'push'
runs-on: go-react
steps:
- uses: actions/checkout@v4
- name: Login to Gitea Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.ACCESS_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build & push backend image
uses: docker/build-push-action@v6
with:
context: ./go-backend
push: true
tags: |
${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE }}:dev
${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE }}:${{ gitea.sha }}
- name: Build & push frontend image
uses: docker/build-push-action@v6
with:
context: ./frontend
push: true
tags: |
${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE }}:dev
${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE }}:${{ gitea.sha }}
+268
View File
@@ -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.<name>.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 |
+11
View File
@@ -0,0 +1,11 @@
FROM catthehacker/ubuntu:act-latest
# Install Go 1.23
RUN curl -sL https://go.dev/dl/go1.23.6.linux-amd64.tar.gz | tar -C /usr/local -xz
# Install Node 22
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
ENV PATH="/usr/local/go/bin:${PATH}"
+72
View File
@@ -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:
+42
View File
@@ -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
+88
View File
@@ -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 "$@"