# M13 — Meta Plan (milestone grouping) > Companion to `M13_FRONTEND_SPEC.md`. This is the cross-milestone > plan; per-milestone detail lives in `M13a_PLAN.md`, `M13b_PLAN.md`, > `M13c_PLAN.md`. **Status:** planning (post-M11, parallel to M12) **Goal:** ship a v1 multi-tenant admin UI that replaces `dlq.html` and adds CRUD + live-tail + audit + auth surfaces, in a single `admind` Go binary that embeds a Vite+React 19 SPA. --- ## 0. Why milestones, not one big plan The original M13 plan (workstream-as-primary-axis, 9 workstreams) assumed one engineer ships end-to-end. In practice you stop and review between surfaces — and you want each stop to be a **shippable artifact**, not "we have some auth working but no UI yet". The milestone split lets you: | Stop after | What you have | Why stop here | |---|---|---| | **M13a** | authd + web skeleton + login works | "Is the design right? Is the auth model right? Is the SPA architecture right?" — review before committing to feature work. | | **M13b** | Companies + Sources + Telegram CRUD | ~80% of operator value. The customer can self-onboard, set up sources, configure telegram. Live tail + DLQ + audit can wait. | | **M13c** | Live tail + DLQ + Audit + K8s + E2E | Full v1. Replaces `dlq.html`, ships Playwright gate, K8s-ready. | Each milestone flips one SPEC.md row. Each has its own `M13x_PLAN.md` with workstreams, estimates, and per-milestone DoD. --- ## 1. Milestone overview ``` ┌──────────────┐ │ M13.0 spec │ (this PR — no code) │ + API │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ M13a │ ~5-6 days │ authd + │ │ web shell │ │ + JWT gate │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ M13b │ ~7-8 days │ CRUD: │ │ Companies │ │ Sources │ │ Telegram │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ M13c │ ~7-9 days │ Live tail │ │ DLQ │ │ Audit │ │ K8s │ │ Playwright │ └──────────────┘ ``` **Total estimate: ~19-23 days with one engineer.** Can be parallelized with a second engineer at M13b (one on Companies, one on Sources). --- ## 2. Milestone summaries ### M13.0 — Spec & API contract - `M13_FRONTEND_SPEC.md` - `M13_API_CONTRACT.md` - No code. This PR. **No DoD beyond "specs reviewed and committed".** ### M13a — authd + web skeleton + JWT gate - `cmd/authd/` — JWT IdP service on :8804, all 7 endpoints. - `web/` — Vite + React 19 + shadcn/ui + TanStack Query + RHF + Zod. Login page works end-to-end. Other routes render "coming soon". - `admind` modified to require JWT on all `/v1/*` endpoints (except `/health`, `/metrics`). - Plan: `M13a_PLAN.md`. ### M13b — CRUD - Companies: list, detail, create, edit, suspend (super); read-only (tenant). - Sources: list, detail, create, edit, rotate secret, suspend. One-time secrets modal. - Telegram: bot config, invite codes, bindings list. - All forms validate; audit log writes; error toasts. - Plan: `M13b_PLAN.md`. ### M13c — Ops surface + K8s + E2E - Live tail: SSE feed, filter bar, drill-in modal, pause-on-scroll. - DLQ: list, detail, replay, discard. Replaces `dlq.html`. - Audit log viewer. - K8s manifests for `admind` and `authd` (carry from M12 W1). - Playwright E2E happy path green in CI. - Plan: `M13c_PLAN.md`. --- ## 3. Cross-cutting concerns These live in the spec but are operationally tested in M13c: - **Single binary:** `admind` embeds the SPA via `embed.FS`. Target size: < 60 MB. - **No CORS:** SPA is served by `admind` itself. `authd` is same-origin via service discovery. - **OpenAPI client gen:** `pnpm run gen:api` in CI on every Go API change. Type drift fails the PR. - **Tenant isolation:** backend enforces `WHERE company_id = $1` for tenant-admins. Tested in Playwright with a cross-tenant 403 check. - **Audit immutability:** every state-changing call writes to `audit_log`. The viewer is read-only. --- ## 4. Dependencies | From | What | Status | Affects | |---|---|---|---| | M11 | gRPC ingest stable, F2 publish counter | ✅ done | M13c (live tail source) | | M12 W1 | K8s manifests for `admind` and `authd` | ⏳ in flight | M13c W7 (K8s manifests) | | Postgres | `auth` schema + tables | to be created in M13a W1 | M13a | | Redis | rate-limit counters for `authd` login | ✅ already in stack | M13a | | NATS | `tailhub` for in-memory SSE feed (M13c) | ✅ already exists | M13c | | SMTP (optional) | magic-link email | NOT required for v1 (psql fallback) | M13a (best-effort) | --- ## 5. Parallelism with M12 | When | What runs in parallel | |---|---| | M13a W1-W2 | M12 W1 (K8s manifests) — independent | | M13b W1-W3 | M12 W2 (NATS cluster) — independent | | M13c W7 | M12 W3-W4 (Helm + 50k/s bench) — blocks K8s manifest merge | M13 does not block M12. M12 W5 (M11 prod gate on K8s) is independent of M13. The two milestones converge at "single PR that ships v1 with K8s + frontend" but the workstream branches don't have to. --- ## 6. Definition of done — whole M13 - [ ] All 3 sub-milestones (M13a, M13b, M13c) have their individual DoD checked. - [ ] `cmd/authd/` exists, builds, runs, healthy on :8804. - [ ] `cmd/admind/` builds with embedded SPA, < 60 MB. - [ ] Playwright happy-path green in CI for 3 consecutive runs. - [ ] Tenant-isolation 403 test green in CI. - [ ] `M13_VERIFICATION.md` published with: screenshots of the 6 modules, the Playwright run log, the tenant-isolation test, the binary size, and the bundle breakdown. - [ ] SPEC.md `M13a`, `M13b`, `M13c` rows flipped to **✅ shipped YYYY-MM-DD**. - [ ] `cmd/admind/ui/dlq.html` removed. - [ ] Demo to a real customer (or internal stakeholder) and signed off. --- **Next step:** commit the 3 docs from M13.0, then start M13a W1 (`authd`).