feat/pub-api-rl
safeedc190e · incrementalPR #266reviewed 2026-07-09 00:52 UTC0H · 0M · 3L · 3I- Purpose
- Raise public v1 API rate-limit budgets so external machine clients aren't throttled at the dashboard's internal per-browser-session defaults.
- Goal
- Explicit budget constants (300/min read, 60/min write, 10/min auth) decoupled from DEFAULT_RATE_LIMITS, with HEAD method correctly classified as read, regression-tested.
- Sub-goals
- SG-1: Raise read/write budgets to published limits and decouple from dashboard defaults
- SG-2: Fix HEAD method classification to read bucket
- SG-3: Add regression tests pinning budgets and classifying all methods
- SG-4: Update api-patterns.md to document rate-limit behavior accurately
- What
- New public-v1-rate-limit.ts module (classifier + budgets + identity/bucket helpers); v1 route.ts wired to use new module; regression tests added; api-patterns.md updated.
- Why
- A prospective API client asked about limits before integrating. The old read budget (~13/min) was inherited from the dashboard's internal DEFAULT_RATE_LIMITS, which is designed for browser sessions, not machine bulk clients.
- Areas
- apps/platform/src/api/utils/public-v1-rate-limit.ts+44−0apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts+95−0apps/platform/src/app/api/v1/[...ts-rest]/route.ts+9−25.claude/rules/api-patterns.md+3−2
- Blast
- 4 files, +151/−27; all within public API utils and docs. Zero production risk on this commit (test-only delta).
Findings · 6
security2
HEAD /auth/token at read budget (300/min) allows rapid metadata probing
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:30
HEAD does not invoke scrypt so read classification is functionally correct. However, the 30x looser read budget vs auth (300 vs 10/min) allows higher-volume probing on a sensitive endpoint. Concrete risk is narrow: Next routes HEAD through the GET handler which won't run credential checks. Worth a comment in the classifier.
Per-instance fail-open rate limits provide weak guarantees for the auth bucket
apps/platform/src/api/utils/public-v1-rate-limit.ts:14
Pre-existing; noted in PR description. A shared-store limiter is needed for hard quotas. Not introduced by this diff.
tests2
PATCH /auth/token not asserted in the method-specificity block
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:29
Block title promises 'other methods on that path are not [auth]' but covers GET, HEAD, DELETE, PUT — not PATCH. Adding one assertion makes the guard provably exhaustive for all standard HTTP verbs.
OPTIONS/CONNECT/TRACE omission is acceptable
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:29
These fall through to write (safe default). No path-specific logic so omission is intentional.
improvement2
it.each table would scale better as method variants grow
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:28
The block now has 4 inline assertions. An it.each table would make adding verbs trivial and give per-row failure messages. Minor improvement.
HEAD /auth/token covered in two test blocks (intentional layering)
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:30
Method-specificity block covers HEAD on auth path; generic read block covers HEAD on non-auth paths. Two different invariants — not redundancy.
History · 6 commits
- edc190esafeincremental0H · 0M · 3L2026-07-09 00:52current
- 1f85ae7needs attentionincremental0H · 1M · 4L2026-07-08 20:16
- d77720dneeds attentionincremental0H · 1M · 4L2026-07-08 18:03
- 28ed416needs attentionincremental0H · 1M · 4L2026-07-08 17:41
- ae8bb22safeincremental0H · 0M · 9L2026-07-07 20:38
- c095510needs attentionfull3H · 3M · 4L2026-07-07 19:36