A POS system that requires a stable internet connection is not a POS system - it is a liability. Lebanese restaurants operate under frequent power fluctuations, intermittent mobile data, and occasional ISP outages that last hours. The architecture of a production-grade POS for Lebanon starts offline and treats connectivity as a bonus.
A POS system that requires a stable internet connection is not a POS system - it is a liability. Lebanese restaurants operate under frequent power fluctuations, intermittent mobile data, and occasional ISP outages that last hours. The architecture of a production-grade POS for Lebanon starts offline and treats connectivity as a bonus, not a prerequisite.
This is how we approach the architecture of offline-first POS systems for restaurant and retail operations in Lebanon and the broader MENA region.
Why online-first POS systems fail in the Lebanese context
Most commercial POS systems are designed for markets with reliable infrastructure. They store session data server-side, route every transaction through a central API, and depend on a live connection for inventory checks, discount validation, and receipt generation.
In Lebanon, that assumption fails regularly. The specific failure modes:
ISP outages. Lebanon's internet infrastructure has reliability problems that are well-documented. A restaurant that cannot process orders for two hours on a Friday night has experienced a business-critical failure regardless of whether the failure was caused by the POS software or the ISP.
Load shedding and generator transitions. Power cuts cause brief network disruptions even when the router and modem are on UPS. Modems reboot. 4G dongles reconnect. These brief outages happen during service hours and cannot pause table service.
Mobile data degradation. Many smaller restaurants use mobile hotspots rather than fixed-line internet. Mobile data degrades during peak hours in dense areas. A system that requires constant connectivity becomes unreliable during the busiest parts of the day.
The solution is not to improve the network - that is outside the control of the POS system. The solution is to design the POS so that network state is irrelevant to the core operation of taking orders and processing transactions.
The sync architecture: local-first with Go and SQLite
The local-first architecture stores all operational data on the device. SQLite is the right choice for the embedded database at the terminal. It is reliable, well-supported, and the single-file database model makes backup and recovery straightforward.
The Go backend runs as a local service on the terminal device. In a typical deployment, a small Go binary runs as a system service. It exposes an HTTP API that the frontend (usually an Electron app or a browser-based UI running locally) communicates with.
The data model has two layers: the local SQLite database that holds all current state, and a sync queue that records every write operation in order.
The sync queue is the critical component. Every state-changing operation - new order, order modification, payment, void, discount application - is written to the local SQLite database and simultaneously appended to the sync queue as a structured event.
When network connectivity is available, a background goroutine in the Go service drains the sync queue by sending events to the central API. The central API applies the events to the main PostgreSQL database and returns acknowledgments. Successfully acknowledged events are removed from the local queue.
When the network is not available, the local database continues to accept writes and the sync queue accumulates. The restaurant continues to operate. When connectivity returns, the queue drains automatically without operator intervention.
Handling conflicts when offline queues converge
In a multi-terminal restaurant - a main POS at the bar, a secondary terminal in the dining room, a tablet for table orders - each terminal maintains its own sync queue. When multiple terminals have been offline and then reconnect, their queues may contain conflicting operations.
Conflict resolution is the hardest problem in offline-first systems. The strategies that work in restaurant POS contexts:
Immutable events with server-side ordering. Rather than sending current state to sync (which creates merge conflicts), send immutable events with monotonic sequence numbers. When two terminals have both modified the same order, the server applies events in sequence number order and the result is deterministic. Terminal A adding item X and Terminal B adding item Y to the same order results in an order with both X and Y - there is no conflict.
Pessimistic locking for payments. Payment operations are the one case where optimistic conflict resolution is dangerous. A table that has been paid by one terminal must not be payable by a second terminal. Payment operations go through a distributed lock that blocks when offline. If a terminal cannot confirm payment with the server, the payment does not complete. This is the right design because a double-payment is a worse outcome than a brief operational pause.
Last-write-wins for low-stakes fields. Table status, order notes, and similar non-financial fields can use last-write-wins semantics. The operational cost of a table status being set to the wrong value for thirty seconds is low.
Data integrity across branch locations
Restaurant groups with multiple locations present additional challenges. Each branch runs its own local-first system, and a head office dashboard needs consolidated data across branches.
The architecture that works: each branch has its own central API instance backed by its own PostgreSQL database. The head office has a separate reporting database that receives replicated data from all branch databases.
PostgreSQL logical replication is the mechanism for feeding the reporting database. Each branch database is a publisher, and the reporting database subscribes to all branches. The reporting database only receives completed transactions, not intermediate states, which means it always shows consistent data.
This architecture means branch operations are fully independent. An outage at the central server for Branch A has no effect on Branch B or on the head office reporting database (which receives from Branch A when Branch A's server comes back online).
The replication and head office reporting problem
Head office dashboards for restaurant groups need real-time visibility into sales across all locations. The reporting database pattern handles the data aggregation, but the presentation layer needs careful design.
The key insight: head office dashboards should show data as of the last successful sync, clearly labeled with the sync timestamp. A branch that has been offline for two hours will show sales data that is two hours old. This is correct and expected behavior - the alternative (showing no data) is less useful operationally.
A branch that is offline for more than a configurable threshold (typically 30 minutes) should be flagged in the head office dashboard. This gives operations managers visibility into connectivity issues at specific locations without requiring constant manual checking.
Menu and configuration sync
Offline-first covers transaction operations. Menu updates, price changes, and configuration changes flow in the opposite direction: from head office to branch terminals.
These are handled through a configuration sync mechanism separate from the transaction sync queue. When a terminal reconnects after an outage, it first pulls any pending configuration updates before resuming transaction sync. This ensures that a terminal that has been offline overnight receives updated menu prices before taking the next order.
Configuration changes have a valid_from timestamp. A price change scheduled to take effect at midnight applies at midnight local time on each terminal, regardless of whether the terminal was online when the change was published.
Key lessons from production
Design for offline first, not as an afterthought. Systems designed with connectivity as an optional enhancement are more robust than systems retrofitted with offline mode after initial deployment.
SQLite's reliability as an embedded database for Go services in production is excellent. It handles concurrent reads well and has strong durability guarantees with WAL mode enabled. The single-file model makes backup straightforward.
The sync queue event model is more robust than state synchronization. Events are immutable and ordered. State synchronization requires conflict resolution logic that becomes complex quickly.
Payment operations need special handling. The risk of double-payment justifies pessimistic locking even in offline-first systems. Every other operation can tolerate eventual consistency.
Label timestamps prominently in head office dashboards. Showing data without indicating how current it is misleads operators. Showing slightly stale data with a clear "last updated: 14 minutes ago" label is honest and operationally useful.
Enjoying this article?
Enter your email and get a clean, formatted PDF of this article - free, no spam.
Not sure where to start?
Voxire builds offline-first POS and operational systems for restaurants and retail businesses in Lebanon and the MENA region. If you are planning a POS deployment or replacing an unreliable online-only system, we can help you design the architecture that actually works in the local infrastructure context.
https://voxire.com/get-a-quote/



