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.

deckgauge · docker compose
web :3000
api :3001
postgres :5433
redis :6379
clickhouse :8123
keycloak :8080

Runtime dependency chain — everything below web ultimately answers to it.

What each service does

ServicePort(s)What it does
web3000Next.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.
api3001Fastify 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.
workernone publishedBullMQ 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.
postgres5433 → 5432Postgres 16, database cockpit. Boards, groups, statuses, sync state, and users all live here.
redis6379Redis 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.
clickhouse8123 (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-db8080Identity — 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 /health endpoint 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 downweb stays up but every board and widget shows an error, since web has 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

SymptomCauseFix
Widgets and dashboards are empty but boards work fineClickHouse is down or unreachableCheck docker compose ps clickhouse and its logs; boards keep working independently
Sync never picks up new Jira/GitHub/GitLab/ADO dataThe worker or Redis is downCheck both containers — the worker depends on Redis being healthy
A container keeps restarting under loadIt's hitting its memory limitSee Troubleshooting for the worker's OOM pattern specifically

Related

Last updated