ADR 0038, D14. A dream (`Dream`) holds the night it belongs to (the morning's date, today's by default), an optional title, its text, the marks lucid, nightmare and recurring, a clarity of 1 to 5, the mood on waking and free labels, and when it was written; a row each in `dream`, sealed for its row with the person's key as the sittings (`DreamRepository` on `SealedRows`, `SyncDreamGateway`), followed by `JournalCubit` for every screen. - The Journal, between Explore and Profile: dreams by month, the newest first, searched over title, text and labels as Explore searches, filtered by marks, `+` above the bar; empty, it says that entries are sealed on the device before they sync. - A dream's screen over the tabs: a new one with its text first and focused, the rest folded below; a kept one to read, with Edit and Delete (asked first); leaving one written but not saved asks first. - Today, from 4 to 12 o'clock while last night has no dream, a gentle card leading to a new one; Settings' Journal card switches it off (`dreamPrompt` in the sealed settings, schema 1 kept). - Profile's Practice: this month's dreams and the lucid ones, once the journal holds one. - English and German texts; What's new 0.1.0 names the journal; the account's deletion says it takes the dreams too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
6.8 KiB
6.8 KiB
Halkyon Meditate
What holds for every app and package of this repository is in the root AGENTS.md; it applies here in full, and Learn's patterns (apps/learn/AGENTS.md) wherever Meditate needs the same thing. What Meditate is and why: ADR 0038 (proposed 3 Nov 2026, built by an agent without the developer's interjection; its decisions await their reading).
- Packages:
halkyon_meditate_server,halkyon_meditate_client(generated, never edited),halkyon_meditate_flutter; app IDapp.halkyon.meditateon every platform; no web build. Licences as Learn's (server SSPL, client and app AGPL;LICENSE.md). Copied from Todo's tree on 3 Nov 2026 and stripped to the shell, so its frame, keys and sealed rows are Todo's and Train's. - The server includes
halkyon_base(ADR 0014) and configures it inserver.dart(meditateBase(),lib/src/meditate_base.dart): its basics say it servesmeditate(never change it once apps use it), sign-in mails name Halkyon Meditate, the source is this repository,minimumAppBuild1, a person's space deleted with them (deletePersonData: [deleteMeditateData],lib/src/meditate_data.dart). Accounts (ADR 0016): Meditate holds its own register when it runs alone, and is a member of the instance's register where the operator setsACCOUNT_REGISTER_URL(AccountsMode.fromEnvironment()) with the instance's sharedINSTANCE_SECRET;INSTANCE_MEMBER_MEDITATEnames it to the register.schedulePruning(lib/src/pruning.dart) keeps the module's pruning scheduled once each. Synced tables (ADR 0038, D7;database: sync, every row sealed):content_key,meditate_settings(one row a person, under an ID keyed by the account),sittinganddream(D14), each indexingspaceId. Migrations:initial(Serverpod's, the auth modules', the module's and the sync engine's tables),sittings(the three tables) anddreams(dream). Tests:test/integration/meditate_server_test.dart(the module's endpoints through the server's own dispatch,halkyon_base.<endpoint>, and the sync engine's connector refusing calls without a session),test/integration/sitting/person_deletion_test.dart. - The app is halkyon_app's
InstanceGateandSessionGatewith Meditate's frame (meditateFrame) andServerpodInstanceChecker(app: 'meditate');MeditateDependenciesper instance,MeditatePersonper person (their sync,SettingsRepository,SittingRepository,DreamRepository, and the device'sBellPlayerandScreenAwake); SimpleLogin's way back onapp.halkyon.meditate://and the loopback port 43826. The person's app (MeditatePersonApp) washes in fern (ScreenColor, D3) and holdsPracticeCubit(settings and sittings, read again on every change) andJournalCubit(the dreams) for every screen. go_router (buildMeditateRouter,MeditatePaths): halkyon_ui'sNavigationFrame(MeditateShell) with Today, Explore, Journal and Profile (D2, D14; a bar below medium windows, a rail with the icon from medium on), a practice's page in Explore's branch (PracticeScreen), and over the tabs the sitting (SittingScreen, handed itsSittingPlanasextra), a dream (DreamScreen,/dreamnew,/dream/:idkept) and Settings. Today (TodayTab, D9): greeting by the hour, from 4 to 12 o'clock a card to write down last night's dream while it has none (dreamPromptDue, D14), Sit now (5, 10, 20 and the timer's own length), the practice of the day (practiceOfDay), the week and the days in a row (WeekCard), favourites, recently sat. Explore (ExploreTab, D10): search folded without case or accents (matchesSearch), four goal tiles, kind chips, practice cards. The Journal (JournalTab, D14;lib/src/feature/journal/): dreams by month, the newest first (dreamsByMonth), searched over title, text and labels and filtered by marks (findDreams), + to write one; a dream's night is the date of the morning after it (defaultNight: today's date at any hour); its screen writes with the text first and focused, the rest folded, and reads a kept one with Edit and Delete. Profile (D2, D8): halkyon_app'sHalkyonProfilewith a Practice tab (minutes, sittings, days, the week, the journal's dreams this month and lucid ones once it holds one, every sitting with Delete). The practices arepracticesinlib/src/feature/practice/model/practice.dart(IDs never change once released), their words in the ARBs by ID (practiceTexts), their cues spread evenly over the length (Practice.cueAt). A sitting (SittingCubit, D6): its time fromclock.now(), the ticks only showing it; the bell at the start (where on), between every interval and at the end; the screen kept on while it runs (where on); kept whole at its end, and ended early kept from a minute on where the person says so. The figures (practiceFigures, D8) on the device: a sitting's day by the wall clock it was sat by (Sitting.offsetMinutes), the streak up to today or yesterday, the week from the language's first day. Settings (D11): Sync, the operator's card, Sitting (bell, starting bell, bells between, screen on, the timer's length), Practice (the streak shown), Journal (Today's morning card,dreamPrompt), the account, What's new, About, the version. Texts in British English (the template) and German (du),en_USanden_GBempty. Widget tests start the whole app with halkyon_app's fakes (test/app/meditate_app_test.dart), the bells and screen recorded (test/support/recording_device.dart); a sitting on screen ticks every second, so tests pump seconds (sit) rather thanpumpAndSettle; a test needing the hour (Today's morning card) starts the app insidewithClock(startAt). - The bells (D5) are
assets/bells/*.wav, synthesised byapps/meditate/tool/bells.py(Python's standard library, run fromapps/meditate; the same bytes every run) and played withaudioplayers(AudioplayersBellPlayer). Only while the app runs: bells with the screen off are for later. - The icon is Lucide's
sproutfrom cobalt through pacific into fern (ADR 0031, D5, D7), drawn by the repository'stool/app_icons.py(python3 -I tool/app_icons.py meditatefrom the root):assets/icon/halkyon_meditate_icon.png, Lucide's licence beside it, every platform's launcher icon. serverpod startruns inapps/meditate/halkyon_meditate_serveron ports of its own (8280 to 8282, PostgreSQL 8290), so it can run beside Learn's (8080…) and Train's (8180…); its tests need throwaway passwords in its git-ignoredconfig/passwords.yaml(database,serviceSecret,serverSideSessionKeyHashPepper,emailSignInPepper) or from the environment, as CI gives them.- Not yet: releases (
apps/meditate/release.dart, its key, F-Droid listing, snap), the deploy beside learn.halkyon.eu (compose.meditate.yaml,config/production.yaml, theDockerfile), and what ADR 0038 lists under Later.