Engineering

Offline-first collaboration: making a local operation queue converge safely

From one household record to a recoverable chain of local writes, replay, deduplication, and conflict handling.

Shared-life records often happen where connectivity is least reliable: checking off the rubbish in a lift, adding a purchase in an underground garage, or completing several tasks just as a signal returns. For this kind of product, “works offline” cannot merely mean that the screen still opens. It has to mean that an action does not disappear because the connection did.

Save the intention before waiting for the network

treetree treats a local action as an intention with its own identity. The interface applies the result to local state first, then records a stable operation ID, target, action type, and occurrence time. A network request follows, but the request no longer decides whether the button “really worked.”

This narrows the boundary of failure. When connectivity breaks, the app retries a known operation instead of guessing whether the person tapped the button at all.

A queue is not a cache of requests

Caching raw HTTP requests also preserves transient authentication headers, temporary addresses, and stale context. An operation queue should store domain actions such as “complete task A” or “add a note to record B,” then construct a fresh request from the current session when replaying it.

Each operation needs to answer four questions: who is it, what does it affect, what does it depend on, and is repetition safe? A stable ID allows server-side deduplication. A target version reveals competing writes. Explicit dependencies prevent a child record from being submitted before its parent exists.

Idempotency contains uncertain delivery

Mobile networks create a familiar ambiguity: the server succeeds, but the client never receives the response. If the only available action is “try again,” the server must understand the same operation ID as the same intention, not a second business event.

Idempotency does not resolve every conflict. A one-way transition such as completing a task can accept a duplicate. Edited notes or scheduled times should retain the server version and ask the client to reapply its change against current data. “Last write wins” is not a universal answer; it can quietly erase information another household member just supplied.

Convergence should remain explainable

Queued work moves through waiting, submitting, confirmed, and attention-required states. The interface does not need engineering vocabulary, but it should reveal whether a record is still on the device, is syncing, or needs review. People can understand “this record is still saved here.” They cannot infer much from a spinner that never stops.

Offline-first design does not make errors vanish. It gives every intention a destination, every replay an identity, and every conflict an explanation. When the network returns, the goal is not to empty the queue as fast as possible. It is to converge without duplicates and without swallowing somebody’s change.