The merge introduces a canonical research guide (`docs/research.md`) as a central reference and updates cross-links across the documentation suite, including agents, architecture, dashboard-guide, settings-reference, and storage docs. The most significant addition is the 436-line research guide itse Fusion-Task-Id: FN-3002
25 KiB
Fusion Dashboard Storage Audit (FN-1202)
1) Summary
- localStorage keys in runtime dashboard code: 20
- Backend settings keys defined in
@fusion/core: 78 total- Global settings: 17 (
GlobalSettings) - Project settings: 61 (
ProjectSettings)
- Global settings: 17 (
- SQLite tables in project DB schema (
packages/core/src/db.ts): 36 (including migration-created tables) - Issues identified: 9
- High: 2
- Medium: 5
- Low: 2
High-level finding: the dashboard currently uses localStorage extensively for UX state and drafts (good for responsiveness), but several keys are not project-scoped in a multi-project app and some data has sync gaps against backend persistence (notably theme settings).
2) localStorage Inventory
| Storage Key | Component/Hook | Data Type | Category | Risk Level |
|---|---|---|---|---|
kb-dashboard-theme-mode |
hooks/useTheme.ts |
enum string (dark/light/system) |
settings overlap | Medium |
kb-dashboard-color-theme |
hooks/useTheme.ts |
enum string (color theme id) | settings overlap | Medium |
kb-dashboard-current-project |
hooks/useCurrentProject.ts |
JSON ProjectInfo object (includes id/name/path/status/etc.) |
project/identity | Medium |
kb-terminal-tabs |
hooks/useTerminalSessions.ts |
JSON array of tab objects (id, sessionId, title, active state, timestamp) |
UI preference (operational session state) | High |
fn-agent-tree-expanded |
hooks/useAgentHierarchy.ts |
JSON string[] of expanded agent ids | UI preference | Low |
kb-planning-last-description |
hooks/modalPersistence.ts (used by PlanningModeModal) |
free-text draft | user draft | Medium |
kb-subtask-last-description |
hooks/modalPersistence.ts (used by SubtaskBreakdownModal) |
free-text draft | user draft | Medium |
kb-mission-last-goal |
hooks/modalPersistence.ts (used by MissionInterviewModal) |
free-text draft | user draft | Medium |
kb-dashboard-view-mode |
App.tsx |
enum string (overview/project) |
UI preference | Low |
kb-dashboard-task-view |
App.tsx |
enum string (board/list/agents) |
UI preference | Low |
kb-dashboard-list-columns |
components/ListView.tsx |
JSON array of visible list columns | UI preference | Low |
kb-dashboard-hide-done |
components/ListView.tsx |
boolean string ("true"/"false") |
UI preference | Low |
kb-dashboard-list-collapsed |
components/ListView.tsx |
JSON array of collapsed column ids | UI preference | Low |
kb-dashboard-selected-tasks |
components/ListView.tsx |
JSON array of selected task IDs | UI preference | Medium |
kb-quick-entry-text |
components/QuickEntryBox.tsx |
free-text task draft | user draft | Medium |
kb-quick-entry-expanded |
components/QuickEntryBox.tsx (legacy cleanup via removeItem) |
legacy bool key (no longer used) | UI preference | Low |
kb-inline-create-text |
components/InlineCreateCard.tsx |
free-text task draft | user draft | Medium |
fn-agent-view |
components/AgentsView.tsx, components/AgentListModal.tsx |
enum string (board/list/tree in view; modal supports board/list) |
UI preference | Medium |
kb-usage-view-mode |
components/UsageIndicator.tsx |
enum string (used/remaining) |
UI preference | Low |
kb-dashboard-recent-projects |
components/ProjectOverview.tsx |
JSON array of recent project IDs | project/identity | Low |
Notes:
- Search scope:
packages/dashboard/app/**/*.ts(x)runtime code (tests excluded). useTheme.getThemeInitScript()also reads the same theme keys before hydration.
3) Backend Settings Inventory
API endpoints reviewed:
GET /api/settings(merged global + project view)PUT /api/settings(project updates)GET /api/settings/globalPUT /api/settings/globalGET /api/settings/scopes
3.1 Global settings (~/.fusion/settings.json)
| Setting Key | Scope | API Endpoint | Description |
|---|---|---|---|
themeMode |
Global | GET/PUT /api/settings/global (+ merged via GET /api/settings) |
Theme mode preference |
colorTheme |
Global | GET/PUT /api/settings/global |
Color/accent theme |
dashboardFontScalePct |
Global | GET/PUT /api/settings/global |
Dashboard Appearance font scale percentage (85–125, default 100) applied before hydration. |
defaultProvider |
Global | GET/PUT /api/settings/global |
Default model provider |
defaultModelId |
Global | GET/PUT /api/settings/global |
Default model id |
fallbackProvider |
Global | GET/PUT /api/settings/global |
Fallback model provider |
fallbackModelId |
Global | GET/PUT /api/settings/global |
Fallback model id |
defaultThinkingLevel |
Global | GET/PUT /api/settings/global |
Default reasoning effort |
ntfyEnabled |
Global | GET/PUT /api/settings/global |
Notifications enabled |
ntfyTopic |
Global | GET/PUT /api/settings/global |
Ntfy topic |
ntfyEvents |
Global | GET/PUT /api/settings/global |
Notification event filters |
ntfyDashboardHost |
Global | GET/PUT /api/settings/global |
Host for deep links |
defaultProjectId |
Global | GET/PUT /api/settings/global |
CLI default project |
setupComplete |
Global | GET/PUT /api/settings/global (internal first-run use) |
Setup wizard completion flag |
favoriteProviders |
Global | GET/PUT /api/settings/global |
Favorited providers |
favoriteModels |
Global | GET/PUT /api/settings/global |
Favorited models |
openrouterModelSync |
Global | GET/PUT /api/settings/global |
Startup model sync behavior |
modelOnboardingComplete |
Global | GET/PUT /api/settings/global |
Onboarding completion flag |
executionGlobalProvider |
Global | GET/PUT /api/settings/global |
Global baseline AI provider for task execution |
executionGlobalModelId |
Global | GET/PUT /api/settings/global |
Global baseline AI model ID for task execution |
planningGlobalProvider |
Global | GET/PUT /api/settings/global |
Global baseline AI provider for planning |
planningGlobalModelId |
Global | GET/PUT /api/settings/global |
Global baseline AI model ID for planning |
validatorGlobalProvider |
Global | GET/PUT /api/settings/global |
Global baseline AI provider for validator/reviewer |
validatorGlobalModelId |
Global | GET/PUT /api/settings/global |
Global baseline AI model ID for validator/reviewer |
titleSummarizerGlobalProvider |
Global | GET/PUT /api/settings/global |
Global baseline AI provider for title summarization |
titleSummarizerGlobalModelId |
Global | GET/PUT /api/settings/global |
Global baseline AI model ID for title summarization |
3.2 Project settings (.fusion/config.json / config.settings)
| Setting Key | Scope | API Endpoint | Description |
|---|---|---|---|
globalPause |
Project | GET/PUT /api/settings |
Hard stop for engine activity |
enginePaused |
Project | GET/PUT /api/settings |
Soft pause for dispatch |
maxConcurrent |
Project | GET/PUT /api/settings |
Max concurrent task-lane agents. Utility AI workflows bypass this limit. |
maxWorktrees |
Project | GET/PUT /api/settings |
Worktree cap |
pollIntervalMs |
Project | GET/PUT /api/settings |
Scheduler poll interval |
groupOverlappingFiles |
Project | GET/PUT /api/settings |
Serialize overlapping file work |
overlapIgnorePaths |
Project | GET/PUT /api/settings |
Project-relative file/directory paths ignored by overlap blocking |
autoMerge |
Project | GET/PUT /api/settings |
Enable auto merge |
mergeStrategy |
Project | GET/PUT /api/settings |
Direct vs PR merge strategy |
worktreeInitCommand |
Project | GET/PUT /api/settings |
Command run on worktree init |
testCommand |
Project | GET/PUT /api/settings |
Project test command |
buildCommand |
Project | GET/PUT /api/settings |
Project build command |
recycleWorktrees |
Project | GET/PUT /api/settings |
Worktree pool toggle |
worktreeNaming |
Project | GET/PUT /api/settings |
Worktree naming strategy |
taskPrefix |
Project | GET/PUT /api/settings |
Task ID prefix |
includeTaskIdInCommit |
Project | GET/PUT /api/settings |
Commit scope formatting |
defaultProviderOverride |
Project | GET/PUT /api/settings |
Project-level override for base default provider |
defaultModelIdOverride |
Project | GET/PUT /api/settings |
Project-level override for base default model ID |
executionProvider |
Project | GET/PUT /api/settings |
AI provider for task execution |
executionModelId |
Project | GET/PUT /api/settings |
AI model ID for task execution |
planningProvider |
Project | GET/PUT /api/settings |
Planning model provider |
planningModelId |
Project | GET/PUT /api/settings |
Planning model id |
planningFallbackProvider |
Project | GET/PUT /api/settings |
Planning fallback provider |
planningFallbackModelId |
Project | GET/PUT /api/settings |
Planning fallback model id |
validatorProvider |
Project | GET/PUT /api/settings |
Validator model provider |
validatorModelId |
Project | GET/PUT /api/settings |
Validator model id |
validatorFallbackProvider |
Project | GET/PUT /api/settings |
Validator fallback provider |
validatorFallbackModelId |
Project | GET/PUT /api/settings |
Validator fallback model id |
modelPresets |
Project | GET/PUT /api/settings |
Reusable model presets |
autoSelectModelPreset |
Project | GET/PUT /api/settings |
Auto-preset by task size |
defaultPresetBySize |
Project | GET/PUT /api/settings |
Size→preset mapping |
autoResolveConflicts |
Project | GET/PUT /api/settings |
Smart conflict auto-resolution |
smartConflictResolution |
Project | GET/PUT /api/settings |
Alias for conflict automation |
strictScopeEnforcement |
Project | GET/PUT /api/settings |
Block out-of-scope file changes |
buildRetryCount |
Project | GET/PUT /api/settings |
Build retry attempts |
buildTimeoutMs |
Project | GET/PUT /api/settings |
Build timeout |
requirePlanApproval |
Project | GET/PUT /api/settings |
Manual plan approval gate |
taskStuckTimeoutMs |
Project | GET/PUT /api/settings |
Stuck task timeout |
autoUnpauseEnabled |
Project | GET/PUT /api/settings |
Auto unpause on rate limits |
autoUnpauseBaseDelayMs |
Project | GET/PUT /api/settings |
Base backoff delay |
autoUnpauseMaxDelayMs |
Project | GET/PUT /api/settings |
Max backoff delay |
maxStuckKills |
Project | GET/PUT /api/settings |
Max detector retries |
maxSpawnedAgentsPerParent |
Project | GET/PUT /api/settings |
Child agents per parent |
maxSpawnedAgentsGlobal |
Project | GET/PUT /api/settings |
Total spawned-agent cap |
maintenanceIntervalMs |
Project | GET/PUT /api/settings |
Maintenance cadence |
autoUpdatePrStatus |
Project | GET/PUT /api/settings |
PR badge polling |
autoCreatePr |
Project | GET/PUT /api/settings |
Automatic PR creation |
autoBackupEnabled |
Project | GET/PUT /api/settings |
Scheduled backup toggle |
autoBackupSchedule |
Project | GET/PUT /api/settings |
Backup cron schedule |
autoBackupRetention |
Project | GET/PUT /api/settings |
Backup retention count |
autoBackupDir |
Project | GET/PUT /api/settings |
Backup directory |
autoSummarizeTitles |
Project | GET/PUT /api/settings |
Auto-title generation |
titleSummarizerProvider |
Project | GET/PUT /api/settings |
Title model provider |
titleSummarizerModelId |
Project | GET/PUT /api/settings |
Title model id |
titleSummarizerFallbackProvider |
Project | GET/PUT /api/settings |
Title fallback provider |
titleSummarizerFallbackModelId |
Project | GET/PUT /api/settings |
Title fallback model id |
scripts |
Project | GET/PUT /api/settings |
Named script map |
setupScript |
Project | GET/PUT /api/settings |
Named setup script reference |
insightExtractionEnabled |
Project | GET/PUT /api/settings |
Insight extraction toggle |
insightExtractionSchedule |
Project | GET/PUT /api/settings |
Insight extraction schedule |
insightExtractionMinIntervalMs |
Project | GET/PUT /api/settings |
Minimum extraction interval |
memoryEnabled |
Project | GET/PUT /api/settings |
Memory system toggle |
tokenCap |
Project | GET/PUT /api/settings |
Token cap for compacting |
runStepsInNewSessions |
Project | GET/PUT /api/settings |
Step session isolation |
maxParallelSteps |
Project | GET/PUT /api/settings |
Parallel step cap |
agentPrompts |
Project | GET/PUT /api/settings |
Per-role prompt templates |
Additional backend notes:
githubTokenConfiguredis returned byGET /api/settingsbut is computed server-side, not persisted.- Non-settings config persisted in backend include
nextId,workflowSteps, andnextWorkflowStepId(configrow / config JSON compatibility path). *Global*keys are never persisted in project settings — these belong exclusively to global settings. Conversely, project-only keys (defaultProviderOverride,executionProvider,planningProvider, etc.) are never persisted in global settings. The two scopes are strictly isolated.
4) SQLite Tables Inventory (packages/core/src/db.ts)
| Table | Purpose |
|---|---|
tasks |
Core task metadata and JSON-backed nested fields (priority, dependencies, steps, log, attachments, comments, model overrides, workflow results, merge details, assignment, mission linkage). |
config |
Single-row project configuration (nextId, settings payload, workflow step counters). |
workflow_steps |
Workflow step definitions (prompt/script) with phase, template metadata, and model overrides. |
activityLog |
Per-project activity/event log with timestamp/type/task indexes. |
archivedTasks |
Archived task snapshots (compact JSON payload + archive timestamp). |
automations |
Scheduled automation definitions, run state, and run history. |
agents |
Agent registry/state/task assignment metadata. |
agentHeartbeats |
Heartbeat run events linked to agents (agentId FK cascade). |
task_documents |
Task-scoped document metadata/content keyed by (taskId, key) with current revision pointer. |
task_document_revisions |
Immutable revision history for task documents (content snapshots by revision). |
__meta |
Schema version + monotonic lastModified change detector. |
missions |
Mission-level planning hierarchy root. |
milestones |
Milestones under missions, including dependency lists and validation state. |
slices |
Slices under milestones with plan-state/activation metadata. |
mission_features |
Features under slices with optional task linkage and execution-loop counters/state. |
mission_events |
Mission event log with ordered sequence numbers and metadata payloads. |
plugins |
Plugin registry, lifecycle state, dependency metadata, and settings blobs. |
routines |
Routine definitions (trigger config, steps/command, catch-up policy, run history, and persisted agentId ownership metadata). Legacy databases missing routine fields (including agentId) are backfilled during init-time compatibility migration. |
roadmaps |
Standalone roadmap metadata. |
roadmap_milestones |
Milestones within roadmaps (roadmapId FK). |
roadmap_features |
Features within roadmap milestones (milestoneId FK). |
project_insights |
Extracted project insights with fingerprint-based deduplication and provenance metadata. |
project_insight_runs |
Insight extraction run history with durable lifecycle metadata (lifecycle JSON includes terminalReason/cause, failureClass, retryable flag, cancellationRequestedAt, timeoutAt, retry lineage fields). Terminal rows are immutable for state transitions. |
project_insight_run_events |
Append-only per-run lifecycle trail (seq, type, message, optional status/classification/metadata) used by cancel/retry/timeout auditing and API inspection. |
todo_lists |
Project-scoped todo list metadata (projectId, title, created/updated timestamps). |
todo_items |
Todo list items (listId FK) with completion state, completion timestamp, and deterministic sortOrder. |
ai_sessions (migration-created) |
Persisted AI interactive sessions (planning/interview/subtask) with status and conversation history. |
messages (migration-created) |
Inter-agent/user message mailbox storage. |
agentRatings (migration-created) |
Agent performance ratings (1-5), optional reviewer metadata, and run/task attribution. |
chat_sessions (migration-created) |
Chat session metadata (agent/project/model/status/title timestamps). |
chat_messages (migration-created) |
Chat message history per session (role, content, thinking output, metadata). |
runAuditEvents (migration-created) |
Run audit trail events across database/git/filesystem mutation domains. |
mission_contract_assertions (migration-created) |
Milestone contract assertions used by mission validator workflows. |
mission_feature_assertions (migration-created) |
Many-to-many links between mission features and contract assertions. |
mission_validator_runs (migration-created) |
Validator run records for mission feature loop execution. |
mission_validator_failures (migration-created) |
Assertion failure records captured during validator runs. |
mission_fix_feature_lineage (migration-created) |
Source↔fix feature lineage for auto-generated mission fix features. |
research_runs |
Research run state (query, topic, status, lifecycle, sources, results, citations, events, exports, token usage). Supports project-scoped active-run uniqueness via (projectId, trigger, status) index. Terminal runs are immutable. |
research_exports |
Persisted export records for research runs (runId FK cascade). Stores format, content, and optional file path. |
research_run_events |
Append-only event log for research run lifecycle tracking (runId FK cascade, ordered by seq). Records status transitions, phase changes, step lifecycle, and failure classifications. |
5) Issues Found
-
Theme dual-storage sync gap
- Severity: High
- Affected:
hooks/useTheme.ts,App.tsx,SettingsModal.tsx, global settings API (/api/settings/global) - Problem: Theme is persisted in both localStorage (
kb-dashboard-theme-mode,kb-dashboard-color-theme) and backend global settings (themeMode,colorTheme), but app bootstrap uses localStorage-only theme hydration. If backend and browser cache diverge, cross-device consistency breaks. - Recommended fix: Make backend global settings the source of truth (or explicitly define local cache precedence + bidirectional sync strategy and conflict resolution).
-
Project-unscoped localStorage keys in multi-project UX state
- Severity: High
- Affected:
App.tsx,ListView.tsx,QuickEntryBox.tsx,InlineCreateCard.tsx,AgentsView.tsx,useTerminalSessions.ts,useAgentHierarchy.ts,UsageIndicator.tsx - Problem: Many keys are global (
kb-dashboard-task-view,kb-dashboard-list-*,kb-dashboard-selected-tasks,kb-quick-entry-text,kb-inline-create-text,kb-terminal-tabs, etc.) and are reused across projects. This can leak preferences/drafts/selections between projects unexpectedly. - Recommended fix: Namespace project-specific keys with
projectId(e.g.,kb:{projectId}:dashboard-list-columns). Keep only true global prefs unscoped.
-
kb-dashboard-selected-taskscan carry stale selections across projects- Severity: Medium
- Affected:
components/ListView.tsx - Problem: Selected task IDs persist globally. In multi-project setups with overlapping ID patterns, stale selections can reappear and affect bulk operations unexpectedly.
- Recommended fix: Project-scope this key, and/or treat selection as in-memory/session-only state.
-
Terminal session persistence stores operational identifiers in localStorage
- Severity: Medium
- Affected:
hooks/useTerminalSessions.ts(kb-terminal-tabs) - Problem: Session IDs and tab metadata persist client-side and are not project-scoped. This is operational state better owned by backend/session layer; stale tabs also survive cache until cleanup logic runs.
- Recommended fix: Move terminal tab/session state to server persistence (or at minimum sessionStorage + project scoping + TTL/versioning).
-
Current project persistence stores full
ProjectInfoobject (includes filesystem path)- Severity: Medium
- Affected:
hooks/useCurrentProject.ts(kb-dashboard-current-project) - Problem: Storing full project objects increases drift risk and stores more data than needed (including local path).
- Recommended fix: Persist only stable
projectId; resolve current object from backend project list each load.
-
Draft persistence is local-only (device/browser-bound)
- Severity: Medium
- Affected:
modalPersistence.ts,QuickEntryBox.tsx,InlineCreateCard.tsx - Problem: Planning/subtask/mission/task-entry drafts are lost on storage clear or browser/device switch.
- Recommended fix: Keep local quick-draft behavior, but add optional server-backed drafts (short TTL) for continuity.
-
Settings scope key lists drift from interfaces
- Severity: Medium
- Affected:
packages/core/src/types.ts,store.ts,routes.ts,SettingsModal.tsx - Problem:
GLOBAL_SETTINGS_KEYS(14) omitssetupComplete,favoriteProviders,favoriteModels;PROJECT_SETTINGS_KEYS(52) omits 9 project interface keys (strictScopeEnforcement,buildRetryCount,buildTimeoutMs,autoUnpause*,maintenanceIntervalMs,scripts,setupScript). This creates scope-classification and patch-filter inconsistencies. - Recommended fix: Generate key lists from schema/interface source (or enforce parity tests) to prevent drift.
-
fn-agent-viewshared by two UIs with different supported modes- Severity: Low
- Affected:
AgentsView.tsx,AgentListModal.tsx - Problem: Both share the same key, but one surface supports
treeand the modal supports onlyboard/list; behavior remains valid but coupling is implicit. - Recommended fix: Decide intentional shared behavior and document it; otherwise split keys by surface.
-
Workflow steps still persisted in config JSON compatibility path (known in-progress work)
- Severity: Low
- Affected:
config.settings/workflowSteps,db.tsconfig table - Problem: Workflow step storage is still tied to config blob structure; this is already being addressed by FN-1201 (migration to dedicated SQLite table).
- Recommended fix: Continue and complete FN-1201; remove config-blob coupling after migration.
6) Recommendations (Prioritized)
P0 — High impact / should do first
-
Unify theme persistence contract
- Backend global settings should be canonical for multi-device consistency.
- Keep localStorage only as startup cache, with explicit hydration/sync rules.
-
Project-scope localStorage keys for project-specific UX state
- Scope at least:
kb-dashboard-task-view, list settings (columns,hide-done,collapsed,selected-tasks), drafts, terminal tabs, agent hierarchy. - Preserve unscoped behavior only for truly global prefs (e.g., appearance if desired).
- Scope at least:
-
Fix settings key parity drift (
*_SETTINGS_KEYSvs interfaces)- Add tests to fail when interface keys and key arrays diverge.
- Prevent accidental mis-scoping and patch filtering anomalies.
P1 — Medium impact
-
Reduce persisted identity payloads
- Store only
projectIdfor current project selection, not full object/path.
- Store only
-
Rework terminal tab persistence model
- Prefer server-managed tab/session restoration or at minimum short-lived, project-scoped client persistence with cleanup/versioning.
-
Adjust selected-task persistence strategy
- Move selection to memory/session scope or project-scoped key with validation on project switch.
P2 — Lower effort / UX polish
-
Optional server-backed draft recovery
- Keep local fast drafts; add opt-in backend draft sync for cross-browser resilience.
-
Clarify shared
fn-agent-viewsemantics- Either intentionally share and document, or split keys by surface.
-
Complete FN-1201 workflow-step migration
- Keep as tracked in-progress storage hardening item.
7) Verification Checklist (for this audit)
- All runtime localStorage keys in
packages/dashboard/appcataloged - Theme dual-storage gap addressed
- Current-project persistence behavior addressed
- Planning/subtask/mission draft behavior addressed
- ListView state scoping addressed
- Terminal tab persistence addressed (
kb-terminal-tabs) - QuickEntry expanded key addressed (
kb-quick-entry-expandedlegacy cleanup) - Agent hierarchy expand state addressed (
fn-agent-tree-expanded) - Backend settings + API route inventory included
- SQLite table inventory included
- Known in-progress FN-1201 called out