Project Structure
Directory layout and key files in the Savannah Cloud monorepo.
distributed-task-queue/
├── cmd/server/main.go # Entry point — wires all services, registers job handlers
├── dashboard/
│ └── src/
│ ├── components/ # Sidebar, AppShell, UI primitives (Button, Input, Badge, Toast)
│ ├── context/ # AuthContext
│ ├── lib/ # api.ts — typed API client
│ └── pages/ # Dashboard, Deployments, Pipelines, Domains,
│ # Email, SMS, Team, Billing, APIKeys, Settings,
│ # Login, Join
├── api.go # HTTP router + all handlers
├── auth.go # JWT, bcrypt, API key, session helpers
├── deploy.go # Deployment engine (framework detection, Docker build/run)
├── dns.go # Custom domain handlers + background DNS verifier goroutine
├── email.go # send_email job handler (Resend)
├── sms.go # send_sms job handler + /sms/send handler (Africa's Talking)
├── mcp.go # MCP server (JSON-RPC 2.0 + SSE)
├── metrics.go # Prometheus counters
├── postgres.go # All PostgreSQL queries (jobs, orgs, users, domains, deployments)
├── session.go # Redis session engine (sliding 30min TTL, HttpOnly cookie)
├── worker.go # Worker pool (BLPOP, retry, backoff)
├── redis_queue.go # Redis queue implementation
├── docker-compose.yml # 5-service stack (app, dashboard, postgres, redis, pdns)
├── Dockerfile # Multi-stage Go + Node build
├── pg_hba.conf # Custom postgres auth rules (trust for Docker network)
├── pdns.conf # PowerDNS configuration
└── fix_scram.sh # One-shot postgres SCRAM password reset scriptKey Files
cmd/server/main.go
Entry point. Wires together all services and registers job handlers:
pool.Register("send_email", emailHandler)
pool.Register("send_sms", smsHandler)
pool.Register("webhook", webhookHandler)
pool.Register("deploy", deployHandler)Add custom handlers here.
api.go
HTTP router using net/http. All route registrations and handler functions. Organized by domain: auth, jobs, deployments, domains, SMS, MCP, usage, team, API keys.
postgres.go
All database queries — no ORM. Uses pgx/v5 with named structs. Each domain (jobs, orgs, deployments, etc.) has its own section.
worker.go
Worker pool with configurable concurrency (WORKER_COUNT, default 4). Each goroutine runs BLPOP with 5s timeout, processes the job, and handles retry logic.
deploy.go
Deployment engine. Detects framework from repo contents, runs the appropriate build command, creates a Docker container, assigns a port from 9100–9999, and injects the Savannah badge.
dns.go
Custom domain management. Creates PowerDNS zones via REST API and runs the background verifier goroutine on a 5-minute ticker.
mcp.go
MCP server. Implements tools/list and tools/call over JSON-RPC 2.0. SSE stream for real-time events.
pg_hba.conf
Custom PostgreSQL auth rules. Tracked in the repo and mounted read-only into the postgres container:
# Docker network — trust (no password needed)
host all all 172.0.0.0/8 trust
# External connections — scram-sha-256
host all all 0.0.0.0/0 scram-sha-256fix_scram.sh
One-shot script to reset the PostgreSQL SCRAM password hash if auth fails after a container rebuild. Run from the server:
bash fix_scram.shDashboard Pages
| Page | File | Description |
|---|---|---|
/dashboard | pages/Dashboard.tsx | Live job feed, WebSocket, quick stats |
/deployments | pages/Deployments.tsx | App deployments, logs, env vars |
/pipelines | pages/Pipelines.tsx | CI/CD pipeline view |
/domains | pages/Domains.tsx | Custom domain management |
/email | pages/Email.tsx | 3-column email compose UI |
/sms | pages/SMS.tsx | SMS compose + history |
/team | pages/Team.tsx | Members, invite, roles |
/billing | pages/Billing.tsx | Plan, usage, Paystack |
/api-keys | pages/APIKeys.tsx | Create/revoke API keys |
/settings | pages/Settings.tsx | Org settings |
/login | pages/Login.tsx | Sign in |
/join | pages/Join.tsx | Accept team invite |