Foodops
All docs

Counter · Updated 2026-08-23 · vd99ec08

Sync Conflicts (Counter)

Audio narration for this article is generated with the weekly docs refresh.

Plain-English summary

The counter app keeps working when the internet drops — orders, payments and customer edits are saved locally and synced to the server when the connection comes back. A sync conflict happens when the same thing was changed in two places at once: e.g. the same order was edited on two tills, or a till edited an order offline while the server copy also changed. Rather than silently pick a winner and risk losing a sale or a payment, the counter flags the conflict and asks a person to decide. The Conflicts screen lists each one — a Sales Order Conflict, Payment Conflict or Customer Conflict — and lets you resolve it by keeping either the local (this device's) version or the server version.

When you'd use this

  • After a till was offline and reconnected, and something it changed had also changed on the server.
  • When two devices edited the same order, payment or customer close together.
  • When a badge or prompt tells you there are unresolved conflicts to clear before the data is trustworthy.

Where to find it

The counter app at /conflicts. [code: foodops.counter.app/src/App.tsx route /conflicts → src/pages/ConflictsPage.tsx @ main]

What a conflict looks like

Each conflict names the kind of record it's about. [code: ConflictsPage.tsx entityTypeLabel() — 'salesorder-payment'/'payment' → "Payment Conflict"; 'salesorder'/order* → "Sales Order Conflict"; 'customer' → "Customer Conflict" @ main]

Type Means
Sales Order Conflict The same order was changed in two places (a line, a status, a total).
Payment Conflict The payment side of an order diverged — e.g. a settle recorded on two devices.
Customer Conflict The same customer record was edited in two places.

For each, the screen shows the local version (what this device holds, from its offline store) alongside the server version, so you can see what differs before you choose. [code: ConflictsPage.tsx — local IDB row vs server conflict record @ main]

Walkthrough — resolving a conflict

  1. Open /conflicts on the counter. Unresolved conflicts are listed with their type and when they occurred.
  2. Open one and compare the local and server versions.
  3. Choose the resolution — keep local (this device's version wins) or keep server (the server's version wins). [code: conflictService.ts resolveConflict(resolution) with 'local' | 'server'; ConflictsPage.tsx resolution UI @ main]
  4. The conflict is resolved and drops off the active list. (A resolved conflict can linger briefly as it settles; the client hides stale-resolved ones. [code: conflictVisibility.ts isStaleResolvedConflict @ main])
  5. You can also dismiss a conflict if it no longer needs action. [code: conflictService.ts dismissConflict @ main]

Key concepts

  • Why conflicts exist at all. The counter is offline-tolerant: it stores work locally (IndexedDB) and syncs later. Conflicts are the honest cost of that — the alternative, silently overwriting, could drop a real sale or double a payment. A short conflict list after a bad-connection shift is the system protecting your data, not a bug.
  • Local vs server is a human decision. The counter deliberately does not auto-resolve order/payment/customer conflicts — money and customer records are too important to guess. You pick the version that's correct.
  • Payment conflicts deserve the most care. A Payment Conflict touches what was actually collected; resolve those against your physical/records evidence, not by reflex.

Common questions

Q: Where is Conflicts on the counter? A: It's the /conflicts screen in the counter app. If there are unresolved sync conflicts you'll usually be pointed to it; you can also navigate there directly.

Q: What causes a sync conflict? A: The same order, payment or customer being changed in two places — most often a till that worked offline and then reconnected while the server copy had also changed, or two devices editing the same order at once.

Q: How do I resolve one — do I keep local or server? A: Compare the two versions on the conflict, then choose keep local (this device's version) or keep server. Pick whichever is actually correct; for payment conflicts, check it against what was really collected before deciding.

Q: Is a conflict a bug or lost data? A: Neither — it's the counter refusing to silently overwrite. Nothing is lost while a conflict is open; it's waiting for you to say which version is right.

Edge cases and known issues

A resolved conflict is still showing

  • Cause: A just-resolved conflict can appear briefly while the resolution settles across client and server. The client filters stale-resolved conflicts from the active view. [code: conflictVisibility.ts isStaleResolvedConflict @ main]
  • Workaround: Refresh the Conflicts screen; it should clear once the resolution has synced.

Related

Go beyond POS.
Choose the total solution.

Focus on creating the best experience for your guests while we handle the rest.