Problem
The email-verification flow (#16) exposes two unauthenticated endpoints that can be abused to burn SendGrid quota or enumerate accounts:
- `POST /api/v1/dj-rest-auth/registration/resend-email/` — given an email, sends a fresh verification link. No rate limit. An attacker scripting this against a user's email could exhaust our SendGrid free-tier quota (100/day) or flood the user's inbox.
- `POST /api/v1/dj-rest-auth/registration/verify-and-login/` — given a key, confirms + issues a token. Keys are HMAC-signed and unguessable, so brute force isn't practical, but adding a basic per-IP limit is defensive hygiene.
Expected behaviour
- Resend endpoint: limit to ~5 requests per email per hour, ~20 per IP per hour.
- Verify-and-login endpoint: limit to ~20 requests per IP per minute (looser, since legit users click the link once).
- Rejected requests return 429 with a clear `Retry-After` header.
Implementation notes
- `django-ratelimit` is the lightweight option; `django-axes` is heavier but adds auth-attempt tracking.
- Must work behind Railway's proxy — use `X-Forwarded-For` for IP extraction.
- Add tests asserting 429 after N requests in a window.
Scope
Follow-up to #16; spec `docs/superpowers/specs/2026-04-20-email-verification-magic-link-design.md` §7 calls this out as out-of-scope for MVP.
Problem
The email-verification flow (#16) exposes two unauthenticated endpoints that can be abused to burn SendGrid quota or enumerate accounts:
Expected behaviour
Implementation notes
Scope
Follow-up to #16; spec `docs/superpowers/specs/2026-04-20-email-verification-magic-link-design.md` §7 calls this out as out-of-scope for MVP.