Comande
One small ordering app, reused three times — from a bar's stock register to the orders of a lounge bar — by keeping the stack and rewriting the domain on purpose.
- Status
- Deployed · venue rollout pending
- Role
- Sole developer
- Period
- Aug – Sep 2026
- Platform
- Web · installable on the phone (PWA)
- Stack
- Next.js · React · TypeScript · Tailwind · Supabase · Postgres
Problem
A bar needs three things from an ordering app: whoever is at the counter or on the floor sends the order from their phone, the counter sees it arrive, and at the end of the night the owner reads what sold, when and who served it. The till already handles the money.
I built a small app for that, and then reused it. It started as a stock register for a bar, derived from the stock and till module of La Fossa Events. I forked it into an ordering app for another bar, and then took that same code, with the same domain, to a lounge bar. The stack stayed the same each time. What I rewrote, on purpose, was the language and the rules.
What I built
- Ordering from the phone: staff tap items from the menu, often standing and one-handed, and send a complete order in a few seconds.
- The counter in real time: orders appear on the bar's screen as they're sent. The owner marks them paid, reprints or cancels them, with a reason.
- The night opens itself and closes by hand, and a forgotten night closes on its own after a set number of hours.
- Reports recalculated from the orders: what sold, by person, by product and by hour, compared with past nights.
- Printing at the counter through a separate process on the bar's PC, which reads a print queue from the database.
- A dark interface on purpose, because the night is dark: it's used at 11 pm in a dim room.



Where it was heading. The third fork made the next step obvious: the same app, installed once per venue. I started on a console to provision and manage each venue, a Flutter app for Windows, Linux and Android, and a print agent that can be installed at different customers. That work sits in private repositories, and it's the first time the project went beyond the browser.
Decisions
An order is a sale — the opposite of the app it was forked from.
The first app was a stock register, and its founding decision was "taking stock is not a sale". When I forked it to take orders at a bar, I wrote down that the domain was now reversed on purpose. The old app keeps the stock and drops the money; this one keeps the money and drops the stock. A bar's stock only stays true if someone maps every drink to what it uses, and nobody does. A number nobody maintains lies with the authority of a number.
No tables, no running bills.
Every ordering app has tables. This one doesn't. Each order is born complete and is paid at the till, so there's no floor map, no split bill, and no second cash register competing with the real one. Every exclusion is written down with the condition under which it would stop holding. For a lounge bar with table service, that condition is the first question to ask the owner.
Security lives in the database, not in the interface.
A sign-up trigger creates every account as a staff member and ignores the metadata the user sends, because that metadata is editable and anyone could be born an owner. The role is written afterwards by a server route with the secret key. The TypeScript guards only shape the interface; row-level security decides. Orders have no insert policy at all, so the only way in is one database function that applies the rules.
Quality
- 354pgTAP assertions on the database rules, run in CI on every push
- 0Supabase security and performance advisor errors allowed — the build fails on the first one
- 3apps from one codebase, each with its own domain written down
How I worked
Spec → tickets → coding agents, every decision reviewed and owned by me. Each fork starts by rewriting the glossary and the ADRs, and states which reasons it inherited without checking them again.
Status and links
- StatusDeployed · venue rollout pending
- CodeOn request