1. The Problem with Naive Cache Strategies
Building mobile applications for field technicians requires assuming network connectivity is a luxury rather than a guarantee. When an engineer is working 30 feet underground in a concrete basement or in a remote utility station, your app cannot freeze on a loading spinner or lose draft reports when a POST request times out.
Many engineering teams attempt to solve "offline mode" by caching HTTP GET responses in memory or LocalStorage. This approach falls apart immediately once write operations occur offline:
- Mutations are queued in fragile in-memory arrays that vanish if the OS kills the app.
- Partial form state is lost during background app refresh.
- Concurrent edits create catastrophic data overwrites upon network reconnection.
2. The Change Journal Architecture
Our architecture treats the local on-device SQLite database as the single source of truth for the mobile client. When a technician submits a work order, attaches a diagnostic photograph, or signs a customer waiver, the UI performs an atomic local transaction:
- Writes the entity directly into local SQLite tables.
- Appends an ordered mutation record to an append-only
sync_mutationsjournal table.
-- Local SQLite Mutation Journal Schema
CREATE TABLE sync_mutations (
id TEXT PRIMARY KEY,
table_name TEXT NOT NULL,
record_id TEXT NOT NULL,
operation TEXT NOT NULL, -- 'INSERT', 'UPDATE', 'DELETE'
payload JSON NOT NULL,
client_timestamp INTEGER NOT NULL,
sync_status TEXT DEFAULT 'pending', -- 'pending', 'syncing', 'synced'
retry_count INTEGER DEFAULT 0
);
3. Deterministic Conflict Resolution with Vector Clocks
When connectivity is re-established, a background worker batches pending journal entries and transmits them to an idempotent API gateway. We employ vector timestamps combined with entity-level Conflict-Free Replicated Data Types (CRDTs) to resolve conflicts without requiring manual technician intervention.
If HQ updated a customer's billing address while the technician updated the equipment serial number on-site, both mutations merge cleanly because resolution occurs at the attribute level rather than overwriting the entire row.
4. Production Architectural Takeaways
- Never block UI on network: Optimistic local SQLite writes guarantee a snappy, instantaneous 60fps user experience.
- Idempotent backend handlers: Every network retry must be safely repeatable without duplicating records.
- Tamper-evident logs: Every sync transaction records cryptographic checksums for forensic auditability.