SCRUM-232 — Dashboard service foundation and token re-verification¶
Plan ref: DSH-C1/C2 (docs/11-admin-plane-plan.md). Replaces the fmt.Println stub
in services/dashboard (module path fixed to
github.com/tanukifurhire/otomo/services/dashboard).
What exists¶
Ported from services/config (guard and verifier identical apart from comments):
| Piece | Notes |
|---|---|
dashboard serve |
no database — Dashboard is a query layer over Prometheus/Loki and other services' REST |
Config DASHBOARD_* |
listen/metrics, staff JWKS URL/issuer/audience/refresh, clock skew, DASHBOARD_PROMETHEUS_URL (http://prometheus:9090), DASHBOARD_LOKI_URL (http://loki:3100), DASHBOARD_UPSTREAM_TIMEOUT (2s), timeouts, log level |
| Route table (doc 01 §4), all viewer, all 501 for now | GET /api/admin/dashboard/{overview, services, services/{name}/series, logs, logs/tail, audit} behind the same handler seam as Config, so later tickets replace one route at a time |
| Guard | staff token re-verified in-service (defence in depth); also on the fallback, so the surface is not enumerable anonymously |
internal/source |
MetricsSource (Instant/Range/Targets) and LogSource (Query/Tail) interfaces the Prometheus/Loki tickets implement |
/readyz |
staff JWKS keys only — a down Prometheus or Loki must degrade panels, not take the Dashboard out of rotation |
dockerfile, .env.example, README.md |
distroless nonroot |
How to verify¶
cd services/dashboard
go vet ./... && go test -race -count=1 ./...
go build -o /tmp/dashboard . && DASHBOARD_STAFF_JWKS_URL=http://127.0.0.1:18180/.well-known/jwks.json /tmp/dashboard &
curl -i localhost:8080/api/admin/dashboard/overview # 401 missing_token (viewer token → 501)
curl -i localhost:8080/nope # 401 too: the fallback is guarded
curl -i localhost:9090/readyz # 503 until JWKS keys arrive
Server tests cover: no token 401 on every route and on an unknown path;
player-issuer token 401; staff token without roles 403; viewer 501 on every route;
viewer on an unknown path 404; wrong method 405 with Allow; internal endpoints only
on the internal listener; readyz 503 → 200 once keys load.
Results at time of writing¶
go vet,go test -race(4 packages): pass. Binary checked as above.
How it was built¶
DeepSeek run scoped (Landlock) to services/dashboard (196 s, ~40k output tokens).
Claude review: guard and verifier diffed against Config; binary run. No changes needed.