Files
2026-05-27 23:29:53 +01:00

60 lines
3.0 KiB
Markdown

# Tasks: enterprise-api-plugin-sse
**Change ID**: enterprise-api-plugin-sse
**Package**: `@suaveplan/api-plugin-sse`
**Target path**: `api/data/api-plugin-sse`
**Prerequisite packages on Verdaccio**: `@suaveplan/api`, `@suaveplan/api-shared`, `@suaveplan/api-plugin-auth`, `@suaveplan/events`, `@suaveplan/rate-limiter`, `@suaveplan/error`
---
## 0. Pre-flight (non-negotiable)
- [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each)
- [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
- [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
## 1. Scaffold + types + errors + events
- [ ] Create directory; `package.json` v0.0.0; standard tooling.
- [ ] Types: `SseEvent`, `SseConnection`, `SsePluginConfig` (Zod).
- [ ] Errors: 3-code union + registration. Test + doc.
- [ ] Events: `SsePluginEventMap` (sse:client:connected, sse:client:disconnected).
---
## 2. Connection manager
- [ ] `ConnectionManager`: `Map<clientId, SseConnection>` keyed by `userId:topic`. On connect: auth check, rate-limit, max-connections check; create connection; start heartbeat. On disconnect: remove + emit event.
- [ ] Heartbeat: send `event: ping` every `heartbeatIntervalMs` (default 30 s); connection dropped if client disconnects.
- [ ] Backpressure: bounded send queue per connection; drop oldest on full.
- [ ] `connection-manager.test.ts` + `connection-manager.md`.
---
## 3. SseService
- [ ] `publish(topic, event)` — fan out to all connections subscribed to `topic`; encode as SSE wire format (`data: ...\n\n`).
- [ ] `broadcast(event)` — fan out to all connections.
- [ ] `connectionCount()`, `getTopicConnectionCount(topic)`.
- [ ] Subscribe to `@suaveplan/events` bus topics in `onInit`; forward to matching SSE connections.
- [ ] OTel gauge `sse.connections_active`; counter `sse.events_sent_total`.
- [ ] `sse.service.test.ts` + `sse.service.md`.
---
## 4. Routes
- [ ] `GET /sse/stream?topic=...` — `requireAuth`; returns SSE stream (Hono `streamSSE`). Rate-limited on connections.
- [ ] `GET /sse/stats` — admin; returns connection counts.
- [ ] Route `.test.ts` + `.md`.
---
## 5. Plugin factory + integration tests + publish
- [ ] `createSsePlugin`: `definePlugin`, `dependencies: ["auth"]`; subscribe to bus in `onInit`; detach in `onClose`.
- [ ] Integration: connect client → publish event via bus → received by SSE stream.
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/api-plugin-sse` — green; 100% coverage.
- [ ] `bun scripts/publish.ts --package @suaveplan/api-plugin-sse`.
- [ ] Archive → `openspec/archive/2026-04-24-enterprise-api-plugin-sse/`.