Observability — Read-Model / Projector (RFC-003 Phase 0)
Grafana dashboards and wiring notes for the read-model observability stack introduced in GOO-192 under GOO-94 §6 Phase 0.
Metrics
All metrics live in the existing NestJS metrics/ module
(apps/api/src/modules/metrics/) and are scraped via the standard /metrics
endpoint.
| Metric | Type | Labels | Purpose |
|---|---|---|---|
read_model_projector_lag_seconds |
Gauge | handler |
Seconds between latest source event and projector cursor. |
read_model_refresh_duration_seconds |
Histogram | view |
Duration of read-model / materialised view refreshes. |
read_model_reconciliation_drift_total |
Counter | model |
Count of drift discrepancies found during reconciliation. |
Emit points
Inject MetricsService and call:
metrics.setProjectorLag(handler, lagSeconds);
metrics.recordReadModelRefresh(view, durationSeconds);
metrics.recordReconciliationDrift(model, count?);
Dashboard
- File:
read-models-dashboard.json(Grafana schema v38). - Import into Grafana (
Dashboards → Import → Upload JSON), pick the Prometheus data source. - Variables:
handler,view,model— derived from Prometheus label values. - Panels:
- Projector lag by handler (time series + thresholded)
- Max projector lag (stat, RAG 30s / 120s)
- Refresh duration p50/p95 by view
- Refresh throughput (refreshes/sec) by view
- Reconciliation drift rate by model (15m rate)
- Total drift events in last 24h (stat, RAG 1 / 10)
Local verification
pnpm --filter @goodgo/api dev
curl -s http://localhost:3001/metrics | grep read_model_
All three metric families should appear with # HELP / # TYPE headers even
before any samples are recorded.