5.7 KiB
5.7 KiB
Tasks — @suaveplan/api-plugin-campaigns
§0 Pre-flight (every dispatched agent, every chunk)
pwd && git worktree list && git status— confirm we are inside.claude/worktrees/agent-*and NOT in/home/paul/web/genesis/directly.- §0a Sync — fast-forward worktree to the orchestrator-supplied
EXPECTED_BASESHA; STOP ifgit merge-base --is-ancestorreturns non-zero.
§A Chunk A — foundation (this dispatch)
- A.1 Package shell —
package.json(@suaveplan/api-plugin-campaigns@0.1.0,"sideEffects": false, subpath exports per feature folder),vite.config.ts,vitest.config.ts,tsconfig.json+tsconfig.lib.json,tests/setup/polyfills.ts,README.md. - A.2
src/error-codes/—CAMPAIGNS_API_CODES(Chunk-A subset of the registered codes; B/C extend) +CampaignsApiErrorwith explicit public constructor. - A.3
src/otel/— meter binding + counter (campaigns_api.requests_total) + histogram (campaigns_api.request_duration_ms); cached + resettable. - A.4
src/types/—CampaignsPluginOptions,CampaignsPluginConfig. - A.5
src/schemas/—CampaignsPluginOptionsSchemaZod validator. - A.6
src/context/+src/services/— HonoContextVariableMapandServiceRegistrydeclaration-merge augmentations (Chunk-A baseline; B will add repo slots). - A.7
src/plugin/—createCampaignsPluginviadefinePluginfrom@suaveplan/api-plugin.onInitis a no-op Chunk-A-correct placeholder; documented inplugin.md. - A.8
src/index.ts— explicit named re-exports for Chunk-A surface. - A.9 Per-file
.mdsiblings with the six required sections. - A.10 Per-file
.test.tssiblings; runner imports from@suaveplan/testing/runneronly. - A.11 Verification gate green:
bunx turbo lint typecheck test --filter=@suaveplan/api-plugin-campaigns,bunx turbo test:coverage --filter=...100/100/100/100,bunx turbo build --filter=..., feature-layout check empty. - A.12
bun scripts/folder-reorg/generate-manifest.tsre-runs cleanly.
§B Chunk B — repositories (follow-up)
- B.1
src/repositories/campaign/—SurrealCampaignRepositoryimplementingCampaignStorefrom@suaveplan/campaigns; uses positional$p0placeholders against the genesisSurrealAdapter. The package also re-exportsInMemoryCampaignStorefrom@suaveplan/campaignsas the in-memory reference implementation. - B.2
src/repositories/suppression/— localCampaignSuppressionStoreinterface +SurrealCampaignSuppressionRepository+ referenceInMemoryCampaignSuppressionStore(tenant + channel shape; NOT a wrapper over@suaveplan/suppression, which is email-only). - B.3
src/repositories/delivery-events/— wrapper that consumes the already-shippedSurrealDeliveryEventStorefrom@suaveplan/delivery-tracking. (Out of scope for this dispatch per orchestrator's Chunk-B scope; rolls into a follow-up.) - B.4 Extended
CAMPAIGNS_API_CODESregistry — added six codes:CAMPAIGN_NOT_FOUND,SUPPRESSION_NOT_FOUND,INVALID_INPUT,DB_UNAVAILABLE,DUPLICATE_SUPPRESSION,TENANT_REQUIRED. - B.5 Bundled SurrealQL DDL strings. (Deferred to Chunk C; plugin's
applySchemaOnInitis wired there.) - B.6 Plugin
onInitregisters the repositories on theServiceRegistryand HonoContextVariableMap. (Deferred to Chunk C which owns the lifecycle; service-registry slots are reserved here as optional fields.) - B.7 100/100/100/100 coverage on the full package (Chunk A + Chunk B
modules); verified via
bunx turbo test:coverage.
§C Chunk C — routes (this dispatch)
- C.1
src/routes/campaigns/— 12 routes total: list/create/get/update/delete plus send/pause/cancel/duplicate/test action routes and stats/events reporting routes. State guard usesCampaignStateMachinefrom@suaveplan/campaigns; invalid transitions raiseCAMPAIGNS_API.INVALID_STATE_TRANSITION(HTTP 409). - C.2
src/routes/suppression/— 4 routes: list/check/add/remove with tenant scoping and channel-keyed dedup. - C.3
src/routes/webhooks/— 2 routes: provider delivery-event ingest (auto-suppress on unsubscribed/bounced/complained) and base64-JSON one-click unsubscribe withINVALID_UNSUBSCRIBE_TOKENmapping. - C.4 Plugin
onInitresolvesapp+db+openAPIRegistryfrom theServiceRegistry, constructsSurrealCampaignRepository,SurrealCampaignSuppressionRepository, andSurrealDeliveryEventStore, injects them on the HonoContextVariableMap, and mounts every route viadefinePluginRoutes. Collision guard raisesCAMPAIGNS_API.ROUTE_PREFIX_COLLISION. Missing-service guard raisesCAMPAIGNS_API.SERVICE_NOT_AVAILABLE. - C.5 Integration tests in
tests/integration/plugin-integration.test.tsagainst a realOpenAPIHonohost with in-memory repositories; 8 happy-path round-trips covering every route group. - C.6 100/100/100/100 coverage on the full package (Chunks A + B + C).
- C.7 Extended
CAMPAIGNS_API_CODESwith five Chunk-C codes:INVALID_STATE_TRANSITION,INVALID_UNSUBSCRIBE_TOKEN,ROUTE_PREFIX_COLLISION,WEBHOOK_REJECTED,SERVICE_NOT_AVAILABLE.
Post-C orchestrator steps (NOT a chunk)
- Fold the spec delta into
openspec/specs/api-plugin-capaigns/spec.md. - Move
openspec/changes/api-plugin-campaigns/toopenspec/archive/<yyyy-mm-dd>-api-plugin-campaigns/. - Update
MANIFEST.mdandCLAUDE.mdpackage roster.