# API QA Checklist > Comprehensive enhancement list for `vibn-frontend/app/api/` derived from the > 2026-05-17 QA pass. Anchored to `BETA_LAUNCH_PLAN.md`. > > **Convention:** each item has an ID like `S-01` (Security), `A-01` (Auth/Arch), > `B-01` (Beta blocker), `C-01` (Chat/AI pipeline), `R-01` (Reliability), > `D-01` (Deletion/cleanup), `O-01` (Code Org). Tick the box as you ship. --- ## Phase 1 — Foundations (`lib/server/*`) - [x] **F-01** `lib/server/api-handler.ts` — `withAuth`, `withTenantProject`, `withWorkspace`, `withAdminSecret` route wrappers. Every new route uses these instead of reimplementing the auth dance. - [x] **F-02** `lib/server/logger.ts` — structured logger that takes `{turnId, projectId, route, userId}` and routes to `console.*` in dev, Sentry breadcrumb in prod. - [x] **F-03** `lib/server/audit-log.ts` — `writeAuditLog({workspace, user, action, resourceType, resourceId, params, ok})` helper + migration for `audit_log` table. - [x] **F-04** `lib/server/rate-limit.ts` — Postgres-backed sliding window. Default: 60 req/min per user per route. Per-route override via opts. - [x] **F-05** `lib/server/coolify-webhook.ts` — verifyCoolifySignature(body, signature, secret). Mirrors `verifyWebhookSignature` from `lib/gitea.ts`. - [x] **F-06** `lib/server/timing-safe.ts` — `timingSafeStringEq(a, b)` helper wrapping `crypto.timingSafeEqual` for every admin-secret bearer check. --- ## Phase 2 — Deletions (security cleanup) These are unauthenticated routes that read/write tenant data using only a URL `projectId`. Delete them now; if anything legitimate calls one, we'll find out fast and reintroduce it under `withTenantProject`. - [x] **D-01** `app/api/debug/cursor-analysis` — Firestore dump - [x] **D-02** `app/api/debug/cursor-content-sample` - [x] **D-03** `app/api/debug/cursor-conversations` - [x] **D-04** `app/api/debug/cursor-relevant` - [x] **D-05** `app/api/debug/cursor-sample-dates` - [x] **D-06** `app/api/debug/cursor-session-summary` - [x] **D-07** `app/api/debug/cursor-sessions` - [x] **D-08** `app/api/debug/cursor-stats` - [x] **D-09** `app/api/debug/cursor-unknown-sessions` - [x] **D-10** `app/api/debug/cursor-workspaces` - [x] **D-11** `app/api/debug/append-conversation` - [x] **D-12** `app/api/debug/check-links` - [x] **D-13** `app/api/debug/check-project` - [x] **D-14** `app/api/debug/context-sources` - [x] **D-15** `app/api/debug/env` — leaks env-var presence - [x] **D-16** `app/api/debug/first-project` - [x] **D-17** `app/api/debug/knowledge` - [x] **D-18** `app/api/debug/knowledge-items` - [x] **D-19** `app/api/debug/prisma` - [x] **D-20** `app/api/cursor/backfill` — comment says "TEMPORARY: no auth required" - [x] **D-21** `app/api/cursor/clear-imports` — same - [x] **D-22** `app/api/cursor/tag-sessions` — same - [x] **D-23** `app/api/firebase/test` — writes/deletes Firestore on every call, no auth - [x] **D-24** `app/api/sentry-example-api` — always throws; dev-only fixture - [x] **D-25** `app/api/test-token` — server-side `auth.currentUser` (broken pattern) - [x] **D-26** `app/api/diagnose` — info-discloses env vars + verifies arbitrary tokens - [x] **D-27** `app/api/admin/check-sessions` — no auth, named `/admin/` - [x] **D-28** `app/api/admin/fix-project-workspace` — no auth, accepts any project --- ## Phase 3 — Auth gates + hardening on the remaining unauthenticated routes - [x] **S-01** `app/api/ai/chat` — wrap in `withTenantProject('projectId')`. Currently anyone can chat as any project. - [x] **S-02** `app/api/ai/conversation` (GET, DELETE) — same. - [x] **S-03** `app/api/ai/conversation/reset` — same. - [x] **S-04** `app/api/context/summarize` — wrap in `withAuth`. No tenant scope needed; just stop unauth Gemini quota burn. - [x] **S-05** `app/api/work-completed` — wrap in `withTenantProject('projectId')` and remove the literal-`1` fallback. - [x] **S-06** `app/api/webhooks/coolify` — verify signature against `COOLIFY_WEBHOOK_SECRET` using `verifyCoolifySignature`. Reject on mismatch. - [x] **S-07** `app/api/admin/migrate` — switch `secret !== incoming` to `timingSafeStringEq(secret, incoming)`. - [x] **S-08** `app/api/admin/path-b/{disable,enable,idle-sweep,autosave}` — same. - [x] **S-09** `app/api/admin/path-b/route.ts` — same. - [x] **S-10** `app/api/internal/infra-health` — same. --- ## Phase 4 — Chat / AI pipeline hardening `app/api/chat/route.ts` and `lib/ai/*` enhancements. - [x] **C-01** Lower `MAX_TOOL_ROUNDS` from 15 to 8. - [x] **C-02** Tighten loop detection: hard-break at 3 identical fingerprints (was 5); add an absolute cap of 6 consecutive tool calls with no intervening assistant text. - [x] **C-03** Add "Mode: respond first, act second" block at the top of `buildSystemPrompt` (above the existing Identity section). - [x] **C-04** SSE heartbeat: emit `{type:"ping"}` every 25s while the loop is running (cleared on `safeClose` / `cancel`). - [x] **C-05** `executeMcpTool` timeout: wrap each tool invocation in `Promise.race([exec, timeout(45_000)])`; surface as `tool_timeout` SSE event. - [x] **C-06** `turnId`: generate a `crypto.randomUUID()` per chat turn; include in every log line and the first SSE chunk so we can correlate prod issues. - [x] **C-07** Recovery-summary trigger expansion: also fire when the AI emitted no text for ≥4 rounds (not just on tool failure / round cap / loop break). - [ ] **C-08** Deprecate `app/api/ai/chat`. Add `Deprecation: true` header + log line; redirect callers to `/api/chat` over 30 days, then delete. *(skipped this pass — needs migration tracking)* --- ## Phase 5 — Beta gaps from `BETA_LAUNCH_PLAN.md` Each maps to a checked task in the plan that's not yet implemented in the API surface. - [x] **B-01 (P4.7)** `audit_log` table + writes from every mutating MCP tool in `app/api/mcp/route.ts` (`apps_create`, `apps_delete`, `apps_deploy`, `databases_create`, `databases_delete`, `domains_register`, `secrets_set`, `ship`). - [x] **B-02 (P4.8)** Invite/waitlist endpoints: `POST /api/invites` (admin-only, creates token), `GET /api/invites/[token]` (validates), `POST /api/invites/[token]/redeem` (consumes on signup). - [x] **B-03 (P6.B1)** `fs_project_dev_servers` table migration + `dev_server_start` MCP tool hook to upsert on success. - [ ] **B-04 (P6.B2)** Auto-resume hook on project page mount. *(scaffolded; full wiring deferred since it touches the project layout page, which is outside `/api`)* - [x] **B-05 (P6.C1)** SSE `plan` event protocol in `app/api/chat/route.ts` — emit `{type:"plan", taskId, text, status}` whenever `plan_task_add` / `plan_task_edit` fires within a turn. - [x] **B-06 (P6.D2)** `fs_project_secrets` table + `POST /api/projects/[id]/secrets`, `GET /api/projects/[id]/secrets` (keys-only), `DELETE /api/projects/[id]/secrets/[key]`. Encrypted via existing `lib/crypto.ts` pattern. - [x] **B-07 (P3.7)** `project_brief` MCP tool stub + extraction scaffold in `lib/integrations/brief-extract.ts`. Wired into `buildSystemPrompt` as `[PROJECT BRIEF]` block when `fs_projects.data.plan.brief` is non-empty. - [ ] **B-08 (P2.5)** Per-request Sentry span+release annotation in every handler. *(deferred — needs Sentry SDK pattern audit across the codebase)* --- ## Phase 6 — Reliability & observability - [x] **R-01** Adopt `lib/server/logger.ts` in `app/api/chat/route.ts` (highest-traffic route). - [x] **R-02** Rate-limit `/api/chat`, `/api/context/summarize`, `/api/extension/link-project`, `/api/admin/migrate`. - [ ] **R-03** Idempotency keys on webhook receivers (`(event_id, project_id)` unique constraint). *(deferred — Coolify event payload schema needs research)* - [ ] **R-04** Per-tool cost/token accounting table `chat_costs`. *(deferred — needs pricing strategy)* --- ## Phase 7 — Code organization - [ ] **O-01** Refactor the 8 highest-traffic routes onto `withAuth` / `withTenantProject` / `withWorkspace`. *(seeded with examples; bulk refactor deferred)* - [ ] **O-02** Decompose `app/api/chat/route.ts` (1088 lines) into `lib/server/chat-{prompt,tool-loop,recovery,sse}.ts`. *(deferred — non-blocking refactor)* - [x] **O-03** `app/api/ROUTES.md` — enumerate every route with `auth`, `tenant`, purpose. - [ ] **O-04** Continue extracting MCP `toolXxx()` into `lib/mcp/tools/*.ts`. *(deferred — non-blocking)* --- ## How to use this doc - Tick a box only when the change is committed AND the unit/smoke test passes. - Items marked `(deferred — …)` are intentional cuts so this lands as one reviewable batch. Re-open them in `AI_CAPABILITIES.md` after beta. - Each phase commit message should reference the IDs it closes, e.g. `feat(api): F-01..F-06 lib/server foundations`.