feat/pub-api-rl
needs attentionviewing older commitd77720d · incrementalPR #266reviewed 2026-07-08 18:03 UTC0H · 1M · 4L · 1I- Purpose
- Raise public v1 API rate-limit budgets so external clients aren't throttled at the old ~13 req/min read cap inherited from the dashboard's internal session defaults.
- Goal
- Decouple public API budgets from dashboard internals; pin them with a regression test so future refactors can't silently revert them.
- Sub-goals
- SG-1: Raise read 200/15min → 300/min, write 50/15min → 60/min, auth stays 10/min
- SG-2: Decouple budgets from DEFAULT_RATE_LIMITS into explicit RATE_LIMIT_BUDGETS constant
- SG-3: Pin budgets with a regression test that fails CI on silent revert
- SG-4: Address loop-review feedback — leaner comments, broader method-specificity coverage
- What
- Incremental commit: adds DELETE + PUT to the method-specificity test for /auth/token classification, adds scrypt WHY comment to classifyRateLimitKind, clarifies SHA-256 hash comment. No logic changes.
- Why
- Loop C review on the prior commit flagged missing method coverage on the /auth/token guard and over-verbose comments; this commit addresses that feedback.
- Areas
- apps/platform/src/api/utils+13−5.claude/rules/api-patterns.md+3−2apps/platform/src/app/api/v1/[...ts-rest]/route.ts+9−25
- Blast
- 4 files, +147/−32 cumulative over the branch; rate-limit classifier + test + route mount + doc update. No schema, no migrations, no infra.
Findings · 6
security2
XFF spoofing can bypass auth rate-limit bucket
apps/platform/src/api/utils/public-v1-rate-limit.ts:33
rateLimitIdentity trusts split(',')[0] of X-Forwarded-For. A load balancer that appends (not overwrites) XFF lets an attacker inject a leading IP per request, obtaining a fresh 10/min auth bucket. Use rightmost non-trusted IP. Pre-existing.
Auth budget is per-instance — acknowledged limitation
apps/platform/src/api/utils/public-v1-rate-limit.ts:14
Multiple warm Lambda instances allow distributing requests above the per-instance cap. Documented as accepted limitation; contractual cap needs shared-store limiter.
conventions2
Comment mixes what + why
apps/platform/src/api/utils/public-v1-rate-limit.ts:21
The 'Token exchange gets...' clause restates the code. Only the scrypt WHY is non-obvious. Trim to: // scrypt per call — stricter budget.
Regression-guard block comment exceeds one-line rule
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:11
Three-line block comment violates the one-short-line-max convention. Shorten or move 200/15min historical detail into the test description.
tests2
HEAD not tested — currently routes to write
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:40
HEAD is semantically GET-like but implementation returns write. A test documenting this edge case prevents regressions.
OPTIONS behavior undocumented in tests
apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:40
OPTIONS (CORS preflight) would be classified as write if it reaches classifyRateLimitKind. A comment or test noting intentional scope would clarify.
History · 6 commits
- edc190esafeincremental0H · 0M · 3L2026-07-09 00:52
- 1f85ae7needs attentionincremental0H · 1M · 4L2026-07-08 20:16
- d77720dneeds attentionincremental0H · 1M · 4L2026-07-08 18:03current
- 28ed416needs attentionincremental0H · 1M · 4L2026-07-08 17:41
- ae8bb22safeincremental0H · 0M · 9L2026-07-07 20:38
- c095510needs attentionfull3H · 3M · 4L2026-07-07 19:36