Files
Jake 26c7307607
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
agent: lumotia-rebrand — docs, scripts, root config, residuals
Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.

transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
  -> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
  as immutable audit trail). Includes architecture-map references
  to magnotia_core::*, magnotia_storage::*, etc. now pointing at
  lumotia_*; dev-setup.md tracing output examples (lumotia_startup
  target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
  audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
  hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
  crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
  crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
  doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
  ("lumotia_task_sync"); magnotia_locale i18n localStorage key
  renamed + migration shim added; CSS keyframe names
  magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
  system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
  keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
  wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
  to "lumotia era" earlier — restored).

Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
  legacy detection strings in legacy_and_target_paths() so the
  migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
  — migration call sites reference the legacy magnotia keys
  deliberately.
- docs/handovers/ — historical audit trail.

cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:38:03 +01:00

8.3 KiB

name, type, slice, last_verified
name type slice last_verified
Stores architecture-map-page 01-frontend 2026/05/09

Stores

Where you are: Architecture mapFrontend → Stores

Plain English summary. Reactive state. Lumotia uses Svelte 5 runes ($state, $derived, $effect) instead of legacy stores. Each file under src/lib/stores/ exports one (or more) $state objects plus the helper functions that read or mutate them. Components import the state directly and Svelte tracks reactivity automatically. Two persistence channels: localStorage for settings, profiles, task lists, templates; Tauri (save_preferences) for accessibility preferences.

At a glance

  • Path: src/lib/stores/
  • Files: 10 (4 085 LOC across stores + utils + types).
  • Cross window sync:
    • localStorage storage event in the float window for settings.
    • Tauri emit("lumotia:preferences-changed") for preferences (handled by every layout).
  • Persistence keys: lumotia_settings, lumotia_profiles, lumotia_task_lists, lumotia_templates, lumotia_locale, plus a viewer handoff key.

The stores

page.svelte.ts (697 LOC). The big one.

Owns:

  • page (PageState): current, status, statusColor, activeProfile, recording, timerText, handedness, taskSidebarOpen. Initial: current = "dictation".
  • settings (SettingsState). Persisted to localStorage["lumotia_settings"] via utils/settingsMigrations.ts. Defaults at line 60 onward. Includes engine choice, model size, language, device, format mode, fillers, anti hallucination, British English, auto copy/paste, transcription preview, meeting auto capture (+ apps list), sound cues + volume, timestamps, theme, font size, AI tier, LLM model id and prompt preset, GPU concurrency, prewarm flag, save audio, output folder, global hotkey, sidebar collapsed, microphone device, energy state, match my energy, TTS voice + rate, rituals (morning/evening + time), launch at login, ritualsPromptSeen, nudges (enabled/muted/speakAloud), showMomentumSparkline.
  • profiles, templates, taskLists arrays.
  • tasks and history arrays.

Helpers (selected, with line refs):

  • addToHistoryadd_transcript (page.svelte.ts:234).
  • mapTranscriptRow, saveTranscriptMetaupdate_transcript (page.svelte.ts:272).
  • deleteFromHistoryByIddelete_transcript (page.svelte.ts:320).
  • addTask, completeTask, uncompleteTask, deleteTask, setTaskEnergy, updateTask → matching *_task_cmd Rust commands. completeTask and friends emit lumotia:task-completed | -uncompleted | -deleted window events (line 470 onward).
  • Task lists: addTaskList, renameTaskList, deleteTaskList, moveTaskList, sortTaskLists, moveTaskToList, moveTaskListToProfile.
  • Profile mutators: addProfileTaskList, removeProfileTaskList.
  • saveSettings, saveProfiles, saveTemplates write to localStorage.

preferences.svelte.ts (172 LOC).

Owns the Preferences shape: theme ("light" | "dark" | "system"), zone ("default" | ...), accessibility (fontFamily, fontSize, letterSpacing, lineHeight, transcriptSize, bionicReading, reduceMotion).

  • DOM is the source of truth at runtime: readFromDOM() reads <html> data attributes and CSS variables; applyToDOM(prefs) writes them.
  • Persists via invoke("save_preferences", { preferences: JSON.stringify(prefs) }) with a debounce. Failure shows a single toast per process (preferences.svelte.ts:101-120).
  • Cross window: broadcastPreferences calls emit("lumotia:preferences-changed", { source, prefs }). Receivers in +layout.svelte and the secondary +layout@.svelte files apply external prefs after a label check.
  • Exposes getPreferences, updatePreferences, updateAccessibility, applyExternalPreferences, PREFERENCES_CHANGED_EVENT constant.
  • Font families resolved from a constant map (Lexend, Atkinson, OpenDyslexic).

profiles.svelte.ts (123 LOC).

The vocabulary profile store (separate from the profiles array on page.svelte.ts). Holds:

  • activeProfileId, list of profiles, vocabulary terms.

Tauri commands: load_profiles_cmd (implicit on load), update_profile_cmd, delete_profile_cmd, delete_profile_term_cmd, plus add term commands. Exposes DEFAULT_PROFILE_ID.

toasts.svelte.ts (99 LOC).

Toast notifications. State is an array of {id, severity, title, body, duration}.

Helpers: toasts.info(title, body?), .warn, .error, .success, plus dismiss(id). Auto dismiss via setTimeout. Read by ToastViewport.svelte.

llmStatus.svelte.ts (64 LOC).

Tracks the LLM lifecycle pill. State is one of idle | loading | generating | downloading | unavailable.

  • refreshLlmStatus(aiTier) calls get_llm_status and updates the chip.
  • markGenerating(), markGenerationDone() are called around cleanup_transcript_text_cmd in DictationPage.svelte.

completionStats.svelte.ts (59 LOC).

Phase 8 gamification. Owns recentCompletions (DailyCompletionCount[]) and a todayCount derivation.

Refresh triggers (no polling): module load, lumotia:task-completed, lumotia:step-completed, lumotia:task-uncompleted, lumotia:task-deleted, window focus (for midnight rollover).

focusTimer.svelte.ts (238 LOC).

Owns the floating focus timer. State: target ms, started at, label, taskId, paused.

  • setInterval at 250 ms (TICK_INTERVAL_MS).
  • Triggered by lumotia:start-timer window events. Emits lumotia:focus-timer-cancelled and lumotia:focus-timer-complete on transitions.

implementationIntentions.svelte.ts (260 LOC).

"When X happens, do Y" rules engine. Owns the rules array.

  • 30 second setInterval (TIME_RULE_POLL_MS) checks time based rules.
  • On match, can route page.current = "tasks" (lines 125, 136, 142) and call tts_speak if speak aloud is enabled (line 170).
  • Uses delete_implementation_rule to remove a rule (line 82).
  • Emits lumotia:implementation-rules-changed after writes.
  • Lifecycle: startImplementationIntentions, stopImplementationIntentions from +layout.svelte.

nudgeBus.svelte.ts (292 LOC).

Owns the nudge engine. Two setInterval handles:

  • blurCheckHandle for window blur detection.
  • triagePollHandle at 5 minute cadence checking morning triage triggers.
  • Plus a microStepTimers Map for per task delayed notifications.

Key commands: deliver_nudge (line 112), tts_speak (line 119). Emits lumotia:morning-triage-finished after the modal closes. Lifecycle: startNudgeBus, stopNudgeBus from +layout.svelte.

speaker.svelte.ts (10 LOC).

Tiny. Holds speakingId so SpeakerButton instances can debounce / cancel each other. Candidate for collapsing into a util (README debt note 9).

Cross store traffic

  • DictationPage.completeRecording()addToHistory (page) → add_transcript Rust → push to history.
  • MicroSteps "start timer" button → lumotia:start-timerfocusTimer store transitions → FocusTimer component renders ring.
  • TasksPage.addTasktasks store → emits lumotia:task-completed/...completionStats refreshes → CompletionSparkline re renders.
  • SettingsPage accessibility toggle → updatePreferences → DOM write + save_preferences invoke + lumotia:preferences-changed emit → secondary windows mirror.
  • Float window settings sync uses localStorage storage event, not the Tauri preference event. Drift candidate.

Watch outs

  • page.svelte.ts is doing a lot. Splitting transcripts, tasks, task lists, settings, profiles into separate stores would help but is outside this map's job.
  • settings and preferences overlap (theme, font size, transcriptSize). Settings are localStorage only; preferences are Tauri persisted. Race possible during the migration $effect.
  • nudgeBus and implementationIntentions both run timers. They are torn down in +layout.svelte onDestroy. Only the main window starts them.
  • completionStats listens on the DOM window for events; it does not subscribe to tasks directly. Adding a new task mutation that does not emit one of the lumotia:task-* events will silently break the sparkline.

See also