Skip to main content

Deployment Architecture

:::info Status Implemented. Source: docker-compose.yml, Caddyfile, DEPLOY.md. :::

Production runs as a fixed set of Docker Compose services on one server, fronted by Caddy for TLS termination and routing.

Compose services

ServiceRole
postgresDatabase, pod-network only, no published port to the internet
website, admin-panel, super-admin-panel, documentation-siteNginx serving each frontend's production build
migrateOne-shot: runs alembic upgrade head, must exit 0 before fastapi-backend starts (service_completed_successfully dependency) — migrations never run at app startup
fastapi-backendThe backend, Uvicorn on :8082
emqxSelf-hosted MQTT broker for device control
icecastAudio streaming server — no published host port; only reachable through Caddy's /stream/* route
otel-collector, tempo, prometheusObservability pipeline — all internal-only, no published host port
grafanaTraces/metrics viewer for the above — the one service in that group actually reached by a person, via its own subdomain (grafana.azan360.com)

Release process

Deployments are triggered by git tags (semantic versioning, v<major>.<minor>.<patch>), via a GitHub Actions workflow that SSHs into the server:

Manual trigger is also available (Actions → Deploy → Run workflow, optional tag input; empty deploys the latest tag).

Rollback

# Deploy an older tag

Re-running the same deploy flow against an earlier tag rolls the containers back; database migrations are forward-only (see Database — migrations), so a rollback that depends on reverting schema changes needs a manually written down-migration — check DEPLOY.md §Rollback before assuming a tag rollback alone is sufficient.

Full operational detail

Broker sizing/HA, stream-gate rollout, recipient fan-out rollout, certificate renewal, and troubleshooting live in Deployment and Operations — this page covers only the static topology.