The Broad Way

[ Sharp Mind · Sharp Blade · Sharp Spirit ]

root@construct:~
/real-time-sync-between-pos-and-cloud
$_
<-- back to /logs
2026-02-28//LOG

Real-Time Sync Between POS and Cloud

At Yooga, our POS terminals need to work offline. A restaurant cannot stop taking orders because the WiFi went down. So the terminal has a local database, processes transactions locally, and syncs with the cloud when connectivity is available. Sounds simple. It is NOT simple. Especially when money is involved. The core challenge is conflict resolution. Terminal A sells the last unit of picanha while offline. Terminal B, also offline, sells the same last unit. Both transactions are valid locally. When they sync, you have a conflict: two sales for one item. In a chat app, you can merge both messages and nobody cares. In a POS system, you just sold inventory you do not have. Someone is not getting their steak. We explored CRDTs early on. Conflict-free Replicated Data Types are BEAUTIFUL in theory. Each terminal maintains its own state, operations are commutative and associative, and merging is automatic. For things like order metadata, customer notes, and configuration changes, CRDTs work great. We use a Last-Writer-Wins register for most configuration and a Grow-Only Set for audit logs. But CRDTs fall apart for inventory and financial data. A counter CRDT can track increments and decrements from multiple nodes, but it can go negative. In inventory, negative means you sold something you do not have. In financial reconciliation, negative means your books are wrong. For these domains, you NEED coordination, and coordination means you need to be online, which defeats the purpose of offline-first. Our solution is a hybrid approach. Non-critical data uses CRDTs and syncs automatically. Inventory and financial data uses an optimistic local-first approach with server-side reconciliation. The terminal records the sale locally with a "pending_sync" status. When it comes back online, it sends the transaction to the server. The server validates it against the current state. If the inventory is available, it confirms. If not, it triggers a reconciliation flow that involves the restaurant manager. The sync protocol itself uses a vector clock for ordering. Each terminal maintains a logical clock that increments with every local operation. When syncing, the terminal sends its clock and the server compares it with the last known state. Operations are replayed in causal order. This is important because "add item to order" must happen before "apply discount to order" even if they arrive out of sequence. Batching is critical for performance. A busy restaurant generates hundreds of operations per hour per terminal. Syncing each one individually would destroy the network and the server. We batch operations into chunks of 50 or time windows of 30 seconds, whichever comes first. The batch is compressed, signed with the terminal's key, and sent as a single payload. The eventual consistency model works for 95 percent of operations. Menu updates, table assignments, staff schedules, these can be eventually consistent and nobody notices a 30-second delay. But payment confirmation MUST be strongly consistent. When a customer pays, the terminal sends the payment event with a synchronous confirmation requirement. If it cannot reach the server, it queues the payment and marks it as "pending confirmation." The receipt prints with a note. This is a UX compromise but it beats the alternative of processing payments blindly. We have been running this system for over a year now. The conflict rate is under 0.3 percent. Most conflicts are inventory-related and resolve automatically because the restaurant had more stock than the system showed. The remaining conflicts go to a dashboard where the manager resolves them manually. It is not perfect, but it works at scale and it works when the WiFi inevitably dies during Saturday dinner rush.
The Broad Way | Kinho.dev