Exam practice that works when the internet doesn’t
AceDrill helps Nigerian students prepare for WAEC, JAMB and NECO on any phone, and keeps working with no data. Teachers get class analytics and timed CBT exams; schools get their own walled-off space.
Most students revise on a phone, on data they pay for by the megabyte. Online-only study apps stop working exactly when a student has a free hour and no signal. And an offline app has a cheating problem: if the answers are on the device, anyone can read them.
So AceDrill had to do three things at once: work fully offline, grade honestly without revealing answers, and bring everything back to the server without losing or doubling progress.
What it does
For students: Topic quizzes, WAEC/JAMB/NECO past questions, a daily spaced-repetition review, an AI tutor, plus XP, streaks, badges and short “Recess” games.
For teachers: Class analytics, a question bank with AI-drafted questions, and timed school CBT exams they can watch live.
For schools: Multi-tenant admin where each school only ever sees its own data.
Four decisions that made it work
01 · Honest offline grading
Grade on the phone without sending the answer
Each question carries a SHA-256 hash of its correct option, not the option itself. The phone grades by checking each choice against the hash. The explanation is encrypted with a key derived from the right answer, so it only unlocks once you’ve answered. The server re-grades every paper with the same code.
02 · Sync that can’t double up
Retry as often as you like
Offline work queues in IndexedDB and syncs in batches, each with an idempotency key the server enforces. Mastery updates are single atomic SQL statements, and reviews are dated when they happened, not when the phone found signal.
03 · Learning science
Questions that match the student
Quizzes adapt with Elo ratings, so difficulty follows the learner. Reviews use SM-2 spaced repetition, capped at a year so intervals never overflow MySQL’s 2038 timestamp limit.
04 · AI that degrades gracefully
A tutor with three fallbacks
The tutor tries Groq first, then Gemini, then a built-in rule-based tutor that works offline. Student input is sanitised before it reaches any model, and AI-reported XP is capped per day.
Problems I hit, and how I solved them
Problem
Every explanation costs money
Thousands of learners answer the same questions. Asking the AI each time would mean paying for the same explanation again and again.
Solution
Write it once, reuse it for everyone
Each explanation is generated once for a question and the answer chosen, then saved to the database and cached for 30 days. Every learner after that gets it instantly, at no cost. If two learners ask at the same moment, a lock makes sure only one AI call goes out.
Problem
Free-tier rate limits
AI providers only allow a handful of requests a minute, so a busy evening of revision would hit the limit fast.
Solution
Step aside instead of hammering
When a model says “too many requests”, it’s put on a cooldown for as long as the provider asks, and the next request goes straight to the next model: Groq first, then Gemini. Each learner is also limited to 20 AI requests a minute, so one person can’t use up the quota for everyone.
Problem
Long chats get expensive
Sending a whole conversation with every message multiplies the tokens you pay for.
Solution
Save the chat, send only what matters
Conversations are saved so learners can come back to them, but only the last six turns go to the model. Token usage is recorded daily for each feature, so the cost is always visible.
Problem
No internet, no AI
The students who need help most are often the ones without data.
Solution
Answer from the question bank
Offline, a built-in tutor answers from the question bank’s own worked explanations. Those offline answers are only kept for ten minutes, so the AI gets another chance once the connection is back.
How it’s built
Laravel API with MySQL · React 19 + TypeScript PWA with Workbox and Dexie · KaTeX for maths · Groq and Gemini · past questions imported from the ALOC API · 288 automated tests.
Proof
288 automated tests across feature, unit and a “sync-storm” load test that hammers the sync endpoint to prove retries never duplicate data.