Skip to content

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.