Skip to content

Deployment

Production runs on a single Docker host with a blue-green deployment model, driven by a GitHub Actions CD workflow. Everything below is a high-level description — host-specific details are intentionally not part of this public documentation.

Environment Purpose
Local dev docker compose (PostgreSQL, Redis) + pnpm dev
Production Docker Compose on a dedicated host, behind a host-level nginx reverse proxy with Let’s Encrypt TLS

Two slots exist for API and web each (api-blue/api-green, web-blue/web-green). Only one slot receives traffic at a time; single-instance services (PostgreSQL, Redis, worker, ClamAV) are shared.

A deployment works like this:

1. Pre-deployment validation
2. Database migration (with automatic pre-migration backup)
3. Build + start the INACTIVE slot
4. Health checks on the new slot
5. Canary traffic shifting (5% → 25% → 50% → 100%)
6. Old slot stopped after a grace period

Rollback = switch traffic back to the still-running previous slot.

  • Merging a PR to master triggers the CD workflow automatically.
  • Fallback: manual workflow_dispatch of the CD workflow.
  • Never deploy manually on the host — the workflow is the only supported path (auditability, consistent steps).

The API exposes liveness and readiness endpoints (see API ReferenceGET /api/health/liveness and GET /api/health/readiness). Readiness verifies the database connection; the CD pipeline gates traffic switching on it.

  • Production secrets are Docker secrets backed by encrypted host storage — see Secrets Management.
  • New secrets must be synced to the host before deploying, or the affected container will not start.
  • The database volume and the secrets volume are encrypted at rest.

Standard checks after every deployment:

  • All containers up; database and cache healthy.
  • GET /api/health/liveness and /api/health/readinessok.
  • Security headers present (HSTS, CSP without unsafe-eval, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, no X-Powered-By).
  • ZAP baseline scan — expected: no new findings.
  • Migrations run through Prisma (migrate deploy) inside the CD pipeline — never by hand against production.
  • A database backup is taken automatically before each migration.