Project 01 of 39 · Backend and web · Flagship
AHIA
Multi-tenant retail platform for small traders, delivered as a FastAPI backend, a Next.js web app, and an offline-first mobile client that ships as an installable Android build. Every business-owned table carries a row-level security policy bound per transaction, so a missing filter returns nothing rather than another shop's data. Sales, payments, stock movements, expenses and audit events are append-only ledgers committed together, and a device that goes offline pushes idempotent operations through a sync service that cannot apply a sale twice. Customers build a list from a public link with no account, the trader prices and sources it, and dispatch records the waybill. The suite runs past two thousand tests, including architecture contracts that fail the build on a layering violation.
01Overview
A multi-tenant retail platform for small traders, built for how trade actually happens: a counter sale, a market run, a customer who sends a list and pays on delivery. It ships as a backend service, a web application and an offline-first mobile client, the last of these as an installable Android build.
The engineering spine is a five-layer architecture with enforced import contracts: entities, schemas, persistence, services and transport. No outward imports, no logic in transport, no database driver outside the persistence boundary, and the build fails on a violation rather than a reviewer catching it.
02How it is built
- Every business-owned table carries a row-level security policy bound into the transaction, so a query that forgets its tenant filter returns nothing rather than another shop's data. A missing scope fails closed.
- Sales, payments, stock movements, expenses, audit events and the ledger are append-only and committed together, so a failure part-way through cannot leave half-recorded money. The rule is enforced by database triggers, not by convention.
- Money is never floating point. A price arriving as a float is refused rather than rounded, prices carry at most two decimal places, and they travel the wire as decimal strings so no client passes money through a binary float.
- Offline devices queue operations under a stable operation identifier and push them through a sync service, so a retry after a lost reply cannot book the same sale twice. Inventory merges additively, catalogue edits resolve last-writer-wins, and a customer draft conflict is surfaced rather than silently resolved.
- Authorization is data. Atomic permissions compose into permission sets and then roles, resolved deny-by-default, and a caller cannot grant a permission they do not hold. The interface hides what a role cannot do instead of offering a button that fails.
- The mobile client ships as a downloadable Android build. Offline sales queue in a local store with durable retry bookkeeping, so a trader who has sold twelve things with no signal can see which have reached the shop and which are still in his hand.
- Reconciliation is decided per data type rather than by one global rule: transactional facts are append-only and merge cleanly, stock merges additively as deltas, catalogue edits resolve last-writer-wins on a timestamp, and a customer draft conflict is shown to the person rather than resolved behind them.
- The catalogue is an arbitrarily deep category tree with price inheritance, so a grade carries one price and only the exceptions are listed by name. A customer can add an item the shop has never stocked, leaving the price for the trader to set.
- A customer builds a list from a public link without an account and is remembered by phone number. The list is shared as a generated image or a multi-page PDF, because a typed list arrives truncated on a phone and cannot be forwarded as a list.
- Dispatch records the transporter, the waybill number, the trip cost and a tracking link, so a parcel on a road is attributable and the cost of the run comes off what the list made.
- Storage and media sit behind a provider-neutral port with two interchangeable adapters, server-side validation and optimisation, and per-tenant quota accounting that holds under concurrent uploads.
- Deployment is one push: the image is built in CI and addressed by commit, a migration job runs before traffic moves, and a rollback is a pointer at an earlier tag rather than a rebuild.
- Roughly two thousand tests, including architecture contracts, an ASCII guard, secret scanning and a dependency audit gate that fails the build on a critical finding.
03Screens