Skip to content

Mindmap Node Save Sequence Diagram

This document describes how mindmap nodes are saved from the Studio component through IndexedDB to the Python backend.

Overview

The persistence architecture follows a local-first pattern:

  1. User edits are immediately persisted to IndexedDB (offline-capable)
  2. Changes are queued in syncQueue for backend sync
  3. SyncManager periodically flushes the queue to the server
  4. Backend processes changes and commits to PostgreSQL

Sequence Diagram

Key Components

ComponentFileResponsibility
StudioStudio.tsxReact component with useReducer for state; useEffect detects changes
Persistencepersistence.tsAsync functions to save nodes/deltas to IndexedDB
db (KemmaDB)db.tsIndexedDB wrapper with nodes, maps, syncQueue stores
SyncManagersync-manager.tsBackground sync loop, queue compression, retry logic
API Clientclient.tsAxios wrapper for HTTP calls to backend
Backendroutes/nodes.pyFastAPI endpoint processing batch updates

Data Flow Details

1. Auto-Save Effect (Studio.tsx)

typescript
useEffect(() => {
  const changes: NodeChange[] = []
  // Compare currentNodes vs prevNodes.current
  // Collect creates, updates, deletes
  if (changes.length > 0) {
    mindmapPersistence.persistNodeChanges(changes)
  }
  prevNodes.current = currentNodes
}, [nodes])

2. IndexedDB Schema (db.ts)

Three object stores:

  • nodes - Cached node data (indexed by userId, mapId)
  • maps - Mindmap metadata
  • syncQueue - Pending changes for backend sync

3. Sync Queue Compression (sync-manager.ts)

Multiple updates to the same node are coalesced:

NODE_UPDATE(id=1, text="A") + NODE_MOVE(id=1, x=10)
  → NODE_COALESCED_UPDATE(id=1, { text: "A", x: 10 })

4. Backend Processing (nodes.py)

python
@router.post("/nodes/batch")
async def batch_update_nodes(batch: SyncBatchRequest, ...):
    for item in batch.changes:
        match record.type:
            case "NODE_CREATE": db.add(new_node)
            case "NODE_DELETE": await db.delete(node)
            case "NODE_COALESCED_UPDATE": # update fields
    await db.commit()

Error Handling

  • Offline: Changes queue locally; sync resumes when online
  • Network errors: Exponential backoff retry (1s, 2s, 4s)
  • 409 Conflict: Ignored (idempotent creates)
  • beforeunload: Triggers sync to prevent data loss