halkyon/docs/adr/0042-mobile-data.md
Tizian 「ティツィアーン」 5d47efd7c5
docs(adr): mobile data, one file store, shared spaces
The developer's decisions of 10 Nov 2026 on their evening's requests:

- ADR 0042: every app holds its sync back on a metered connection, as the
  OS says, and asks in a quiet banner (Sync now, Without files, Not now);
  an answer holds until the connection changes; Settings › Sync chooses
  Ask, Without files or Everything.
- ADR 0043: Learn's file store moves into halkyon_base, room counted per
  service; Todo gets sealed attachments in descriptions and comments, any
  file up to 100 MB, fetched when shown.
- ADR 0044: shared spaces in halkyon_base for every app, Learn's studysets
  first: Owner, Editor and Viewer, keys wrapped to members' key pairs,
  invites by handle or email, links off at first, the material to publish
  chosen item by item, and agents as accounts of their own whose changes
  are suggestions a person accepts. Its open questions come before
  building, first how rows move between spaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-10 23:07:58 +01:00

3 KiB
Raw Blame History

ADR 0042: Sync held back on mobile data

  • Status: decided 10 Nov 2026 by the developer: D1 is their own request, D2 to D5 the agent's recommendations, which they chose. Not built yet.
  • Builds on: ADR 0014 (halkyon_app, every app's shell, with its SyncService).

Context

Every Halkyon app syncs whenever something changes and on a timer, on whatever network the device has. Learn's library holds tens of thousands of rows and hundreds of megabytes of PDFs; a first sync, or an import on another device, can take a phone's monthly data on the go. The developer asked (10 Nov 2026): "It should hold back everything, asking the user whether one wants to sync. Then, give also the option to exclude files, images etc."

Decisions

  • D1. On mobile data, every app holds back its sync, rows and files alike, and asks first. Built once, in halkyon_app, around its SyncService; nothing an app does on the device waits on it (local-first as before: what is written is kept and sent later).
  • D2. Mobile data is a metered connection as the operating system says: on Android its NET_CAPABILITY_NOT_METERED missing, which takes in cellular and also a phone's hotspot or a Wi-Fi network marked metered; read by a few lines of Kotlin in halkyon_app's plugin code (connectivity_plus tells only the kind of network, which misses the hotspot). iOS: NWPath.isExpensive, once the iOS builds ship. Desktops are never metered.
  • D3. It asks with a quiet banner above the lists, never a dialog: On mobile data · 12 changes waiting with Sync now, Without files and Not now. Not now hides it until something new waits. Pulling a list down to sync is an explicit ask too, and syncs as Sync now would.
  • D4. An answer holds until the connection changes: while the device stays on this metered network; asked again after Wi-Fi came and went, or when the app starts again on mobile data.
  • D5. Settings › Sync has On mobile data: Ask (the default), Without files, Everything. No Never: Not now holds back already. A device setting (as the look), not synced: a tablet on Wi-Fi alone and a phone differ.

What "without files" means

Rows sync; files neither go up nor come down. Each app names its files to halkyon_app as a queue of its own (Learn's asset uploads and downloads, its PDFs and Jellyfin covers; Todo's attachments, ADR 0043; Train's maps' tiles stay as they are, fetched when shown), which SyncService pauses and resumes. What is waiting shows in Sync's card (3 files waiting for Wi-Fi).

To work out when building

  • Where the banner sits in each app's frame: halkyon_ui's NavigationFrame has no place for one above every tab yet.
  • The sync engine's stream: whether held back means not opening it at all (the recommendation: nothing goes over the network, not even the handshake) or opening it and sending nothing.
  • Learn's offline reads (b578fcb9) must not wait on a sync held back: the tests of ContentKeys and the gateways already run without one.