ExamWiz — Hackathon Story
Built for the #H0Hackathon — AWS Databases × Vercel 2025
Inspiration
In my fourth year studying medicine at the University of Benin, I failed out.
Not by a small margin. I failed Pathology and Pharmacology in the same semester — two of the most memorisation-heavy courses in the entire medical curriculum. PATH and PHARM together cover hundreds of drug mechanisms, disease classifications, histological patterns, and clinical correlates. My study strategy was the one everyone uses: read the textbook, highlight, re-read. It felt productive. It produced nothing.
I was given a chance to transfer to Edo State University to restart. I took it. Sitting in a minibus between Benin City and Iyamho, I made a decision: I was not going to fail again because of how I studied.
The first version of ExamWiz was just a past questions app.
The logic seemed obvious. Nigerian medical schools are notorious for recycling exam questions. If you could drill every past question for a course, you would pass. So I built a simple quiz interface, loaded it with years of past questions, and started practising.
It worked — until it didn't. Past questions have a fundamental weakness: lecturers change. New faculty join, course content shifts, and the questions from five years ago stop predicting what appears this semester. I found myself drilling questions that would never appear on my exam while the actual exam drew from topics the past papers had never touched.
But something else was consistent. Lecturers always set their exams from their own slides. A lecturer might change the questions, but they cannot change the fact that everything they consider worth testing comes from the material they teach. The slides are the real source of truth — past questions are just one imperfect sample from that source.
That realisation changed the architecture of ExamWiz entirely. The product stopped being a database of pre-loaded questions and became a system for generating questions from any uploaded content. A student uploads this semester's lecture slides, and ExamWiz generates questions from those slides — not from a five-year-old question bank. Past questions became one input among many, not the whole product.
The combination of both — past questions for pattern recognition, slide-generated questions for current content — turned out to be far more effective than either alone. Past questions tell you how a lecturer used to think. Slide-generated questions tell you what they are currently teaching. Together, they triangulate what will actually appear on the exam.
The core insight behind everything ExamWiz does is uncomfortable but well-supported by cognitive science: reading creates familiarity, testing creates memory. Most students mistake the feeling of recognition for the ability to recall under exam pressure. Every time you re-read a page of Robbins Pathology, your brain says I know this — but knowing and retrieving are different neurological processes. ExamWiz forces retrieval practice, the only study activity with a consistent evidence base behind it.
I also noticed something about the tools that existed. Quiz apps gave you a score at the end of a session. Flashcard apps let you rate your recall. But nothing connected your practice activity to a prediction of your actual exam outcome. You could answer 200 questions and still have no idea whether you were going to pass. That gap — between effort and forecast — is what ExamWiz was built to close.
What it does
ExamWiz is an AI-powered exam preparation platform. A student uploads any study material — a PDF, lecture slides, a YouTube video, typed notes, a website URL — and the system generates quizzes, flashcards, summaries, and mind maps from it automatically. Every question the student attempts feeds a performance ledger. That ledger powers the Exam Readiness Score: a single number between 0 and 100 that estimates exam preparedness, plus a grade prediction (A through F) based on topic-by-topic accuracy.
Core features
Quiz generation. The AI extracts testable concepts from uploaded content, classifies them by topic, and generates multiple-choice questions with clinically plausible distractor options — wrong answers that a student under pressure would genuinely consider. This is harder than it sounds. A wrong answer that is obviously wrong is not a useful study tool.
Spaced repetition flashcards. The flashcard system implements the SM-2 algorithm. The inter-repetition interval for a card after the $n$-th successful review is:
$$ I(n) = \begin{cases} 1 & \text{if } n = 1 \ 6 & \text{if } n = 2 \ I(n-1) \cdot EF & \text{if } n > 2 \end{cases} $$
where the easiness factor $EF$ starts at 2.5 and updates after each review:
$$ EF' = EF + \bigl(0.1 - (5 - q)(0.08 + (5 - q) \cdot 0.02)\bigr), \quad EF' \geq 1.3 $$
with $q \in {0, 1, 2, 3, 4, 5}$ representing quality of recall. Cards you find easy are pushed further into the future. Cards you struggle with reappear the next day. The algorithm manages the schedule so the student only needs to manage the content.
Exam Readiness Score. The readiness score $R$ is a difficulty-weighted accuracy metric across all topics in a course:
$$ R = \frac{\displaystyle\sum_{i=1}^{T} w_i \cdot a_i}{\displaystyle\sum_{i=1}^{T} w_i} \times 100 $$
where $T$ is the number of topics, $a_i$ is the student's accuracy on topic $i$, and $w_i$ is the population-level difficulty weight of that topic (derived from the aggregate incorrect rate across all users). The score maps to a letter grade:
$$ \text{Grade} = \begin{cases} \text{A} & R \geq 85 \ \text{B+} & 75 \leq R < 85 \ \text{B} & 65 \leq R < 75 \ \text{C+} & 55 \leq R < 65 \ \text{C} & 45 \leq R < 55 \ \text{D} & 35 \leq R < 45 \ \text{F} & R < 35 \end{cases} $$
Live oral exam (ExamWiz Live Professor). A Gemini Live-powered voice session that simulates a viva voce examination. The AI asks questions from the student's weakest topics, listens to spoken answers, gives verbal feedback, and scores each response in real time. The scores feed directly back into the Exam Readiness Score.
Study materials workspace. A notebook-style interface where students manage their uploaded sources, generate multiple artifact types from the same material, and attach materials directly to courses for organised revision.
Courses and study plans. Students create courses with exam dates and topic outlines. The system generates a day-by-day study plan, surfaces the weakest topics first, and updates the schedule as performance data changes.
How we built it
Frontend and deployment
The frontend is built with Next.js App Router and deployed on Vercel. Vercel's serverless functions handle all API routes — including the AI generation pipelines, which can run for up to 60 seconds on streaming routes. The combination of Next.js and Vercel meant zero configuration for deployment, edge caching for static pages, and automatic scaling without thinking about servers.
The UI is built with Tailwind CSS and a component library built in-house. The app is a full Progressive Web App — it ships a web manifest, service worker with offline caching, and app icons at every required size, so students can install it on their phones and use cached content when they lose connectivity during a study session.
Database architecture
The data layer splits across two stores based on access pattern:
MongoDB (via Mongoose) stores documents that are read and written as complete objects: quizzes, study materials, flashcard decks, courses, user profiles, and subscriptions. These entities have rich nested structures (a quiz contains questions, which contain options and explanations) that map naturally to documents.
Amazon DynamoDB stores the performance ledger — every question attempt and flashcard review. The schema is intentionally flat:
PK: userId SK: attemptedAt#questionId
Attributes: quizId, isCorrect, timeSpent
Every active user generates dozens of these records per study session. We chose DynamoDB for this table because its write throughput is effectively unbounded without connection pooling, read replicas, or any operational configuration. The readiness score calculation queries the last 180 days of a user's attempts in a single Query operation against the partition key — a scan that stays fast regardless of how many other users are writing simultaneously.
The Vercel serverless function that computes the Exam Readiness Score:
- Queries DynamoDB for the user's recent attempts (fast key-value read)
- Fetches quiz topic metadata from MongoDB (document read)
- Runs the weighted accuracy calculation in memory
- Returns the score and grade prediction
The entire path executes in under 300ms including cold start.
AI pipeline
Quiz generation runs as a multi-stage streaming pipeline on Vercel:
- Extraction — uploaded documents are parsed to plain text (PDFs via
pdfjs-dist, images via Gemini Vision OCR, YouTube via transcript API) - Topic analysis — a Gemini call identifies topics and subtopics in the content
- Question generation — a second Gemini call generates questions per subtopic in parallel batches, with prompt constraints that enforce plausible distractors and prevent trivially easy wrong answers
- Storage — questions are written to MongoDB; the quiz ID is returned to the client
The oral exam uses Gemini 2.0 Flash Live via ephemeral auth tokens. The token is scoped with lockAdditionalFields: ["system_instruction", "tools", "response_modalities"] so the client cannot override the system prompt or inject different questions. The AI acts as a named persona (ExamWiz Live Professor) and is explicitly instructed never to reveal the underlying model.
Auth and payments
Authentication is NextAuth.js with Google OAuth and email/password. Payments are processed via Paystack (West African market) with IAP verification for mobile. A quota system tracks AI generation usage per billing period and gates features by plan.
Challenges we ran into
Generating wrong answers that are actually wrong in the right way
The hardest prompt engineering problem was distractor quality. A multiple-choice question is only useful if the wrong answers are genuinely tempting. For a Pharmacology question about beta-blocker mechanism, "blocks alpha-1 adrenergic receptors" is a much better wrong answer than "inhibits DNA synthesis" — both are wrong, but only the first tests whether the student actually knows the drug class.
Getting the AI to generate plausible distractors consistently required iterative prompt refinement over several weeks. The final approach includes: a constraint that each distractor must be a real pharmacological mechanism or drug effect, a requirement to explain why each distractor is wrong in the question's explanation field, and a post-processing step that rejects questions where the distractor options are obviously in different categories from the correct answer.
The cold-start problem
When a new user has zero attempt history, the Exam Readiness Score cannot be computed — there is no data. The first version simply showed zero, which was demoralising and useless.
The solution was a short diagnostic intake quiz — ten questions drawn from each topic in the student's course — that fires automatically the first time a student opens a quiz set. This seeds the performance ledger with real data before the student starts revising. The first readiness score the student sees is therefore based on actual diagnostic evidence, not a placeholder.
Honest feedback without demoralising the user
A student who scores 28% on a diagnostic does not want to see "28/100" displayed prominently. But showing a falsely optimistic number undermines the entire purpose of the score. The tension between accuracy and motivation is real and it took several UI iterations to resolve.
The framing that worked: accurate number, specific path forward. The UI shows the score, then immediately shows the three weakest topics and an estimated time-to-improvement ("~6 focused hours to reach B territory based on your current accuracy"). The number is not softened, but it is contextualised. The student leaves knowing not just how bad things are, but exactly what to do about it.
DynamoDB query design for the readiness score
The initial DynamoDB table design used userId as the partition key and questionId as the sort key. This made it impossible to query by date range — to compute the 180-day window for the readiness score, we had to scan the entire user partition and filter in memory.
We redesigned to a composite sort key of attemptedAt#questionId, which enables a Query with a begins_with condition on the sort key to efficiently retrieve only attempts within the desired date range. The migration required a one-time backfill of existing records. After the redesign, the readiness score query time dropped from ~800ms to under 80ms for users with large attempt histories.
Accomplishments that we're proud of
The oral exam works. A student can upload their Pharmacology notes, generate a quiz, and then start a voice session where an AI examiner asks them the weakest questions from that quiz, listens to their spoken answers, and grades them in real time. The grade updates the Exam Readiness Score immediately. The full pipeline — from PDF upload to live voice examination — runs on a serverless stack with no persistent compute.
The readiness score is calibrated, not guessed. The difficulty weights in the weighted accuracy formula are derived from aggregate user performance across all ExamWiz users. A topic that the majority of students answer incorrectly contributes more heavily to the score. This means the readiness score reflects actual exam risk, not just raw question count.
Zero operational incidents as the user base grew. Deploying to Vercel with DynamoDB as the high-write backend meant that as more students signed up and started practice sessions, nothing broke. No connection pool exhaustion, no database CPU spikes, no 3am incident pages. The infrastructure scaled passively.
We passed the exams. This is the one that matters. The PATH and PHARM examinations at Edo State University — the same subjects that ended the first chapter of this story — were passed on first sitting using ExamWiz as the primary study tool.
What we learned
Per-event data beats session summaries
The first version of ExamWiz stored quiz scores as a single percentage per session: 72%, 88%, 64%. That is what most quiz applications store, because it is simple. But a session percentage is nearly useless for diagnosis. It tells you that you are struggling; it does not tell you where.
The switch to per-question, per-attempt records — storing isCorrect, timeSpent, questionId, quizId, and attemptedAt for every single answer — is what made the Exam Readiness Score possible. More granular data, stored cheaply in DynamoDB, unlocks analysis that a session summary never can. The cost difference between storing one number and storing one record per question is negligible. The analytical difference is enormous.
Build the tool you need, while you need it
Building a study tool while actively preparing for the exam it is designed to help with creates a feedback loop that no amount of user research can replicate. When the flashcard system was generating cards with a drug name on the front and a paragraph of mechanisms on the back, I knew immediately that was wrong — not because of user complaints, but because I was the student sitting there trying to use them at midnight before a test. One fact per card. Short, atomic, reversible. That constraint came from being the user, not from being the developer.
Serverless is only simple if your data model is right
The readiness score computation runs entirely in a serverless function. At first, this seemed like a constraint — no long-running process, no in-memory cache, no connection pool. In practice, the constraint forced better data model decisions. Because every invocation starts cold, the function must complete its database queries and computation in under a second. That requirement pushed us toward the DynamoDB key design described above, which turned out to be the right design anyway.
What's next for ExamWiz
Shared question banks. Right now, every student generates their own questions from their own materials. The next step is allowing questions to be pooled within a university course — so the 200 students taking PHARM 301 at EDSU collectively build a question bank that any of them can practice from. The per-question difficulty weights improve with more attempts, so shared banks produce better readiness score calibration for everyone.
Offline-first mobile experience. The PWA is live, but true offline support — generating quizzes from cached materials, syncing attempt records when connectivity returns — requires a local-first architecture. We plan to store pending attempt records in IndexedDB and sync to DynamoDB when the device comes back online. This matters for students in areas with unreliable connectivity, which describes most of the universities ExamWiz serves.
Calibrated grade thresholds per institution. The current grade prediction uses a universal threshold table. A student at a university where 60% is a passing grade sees the same thresholds as a student where 40% passes. We are building per-institution threshold calibration, seeded from historical exam data where available and adjustable by the student where it is not.
Group study rooms. A shared session where two to four students attempt the same questions simultaneously, see each other's answers after submission, and discuss disagreements. The database infrastructure — DynamoDB for real-time event writes, MongoDB for session state — already supports this. The UI is the remaining work.
ExamWiz for institutions. An admin dashboard for universities and exam-prep centres to distribute course materials to enrolled students, monitor aggregate readiness scores across a cohort, and identify topics where an entire class is underperforming before the exam date. The B2B version of the same product.
ExamWiz is live at examwiz.org. Vercel project: vercel.com/interactive-technologys-projects/exam-wiz Stack: Next.js · Vercel · Amazon DynamoDB · MongoDB · Gemini API Hackathon: #H0Hackathon — AWS Databases × Vercel 2025
Note for hackathon judges: The source repository is private. The Vercel deployment is live at examwiz.org. Vercel Team ID, AWS console screenshot confirming DynamoDB usage, and architecture diagram are included in the submission form.
Built With
- mongodb
- nextjs
- vercel
Log in or sign up for Devpost to join the conversation.