Carnet de Bord must work in a parking lot with no 4G. If a trip vanishes, the driver (and RSE payroll) pays. Here is what I kept after several iterations.
Non-negotiable order
- Write locally (immediate source of truth)
- Mark “pending sync”
- Push to Firestore when connectivity allows
- Show an honest UI state (no eternal spinner)
// Flow spirit — not the exact file
await localStore.saveTrip(trip);
syncQueue.enqueue(trip.id);
unawaited(syncService.flush());
Conflicts
I did not build a CRDT. Last-write-wins + server timestamps are enough for this trade. Two devices editing the same day is rare; a perfect merge is not worth the product delay.
Next
The Laravel site also hosts Flutter Web under /app/ — same product, other surface. Offline discipline stays native-mobile-first.