The moment that changed our architecture happened on an ordinary stormy evening. A venue running our early POS build lost internet mid-service — fiber down across the neighbourhood, mobile data crawling. The app kept rendering beautifully. It just couldn't do anything. Orders wouldn't save, the kitchen stopped receiving tickets, and the staff did what staff always do when the system fails: grabbed a notepad. Watching a paper notepad outperform your software is a formative experience.
"Offline mode" went from a backlog item to the defining requirement that night. Here's what we actually built, including the parts that went wrong.
Principle: the terminal is the source of truth during service
Cloud-first POS treats the server as truth and the terminal as a window into it. That's exactly backwards for a restaurant in a country where the connection is the least reliable component in the building. We inverted it: during service, the terminal is authoritative. Every order, every payment writes to a local store first — IndexedDB in the browser build — and the write to the cloud is a background job that can wait.
The mental shift matters more than the technology: sync became a replication problem instead of a request problem. A request can fail. Replication just falls behind and catches up.
The outbox queue
Every state change becomes an event in a local outbox: order created, line added, course fired, payment taken. A background loop drains the queue whenever connectivity allows, with exponential backoff so a flapping connection doesn't hammer the server. Two details cost us real debugging nights:
- Idempotency. When the connection drops mid-upload, you often can't know whether the server received the event. So every event carries a client-generated ID, and the server treats duplicates as no-ops. Retry becomes safe instead of scary.
- Ordering. Events for the same order must apply in sequence — a payment for an order that hasn't arrived yet is nonsense. We ended up with per-order sequence numbers; the server holds out-of-order events briefly until the gap fills.
Conflicts are a business decision, not a technical one
Two terminals, both offline, both touch table 12. Who wins? We burned a week on clever merge strategies before accepting the truth: the answer depends on what the operation means to a restaurant. Adding items from two terminals? Merge both — food was genuinely ordered. Closing a check twice? First close wins, second becomes a no-op. Editing the same line's quantity? Last write wins, and we log it for the manager's end-of-day review rather than blocking service.
Once we started asking "what would the floor manager want?" instead of "what would a distributed-systems paper want?", every conflict rule wrote itself.
Printing without the cloud
Here's the trap almost every cloud POS falls into: the order travels from the terminal up to a server on another continent and back down to reach a printer sitting four meters from the till. Internet dies, printing dies, kitchen stops — even though every device involved is on the same local network and perfectly healthy.
So our tickets never leave the building: terminals talk to the thermal printers directly over the LAN using the ESC/POS protocol. The router doing local switching is enough; the WAN cable can dangle. On iPad we went further and wrote a native TCP printing layer, which also let us render prettier receipts — logo, proper Lao text, QR codes — as raster images.
The kitchen doesn't care about your cloud. The kitchen cares about paper appearing next to the wok.
The honest limits
Offline-first is not magic, and claiming otherwise is how vendors lose trust. While disconnected: cross-location dashboards lag (the owner sees numbers when sync resumes), new menu items published from the office don't arrive, and card/QR payment processing still needs a connection — though recording a payment taken by bank transfer works fine. What never stops: orders, kitchen tickets, coursing, splitting, cash. Which is to say — service never stops. That was the whole point.
If you're evaluating any POS in Laos
Skip the feature matrix. Unplug the router and try to serve one full table: order, fire to kitchen, print the check, take payment, and then reconnect and watch whether everything reconciles without double entries. Fifteen minutes, and you'll know more than any sales deck will tell you. We wrote a broader buying guide here.