postgres
Always-on app database.
infra-compose
infra/compose composes apps/api and apps/ui into one running
stack. It targets your laptop and a first VPS before you need cluster
machinery, while keeping observability, email, and queue tooling close to the
app.
Compose
local and single-host runtime
Traefik
prod ingress and TLS
Overlays
observability, mail, queues
The base stack (always on) plus per-profile services:
Always-on app database.
Redis-protocol cache plus BullMQ queue backend.
Prod reverse proxy, ACME, and one-domain path routing.
One-shot schema push plus optional superuser seed.
Bun + Elysia in dev, GHCR image in production.
Vite dev server locally, nginx static image in production.
Prometheus, Grafana, Loki, Promtail, and exporters on demand.
Mailpit, Bull Board, GlitchTip, and WUD are profile overlays.
$ ./dev.sh up -d
$ STACK=prod ./dev.sh up -d
$ WITH_OBSERVABILITY=1 ./dev.sh up -d
$ WITH_GLITCHTIP=1 ./dev.sh up -d
$ WITH_BULLMQ=1 ./dev.sh up -d
$ WITH_WUD=1 ./dev.sh up -d
$ WITH_MAILPIT=1 ./dev.sh up -d
# baseline dev: no Traefik; Vite proxies /api/*
# prod: GHCR images, Traefik, HTTPS via ACME
# overlays: metrics, logs, error tracking, queues, mail, image updatesFlags compose: WITH_OBSERVABILITY=1 WITH_GLITCHTIP=1 ./dev.sh up -d brings up both overlays alongside the base. See Profiles & overlays.
Two bridge networks. Services are split on purpose:
backend
postgres, valkey, api[-dev], api-migrate, exporters, glitchtip, and mailpit.
frontend
traefik in prod, ui[-dev], and glitchtip-web. Traefik joins both when it needs to route.
In prod, Traefik joins both networks so it can route HTTPS from frontend to services on backend. The data plane (Postgres, Valkey) is never exposed to frontend.
Every service has deploy.resources.limits and reservations driven by env vars with sane defaults sized for a 4-vCPU / 8 GB host. Adjust in compose/.env; see Resource limits for sizing guidance.
infra/bootstrap handles that.WITH_*=1 flags compose over the base.