# Phase 2 — Surface B: cluster topology ~3 days. Proves the snapshot + SSE pipeline end to end. ## RED - [ ] `stream_test.go` — SSE emits a delta within 5s of a pod state change - [ ] `topology.test.tsx` — graph re-renders on delta without a full reload - [ ] `topology.e2e.ts` (Playwright, hard requirement) — load `/topology`, assert graph nodes render, delete a pod, assert node count updates without reload ## GREEN - [ ] `GET /api/topology` — nodes, namespaces, workload summaries; envelope `{"data": {}, "meta": {"snapshotAge", "generation"}}`; capped 256 KB, `meta.truncated: true` on overflow, never a silent drop - [ ] `GET /api/stream` — SSE, session cookie, 2 concurrent/IP, `topology` event type; keepalive comment frame every 30s; `Last-Event-ID` supported for resumable deltas - [ ] Frontend: React Flow, force layout, node → namespace → workload - [ ] Security headers on all responses: CSP (no `unsafe-inline`), `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`, HSTS; CORS same-origin only - [ ] Rate limiting Tier 1 (Cloudflare edge — WAF, Bot Fight Mode, per-IP rules) + Tier 2 (Kong `rate-limiting`, `policy: redis`, generous profile for topology) ## REFACTOR - [ ] `simplify` pass on SSE handler + React Flow wiring ## Verify ```bash # delete a pod, observe graph update in <5s without reloading kubectl delete pod -n pnpm test:e2e topology.e2e.ts # required, must pass before merge ``` Next: [04-phase3-delivery.md](04-phase3-delivery.md)