contact@satumm.com+88 01749 334279Mon–Fri, 09:00–18:00 (Bangladesh time, GMT+6)LinkedInWhatsApp
Home / Insights / Software Engineering
Software Engineering

Offline-first: designing a counter that keeps selling when the line drops

For a shop, "the system is down" is not an inconvenience. It is a queue of customers walking out. That requirement rewrites the architecture.

On this page

  • Offline-first is not caching
  • What must be local, and what can wait
  • Conflicts are a business decision, not a technical one
  • Sync has to be boring
  • The commercial decision that followed the technical one
  • Testing it means breaking the network on purpose

Most business software is allowed to wait. A report can render a second late; an invoice can be saved when the connection returns. A point of sale is not allowed to wait, because the person at the counter has a queue behind them and a decision to make right now.

We built a POS for supershops where the internet is not dependable. The requirement was blunt: the counter keeps selling when the line is down, and nothing is lost when it comes back. Almost every architectural decision in the product traces back to that sentence.

Offline-first is not caching

A cached application is an online application that degrades. An offline-first application is a local application that happens to synchronise. The difference shows up in where the truth lives.

In the offline-first version, a sale is complete the moment it is written locally. The server is not asked for permission; it is informed later. That inverts the usual flow and forces you to answer questions the online design lets you avoid — chiefly, what happens when two tills and a server all believe different things.

If the sale is not final until the server says so, you have not built an offline system. You have built an online system with a nicer error message.

What must be local, and what can wait

Not everything needs to work offline, and pretending otherwise makes the product enormous. We split it:

  • Must work with no connection: scan, price, discount, total, take payment, print, open the drawer, start the next customer.
  • Can be stale for a while: stock levels, product catalogue changes, price-list updates, staff accounts.
  • Can wait entirely: reporting, dashboards, multi-branch consolidation, anything a head office reads rather than acts on.

Writing that list before writing code is the single most useful hour in an offline project.

Conflicts are a business decision, not a technical one

Two tills sell the last unit of the same item while both are offline. No synchronisation algorithm can tell you what should happen, because that is a question about the business, not the data. Does the shop oversell and reconcile? Does the second sale become a back-order? Does stock go negative and get flagged?

Our rule: the engineering team never picks the resolution. We present the cases, the owner decides, and the decision is written down and implemented explicitly. A conflict rule discovered by a cashier at the counter is a defect regardless of what the code does.

Sync has to be boring

Synchronisation is the part most likely to lose data, so it gets the dullest possible design:

  • Append-only locally. Sales are events, not rows to be edited. A void is another event, not a deletion.
  • Every event carries an identifier generated at the till. Re-sending is then harmless, which matters because re-sending will happen.
  • Sync is resumable and idempotent. It will be interrupted halfway. Assume it, test it deliberately.
  • The till shows its own state honestly: how many events are unsent, and when it last reached the server. Staff trust a system that tells them where it stands.

The commercial decision that followed the technical one

A system that genuinely works without the internet invites an obvious question: why is it billed monthly like a service that depends on being online? For this product the answer was that it should not be. It ships on a one-time licence — which is also a constraint on us, because software sold once has to be cheap for us to support.

Testing it means breaking the network on purpose

You cannot verify an offline product on a good connection. Our test routine includes pulling the connection mid-transaction, restarting the machine with unsent events queued, running two tills against the same stock while both are offline, and reconnecting them in the wrong order. Each of those found something the first time we ran it.

Where this came from

SATUMM's POS System is deployed at TS Future in Klang, Malaysia. The approach described here is what that deployment runs on.

Discuss this with us
More engineering notes

Related reading.

Is this a live problem for you?

If it is, we would rather talk it through than have you read another article about it.