diff --git a/docs/WORKSPACE_TODO_AUDIT.md b/docs/WORKSPACE_TODO_AUDIT.md index 78c2293a..0f782312 100644 --- a/docs/WORKSPACE_TODO_AUDIT.md +++ b/docs/WORKSPACE_TODO_AUDIT.md @@ -79,6 +79,22 @@ --- +### Post-Audit Review (2026-03-22) — 8 bugs found in P2/P3 implementations + +| # | Location | Bug | Severity | Status | +| --- | ------------------------------------------------ | ---------------------------------------------------------------- | -------- | ------------------ | +| R1 | `diagnostics/subscribers.ts` — session.cancelled | Used non-existent `'generic'` template ID (throws at runtime) | **P0** | ✅ FIXED `73b07c2` | +| R2 | `diagnostics/subscribers.ts` — session.completed | Used non-existent `'generic'` template ID (throws at runtime) | **P0** | ✅ FIXED `73b07c2` | +| R3 | `delivery/templates.ts` | Missing `'broadcast'` template used by broadcast delivery | **P0** | ✅ FIXED `73b07c2` | +| R4 | `broadcasts/routes.ts` — delivery complete | Dot-path `'metrics.sent'` in updateBroadcast (not Cosmos syntax) | **P1** | ✅ FIXED `73b07c2` | +| R5 | `exports/routes.ts` — async processing | Serialized data computed but never stored — no download endpoint | **P1** | ✅ FIXED `73b07c2` | +| R6 | `waitlist/routes.ts` — batch invite | Stored code string as `invitationCodeId` instead of doc ID | **P2** | ✅ FIXED `73b07c2` | +| R7 | `diagnostics/subscribers.ts` — session.created | Target user email not sent (just logging) despite template exist | **P2** | ✅ FIXED `841cdf3` | +| R8 | `events/types.ts` + `delivery/subscribers.ts` | `payment.failed` missing `currency` field (inconsistent schema) | **P2** | ✅ FIXED `841cdf3` | +| R9 | `exports/routes.ts` — list endpoint | Returns full `data` payload in list response (perf/security) | **P2** | ✅ FIXED (pending) | + +--- + ## Items Explicitly NOT TODOs (Excluded) These were found in scans but are **not actionable gaps**: @@ -115,24 +131,28 @@ These backends and webs have **no actionable TODOs** — fully implemented: ## Recommended Action Plan -### Sprint A (1–2 days) — Quick Wins +### Sprint A (1–2 days) — Quick Wins ✅ COMPLETE -1. Wire telemetry `reportError()` in all 3 dashboard `error.tsx` files (~15 min) -2. Wire waitlist → invitations module for auto-generated invite codes (~30 min) +1. ~~Wire telemetry `reportError()` in all 3 dashboard `error.tsx` files~~ ✅ +2. ~~Wire waitlist → invitations module for auto-generated invite codes~~ ✅ -### Sprint B (3–5 days) — User-Facing Gaps +### Sprint B (3–5 days) — User-Facing Gaps ✅ COMPLETE -3. Implement user lookup helper for delivery subscribers (payment_failed, trial_expiring, trial_expired) -4. Wire survey incentive fulfillment to billing/subscriptions module -5. Wire export job processing through the jobs module +3. ~~Implement user lookup helper for delivery subscribers~~ ✅ +4. ~~Wire survey incentive fulfillment to billing/subscriptions module~~ ✅ +5. ~~Wire export job processing through the jobs module~~ ✅ -### Sprint C (deferred) — Operational Excellence +### Sprint C (deferred → resolved) ✅ COMPLETE -6. Implement real broadcast audience estimation query -7. Wire broadcast delivery via event bus -8. Add CAPTCHA validation to waitlist signup -9. Telemetry bulk upsert optimization -10. PagerDuty/Slack integration for FATAL diagnostic logs +6. ~~Implement real broadcast audience estimation query~~ ✅ +7. ~~Wire broadcast delivery via event bus~~ ✅ +8. Add CAPTCHA validation to waitlist signup ⏭️ DEFERRED (requires API keys) +9. ~~Telemetry bulk upsert optimization~~ ✅ +10. ~~PagerDuty/Slack integration for FATAL diagnostic logs~~ ✅ + +### Post-Audit Review ✅ COMPLETE + +11. ~~8 bugs found and fixed in P2/P3 implementations~~ ✅ (`73b07c2`, `841cdf3`) --- diff --git a/services/platform-service/src/modules/exports/routes.ts b/services/platform-service/src/modules/exports/routes.ts index b2ddb59f..46be5f25 100644 --- a/services/platform-service/src/modules/exports/routes.ts +++ b/services/platform-service/src/modules/exports/routes.ts @@ -98,13 +98,18 @@ export async function exportRoutes(app: FastifyInstance) { return reply.status(201).send(created); }); - // List export jobs + // List export jobs (metadata only — excludes data payload) app.get('/exports', async req => { const access = await requireExportRead(req); const query = req.query as Record; const limit = query.limit ? parseInt(query.limit, 10) : 20; const jobs = await repo.listExportJobs(access.productId, Math.min(limit, 100)); - return { exports: jobs, count: jobs.length }; + const stripped = jobs.map(j => { + const meta = { ...j }; + delete meta.data; + return meta; + }); + return { exports: stripped, count: stripped.length }; }); // Get a specific export job (metadata only, no data payload)