← The Workshop Floor
VarsityOS logo

VarsityOS

Infrastructure for first-generation students

Built around one question: what does a first-generation South African university student actually need in order to survive the year, not just pass it?

595 commits
2026-03-01 → 2026-08-03
TypeScript 94.6%
private repository
varsityos.co.za
The problem

The student-productivity category assumes a student with a laptop, a data plan, a stable home and a parent who has done this before. Change any one of those assumptions and the product stops fitting. Change all four and you are describing most first-generation students in South Africa.

So the feature list reads oddly next to a Notion clone: NSFAS allowance budgeting, load-shedding awareness, eleven languages, crisis support, and balancing a part-time job against a timetable. None of that is a productivity feature. All of it is what determines whether the year finishes.

4 decisions

What the constraint forced.

Each of these is a choice with a reason attached. The reason is the part worth reading — a stack list tells you what was used, and nothing at all about the judgment that put it there.

  1. 01

    Cache the knowledge base, inject the student.

    The AI companion runs against a large standing knowledge base held in the prompt cache, with the individual student's real budget, tasks, exam dates and mood injected fresh on every call. The split is deliberate: the expensive, stable, carefully-written part is paid for once; the part that must be current is small. Advice that does not know your actual balance is horoscope writing.

  2. 02

    Crisis detection is keyword matching, and that is the correct choice.

    A student in crisis gets emergency resources shown by deterministic keyword match, not by model judgment. A model is better at nuance and worse at guarantees, and this is the one path in the product where a false negative is unacceptable and a false positive costs nothing but a visible helpline. Use the dumb, auditable mechanism where the failure is asymmetric.

  3. 03

    Meter the free tier in the counter, not the UI.

    Ten free AI messages a month, enforced by a Redis counter checked before generation. Enforcing a limit in the interface means enforcing it nowhere — the API is the product surface for anyone who opens devtools, and a free tier that can be bypassed is a free product with extra steps.

  4. 04

    Correct the price on the page, in public, when it drifts.

    Three separate commits in this repository exist only to make a published price match the tiers that actually exist — a tier that had been removed, a range that had gone stale. That is unglamorous and it is the job. A wrong price on a live page is not a content bug; it is a promise the system cannot keep.

What generalises

The part that survives the build.

Constraints local to a market are product features, not localisation.

Load shedding is not a translation string. It changes whether you can assume a network, whether a write can be deferred, and whether an evening study block is a reasonable default. Software written for a market where the power stays on has these assumptions everywhere and cannot list them, because nobody wrote them down.

Row-level security will bite you on recursion before it bites you on access.

Group membership policies that check group membership are a loop, and Postgres says so at the least convenient moment. The fix is a security-definer function that breaks the cycle; the lesson is that RLS is a small program per table and deserves to be read as one.

A payment gateway integration is finished when a failed payment is also correct.

Most of the payment work in this repository is not the happy path. It is field ordering, character encoding in item names, whitespace in a passphrase, and getting return, cancel and notify URLs pointing at the right host after a domain move. The happy path takes an afternoon.

The record

Built with

  • Next.js 14
  • TypeScript (strict)
  • Supabase (Postgres + RLS)
  • Claude API
  • Zustand
  • React Hook Form + Zod
  • Recharts
  • PayFast
  • Vercel

Measured

commits
595
last commit
2026-08-03
journal sections
37

Written from Campus Compass build journal — dossier, 54 sections. The dossier is composed from the journal rather than quoted out of it — the raw sections stay behind the review gate described in docs/THE_FORGE.md §4, and every figure above is read from the GitHub API at build time.