product · 2026 · building
Restaurant Manager
Split the bill by QR: everyone pays their share, the waiter watches the table turn green.
Build recipe
AI: Claude Code · phase-gated plan · e2e-first verification · Playwright-checked UI
Human: The product vision, the split-payment UX calls, and the acceptance bar at every one of the 12 phases.
AI wrote the code. I wrote the spec, made the calls, and shipped it.
-
itchGroup dinners end with one waiter charging six cards one by one. The bill should split itself. -
specTwo products in one plan: a multi-tenant restaurant platform (tables, menus, reservations, staff roles) and SplitPay, the QR pay-at-table flow. -
buildpnpm/Turborepo monorepo: NestJS API + two Next.js apps. 12 phases, each shipped working and locked in with e2e tests — 61 by the end. -
hardenThe hard part is concurrency: item claims with TTL so two diners can't pay the same dish, pending-intent reservations against double "pay it all", Stripe webhooks as the only source of truth. -
shipStripe test mode verified end to end — real PaymentIntent, real signed webhook, table flips to paid live over SSE. Own brand: hand-drawn icon set, Fraunces + Inter, editorial public menu page.
Overview
A SaaS for restaurants and small chains: any owner signs up, builds their venue (zones, tables with printable QR codes, seasonal menus with EU allergen labelling, reservations with pacing-based availability, staff with roles) and gets the differentiator on top — SplitPay. Diners scan the table QR, see the live bill, and pay their part: everything, an equal share, their own dishes, or a custom amount. No app install, no sign-up, tips included, cash mixed in when someone insists.

The challenge
Split payments are a distributed-systems problem wearing a hospitality costume. Several phones mutate one bill concurrently: two people claiming the same croquetas, two people tapping “pay the rest” at once, a payment succeeding after the diner closed the browser. Every amount is validated server-side, item claims hold a TTL lease, pending intents reserve their amount, and nothing counts as paid until Stripe’s signed webhook says so.
My role & the AI’s role
I set the product direction and made the calls a founder makes: what the MVP is, how splitting should feel on a phone, which trade-offs were acceptable (static QR per table, no diner accounts, tips go whole to the restaurant). Claude Code executed a 12-phase plan — schema to UI to tests — with each phase verified against the running system before moving on. I reviewed the result of every phase and sent back what didn’t meet the bar, typography included.

Key decisions
- One modular API, three surfaces — back office, public restaurant page and the diner app share a NestJS core; the diner app stays feather-light because it loads on bad restaurant Wi-Fi.
- Webhook-only truth — the UI never marks money as received;
payment_intent.succeededdoes. Demo mode swaps Stripe for a simulated confirm so the whole flow works without keys. - Money as integer cents, everywhere. The equal-split remainder lands on the last share; a 10 €/3 dinner sums back to exactly 10 €.
- 61 e2e tests as the contract — auth, roles, menu scheduling across timezones, availability pacing, and the concurrency races that make or break split payments.

Results
v1 complete and running locally end to end: demo restaurant, printable QRs, live SSE updates on the waiter’s floor plan, and a real Stripe test charge confirmed through the full webhook pipeline. Next: Stripe Connect onboarding for real payouts per restaurant, then a public deployment.