A production-grade consumer app Khula built end to end — real auth, real data, offline-first, shipped from plan to planned-vs-actual in the trolley.
Plan the list. Scan the aisle. See the spend before the till does.
Tally is a mobile-first Progressive Web App for South African households — prepare a list, scan packaged products in-store, capture shelf prices, and watch planned versus actual spend update live in the trolley. Proof that Khula doesn’t stop at slides or prototypes: real authentication, secure data, offline support and continuous delivery, built end to end.
Illustrative Tally cart screen — live trolley total against the planned budget, working offline on in-store signal.
Built around how a shop actually happens
Tally doesn’t bolt a budget onto a note-taking app. It follows the real arc of a grocery trip — from the kitchen table to the till — and keeps the number honest at every step.
Plan
Build the list at home with an intended budget for the shop.
Scan
Scan packaged products in-store with the phone camera.
Price
Capture the shelf price against each item as it goes in.
Live total
The trolley total updates as you shop, against the plan.
Review
See planned versus actual afterwards and learn from it.
Why the trolley total is the whole point
Most budgeting apps tell you what you spent after the money is gone. Tally’s bet is that the only number that changes behaviour is the one you see while your hand is on the shelf — so the entire app is engineered to keep a correct, live trolley total on a cheap phone with patchy in-store signal. That constraint, not a feature list, is what drove every technical decision below: offline-first storage, integer-cent money maths, and a service worker that never blocks the scan.
A plan at home, a surprise at the till
South African households plan a grocery list, then watch the trolley total drift past the budget — with no simple way to see planned versus actual spend while they shop. Prices move week to week, specials mislead, and the mental arithmetic falls apart somewhere around the third aisle.
By the time the total appears on the till slip, every decision that made it too high has already been made. The plan and the spend were never in the same place at the same time.
The gap between the list at home and the number at the till is where money quietly leaks — not through overspending on any one thing, but through never seeing the running total soon enough to act on it.
Prices you can’t predict
Shelf prices shift constantly, so a list costed at home is out of date the moment you reach the store.
No running total
Nothing tells you where the trolley stands against the budget until the cashier does — too late to swap or drop an item.
Patchy in-store signal
Big-box stores kill mobile data, so any tool that needs the cloud to add up a cart is useless exactly when it’s needed.
A real full-stack build, not a prototype
Tally is production-grade software: authenticated, secure, offline-capable, tested and continuously delivered. Six deliberate engineering choices carry the live-total promise.
Modern, mobile-first
Next.js 16, React 19, TypeScript and Tailwind CSS 4 — installable as a PWA with a production service worker.
Secure by default
Supabase Postgres, Auth and Storage with row-level security and consent-aware telemetry — every row scoped to its owner.
Works in the aisle
Dexie / IndexedDB cart with Serwist PWA caching and offline replay, so the trolley keeps totalling with no signal.
Scan on the shelf
ZXing barcode scanning through the phone camera, with browser-native barcode detection as a future path.
Money that adds up
Integer-cent money utilities under unit test — no floating-point rounding bugs in a total people trust.
Shipped continuously
GitHub Actions quality workflow, Playwright smoke tests, and Vercel + Supabase preview environments per change.
Stack, device to database
Tally was deliberately built to start entirely within the free tiers of Vercel and Supabase — no separate servers, no Redis, no paid analytics. Consumer economics done the way a bootstrapped product actually has to.
From a guessed total to a live one
The same shop, done the usual way and the Tally way. Illustrative figures — the shape of the change, not a specific household’s data.
A list costed from memory, no running total, and a number that only appears when it’s too late to change it.
| Item | Guessed | Status |
|---|---|---|
| Maize meal | ~R55 | Off by R10 |
| Milk ×2 | ~R70 | On special |
| Eggs 18s | ~R50 | Up again |
| Rice 5kg | ? | No idea |
| Total | Guess | At the till |
Each item scanned and priced, the total live against the budget, and a planned-vs-actual review afterwards.
| Item | Actual | Running |
|---|---|---|
| Maize meal | R64.99 | R65 |
| Milk ×2 | R77.98 | R143 |
| Eggs 18s | R59.99 | R203 |
| Rice 5kg | R99.99 | R303 |
| Trolley now | R820.14 | 18% under |
A working foundation, hardened first
Tally was built groundwork-first — the secure spine before the flashy screen — so the offline-first active cart lands on foundations that already hold.
App shell
Responsive dashboard and app navigation, installable as a PWA with a production service worker.
Auth
Full password authentication — sign-in, registration, reset and account settings — on PKCE with cookie refresh.
Identity & consent
Profile and consent provisioning under row-level security, with consent-aware telemetry.
Money core
Integer-cent money utilities under unit test — the tested arithmetic the live total is built on.
Next: active cart
The offline-first scanning cart and planned-vs-actual review, landing on the hardened groundwork above.
Why Tally is in this portfolio
Tally is the end-to-end proof point. It shows Khula can take an everyday problem and ship real, secure, tested, deployable software — the same rigour that underpins the compliance and quality-science builds, pointed at a consumer product a household would actually keep on their phone. Slides don’t install. This does.
Tally was built so the number that decides your shop shows up while you can still do something about it — not on the slip, after the fact.
Plan to till, in one offline-first app: the list you make is the trolley you fill, and the trolley you fill is the total you see, live.