Third and final sub-milestone of M13. Delivers the ops surface (live tail, DLQ, audit), the K8s manifests, and the Playwright E2E gate. After this lands, M13 v1 is done.
Status: planning (post-M13b)
Target: M13_FRONTEND_SPEC.md §4.3
Estimate: 7-9 days with one engineer
cmd/admind/ui/dlq.html).admind and authd (carry from M12 W1).M13_VERIFICATION.md with screenshots + run logs.M13c row flipped to ✅.What M13c is NOT:
┌──────────────────────────┐ ┌──────────────────────────┐
│ W1: Live tail (SSE) │ │ W2: DLQ surface │
│ (filter bar, drill-in, │───▶│ (replaces dlq.html, │
│ pause-on-scroll) │ │ replay + discard) │
└──────────────┬───────────┘ └──────────────┬───────────┘
│ │
▼ ▼
┌──────────────────────────────────────────────────────────────┐
│ W3: Audit log viewer (read-only, filterable) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ W4: K8s manifests (admind + authd) + ConfigMap + Secret │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ W5: Playwright E2E + CI pipeline + M13_VERIFICATION.md │
└──────────────────────────────────────────────────────────────┘
Five workstreams. W1 → W2 → W3 → W4 → W5. W4 (K8s) is independent of W1-W3 and can start in parallel. W5 is the final gate.
Goal: Real-time feed of inbound alerts. Filterable. Drill-in modal.
Scope:
/tail.web/src/features/tail/.TailFeed, TailFilterBar, TailRow, TailDetailModal,
SSEStatusBadge.EventSource with ?access_token=*** query
param (workaround for EventSource's lack of custom headers)./v1/tail/recent?since=<ts> every
5s.Exit criteria:
loadgen sends 1 alert → appears in live tail within 2s.Estimated: 2-3 days.
dlq.html)Goal: Replace cmd/admind/ui/dlq.html with the new SPA. Same
list/replay/discard flow, plus filters.
Scope:
/dlq, /dlq/:id.web/src/features/dlq/.DLQList, DLQDetail, DLQReplayDialog,
DLQDiscardDialog (typed confirmation).type "discard" to confirm), audit
row written.cmd/admind/ui/dlq.html and remove the old GET /dlq
handler from cmd/admind/main.go (SPA fallback now serves the
new DLQ page).Exit criteria:
ba_deliverd_attempts_total{result=ok} increments).status=discarded.dlq.html file deleted from cmd/admind/ui/.GET /dlq handler in admind removed.Estimated: 2-3 days.
Goal: Read-only table of audit_log rows, filterable.
Scope:
/audit.web/src/features/audit/.AuditList, AuditDetailModal (expanded JSON
metadata).GET /v1/audit in cmd/admind/main.go.
Reads from the audit_log table that M9 already created.SELECT ... FROM audit_log WHERE company_id = $1 ORDER BY
ts DESC LIMIT $2 OFFSET $3 (super-admin passes company_id query
param; tenant-admin forced to own).Exit criteria:
ingestd, routerd, deliverd,
admind actions all visible.Estimated: 1-2 days.
Goal: K8s manifests that bring up admind and authd alongside
the rest of the M12 stack. Carry-over from M12 W1 with M13-specific
additions (authd Service, JWT secret Secret).
Scope:
deploy/k8s/base/admind/:
deployment.yaml — 2 replicas, resource limits, env from
ConfigMap + Secret.service.yaml — ClusterIP, ports 8803 (HTTP) + 9090 (gRPC,
unused by frontend but kept for parity).configmap.yaml — BA_HTTP_ADDR, BAPG, BANATS.pdb.yaml — minAvailable: 1.deploy/k8s/base/authd/:
deployment.yaml — 2 replicas, env from Secret.service.yaml — ClusterIP, port 8804.configmap.yaml — BA_AUTHD_HTTP_ADDR, BA_AUTHSMTP*.secret.yaml.example — BA_AUTH_JWT_SECRET (real one gitignored).pdb.yaml — minAvailable: 1.deploy/k8s/base/kustomization.yaml updated to include both.deploy/k8s/README.md — quickstart, secret-rotation note.Exit criteria:
kubectl apply -k deploy/k8s/base/ brings up admind and
authd alongside the rest.kubectl get pods -n broad-announce shows both Running +
Ready.kubeconform (or
kubectl apply --dry-run=server).admind binary size < 60 MB.deploy/k8s/README.md documents the quickstart and the
JWT-secret rotation procedure.Estimated: 1 day (most of the templates already exist from M12 W1).
Goal: Single Playwright happy-path test that runs in CI.
Final M13_VERIFICATION.md with screenshots.
Scope:
web/tests/e2e/happy-path.spec.ts:
web/playwright.config.ts — chromium only, base URL from env.scripts/m13_e2e.sh — wraps the Playwright run, brings up
docker-compose, runs, teardown (no -v, learned from M11)..github/workflows/m13-e2e.yml (or GitLab CI equivalent) — runs
the smoke on every PR that touches cmd/** or web/**.M13_VERIFICATION.md:
Exit criteria:
M13_VERIFICATION.md published.M13a, M13b, M13c rows all flipped to
✅ shipped YYYY-MM-DD.Estimated: 1-2 days.
W1 (2-3d) ──┐
├──▶ W2 (2-3d) ──▶ W3 (1-2d) ──▶ W5 (1-2d)
│
W4 (1d) ────┴── (parallel with W1-W3, joins W5 at the end)
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| SSE through corporate proxy | Medium | Medium | HTTP fallback (/v1/tail/recent) is in the API; UI has a "use polling" toggle |
| Playwright flakes in CI | Medium | Medium | Retry once on failure; isolate test data per run (unique company slug with timestamp) |
dlq.html removal breaks a customer who's bookmarked it |
Low | Low | Note in release notes; old URL → new SPA /dlq route |
| Audit log volume overwhelms the list | Medium | Low | Server-side pagination (25/50/100); filters required for >1k rows |
| K8s manifest drift from M12 W1 | Medium | Low | Reuse M12 templates; W4 PR diff'd against M12 W1 to catch unintended changes |
| Single binary size > 60 MB | Low | Low | Per-feature code splitting; gzip embed; CI size gate |
cmd/admind/ui/dlq.html removed.GET /dlq handler in admind removed.admind binary size < 60 MB.admind and authd
Running.M13_VERIFICATION.md published.M13a, M13b, M13c rows all flipped to
✅ shipped YYYY-MM-DD.M13 row (top-level) updated to ✅ shipped
YYYY-MM-DD with a one-line summary linking to M13a/b/c
VERIFICATION docs.Next step: M13c W1 (Live tail). W4 (K8s) can start in parallel from a separate branch.