Skip to content

SCRUM-230 — Dashboard: observability stack in compose

Plan ref: DSH-A1–A4 (docs/11-admin-plane-plan.md), decision D7. Stacked on SCRUM-242.

What exists

Service (image, memory limit) Notes
prometheus (prom/prometheus:v3.15.0, 200 MB) observability/prometheus.yml, 15 s scrape, 7 d / 2 GB retention, prometheus-data volume; every Go service's :9090 plus the exporters, each target labelled service: <compose name>
loki (grafana/loki:3.7.8, 150 MB) single binary, filesystem on loki-data, tsdb v13, 72 h retention via the compactor
alloy (grafana/alloy:v1.20.0, 100 MB) Docker discovery (socket read-only; root-equivalent read access, accepted per doc 01) for this project only; service from the compose service label; JSON level lower-cased (warning → warn); only service and level survive as stream labels
node_exporter (v1.9.1, 30 MB), cadvisor (v0.52.1, 80 MB), postgres_exporter (v0.17.1, 30 MB) host, per-container and Postgres metrics; postgres_exporter uses a new pg_monitor role provisioned idempotently (password generated like the others, filled into an existing .env)

Total limits 590 MB; no published ports (asserted by check-compose.sh, with the memory limits and data volumes). Every service label, Alloy's log label and the Dashboard's prober target use the compose service name (admin-auth), so the Dashboard sees one identity per service (needs the SCRUM-239 target-name change).

How to verify

cd deploy
promtool check config observability/prometheus.yml
alloy fmt observability/config.alloy >/dev/null
loki -config.file=observability/loki.yml -verify-config
sed 's/^\([A-Z_]*PASSWORD\)=$/\1=x/' .env.example > /tmp/t.env
docker compose --env-file /tmp/t.env -f compose.yaml config --quiet && sh scripts/check-compose.sh /tmp/t.env
sh scripts/test-provision.sh && sh scripts/test-generate-secrets.sh

Results at time of writing

  • promtool 3.15.0, alloy v1.20.0 fmt, loki 3.7.8 -verify-config: pass.
  • compose config, check-compose, test-provision (now incl. pg_monitor isolation), test-generate-secrets: pass. All six image tags confirmed to exist in their registries.
  • Not yet run on a VM: "every :9090 scraped, logs queryable by service and level, data survives restart" needs a Docker host (after SCRUM-244's sign-off).

How it was built

DeepSeek run scoped (Landlock) to deploy (256 s, ~38k output tokens, reasoning effort low). Claude review: validated the configs with the real binaries, checked every pinned tag, and unified the service identity: the prober target was named admin_auth while Prometheus and Loki used admin-auth, which would have listed admin-auth twice on the overview.