Local-First Data Flow

For this stack, local-first means the app remains useful when the network is absent and user data lives in a local source of truth.

flowchart LR
    input["User input or SMS import"] --> repo["Repository"]
    repo --> dao["Room DAO"]
    dao --> db[("SQLite via Room")]
    db --> flow["Flow query"]
    flow --> vm["ViewModel UI state"]
    vm --> ui["Compose list"]
    repo --> export["CSV or backup export"]

Default Rule

Room is the source of truth for structured app data.

Use this flow:

DAO exposes Flow -> repository maps domain rows -> ViewModel exposes UI state -> Compose renders rows

Writes should also go through repositories:

UI event -> ViewModel -> repository -> DAO transaction
SMS scan -> repository -> parser -> DAO transaction
Worker -> repository -> DAO read/write -> export or sync

Finance App Shape

For a ledger or expense tracker, keep these concepts separate:

ConceptExampleStorage Rule
Raw importOriginal SMS body, sender, timestampStore only if needed and disclosed
Parsed transactionamount, direction, merchant, account, dateStore as normalized Room entity
User correctionrenamed merchant, category overrideStore separately or as explicit fields
Export rowCSV-safe dataGenerate from normalized data, not raw SMS by default

Migrations

Treat each schema change as a user-data migration.

Required practices:

  • Export Room schemas.
  • Write migration tests before release.
  • Avoid destructive migration for real user data.
  • Back up or export before high-risk migrations.
  • Keep version changes small and explainable.

Backup And Export

Start with explicit user-initiated export. It is simpler and easier to explain than silent cloud sync.

Good v1 export options:

  • CSV for spreadsheet compatibility.
  • JSON for lossless app backup.
  • ZIP bundle only when there are multiple files.

Avoid automatic cloud backup for sensitive finance data until privacy policy, encryption, deletion, and account recovery are designed.

Encryption Decision

Encryption is valuable, but it adds key management and recovery risk. For a first local-only prototype, document whether data is plain Room storage, encrypted Room storage, or export-only encrypted.

Do not imply encryption unless the app actually implements and tests it.

Gotcha: Privacy-first does not mean “no policy work.” If you read SMS, you still need clear disclosure, data minimization, restricted permission declaration, and a useful denied-permission mode.