Docs/Architecture

Architecture

VersionGate is a Fastify API plus a background worker, backed by PostgreSQL via Drizzle ORM and Redis event pub/sub. It orchestrates the Docker CLI and rewrites Nginx upstreams to switch traffic atomically.

Deployment pipeline

Every deploy runs the same locked, crash-safe sequence:

pipeline
POST /api/v1/deploy { projectId }
  │
  ├─ Acquire lock          → 409 if a deploy is already running
  ├─ Git clone / pull      → fetch the configured branch
  ├─ Pick color & port     → ACTIVE=BLUE ? use GREEN : use BLUE
  ├─ DB: DEPLOYING         → crash-safety marker
  ├─ docker build          → versiongate-<name>:<timestamp>
  ├─ docker run            → <name>-blue | <name>-green
  ├─ Health check          → GET :port/health (retries + latency cap)
  │     ├─ PASS → Nginx upstream rewrite + reload
  │     └─ FAIL → stop + rm container, DB: FAILED
  ├─ DB: new=ACTIVE, old=ROLLED_BACK
  ├─ Stop + remove old container
  └─ Release lock (always)

Blue-green slots

Each environment owns two container slots. The active slot serves traffic on basePort or basePort + 1; deploys always target the idle one. Nginx flips the upstream only after the new container is confirmed healthy, so there is no moment where traffic hits a cold or broken build.

Status lifecycle

deployment status
PENDING → DEPLOYING → ACTIVE
                 │           │
                 └→ FAILED   └→ ROLLED_BACK (after next deploy or rollback)

Crash recovery

On startup, reconciliation finds any deployment stuck in DEPLOYING, stops and removes its containers, and marks it FAILED. Records marked ACTIVE are verified against docker inspect — if the container is not running, they are marked failed too. Only then does the engine accept requests.

Component overview
HTTP request → Fastify router → controller → service layer → Drizzle ORM + Redis (state/queue) + Docker CLI (build/run/stop) → Nginx (traffic switch). A job queue with a dedicated worker handles long-running deploys and streams logs to the dashboard over WebSockets.