refactor(base,learn): people's files kept by halkyon_base

ADR 0043, D2, D4, D6 and D7, the first step towards Todo's attachments:
Learn's file store moves into the module, for every server that keeps
files, and Learn becomes its first host.

halkyon_base gets the store as Learn had it: uploads into the caller's
own space by SHA-256, downloads by a row the caller may read, each
person's room (FILE_LIMIT_IDENTIFIED_MB, FILE_LIMIT_INSTANCE_MB, the
operator's file_allowance, which moves into the module unchanged) and
the pruning of files no live row names. It stays free of the sync
engine: a host hands it a FileStore saying which of its rows name a file
and what it takes (HalkyonBase.files); without one the files endpoint
refuses. Its tests, with refusals, run on a stand-in host.

Learn hands it learnFiles: its asset rows, read by their space's members,
a readable file over 20 MB only as a PDF, up to 100 MB. Its app calls the
module; its own asset endpoint stays for released apps alone, forwarding
to the module in Learn's own models, whose names are on the wire. Its
file tests still pass through it, end to end.

Migrations: the module's creates file_allowance. Learn's server migration
holds version rows alone, as tables are matched by name (ADR 0014); its
device migration creates the module's empty table, as every module's.
Todo's, Train's and Meditate's create the empty table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-11 00:11:36 +01:00
commit b7f0aaaec7
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -9,7 +9,7 @@ Halkyon's apps and the packages they share, in one repository and one pub worksp
- **`apps/<app>/`**: each app's packages, as `serverpod create` lays them out (`halkyon_<app>_server`, `_client`, `_flutter`), plus what is the app's alone (Learn's curator, the scripts writing Learn's assets in `apps/learn/tool/`, run from `apps/learn`; the apps' icons are the root's `tool/app_icons.py`, ADR 0031). Learn is the app that runs; Train, Todo and Meditate run too (ADR 0030, ADR 0033, ADR 0038), Todo and Meditate not released yet.
- **`packages/`**: what the apps share, each with its README and licence, which the apps take by path (`path: ../../../packages/<package>`), so a change to a shared package and to the apps using it is one commit:
- `halkyon_ui`: Halkyon's look, the theme around cobalt and copper, Noto Sans bundled, the window-size classes and the widgets every screen is built of (the navigation bar flush with the foot with its fade, and the rail, a banner above every tab, `NavigationFrame.banner`, `FoldingTabs`' tab row folding into the title), with texts of its own (English, German).
- `halkyon_base_server`, `halkyon_base_client`: the Serverpod module every Halkyon server includes (ADR 0014): signing in (a password with TOTP and the resets of ADR 0017, SimpleLogin on `halkyon_oidc`, email codes proving an address; no anonymous accounts since ADR 0020, D25, nor GitHub since D36), an account's ways in and its deletion with a hook for each app's own data, the pruning, the instance's basics, people's handles and public profiles, who may sign up (`SIGN_UP`: open, approval, closed) with the accounts waiting for approval and the instance's operators who approve them (Halkyon Learn's ADR 0021, step 1), the operator's assistants forwarded on halkyon_llm with their grants, each person's budget, the efforts they allow and counted figures, and the instance's privacy page made from its settings (step 2), and the instance's register (ADR 0016): one account per person across an operator's services, held by one service (Learn's server on learn.halkyon.eu) and asked by the others, its members (`ACCOUNT_REGISTER_URL`), all sharing a secret (`INSTANCE_SECRET`); its README says how.
- `halkyon_base_server`, `halkyon_base_client`: the Serverpod module every Halkyon server includes (ADR 0014): signing in (a password with TOTP and the resets of ADR 0017, SimpleLogin on `halkyon_oidc`, email codes proving an address; no anonymous accounts since ADR 0020, D25, nor GitHub since D36), an account's ways in and its deletion with a hook for each app's own data, the pruning, the instance's basics, people's handles and public profiles, who may sign up (`SIGN_UP`: open, approval, closed) with the accounts waiting for approval and the instance's operators who approve them (Halkyon Learn's ADR 0021, step 1), the operator's assistants forwarded on halkyon_llm with their grants, each person's budget, the efforts they allow and counted figures, and the instance's privacy page made from its settings (step 2), people's files, kept by space and SHA-256 in the server's private storage with the room each may take and the pruning, for a host that keeps them (`HalkyonBase.files`, `FileStore`: which of its rows name a file and what it takes; Halkyon's ADR 0043; Learn's `asset` rows, Todo's attachments), and the instance's register (ADR 0016): one account per person across an operator's services, held by one service (Learn's server on learn.halkyon.eu) and asked by the others, its members (`ACCOUNT_REGISTER_URL`), all sharing a secret (`INSTANCE_SECRET`); its README says how.
- `halkyon_app`: every app's shell on the module's client (ADR 0014): the instances a device keeps accounts on and the first start, signing in and switching person, the gates building an app's dependencies per instance and per person, the sync service and where it stands, held back on a metered network as the device's `MobileDataGate` allows (ADR 0042: Android's flag through halkyon_app's own Android plugin, `HalkyonAppPlugin.java`, in Java so that it applies no Kotlin Gradle Plugin, `FakeNetworkWatch` in `testing.dart`; `mobileDataBannerOf` above every tab in each app's frame; the setting in `SyncStatusCard`; an app's files ask `SyncService.filesAllowed`), the account section of an app's settings (`AccountTiles`), every app's Profile (`HalkyonProfile`, decided 2026-11-02: the person's own tab, the same in every app, with their account, the ways they sign in and their public profile, one for all apps, then the app's own tabs) and people's public profiles (`PublicProfileRepository`, `PublicProfileSection`, `showProfileOf`), the wait screen of an account waiting for approval and the operator's card, badge and screen (ADR 0021), the assistants of an app's settings (`AssistantsCard`: granted, by provider, agreed to, what is left of the person's budget, used, and the person's own keys) and the operator's grants from that screen (`AssistantGrantsScreen`: several assistants to several people at once, each with one budget, D57 to D63), with the repositories asking them through the module, at an effort the operator allows, or a person's own key directly (step 2) and what an app's warning before a private studyset goes names (`providerTermsOf`, `OwnAssistant.onThisMachine`, step 3), About with the instance's source link (`showAppAbout`), the device's own speech recognition (`SpeechInput`, `DeviceSpeechInput`: on Android the voice input app handling `RECOGNIZE_SPEECH` where one is installed, `VoiceInputApp` on each app's `VoiceInput.kt`, `app.halkyon/voice_input`, FUTO Voice Input for one, which records itself and returns text, else `speech_to_text`; `FakeSpeechInput` in `testing.dart`; none on Linux; Meditate's ADR 0038, D18) and dictation into a text at its cursor, listening again after each pause (`Dictation`, Meditate's ADR 0038, D15; an app that listens declares the microphone and its usage texts itself), what's new after an update (`WhatsNew`, `WhatsNewOnUpdate`, `WhatsNewTile`, from the app's `assets/whats_new/`, Train's ADR 0030, D61), the device's appearance and language, chosen in Settings and applied before anyone signs in (`Look`, `FileLookStore`, `LookCubit`, `DeviceLookCard`; Learn keeps them among its own device settings and shows `LookSettingsCard`; ADR 0014's amendment of 4 Nov 2026), the language every app picks (`resolveAppLocale`) and countries' and subdivisions' names (Unicode CLDR's, bundled), with texts that name the app.
- `halkyon_editor` (ADR 0033, D37, 6 Nov 2026): rich text, the general parts of Learn's editor on our fork of `appflowy_editor`: `RichContent` (the editor's document JSON, which Learn and Todo store), `RichContentEditor`, `RichContentView`, the format bar, links, the clipboard keeping formats, superscript and subscript, and `EditorBlocks`, through which an app adds blocks, marks within lines and their buttons (`basicBlocks` without any), with texts of its own (English, German). What is Learn's alone stays in Learn on top of it.
- `halkyon_core` (low-level primitives in pure Dart: ids, a logger, `SerialQueue`, `CoalescingRunner`) and `halkyon_interop` (contracts between apps, pure Dart).