The services and how they fit together
Eight containers make up a Deckgauge stack. This page is the map: what each one does, which host port it publishes, and what actually stops working when it's down.
Runtime dependency chain — everything below web ultimately answers to it.
What each service does
| Service | Port(s) | What it does |
|---|---|---|
web | 3000 | Next.js server — the board UI. It's a standalone server that retries the API at request time, so it only waits for the api container to start, not pass its health check. |
api | 3001 | Fastify REST API + Prisma. Verifies every request's Keycloak JWT, and is the only service that talks to Postgres, Redis, and ClickHouse on the web app's behalf. Like worker, it runs its TypeScript source directly via tsx rather than a compiled build. |
worker | none published | BullMQ host for the sync queues — Jira, GitHub (three-tier hot/warm/cold sync plus its own intelligence queue), GitLab, and Azure DevOps (plus its own intelligence queue) — as well as org-tree, org-source, and calendar-source sync, and daily sync-run pruning. Runs its TypeScript source directly via tsx, the same as api. |
postgres | 5433 → 5432 | Postgres 16, database cockpit. Boards, groups, statuses, sync state, and users all live here. |
redis | 6379 | Redis 7, backing the worker's BullMQ queues. Capped at 384MB max memory with noeviction so a full queue fails loudly rather than silently dropping jobs. |
clickhouse | 8123 (HTTP), 9000 (native) | Analytics store for engineering-intelligence data — Jira/GitHub/GitLab/ADO issues, PRs, transitions, and commits feed the DORA, flow, and ranking widgets. |
keycloak / keycloak-db | 8080 | Identity — OIDC realm, clients, and its own dedicated Postgres database, separate from cockpit. |
What breaks when one is down
- Postgres down — nothing works: boards, sync state, and auth-user lookups all read from it. The API's own
/healthendpoint doesn't check Postgres, though — it returns a static "ok" regardless, so a green health check during a Postgres outage isn't proof the API can actually serve a request. - Redis down — the worker can't process its queues; sync jobs (Jira, GitHub, GitLab, ADO) stop advancing, but the board itself keeps serving from Postgres.
- ClickHouse down — engineering-intelligence widgets and dashboards fail to load; boards, statuses, and manual editing are unaffected since they never touch ClickHouse.
- Keycloak down — no one can sign in or refresh a session; anyone already signed in keeps working until their token needs to be re-verified.
- api down —
webstays up but every board and widget shows an error, sincewebhas no direct path to Postgres, Redis, or ClickHouse. - worker down — the board and dashboards keep serving whatever data already synced; nothing new arrives from Jira, GitHub, GitLab, or Azure DevOps until it's back.
Under the hood
Every service in docker-compose.yml carries a hard memory limit (deploy.resources.limits.memory), sized from real incidents rather than guesswork — for example the worker's cap grew from 384M to 768M after large Azure DevOps projects were repeatedly cgroup-killed mid-sync. docker-compose.phase3.yml is a separate overlay that remaps every port so a second, parallel stack (deckgauge-next) can run alongside the main one for staging engineering-intelligence work — it isn't part of a normal single-stack install.
If it looks wrong
| Symptom | Cause | Fix |
|---|---|---|
| Widgets and dashboards are empty but boards work fine | ClickHouse is down or unreachable | Check docker compose ps clickhouse and its logs; boards keep working independently |
| Sync never picks up new Jira/GitHub/GitLab/ADO data | The worker or Redis is down | Check both containers — the worker depends on Redis being healthy |
| A container keeps restarting under load | It's hitting its memory limit | See Troubleshooting for the worker's OOM pattern specifically |
Related
- Install & first run — bringing the whole stack up for the first time.
- Configuration reference — every variable each service reads.
- Troubleshooting — resource limits and crash-loop patterns evidenced in the repo.
Last updated