Pharmapedia — pharmacy revision platform
A revision platform for pharmacy students, in production through two exam periods. Six study years of curriculum, access sold as licences rather than enrolment, and revision quizzes generated on demand from a question bank. The load is the interesting part: it is close to nothing for most of the year, then the whole cohort arrives in the fortnight before exams.
- CURRICULUM
- Six years, semester → module → lesson
- ACCESS
- Licences by year, semester or module
- ASSESSMENT
- Practice, timed exam, generated revision
- SURFACE
- 80 route handlers, one Next.js process
- PEAK
- Exam fortnight, a few thousand students
modules / lessons
scope check
active only
shuffled, ×N
↳ progress autosaved; submit is transactional↳ a second submit on a finished attempt is rejected
- USERS
- A few thousand pharmacy students
- SHAPE
- Load concentrated in exam periods
- OBSERVED
- No reported outage across two exam periods
- DATA
- PostgreSQL 16 · Prisma · 12 migrations
THE HARD PART
Access is sold as licences, not enrolment, and a licence scopes to a study year, a semester or a module — exactly one of the three. Working out what a student may open means intersecting their year with every active licence they hold, on every request, and that is the query that has to stay cheap when the whole cohort signs in the same evening.
WHAT I REJECTED
Enrolment as the access model. It matches how a university thinks, but not how the product sells: a student buys one module, or a semester, or the year. Making the licence the unit meant access could be granted and expired without touching the curriculum it points at.
WHAT I'D FIX FIRST
Caching and rate limiting are both in-process, which pins the application to a single replica: a second instance would serve its own stale reads and double the effective rate limit. Moving both behind Redis is what has to happen before the load grows again — the current shape has been survivable, not comfortable.