Deployment
Deployment
Section titled “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.
Environments
Section titled “Environments”| 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 |
Blue-green model
Section titled “Blue-green model”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 validation2. Database migration (with automatic pre-migration backup)3. Build + start the INACTIVE slot4. Health checks on the new slot5. Canary traffic shifting (5% → 25% → 50% → 100%)6. Old slot stopped after a grace periodRollback = switch traffic back to the still-running previous slot.
Triggering a deployment
Section titled “Triggering a deployment”- Merging a PR to
mastertriggers the CD workflow automatically. - Fallback: manual
workflow_dispatchof the CD workflow. - Never deploy manually on the host — the workflow is the only supported path (auditability, consistent steps).
Health checks
Section titled “Health checks”The API exposes liveness and readiness endpoints (see
API Reference — GET /api/health/liveness and
GET /api/health/readiness). Readiness verifies the database
connection; the CD pipeline gates traffic switching on it.
Secrets & storage
Section titled “Secrets & storage”- 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.
Post-deployment verification
Section titled “Post-deployment verification”Standard checks after every deployment:
- All containers up; database and cache healthy.
GET /api/health/livenessand/api/health/readiness→ok.- Security headers present (HSTS, CSP without
unsafe-eval,X-Frame-Options: DENY,X-Content-Type-Options: nosniff, noX-Powered-By). - ZAP baseline scan — expected: no new findings.
Database migrations
Section titled “Database migrations”- Migrations run through Prisma (
migrate deploy) inside the CD pipeline — never by hand against production. - A database backup is taken automatically before each migration.