What “offline-first” actually requires
Offline-first is a different architecture, not a feature checkbox. The bar is uncomfortably high.
Local-first storage. Every state change a driver makes must be written to durable storage on the device before UI confirmation. SQLite, IndexedDB, or a structured key-value store. Memory-only state is offline-hostile by design.
Append-only event log. The app should not edit a delivery record in place. It should append events (“arrived at stop”, “captured signature”, “marked failed”) to a local log, then sync them later. Append logs survive crashes, force-quits, and partial sync failures.
Idempotent sync. The server has to tolerate the same event being sent twice, or out of order, without duplicating state. The driver does not know the network dropped between two retries.
Conflict resolution. Two drivers cannot both complete the same parcel, and the dispatcher can reassign mid-route. Something has to decide what wins when offline state conflicts with server state. Last-write-wins is almost always the wrong answer here.
South African conditions that punish naive offline handling
Some drivers spend their morning in coverage gaps that genuinely matter.
The Huguenot tunnel and the Hex River Pass have stretches with no signal at all. Drivers crossing them with active deliveries hit dead zones for several minutes.
Industrial parks in places like Spartan and Isando have inconsistent LTE coverage even when the surrounding suburbs are fine. A loading bay can act as a faraday cage.
Rural drops on the N3 between Joburg and Durban can have signal one minute and none the next. Status capture in a thunderstorm is its own subgenre of pain.
Load-shedding at the dispatcher's depot can take the whole sync target offline for four hours at a time. The driver may have signal; the server is what is missing.
The patterns that keep failing
Three patterns we keep seeing fail in field testing.
Online-only forms with a “saving...” spinner. The driver waits for the spinner. The signal does not come back. The driver kills the app. The data is gone.
Optimistic UI without durable persistence. The app shows the delivery as complete, but the underlying state was only in memory. A force-close erases it.
Sync-on-foreground only. The app only syncs when the driver opens it. Background sync should be the default, not a setting buried in a menu.
These look like small product choices. They are architectural mistakes that show up only in the field, weeks after launch, when the driver workforce has stopped trusting the app.
How we approach offline in the CouriB driver app
The CouriB driver app is React Native on Expo. The offline architecture rests on three commitments.
Every delivery action writes to a local database before the UI reacts. The driver gets fast confirmation; the data is durable.
Every action becomes an event in an append-only log on the device. Sync is a separate concern, decoupled from UI state.
Sync runs in the background and tolerates duplicate, out-of-order, and stale events. The server is the single source of reconciled truth, but it is never on the critical path of a driver completing a stop.
This is not a marketing claim. The driver-app features page describes what the app currently supports, and the proof-of-delivery page covers the evidence-capture surface specifically. Engineers evaluating courier software for South African conditions will get more value from those two pages than from a vendor uptime badge.