Saksham Jain
Back to work
/ 02Case study2025

PS Classes

Pharmacy exam-prep platform for Drug Inspector aspirants — category-wise test series with real-exam pacing, chapter-wise analytics and All-India Rank, plus course library, student auth, and free-trial flow.

EdTechPharmacy ExamsTest SeriesFull-StackAuth
Visit psclasses.in
PS Classes homepage hero showing Drug Inspector exam prep positioning and course video panel.
Role
Full-stack Developer
Focus
Test engine & analytics
Year
2025
Status
Production

Overview

PS Classes is a pharmacy exam-prep platform built around Drug Inspector aspirants targeting UPSC and State PSC syllabi. Students drill down from exam category to exam to test series, sit timed mock tests with real-exam pacing, and see where they rank against every other student on that series — alongside a course library and a free-trial flow ahead of purchase.

My role

I worked as a full-stack developer on PS Classes, building the platform end to end: student auth and free-trial gating, the course/test-series catalog with its category → exam → series drill-down, the timed test-taking engine itself, and the chapter-wise analytics and All-India Rank that get computed once a student submits. Payments run through Razorpay for course and test-series purchases.

The complexity

Problem — Concurrent test-takers on a shared test series need a countdown nobody can extend by editing their system clock or letting the tab sit in the background — and with 500+ students starting a series at the same slot time, that timer state can't be a slow round trip to the primary database on every answer.

Approach — Made the server the source of truth for the timer, backed by Redis: each answer is written to a Redis-held session on selection (sub-second, no DB round trip) and periodically flushed to MongoDB, with the server auto-submitting the attempt once the deadline passes regardless of what the client believes the time is.

Problem — A flaky connection can make a student hit submit twice from two tabs — scoring the same attempt twice would double-count it in the rank aggregate.

Approach — A short-lived Redis lock (SETNX-style) on the attempt ID makes the first submit win; the second is rejected as already-processed instead of racing the first into the scoring queue — pessimistic by design, since a submit only happens once and losing a few milliseconds to the lock is cheaper than a corrupted rank.

Problem — All-India Rank and chapter-wise breakdowns need to reflect every attempt on a series without re-scanning every submission each time a student opens their result.

Approach — Submitted attempts go on a RabbitMQ queue; a scoring worker consumes them, updates the score/percentile rollup incrementally, and writes the result to Redis so rank and chapter-wise analytics are read from a fast cache instead of computed live per page view.

Problem — Free-trial students, paying students, and admin-authored content all sit behind the same auth — access needs checking on every test and course request without copy-pasting that check into each route.

Approach — Centralized the entitlement check (trial vs. purchased vs. admin) in one middleware layer every test/course endpoint routes through, instead of re-implementing access logic per feature.

Architecture

Test attempt
Student client
Category → exam → series
Test session API
Server-owned timer
Redis session
Answers, sub-second writes
Auto-submit
On deadline or manual submit
RabbitMQ queue
Scoring worker
Updates Redis rank cache
Result dashboard
All-India Rank + chapters
Access control
Request
Test or course route
Auth
Entitlement check
Trial / purchased / admin
Allow
Or 403 → upgrade prompt

What shipped

  • Category → exam → test-series drill-down browsing with real-exam pacing.
  • Server-authoritative timed test engine with autosave and auto-submit.
  • Chapter-wise analytics and All-India Rank per test series.
  • Course library, student auth, free-trial gating, and Razorpay checkout.

What I owned

API & data model
Attempt state, answer autosave, and the scoring pipeline that feeds rank and chapter analytics off one submission.
Infrastructure
Redis for live timer/session state and the rank cache; RabbitMQ decoupling scoring from the submit request.
Access control
Single entitlement middleware gating trial, purchased, and admin access across every test and course route.
Frontend
Category → exam → series drill-down, the timed test-taking UI, and the result/analytics dashboard.

Engineering properties

  • Server-owned exam timer, not client-trusted
  • Redis-backed session state, sub-second answer writes
  • RabbitMQ queue decouples scoring from submission
  • Distributed lock stops a double-submit from two tabs

Stack

Next.jsNode.jsExpressMongoDBRedisRabbitMQAuthRazorpay