advanced 3 min answer

You are designing a field-service application for engineers who work in basements and rural sites with no reliable connectivity. What is the architecture, and what are the decisions that will bite later?

offlinemobilesyncconflict-resolution
Show the full answer Hide the answer

The shape: local-first, with the server as an eventual replica

Connectivity is an optimisation, not a precondition. The application writes to a local store, renders from local state, and synchronises in the background when a connection exists. The engineer completes a job in a basement and it reaches the server hours later without them doing anything differently.

This is not a caching layer added to an online application. It changes what is authoritative, and everything below follows from that.

The decisions that will bite

Conflict resolution, per data type. Two engineers, or one engineer and the office, change the same record while neither can see the other. Last-writer-wins is simple and discards a change silently — acceptable for a preference, not for a job status or a parts list. Field-level merge lets both succeed when they touched different fields. A convergent data type suits an append-oriented structure such as a list of parts used. Surfacing the conflict is honest and only tolerable if conflicts are rare.

Decide this per entity, with the business, in terms of what losing that change would mean. Deciding it globally in code is how a completed job report disappears.

Do not order by device clock. Device clocks are wrong, and a phone several minutes fast wins every conflict regardless of the actual order. Use a logical clock or version vector; keep device time as data, not as the ordering key.

Server rejection after local success. The engineer has already seen the action succeed when the server rejects it on a business rule. There must be a designed way to surface and reverse that — and as much validation as possible should happen locally so the remaining cases are genuinely exceptional.

Data scoping. You cannot ship the whole database to the device. Scope it — this engineer's jobs for the next three days, plus the reference data those need — with a policy for what happens when they are reassigned while offline.

Background execution is a request. The platform decides whether your sync runs, and on a device in a battery-saving mode it may not. Sync on foreground, on connectivity change, and on explicit user action — never rely solely on a scheduled background task.

Storage limits and eviction. Devices run out of space, and the platform may evict your data. Anything not yet synchronised must be protected from eviction or the work is lost.

What to build early

The sync engine is the hard part and it should be built and tested first, against deliberate adversity: airplane mode mid-write, process termination during sync, clock skew, duplicate delivery, partial batch failure, and two devices editing the same record. Every one of those occurs in the field, and each is far cheaper to find in a test harness than in a basement.

The observability for it is equally structural: because you cannot reach the device, whatever telemetry is not built now is not available when a specific engineer's data is missing. At minimum, sync attempts, outcomes, queue depth, conflicts detected and their resolution, all reported when connectivity returns.

What to tell the business

Offline-first is materially more work than an online application, and it is not optional given where these engineers work. The cost lands in conflict handling and sync testing, not in the interface. And there is one product decision they own rather than engineering: for each kind of record, what should happen when two people change it at once — because that is a question about the work, not about the software.