randomayzer/agents/antigravity/inbox/TASK-2026-08-21-02-rate-limit-client-identity.md

23 lines
1.8 KiB
Markdown

# Task 02: Client Identity for Rate Limiting
**Assigned to:** Antigravity (Implementation Orchestrator)
**Priority:** HIGH (availability)
**Date:** 2026-08-21
**Base SHA:** `92f6d1922500791ef221cc11ed63f606afc01b53`
## Scope
1. User-scoped rate limiting for authenticated routes (`/api/giveaways*`):
- Scope rate limit key by `sessionUser.id` instead of IP (`draw:${sessionUser.id}:${id}`, `snapshot-lock:${sessionUser.id}:${id}`, `participants:${sessionUser.id}:${id}`, `giveaways:${sessionUser.id}`).
- Order of execution: `requireAuthenticatedUser` / `requireGiveawayOwner` authenticates the request and extracts `sessionUser`, then user-scoped rate limiter runs. Unauthenticated requests fail with 401 immediately and cannot exhaust organizer rate limit buckets.
2. Anonymous route rate limiting (`/api/auth/vk/start`, `/api/posts/preview`):
- When IP cannot be resolved (empty `req.ip` and `TRUST_PROXY !== 'true'`), use a dedicated anonymous fallback bucket (`anon:direct-client` or similar) separate from user buckets.
3. Production configuration guard & documentation:
- In `docs/PRODUCTION_GUARDS.md`, document proxy configuration and IP resolution behavior.
4. Concurrency & Isolation tests in `tests/rate-limit-identity.test.ts`:
- Two authenticated organizers with empty `req.ip` do not affect each other's rate limits.
- Exhausting anonymous rate limit does not affect authenticated organizers.
- Unauthenticated requests cannot bypass authentication or drain organizer limits.
- Existing `TRUST_PROXY=true` behavior and tests remain green.
5. Verification:
- `npm ci`, `npx prisma generate`, `npm test`, `npm run lint`, `npm run build`, `npx tsc --noEmit`.
6. Output report in `agents/antigravity/done/TASK-2026-08-21-02-rate-limit-client-identity.md`.