From 4b60c4b7b2e0b096c21c252327b910c80003ba2b Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Mon, 20 Oct 2025 15:17:36 +0200 Subject: [PATCH] docs: add comprehensive JSDoc for all state sync points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements Phase 6.1 of the state management refactoring plan. Added detailed documentation for all 5 critical sync points in the state management architecture, making data flow explicit and traceable. Sync Points Documented: 1. Document → graphStore (useActiveDocument.ts:67-80) - When: Active document switches - What: Loads timeline state into editor - Direction: ConstellationDocument → graphStore 2. graphStore → timeline current state (useActiveDocument.ts:197-214) - When: Graph changes detected - What: Updates timeline's current state - Direction: graphStore → timeline.states[currentStateId] 3. timeline → document (workspaceStore.ts:789-818) - When: Document save - What: Serializes timeline to storage - Direction: timelineStore → document.timeline → localStorage 4. document types → graphStore (workspaceStore.ts:1018-1034) - When: Type management operations - What: Syncs types to editor if active - Direction: document → graphStore (if active) 5. timeline → graphStore (timelineStore.ts:286-311) - When: Timeline state switch - What: Loads state's graph into editor - Direction: timeline.states[targetId] → graphStore Each sync point includes: - ✅ Visual separator for easy identification - ✅ Trigger condition (when it occurs) - ✅ Data being synchronized (what changes) - ✅ Source of truth clarification - ✅ Data flow direction - ✅ Context and rationale Benefits: - Clear understanding of data flow through the system - Easier onboarding for new developers - Prevents accidental breaking of sync relationships - Makes debugging state issues much faster 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/stores/timelineStore.ts | 19 ++++++++++++-- src/stores/workspace/useActiveDocument.ts | 29 ++++++++++++++++++-- src/stores/workspaceStore.ts | 32 ++++++++++++++++++++++- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/stores/timelineStore.ts b/src/stores/timelineStore.ts index ae66a01..0be74fb 100644 --- a/src/stores/timelineStore.ts +++ b/src/stores/timelineStore.ts @@ -283,8 +283,23 @@ export const useTimelineStore = create( return { timelines: newTimelines }; }); - // Load target state's graph (nodes, edges, and groups - types are global) - // IMPORTANT: Use loadGraphState for atomic update to prevent React Flow errors + /** + * ═══════════════════════════════════════════════════════════════════════════ + * SYNC POINT 5: timeline → graphStore + * ═══════════════════════════════════════════════════════════════════════════ + * + * When: Timeline state switch (user navigates to different state in timeline) + * What: Loads target state's graph (nodes, edges, groups) into graphStore + * Source of Truth: timelineStore (targetState.graph) + * Direction: timeline.states[targetStateId].graph → graphStore + * + * When switching between timeline states, we load the target state's graph + * into the editor. Types and labels remain the same (document-level config), + * only nodes/edges/groups change between states. + * + * IMPORTANT: Uses loadGraphState for atomic update to prevent React Flow + * "Parent node not found" errors when groups and their children load. + */ const graphStore = useGraphStore.getState(); graphStore.loadGraphState({ nodes: targetState.graph.nodes as unknown as Actor[], diff --git a/src/stores/workspace/useActiveDocument.ts b/src/stores/workspace/useActiveDocument.ts index 3884609..3396424 100644 --- a/src/stores/workspace/useActiveDocument.ts +++ b/src/stores/workspace/useActiveDocument.ts @@ -64,7 +64,20 @@ export function useActiveDocument() { labels: [], }); - // Load active document into graphStore when it changes + /** + * ═══════════════════════════════════════════════════════════════════════════ + * SYNC POINT 1: Document → graphStore + * ═══════════════════════════════════════════════════════════════════════════ + * + * When: Active document switches (document tab change) + * What: Loads nodes, edges, groups, types, labels from document into graphStore + * Source of Truth: ConstellationDocument (persistent storage) + * Direction: document.timeline.currentState → graphStore (working copy) + * + * This is the entry point for loading a document's data into the editor. + * It deserializes the document's current timeline state and populates the + * graphStore with the working copy that React Flow will render. + */ useEffect(() => { if (activeDocument && activeDocumentId) { console.log(`Loading document into graph editor: ${activeDocumentId}`, activeDocument.metadata.title); @@ -181,7 +194,19 @@ export function useActiveDocument() { labels: graphLabels as LabelConfig[], }; - // Update the timeline's current state with the new graph data (nodes, edges, and groups) + /** + * ═══════════════════════════════════════════════════════════════════════════ + * SYNC POINT 2: graphStore → timeline current state + * ═══════════════════════════════════════════════════════════════════════════ + * + * When: Graph changes detected (node/edge/group add/delete/move) + * What: Updates timeline.states[currentStateId].graph with latest graphStore data + * Source of Truth: graphStore (working copy) + * Direction: graphStore → timeline.states[currentStateId].graph + * + * This keeps the timeline's current state in sync with the editor's working copy. + * When the document is saved, this updated timeline will be serialized to storage. + */ useTimelineStore.getState().saveCurrentGraph({ nodes: graphNodes as never[], edges: graphEdges as never[], diff --git a/src/stores/workspaceStore.ts b/src/stores/workspaceStore.ts index fb67745..913966f 100644 --- a/src/stores/workspaceStore.ts +++ b/src/stores/workspaceStore.ts @@ -786,7 +786,20 @@ export const useWorkspaceStore = create((set, get) // and are managed via workspaceStore's type management actions. // We do NOT copy them from graphStore because the document is the source of truth. - // Save timeline data if exists + /** + * ═══════════════════════════════════════════════════════════════════════════ + * SYNC POINT 3: timeline → document + * ═══════════════════════════════════════════════════════════════════════════ + * + * When: Document save (auto-save or manual) + * What: Serializes entire timeline (all states) to document.timeline + * Source of Truth: timelineStore (transient working copy) + * Direction: timelineStore → document.timeline → localStorage + * + * This persists the complete timeline structure to storage. The timeline's + * current state has already been updated by SYNC POINT 2, so we're saving + * the latest graph data along with all historical timeline branches. + */ const timelineState = useTimelineStore.getState(); const timeline = timelineState.timelines.get(documentId); @@ -1002,6 +1015,23 @@ export const useWorkspaceStore = create((set, get) } }, + /** + * ═══════════════════════════════════════════════════════════════════════════ + * SYNC POINT 4: document types → graphStore + * ═══════════════════════════════════════════════════════════════════════════ + * + * When: Type management operations (add/update/delete node/edge types, labels) + * What: Updates document types/labels and syncs to graphStore if document is active + * Source of Truth: ConstellationDocument (document.nodeTypes, document.edgeTypes, document.labels) + * Direction: document → graphStore (if active document) + * + * Type configurations are document-level properties. When modified, changes + * are persisted to the document first, then synced to graphStore if this is + * the currently active document. This ensures the editor always displays the + * correct types for the current document. + * + * All type operations use atomic transactions with rollback (Phase 3.1). + */ addNodeTypeToDocument: (documentId: string, nodeType) => { const state = get(); const doc = state.documents.get(documentId);