Files
Lumotia/docs/architecture-map/01-frontend/stores.md
jars a1f3f3f134 docs: architecture map (initial 5-slice generation, 105 pages)
Five-slice navigable map of the entire codebase under
docs/architecture-map/. Each slice is a self-contained
breadcrumbed sub-tree:

  01-frontend (16)              Svelte/SvelteKit UI
  02-tauri-runtime (26)         src-tauri commands + lifecycle
  03-audio-transcription (16)   audio + transcription crates
  04-llm-formatting-mcp (19)    llm, ai-formatting, mcp, cloud
  05-core-storage-hotkey-build  core, storage, hotkey, workspace,
                          (26) CI, dev glue

Plus master README.md and data-flow-end-to-end.md tracing
audio bytes from microphone to FTS5 search to MCP read.

Generated by 5 parallel subagents on 2026/05/09 against
HEAD 3c47000. Each page has YAML frontmatter, file:line code
refs, sibling cross-links, plain-English summaries.

Aggregated debt surfaced (full lists in master README):
RB-08 macOS power assertion, schema head drift v14 vs v15,
VAD blocked on ort version conflict, streaming primitives
not wired into live.rs, no prompt versioning, MCP has no
auth, cloud-providers in-memory keystore, SettingsPage
2 484 LOC, commands/live.rs 1 737 LOC, dual theme system,
brand rename to Lumenote pending across the codebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:04:13 +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. Magnotia 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("magnotia:preferences-changed") for preferences (handled by every layout).
  • Persistence keys: magnotia_settings, magnotia_profiles, magnotia_task_lists, magnotia_templates, magnotia_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["magnotia_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 magnotia: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("magnotia: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, magnotia:task-completed, magnotia:step-completed, magnotia:task-uncompleted, magnotia: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 magnotia:start-timer window events. Emits magnotia:focus-timer-cancelled and magnotia: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 magnotia: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 magnotia: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 → magnotia:start-timerfocusTimer store transitions → FocusTimer component renders ring.
  • TasksPage.addTasktasks store → emits magnotia:task-completed/...completionStats refreshes → CompletionSparkline re renders.
  • SettingsPage accessibility toggle → updatePreferences → DOM write + save_preferences invoke + magnotia: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 magnotia:task-* events will silently break the sparkline.

See also