Implement Upstash rate-limit driver
Problem¶
.cursor/rules/120-security.mdc requires Upstash Redis (@upstash/ratelimit) for production rate limiting. The original implementation was split:
- LMS had a driver pattern in
src/lib/rate-limit/*. - CMS used a separate in-memory limiter in
src/lib/api/rate-limit.ts.
The split risked behavior drift and made production parity harder to maintain.
Implemented approach¶
- Added shared package
@open-learning-hub/server/rate-limitinpackages/server/with:memoryDriver(fixed-window, in-memory)upstashDriver(@upstash/ratelimit+@upstash/redis)selectRateLimitDriver(RATE_LIMIT_DRIVER-based)
- Migrated LMS and CMS to consume the shared driver surface.
- Kept app-specific policy wiring local:
- LMS
RATE_LIMIT_POLICIES+limit()wrapper remain inapps/lms/src/lib/rate-limit/index.ts. - CMS route-bucket rules remain in
apps/cms/src/lib/api/rate-limit.ts.
- LMS
- Documented
RATE_LIMIT_DRIVERandUPSTASH_*in both.env.local.templatefiles. - Added shared package unit tests for memory/upstash drivers and updated CMS rate-limit tests for async driver calls.
Acceptance criteria¶
-
RATE_LIMIT_DRIVER=upstashworks end-to-end in LMS and CMS. - Documented env vars present in
.env.local.templateand CI secrets. - Tests cover the standard policies (auth, sign-up, enroll, quiz, revalidate).
-
npm run checkpasses.
Out of scope¶
- Moving away from sliding-window/fixed-window policies.
- Multi-region / multi-key replication strategy.
Notes / decisions log¶
- 2026-05-24: Ticket created. Deferred per current product priorities; reactivate when production scale-out is on the roadmap.
- 2026-07-07: Implemented via shared package
@open-learning-hub/server/rate-limit; LMS and CMS now share driver selection and Upstash integration. - 2026-07-08: CMS Vercel environments were updated to
RATE_LIMIT_DRIVER=upstashwithUPSTASH_REDIS_REST_URL/TOKENmapped from existing KV integration values. - 2026-07-08: Shared driver now accepts
KV_REST_API_URL/TOKENas fallback names; follow-up remains to split LMS/CMS into separate Upstash stores for stronger isolation.