Skip to content

ADR-004: Offline Data Storage Strategy

Status

Accepted

Context

Field coordinators conduct bulk screenings in schools where internet connectivity is absent or unreliable. Students must be able to log health data and watch video content between sync windows. The mobile app must function fully without network access for up to 30 days and sync reliably when connectivity resumes.

Key requirements: - Store up to 30 days of health logs, quiz responses, and video completion events locally. - Prevent data loss on app crash or device restart before sync. - Handle sync conflicts (e.g., same student screened by coordinator and self-logged on the same day).

Options Considered

Option Description Trade-offs
SQLite via sqflite Flutter plugin wrapping native SQLite Mature, ACID-compliant, full SQL query support, widely used in Flutter health apps
Hive (NoSQL) Lightweight key-value store for Flutter Faster for simple reads, but no relational queries — poor fit for student-screening hierarchy
ObjectBox Embedded object DB for Flutter High-performance, but commercial licence for large deployments
Drift (sqflite wrapper) Type-safe Dart ORM over SQLite Better developer ergonomics than raw sqflite, generates migrations automatically

Decision

We will use Drift (SQLite) as the local data store on the Flutter mobile app.

Drift provides a type-safe ORM over SQLite, auto-generates table migrations (avoiding manual SQL in code), and supports reactive streams for real-time UI updates when data changes locally.

Sync Strategy

  1. All writes go to the local Drift database first — the app never waits for the network.
  2. A background sync worker runs every 5 minutes when connectivity is available.
  3. On sync, records are sent to the backend API with their local timestamp.
  4. Conflict resolution: server-wins for coordinator-entered screening data; client-wins for student self-logs.
  5. Successfully synced records are marked with a synced_at timestamp; they remain on-device for 30 days then purged.

Consequences

Positive

  • Full offline capability — no network required for core user flows.
  • ACID compliance ensures no data loss on app crash mid-write.
  • Drift's query DSL catches schema errors at compile time.
  • Records persist until confirmed synced — no silent data loss.

Negative

  • Local SQLite storage counts toward device storage — approximately 2 MB per 1,000 screening records.
  • Sync conflict edge cases require careful testing (coordinator + student logging same record).
  • Data on-device before sync is not covered by cloud DR — device loss means data loss for that window.