Hospitality POS that keeps working when the internet doesn't
A venue system built as a desktop terminal that owns its own data, so tabs stay open, dockets keep printing, and a dropped line is an inconvenience instead of a closed bar.
How the work was scoped
Restaurants & Hospitality
26 weeks
Dedicated team
Client name withheld under NDA. Engagement details are shown to the extent our agreement permits.
The hard problem
A tab isn't a shopping cart. It stays open for hours, moves between tables, splits across six people, and re-rates itself when happy hour ends. Their previous system modeled a sale as a single moment, so every one of those was a workaround. And when the line dropped, the bar stopped.
The deeper fault was the data model, more than the network. Their system represented a sale as one moment, and a tab is nothing like that: it opens at the bar, moves to a table, absorbs rounds from three staff, splits six ways and settles hours later. Every one of those was a workaround, and each workaround was a place where the connection mattered again.
A desktop terminal with a real database on the machine, not a cache. Floors and tables, tabs that stay open, dockets queued to the right printer, and stock that depletes by recipe. The server is where terminals meet, not where the truth lives.
The system we were asked to build
Four bars and a restaurant ran on registers that assumed a working connection, and on a Friday night that assumption cost them service. We built a terminal that keeps its own database and treats the network as an optional extra.
Four bars and a restaurant under one operator, all running registers that assumed a working connection. On a Friday night that assumption stopped service. Not degraded it: stopped it. The engagement began after a Saturday when the line dropped at nine and one venue took cash on paper for two hours, then spent Sunday reconstructing the evening from receipts.
Desktop & Platform Engineering
How the pieces fit
- 01
Modeled the venue first (floors, tables and tabs) before anything about payment
Two weeks of running service alongside their staff came before a screen was drawn, which is where the tab-as-a-sale problem surfaced.
- 02
Gave each terminal its own database file, so service never depends on a link
Each terminal holds its own database file, a real one and not a cache, so a dropped line is an inconvenience for syncing and never for serving.
- 03
Queued dockets per printer, so a jammed printer delays one station and not the round
Every line knows the station that makes it and each printer drains its own queue, so a jam holds that station's tickets and reprints on clear.
- 04
Depleted stock through recipes, so a poured cocktail moves five ingredients
Recipes were captured from the bar team over two weeks, and the exercise itself found four drinks being poured to two different specifications.
- 05
Reconciled terminal clocks on reconnect, so a late arrival can't reorder history
Clocks reconcile on reconnect and disagreements are logged, so a terminal rejoining late can't reorder the evening's history.
Tabs that behave like tabs
Open at the bar, move to a table, split any way the table wants, and settle whenever.
A tab is a first-class record with its own lifecycle, so it can open at the bar under a name or a card pre-auth, move to a table, absorb rounds from three staff on three terminals, and settle hours later. Splitting is arbitrary (by item, by share, by amount), and a split that doesn't reconcile refuses instead of silently rounding. Nothing about the tab depends on the server being reachable.
- Tabs are records, not unpaid orders: they move and merge
- Arbitrary splits by item, share or amount
- A split that doesn't reconcile refuses instead of rounding
An open tab mid-settle: opened at the bar under a card pre-auth, moved to Table 12, four rounds from three staff on three terminals, three shares already paid by item and amount, and a split that didn't reconcile refused instead of rounded.
The kitchen display with dockets queued per station: the grill printer jammed and holding its four tickets to reprint on clear, while fry, cold and bar keep draining, every ticket carrying its course and fire time.
Dockets per station
Each line goes to the printer that makes it, queued independently so one jam never stops the kitchen.
Every line knows the station that makes it, so a docket goes to the grill printer, the fry printer or the bar independently. Each queue drains on its own: a jammed printer holds its own tickets and reprints on clear, while the rest of the kitchen keeps working. Dockets carry the course and the fire time, so a kitchen sees sequence instead of a stream of items.
- Lines routed to the station that makes them
- Per-printer queues: one jam never stops the kitchen
- Course and fire time on the docket, so sequence survives
Happy hour that re-rates itself
A round started at 17:58 and completed at 18:02, re-rated when the tab settled: both lines priced by the round's happy-hour window, whatever moment each was rung in, with the rule evaluated on the terminal itself.
Prices follow the happy-hour window the item belongs to, so nobody retypes a round.
Prices resolve against the window the item belongs to, whatever the instant it was rung in, so a round started at 17:58 and completed at 18:02 re-rates itself when the tab settles. Nobody has to void it and retype it. The rules are calendar-driven and evaluated on the terminal, which means happy hour still works when the connection doesn't.
- Prices resolve against the window, not the ring-in moment
- Rounds spanning the boundary re-rate at settle
- Rules evaluated on the terminal, so they survive an outage
The night's count by recipe: a Dry Martini depleting 50ml of gin, 25ml of vermouth and a twist, a five-ingredient sour, versioned pours, and spirits running eight percent over, visible the same night.
Recipe-level stock
A poured drink moves its ingredients, so variance is visible the same night.
A cocktail depletes 50ml of gin, 25ml of vermouth and a garnish, so stock reflects what was actually poured. Variance shows up the same night instead of at the monthly count, and a bar running eight percent over on spirits becomes a conversation on Tuesday, not a discovery in four weeks. Recipes are versioned, so a changed pour doesn't rewrite history.
- Depletion by recipe ingredient, not by unit sold
- Variance visible the same night, not at month end
- Recipes versioned, so a changed pour doesn't rewrite history
Multi-venue transfers
Stock moves between venues against one ledger, so a keg leaving one bar arrives in another's count.
Transfers between venues move against one ledger, so a keg leaving one bar is in the other's count before it arrives, with no one left to remember to adjust both. Each venue's terminals hold their own database and reconcile through the ledger, which means group-level stock is derived from it, never maintained by hand, and two venues can't disagree about where something is.
- Inter-venue transfers written to one shared ledger
- Group stock derived, never separately maintained
- Two venues can't disagree about where a keg is
Five venues on one ledger: two kegs moving from Copper Gantry to The Salt Loft, written to both counts before they arrive, group stock derived from the ledger, and North Quay Tap trading offline with its changes queued.
Phase by phase
Phase 1: Venue Modelling
Floors, Tables and the Life of a Tab
Sat through service at two venues to map how a tab actually behaves (opened at the bar, moved to a table, split at the end) and modeled that before any screen was drawn.
- Venue Domain Model
- Tab Lifecycle Specification
- Floor Layout Editor Brief
Phase 2: The Terminal
A Desktop Application That Owns Its Data
Built the terminal as a desktop application over a local database file, so the register is authoritative for its own service and the network is something it uses, never something it needs.
- Desktop Terminal Build
- Local Schema and Migrations
- Packaged Installer
Phase 3: Dockets and Stations
Print Queues Per Station
Routed each line of an order to the station that makes it, and queued per printer so a jam at the grill holds the grill's dockets and nothing else.
- Docket Routing Rules
- Per-Printer Queue
- Reprint and Void Handling
Phase 4: Stock by Recipe
Ingredients, Not Units
Made stock depletion follow the recipe, so pouring a cocktail moves every component, and transfers between venues reconcile against the same ledger.
- Recipe Model
- Inter-Venue Transfers
- Variance Report
Phase 5: Reconnection
Clock Drift and Ordered Replay
Replayed queued work in the order it happened, whatever order it arrived in, and logged terminals whose clocks disagreed so a drifting machine is found before it corrupts a night's history.
- Replay Ordering
- Clock Reconciliation Log
- Conflict Review Screen
Reconnection after the outage: one tab's queued changes from three terminals replayed in the order they happened, and the Service bar terminal's fast clock corrected and logged for review.
What it carries now
Uninterrupted
Service continuity
−58%
Time to settle a split tab
−41%
Stock variance
5
Venues on one system
Service continuity is a statement about outages since cutover: the line has dropped and service hasn't. Time to settle a split tab is measured from the register's own timestamps at comparable trading periods. Stock variance compares recipe-level depletion against physical counts, before and after, a like-for-like the previous unit-level system couldn't produce.
Client name withheld under NDA. Figures are approximate, drawn from the engagement’s own reporting.
What the architecture settled
- 01
A tab is a long-lived object, not a transaction. Model it as a sale and every real behavior becomes a workaround.
A tab is a long-lived object with a lifecycle, and modeling it as a transaction turns every genuine bar behavior into something the staff have to work around.
- 02
A terminal that owns its data doesn't need the network to be reliable, only to be present eventually.
The network still matters for reconciliation and for the other terminals; what changed is that it stopped mattering for taking an order.
- 03
Queue per printer, not per order: one jammed station should never hold a whole round.
Per-printer queues over per-order ones is a small decision with a large consequence: one jammed station should never hold an entire round.
- 04
Replaying by arrival order silently corrupts history. Order by when it happened, and log the clocks that disagree.
Replaying by arrival order corrupts history silently. Ordering by when things happened, and logging the clock disagreements, is what makes the reconstruction trustworthy.
How the work was run
We ran service alongside their team at two venues before drawing a screen, which is where the tab-as-a-sale problem surfaced. The terminal shipped venue by venue, with the busiest bar last. By the time it cut over, the queue and replay behavior had already survived four quieter Fridays.
A dedicated team for twenty-six weeks, running service alongside the venue staff at two sites before drawing a screen. That's where the tab-as-a-sale problem surfaced. The terminal shipped venue by venue with the busiest bar last, so by the time it cut over, the queue and replay behavior had already survived four quieter Fridays.
Five changes, three orders
Replay by arrival and the night quietly rewrites itself.
One tab collects a move, a round, a split and a payment from three terminals while the line is down. Here are the same five changes replayed in three orders against the same rules. Switch tabs, or use the arrow keys once one is focused.
Queues are applied in the order they reach the server. Bar 1 reconnects first, so its split is applied while the tab still only holds two pints.
Line down 21:05–21:24 · 5 changes, 3 terminals · applied in this order
- 121:02:10Open tab · Bar 1Hale · card pre-auth · 2 × Harbor Pale $16.00Tab opened at $16.00
- 221:24:01Split tab · Bar 13 shares, even$16.00 does not split evenly: refused
- 321:24:03Move tab · FloorBar → Table 7Moved to Table 7
- 421:24:03Settle share · FloorShare 1 of 3 · $24.00No $24.00 share to settle: to review
- 521:24:06Add round · Service bar4 × Negroni $56.00Tab now $72.00
Tab T-4502 · Hale, Table 7
History reordered
The split was taken against a tab that didn't yet hold the round, so it refuses, and the payment has nothing to settle against.
Illustrative: times, amounts and the replay speed are drawn for this example. The rule is the product’s: order by when it happened, and log the clocks that disagree.
From a round at the bar to one ledger across five venues
The first three stages run on the terminal in the room and never wait on the line. The last two need the network only to be present eventually: the server is where terminals meet, not where the truth lives.
- 01 · TriggerA line rung in on a tabA tab is a record with its own lifecycle, so it opens, moves, splits and settles without the server being reachable.
- 02 · StorageThe terminal's own database fileA real database on the machine, not a cache. A dropped line is an inconvenience for syncing, never for serving.
- 03 · EnginePricing, dockets and recipes, on the terminalHappy-hour rules evaluate locally, each printer drains its own queue, and stock depletes by recipe ingredient.
- 04 · QueueOrdered replay on reconnectQueued work replays in the order it happened, whatever order it arrived in, and clock disagreements are logged.
- 05 · DeliveryOne ledger, shared by every venueTransfers write to one ledger and group stock is derived from it, so two venues can't disagree about a keg.
What happens when the connection goes
No more cash on paper, and no Sunday spent rebuilding Saturday
The line drops; service does not
Each terminal holds its own database file, and tabs, splits, happy-hour pricing and dockets all run from it. The network matters for reconciliation and the other terminals. Taking an order never waits on it.
One jammed printer holds one station
Every line is routed to the station that makes it, and each printer drains its own queue. A jam at the grill holds the grill's tickets and reprints them on clear; the rest of the kitchen keeps working.
A late terminal can't rewrite the night
Queued work replays in the order it happened, whatever order it arrived in. Terminal clocks are reconciled on reconnect and disagreements logged, so a drifting machine is found before it corrupts the history.
Running venues that cannot stop serving when the line does? Scope your build in 3 minutes.
Scope your buildNearby engagements
AI & AutomationAI phone ordering that fills every table's takeout slot
A voice agent that answers every takeout call, takes orders straight into the POS, and upsells like a trained host, even at the dinner rush.
Restaurants & Hospitality · 9 weeks
Mobile AppsA delivery app built around fast decisions
A food delivery app where browsing, ordering, and live order tracking are built around quick decisions and a smooth checkout.
Restaurants & Hospitality · 14 weeks
Web PlatformsA property portal built around how buyers browse
A property listing and search portal that helps buyers and renters find the right home fast, with a listing manager built for agents behind the scenes.
Residential Brokerage · 14 weeks
Let's talk
Running a large platform, shaping a first MVP, or getting a product ready for a funding round? Tell us where you are. We'll shape the process around it, and stay with you after launch.














