Skip to content

ADR-0015: Offline-first, no network

Context

The app reads sensitive bank notification text. Any network capability creates a data-leak surface and Play-review risk for a notification-listener app.

Decision

AutoBudget is fully offline-first:

  • No app code path performs network I/O — the release manifest does carry network permissions merged from MapLibre (see Amendment), but nothing in the app opens a socket or issues an HTTP request.
  • No analytics, no crash-reporting, and no ad or telemetry SDK that phones home.
  • All state lives in the on-device SQLCipher DB.

Consequences

  • The shipped app has no notification-data upload path: no app code performs a request, and the network permissions present are unused MapLibre manifest entries. This is a code-level guarantee, not a permission-level one.
  • Play Data Safety still answers "no data collected" / "not shared" (all processing is on-device); the console disclosure must acknowledge the merged network permissions rather than claim their absence.
  • Backup paths are also disabled (see ADR-0010), closing the last off-device copy path.

Amendment (2026-10-19): MapLibre's merged network permissions

org.maplibre.android:android-sdk:13.0.2 — pulled transitively by maplibre-compose:0.14.0 for ADR-0030's offline basemap — declares INTERNET, ACCESS_NETWORK_STATE, ACCESS_WIFI_STATE, ACCESS_COARSE_LOCATION, and ACCESS_FINE_LOCATION in its AAR manifest. Manifest merger propagates all five into the release manifest; the app declares no tools:node="remove" rule. The original "no INTERNET permission" claim was therefore false from the MapLibre upgrade onward.

The behavioural decision is unchanged and this ADR stays Accepted:

  • No app code performs an HTTP, socket, tile, style, glyph, or geocoder request. Maps render from the bundled PMTiles overview and user-imported packs (ADR-0030, ADR-0032); style, glyphs, and attribution ship in assets.
  • No analytics, crash-reporting, ad, or telemetry SDK is present.
  • scripts/check-release-permissions.sh pins the complete merged permission set from the release APK and fails on any addition, so a later dependency bump cannot silently add a network-dependent SDK.

Play Data Safety: answer "no data collected" / "no data shared"; do not claim the app has no network permission. If Play review asks, explain that MapLibre supplies the declared permissions and the app code never uses them.

Amendment (2026-11-02): maplibre-compose 0.20 runtime permissions

maplibre-compose:0.20.0 no longer pulls org.maplibre.android:android-sdk directly; its Android OpenGL runtime artifact (maplibre-compose-runtime-opengl-android) supplies MapLibre Native and merges INTERNET and ACCESS_NETWORK_STATE. The app's own manifest declares ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION, and the runtime no longer declares ACCESS_WIFI_STATE; the release gate pins the complete merged set. The behavioural decision and the offline guarantee are unchanged.

Alternatives considered

  • Optional cloud sync/backup — rejected: scope, privacy risk, Play sensitive-permission scrutiny. The review queue + export/import cover portability.
  • Crash reporting — rejected: would need network and would send notification-derived context.