Problem
Only 5 of 203 API routes validate their body with a schema. The rest duck-type, for example app/api/repos/[id]/rules/route.ts:84 checks body.rule_id && typeof body.excluded === "boolean" and then writes body.rule_id straight into an upsert.
The routes with the highest blast radius also have no tests at all: everything under app/api/teams/[teamId]/ (RBAC: members, invites, keys, models, installations, icon) and app/api/connections/ (OAuth connect and callback).
Where
- Routes that already use zod, to copy from: app/api/v1/mogplex/repos/[repoId]/env-vars, app/api/runs/[runId]/guidance, app/api/control/continuations.
- Untested targets by size: app/api/teams/[teamId]/invites/bulk (224 lines), icon (223), invites (198), installations (171), invites/[inviteId] (163), members (158), keys (155), models (152), app/api/connections/route.ts (206), oauth (116), oauth/callback (111).
Fix
One PR per route. For each:
- Define a zod schema for the body next to the route (schema.ts in the route directory).
- Parse with safeParse; return 400 with the flattened error on failure.
- Add a tests/unit/ suite covering success, invalid body, and the auth failure path (the testing policy requires all three for API routes).
Start with members and invites, since those decide who can see what.
Exit criteria
- Every route listed above has a schema and a test suite with the three required paths.
- A checklist comment on this issue tracks per-route PRs.
- pnpm lint, pnpm typecheck, pnpm test:unit pass after each PR.
Out of scope
The other 80-odd routes without zod. Once the pattern is established, open one issue per area.
https://claude.ai/code/session_01SQ4nS96XYRztd5w9QkubPf
Reactions are currently unavailable
Problem
Only 5 of 203 API routes validate their body with a schema. The rest duck-type, for example app/api/repos/[id]/rules/route.ts:84 checks body.rule_id && typeof body.excluded === "boolean" and then writes body.rule_id straight into an upsert.
The routes with the highest blast radius also have no tests at all: everything under app/api/teams/[teamId]/ (RBAC: members, invites, keys, models, installations, icon) and app/api/connections/ (OAuth connect and callback).
Where
Fix
One PR per route. For each:
Start with members and invites, since those decide who can see what.
Exit criteria
Out of scope
The other 80-odd routes without zod. Once the pattern is established, open one issue per area.
https://claude.ai/code/session_01SQ4nS96XYRztd5w9QkubPf