
An offline-first K53 learner's-licence drill PWA, 2,195 answerable questions across 26 drill modes in English, Afrikaans and isiXhosa, built for budget Android on 3G.
View the product pageThe problem
SA's K53 failure rate exceeds 60%, people fail on never having seen the question format under timed pressure, not on knowledge. Existing options (out-of-stock booklets, 15–40MB government PDFs, a 2009 quiz site) all fail the budget-device, prepaid-data user.
.jpg&w=3840&q=75)
Architecture
A container-level view of the real system, the boundaries, the trust edges, and where intelligence and money actually flow.
A routerless client SPA: all learning state lives in localStorage (including the SM-2 schedule), so the app works fully offline. Supabase only handles magic-link auth and the PayFast-ITN subscriber activation.
.jpg&w=3840&q=75)
By the numbers
~107KB
index JS (gzip) · 180KB full
100
Lighthouse PWA & SEO
2,195
questions · 1,249 authored + 946 generated
R0.54
AI cost / month @ 10k calls
Stack
Intelligence
The AI Tutor runs OpenAI gpt-4o-mini, a deliberate, honest exception to the platform’s Anthropic default (it shows range). The key lives server-side in a Supabase Edge Function (ai-explain), never in the client; the browser keeps a djb2-hashed localStorage cache (200 entries), allows 3 free calls a day, and deducts quota only on a successful reply. Temperature 0 makes repeat questions deterministic, so cache hits keep cost near R0.54/month at 10k calls.
Data model
1 Supabase table + ~15 localStorage stores
Key decisions
Architecture Decision Records, the trade-offs made deliberately, in the open.
.jpg&w=3840&q=75)
The hard parts, solved
SM-2 spaced repetition schedules review (interval ladder 1d → 6d → round(interval × EF); "mastered" at ≥21 days) while a separate "K53 Nervous System", ~230 lines of dependency-free JS, runs a 6-node hexagon of "nerves," an XP model with combo bonuses and a 6-level ladder (Learner → Traffic Officer, 0 → 15,000 XP) with time-decaying health. Every answer is recorded into both.
Checkout mints an HMAC-SHA256 unlock token, but verification also demands a subscribers row written only by the server-to-server PayFast ITN handler, closing the "return_url token = free premium" hole. The client polls verify up to 12× over ~30s to absorb the redirect-vs-ITN race.
The same app ships as a web PWA and a native Android build, runtime-forking auth (PKCE + a za.co.k53drillmaster:// custom scheme, exchanged on the Capacitor appUrlOpen event) and payments (opened in the system browser; the ITN activates regardless), with the Capacitor build stripping the service worker so the webview never fights Workbox.
Sourced from nanda-k53-drill-master, BUILDLOG_k53, WONDERLAND_DECISIONS_K53, masteryStore.js, spacedRepetition.js, api/{itn,verify,paystack-webhook}.js.
.jpg&w=3840&q=75)
Keep exploring