Skip to content

Repository files navigation

🧠 MindMap Pro β€” Collaborative Infinite Canvas Engine

React TypeScript Vite Zustand Socket.io Groq License: MIT Node

MindFlow Hero

A real-time collaborative mind mapping application built on a custom SVG infinite canvas engine with offline-first editing, WebSocket-based multi-user sync, AI-powered map generation via Groq, and a zero-re-render drag system β€” designed to rival tools like Miro and Whimsical at the architecture level.


πŸ”— Repository Navigation

Resource Link
πŸ–₯️ Frontend Repo (this) mindmap-client
βš™οΈ Backend Repo mindmap-server
πŸ“‘ API Reference API Reference β†’
πŸ—οΈ Architecture Architecture β†’
πŸš€ Getting Started Setup β†’

🌐 Live Demo & Previews

πŸ”— Live App: https://mindmap-client-nu.vercel.app/

πŸ“¦ Backend API: https://mindmap-server-wr7o.onrender.com

Screenshots

Dashboard View Infinite Canvas Editor
Dashboard Editor
User Login Create Account
Login Sign Up

πŸ’‘ Project Motivation

Most collaborative mind mapping tools (Miro, Whimsical, XMind) are closed-source, subscription-gated, and treat maps as read-only in offline mode. MindMap Pro was built to explore:

  1. How far you can push a custom SVG canvas before needing WebGL β€” turns out, very far.
  2. Offline-first collaborative editing without full CRDTs (using operation queuing + Last Write Wins).
  3. Real-time multi-user state without a specialized backend (Yjs, Liveblocks) β€” built directly on Socket.io rooms.

The result is a production-grade architecture that maps onto real engineering problems at companies building collaborative software.


πŸ“– Table of Contents


πŸš€ Features at a Glance

Category Features
Canvas SVG Infinite Canvas Β· Pan Β· Zoom Β· Mini Navigator Β· Lasso Selection
Nodes Rich properties Β· Color coding Β· Font size Β· Notes Β· Collapse/expand
Layout Recursive Auto-Layout (FLIP animated) Β· Align Β· Distribute Β· Fit to Screen
Offline Operation queue (IndexedDB) Β· Sync on reconnect Β· Last-Write-Wins conflict resolution
AI One-prompt mindmap generation via Groq Llama 3 70B
Collaboration Live Cursors Β· Presence Avatars Β· Edit Locking Β· Remote Selection
Sharing Role-Based Permissions (Owner / Editor / Viewer) Β· Invite by Email
Comments Threaded per-node discussion panels Β· Real-time via WebSocket
History Infinite Undo/Redo Β· Version Snapshots Β· Activity Log
Focus Mode Subtree isolation with fade-out Β· One-click exit pill
Exports PNG Β· PDF Β· JSON Β· Markdown
Templates Pre-built map blueprints (Startup, Project, Study, Brainstorm)
Auth JWT Authentication Β· Persistent sessions Β· Protected routes

βš™οΈ Engineering Challenges

1. Zero-Re-render Drag Engine

Problem: React's reconciler is too slow for 60fps drag on large graphs. Updating Zustand state on every mousemove event caused visible frame drops with 100+ nodes.

Solution: The drag engine bypasses React entirely during drag by mutating the SVG transform attribute directly via a DOM ref. React state is updated only on mouseup, keeping the component tree frozen while the canvas stays fluid.

mousemove β†’ ref.current.setAttribute("transform", ...) β†’ 60fps, zero re-renders
mouseup   β†’ commitDragEnd() β†’ Zustand update β†’ React re-render (once)

2. Coordinate Space in SVG

Problem: Pan + zoom creates a transformed coordinate space. Click positions need to map accurately into "world coordinates" at any zoom level.

Solution: getScreenCTM().inverse() on the SVG viewport element gives the exact inverse transform matrix. Every mouse event runs through this to get precise world-space (x, y) β€” accurate from 0.1x to 3x zoom.

3. Offline-First Editing Without CRDTs

Problem: Supporting offline edits without full CRDT infrastructure (Yjs, Automerge) while still being safe for concurrent multi-user editing.

Solution: An operation queue in IndexedDB records every edit as a typed Operation object. On sync, the server applies Last Write Wins β€” operations older than node.updatedAt are discarded. The ProcessedOperation collection prevents double-apply on retry.

4. FLIP Layout Animation

Problem: Auto-layout repositions every node simultaneously, which is visually jarring if done with CSS transitions (nodes teleport).

Solution: FLIP (First, Last, Invert, Play) animation using the Web Animations API: capture all node positions before layout, compute new positions, then animate each node from its old position to its new one using cubic-bezier(0.2, 0.8, 0.2, 1).

5. Focus Mode Without Render Loop

Problem: Computing which nodes are "inside the focused subtree" on every render caused an infinite loop because the Set reference changed each time, triggering Zustand subscribers.

Solution: The focused subtree Set<string> is computed with useMemo keyed on [nodes, focusNodeId]. The same reference is returned when the inputs haven't changed, which prevents useSyncExternalStore from triggering phantom re-renders.

6. Socket Reconnect Race Condition

Problem: On page load, Zustand's persist middleware hydrates the auth token asynchronously. The online event listener could fire syncOperationQueue before the token was ready, resulting in tokenless sync requests β†’ 403s.

Solution: syncOperationQueue now reads from useAuthStore.getState().token as the first guard. If no token, sync aborts silently. The token will be present on the next trigger.


⚑ Performance Optimizations

Optimization Technique Impact
Drag rendering Direct DOM mutation via ref, bypasses React 0 re-renders during drag
Cursor smoothing requestAnimationFrame lerp loop (ease = 0.25) 60fps cursor for all peers
Operation compression Merge consecutive MOVE_NODE/EDIT_NODE ops for same node Smaller sync payloads
Batch sync Single POST /sync with all queued ops instead of one-per-op Fewer HTTP round trips
Subtree memoization useMemo BFS for Focus Mode subtree Stable Set reference, no phantom renders
FLIP animation Web Animations API, not CSS transitions GPU-composited layout moves
Socket debounce 1000ms disconnect delay guards against StrictMode double-mounts No spurious reconnects
replaceNodes Silent node replacement without unmounting Canvas No canvas blink on AI generation

🧭 System Design Principles

Offline-First

Every edit dispatches an Operation to a local IndexedDB queue before any network call. The network sync is opportunistic β€” latency or downtime never blocks the user.

Optimistic UI Updates

Node changes appear instantly in the local Zustand store. The server sync and Socket.io broadcast happen after, in the background. Users never wait for a server round-trip to see their own edits.

Idempotent Operations

Each operation carries a client-generated UUID (operationId). The server's ProcessedOperation collection tracks applied IDs β€” retrying a failed sync batch is always safe, since duplicates are detected and skipped.

Event-Driven Collaboration

All multi-user state flows through Socket.io events scoped to a map room. The server is the single authority for relay β€” it doesn't store ephemeral state like cursor positions. If a user disconnects, their cursor and edit lock are cleaned up automatically by the disconnect handler.

Separation of Concerns via Slices

The editor state is split into 6 Zustand slices (canvasSlice, nodeSlice, collabSlice, versionSlice, commentSlice, activitySlice), each owning one concern. The top-level editorStore.ts is a thin 45-line orchestrator that composes them.

Zero Circular Dependencies

Type imports that previously caused circular dependency chains (socket.ts importing from editorStore.ts) have been broken out into src/types/mindmap.ts β€” a shared type-only module imported by both.


πŸ—οΈ Architecture

Database Entity Relationship Diagram (ERD)

The system relies on a NoSQL document database (MongoDB), but relationships are strictly enforced at the application level to maintain data integrity across collaborative sessions.

erDiagram
    USER ||--o{ MINDMAP : "owns/edits"
    MINDMAP ||--o{ NODE : contains
    MINDMAP ||--o{ MAP_VERSION : has
    MINDMAP ||--o{ PROCESSED_OPERATION : logs
    MINDMAP ||--o{ COLLABORATOR : "has access"
    NODE ||--o{ NODE_COMMENT : "has comments"
    
    USER {
        ObjectId _id
        String name
        String email
    }
    MINDMAP {
        ObjectId _id
        String title
        ObjectId creator
    }
    NODE {
        String id
        ObjectId mindMapId
        String text
        Float x
        Float y
        String parentId
    }
    NODE_COMMENT {
        ObjectId _id
        String nodeId
        ObjectId userId
        String text
    }
Loading

Frontend Component Hierarchy

The frontend is highly modularized to prevent unnecessary re-renders in the infinite canvas execution path.

graph TD
    App[App.tsx] --> Auth[AuthProvider]
    Auth --> Router[React Router]
    
    Router --> Dash[Dashboard]
    Router --> EditorView[EditorPage]
    
    EditorView --> Header[EditorHeader]
    EditorView --> Toolbar[FloatingToolbar]
    EditorView --> CanvasArea[Canvas]
    EditorView --> Panels[Side Panels]
    
    CanvasArea --> MiniNav[MiniNavigator]
    CanvasArea --> Zoom[ZoomControls]
    CanvasArea --> Nodes[Node Components]
    CanvasArea --> Edges[EdgeLayer]
    CanvasArea --> Cursors[CursorLayer]
    
    Panels --> PropPanel[NodePropertiesPanel]
    Panels --> History[VersionPanel]
    Panels --> Activity[ActivityPanel]
Loading

Full System Architecture

flowchart TB
    subgraph Client["πŸ–₯️ Frontend (React + Vite)"]
        direction TB
        Pages["Pages\nAuth Β· Dashboard Β· Editor"]
        Store["Zustand Store\nuseEditorStore + useSyncStore + useAuthStore"]
        Canvas["SVG Canvas Engine\nNodeLayer Β· EdgeLayer Β· CursorLayer"]
        Engine["Motion & Drag Engines\nFLIP (Web Animations API) Β· rAF drag"]
        Services["Services\napi.ts (Axios+JWT) Β· socket.ts (Socket.io)"]
        IDB["IndexedDB\nOperation Queue Β· Local Map State\n(idb-keyval)"]
    end

    subgraph Server["βš™οΈ Backend (Node.js + Express)"]
        direction TB
        Auth["Auth Middleware\nJWT verify + req.user"]
        Routes["Routes"]
        Controllers["Controllers"]
        SvcLayer["Services\nmapPermissionService Β· aiService Β· authService"]
        DB[("MongoDB\n9 collections")]
        SocketSrv["Socket.io Server\nRoom presence map"]
    end

    AI["πŸ€– Groq API\nllama3-70b-8192"]

    Pages --> Store
    Store --> Canvas
    Store --> Engine
    Store --> Services
    Store --> IDB
    Services -- "REST (Axios + JWT)" --> Auth
    Services -- "WebSocket" --> SocketSrv
    Auth --> Routes --> Controllers --> SvcLayer --> DB
    Controllers --> SocketSrv
    SvcLayer -- "AI generation" --> AI
    IDB -- "sync on reconnect" --> Services
Loading

End-to-End Edit Flow

sequenceDiagram
    actor User
    participant Store as Zustand Store
    participant Dispatcher as operationDispatcher
    participant IDB as IndexedDB
    participant API as REST API
    participant Socket as Socket.io
    participant Peers as Other Users

    User->>Store: Edit node (drag / type / color)
    Store->>Store: Optimistic UI update (instant)
    Store->>Dispatcher: dispatchOperation("EDIT_NODE", ...)
    Dispatcher->>IDB: Push/merge op to queue
    alt Online + authenticated
        Dispatcher->>API: POST /mindmaps/:id/sync
        API-->>Dispatcher: { acknowledged: ["opId"] }
        Dispatcher->>IDB: Remove acknowledged ops
        API->>Socket: Emit node-updated to room
        Socket-->>Peers: See update in real-time
    else Offline
        Note over IDB: Op stays in queue
        Note over Dispatcher: Sync fires on next 'online' event
    end
Loading

Zustand Store Slice Graph

graph TD
    ES["useEditorStore\n(45 lines β€” thin orchestrator)"]

    ES --> CS["canvasSlice\nzoom Β· pan Β· selection\nundo/redo Β· history"]
    ES --> NS["nodeSlice\nCRUD Β· drag commit\nauto-layout Β· align"]
    ES --> CoS["collabSlice\nlive cursors\nonline presence"]
    ES --> VS["versionSlice\nsnapshots Β· restore"]
    ES --> CmS["commentSlice\nnode comments"]
    ES --> AS["activitySlice\nlogs Β· members Β· role"]

    NS & CoS & VS & CmS & AS --> MT["src/types/mindmap.ts\nShared type definitions"]
    NS & CS --> UI["utils/userInfo.ts"]
    NS & CS & VS --> ME["engine/motionEngine.ts\nFLIP animations"]
    NS & CS & VS --> SK["services/socket.ts\nWebSocket emitters"]
    NS --> OD["operationDispatcher.ts"]
    OD --> IDB["indexedDb.ts\nidb-keyval"]
    OD --> SS["useSyncStore.ts"]
Loading

πŸ“΄ Offline Sync

MindMap Pro is offline-first. Every edit is preserved locally even without internet and automatically synced when connectivity returns.

Sync State Machine

stateDiagram-v2
    [*] --> idle : App loads, user authenticated
    idle --> syncing : Edit made + online
    syncing --> idle : All ops acknowledged
    syncing --> idle : API error (4xx β€” queue cleared)
    idle --> offline : navigator.onLine = false OR network timeout
    offline --> idle : window 'online' event fires
    offline --> syncing : Reconnected + queue has ops
    syncing --> offline : No response (true network failure)
Loading

Operation Types

Type Triggered By payload fields
CREATE_NODE Adding a new node text, parentId, x, y, color, fontSize
MOVE_NODE Drag commit on mouseup x, y
EDIT_NODE Text / color / notes changes text?, color?, notes?, fontSize?
DELETE_NODE Node deletion (empty β€” nodeId in op root)

Key Files

File Responsibility
store/operationDispatcher.ts Create, compress, and queue ops; trigger sync
store/indexedDb.ts IndexedDB persistence via idb-keyval
store/useSyncStore.ts networkStatus Β· syncLock Β· lastSyncTimestamp
app/App.tsx window online/offline listeners; sync on reconnect

πŸ› οΈ Editor

Infinite Canvas

Rendered entirely in SVG for full control over transformations, animations, and event delegation. A custom pan/zoom layer applies a transform matrix using getScreenCTM().inverse() to map screen coordinates into world coordinates β€” accurate at any zoom level (0.1x–3x).

Node Management

  • Create: Click βŠ• on any node, press Tab, or use the floating toolbar.
  • Edit: Double-click or press Enter for inline text editing.
  • Rich Properties Panel: Slide-in sidebar with title, multi-line notes, color palette, and font-size controls.
  • Color Coding: Six curated colors (Coral, Orange, Green, Blue, Purple, Teal).
  • Collapse/Expand: Toggle subtree visibility with animated entrances/exits.

Auto-Layout & Alignment

flowchart TD
    Start[Trigger Auto-Layout] --> Capture[Capture Current DOM Positions]
    Capture --> DFS[Depth-First Traversal]
    DFS --> Calc[Calculate Node Subtree Heights & Widths]
    Calc --> Position[Assign Target X, Y based on parent & sibling dimensions]
    Position --> React[Update Zustand state with Target Coordinates]
    React --> Render[React Renders Nodes at Target Coordinates]
    Render --> Animate[Web Animations API: Animate from Captured to Target]
    Animate --> End[FLIP Animation Complete]
Loading
  • Recursive Auto-Layout: A depth-first algorithm that calculates the bounding box of each subtree recursively. It positions children nodes avoiding vertical overlap by dynamically spacing them based on the computed heights of their descendants.
  • FLIP Animation Engine: Because React state updates instantly snap nodes to their new coordinates, the Web Animations API is used to capture positions before the render paint, and smoothly animate them from their old positions using a physically-based cubic-bezier(0.2, 0.8, 0.2, 1) easing.
  • Align Tools: Left, Center, Right, Top, Middle, Bottom edge alignment.
  • Distribute Tools: Evenly space selected nodes along horizontal or vertical axes.

πŸ€– AI Mindmap Generation

Click ✨ AI Generate in the editor toolbar to generate a complete mindmap from a single topic prompt.

AI Generation Execution Flow

sequenceDiagram
    actor User
    participant C as Frontend (AI Modal)
    participant API as Backend API
    participant AI as Groq Llama 3
    
    User->>C: Enter prompt & Submit
    C->>C: set isLoadingMap(true)
    C->>API: POST /api/ai/generate-mindmap { prompt }
    API->>AI: Send system prompt + user topic
    AI-->>API: Stream/Return JSON tree structure
    API->>API: Parse JSON & Apply Layout Algorithm
    API-->>C: Return flattened Node array with x,y coords
    C->>C: useEditorStore().replaceNodes(nodes)
    C->>C: set isLoadingMap(false)
    C->>User: View newly generated map
Loading

How it works in-depth:

  1. Prompt Injection: The user prompt is wrapped in a strict system prompt instructing Groq's llama3-70b-8192 model to return a structured nested JSON indicating the tree hierarchy.
  2. Server-Side Rendering (Layout): Before returning the generated nodes, the backend runs a two-pass depth-first search (DFS) layout algorithm to compute subtree-centered x,y positions for every node so it renders beautifully on the canvas instantly.
  3. Optimistic Replacement: The existing nodes are replaced silently via replaceNodes avoiding costly canvas unmounts, preserving the user's viewport matrix.
Action Sets isLoadingMap Canvas unmounts Use case
loadNodes βœ… Yes βœ… Yes Initial page load
replaceNodes ❌ No ❌ No AI generation, silent refresh

🀝 Real-Time Collaboration

All editor events are synchronized via Socket.io with a room per mapId.

WebSocket Event Map

Event (client β†’ server) Event (server β†’ client) Payload
cursor-move cursor-moved { x, y, name, color }
node-editing node-editing-started { nodeId, user }
node-editing-stopped node-editing-stopped { nodeId }
selection-update selection-updated { nodeIds, user }
node-added node-added NodeType
node-updated node-updated { id, updates }
node-deleted node-deleted { nodeId }
map-restored map-restored { nodes, versionId }

Live Cursors: Mouse positions broadcast at ~20 Hz, smoothed with a requestAnimationFrame lerp loop (ease = 0.25) β€” 60fps cursor movement for all peers.

Edit Locking: When a user edits a node, peers see a colored glow border and name badge. Double-clicks from others are silently blocked. Lock releases automatically on edit end.


πŸ‘₯ Sharing & Permissions

Role Capabilities
Owner Full control β€” edit, invite, remove members, delete map
Editor Create, move, edit, delete nodes
Viewer Read-only β€” canvas is non-interactive

πŸ’¬ Node Comments

Per-node threaded comment panels in the Node Properties sidebar. Stored in NodeComment, real-time via comment-added / comment-deleted WebSocket events.


⏳ Version History & Activity

  • Snapshots: Named point-in-time saves. Restore broadcasts map-restored to all live collaborators.
  • Activity Log: NODE_CREATED, NODE_DELETED, NODE_EDITED, NODE_MOVED, NODE_COLOR_CHANGED β€” with user, timestamp, and diff metadata.
  • Undo/Redo: Full in-memory stack. Ctrl+Z / Ctrl+Y.

πŸ” Focus Mode

Select any node β†’ βŠ™ Focus in the toolbar β†’ all outside nodes fade to 15% opacity. A pill at the top reads "Viewing Subtree Β· Exit Focus". Subtree computed via useMemo BFS for a stable Set<string> reference.


πŸ“¦ Export System

Format Method
PNG html-to-image captures the SVG viewport
PDF Same capture piped into jsPDF
JSON GET /api/mindmaps/:id/export/json
Markdown GET /api/mindmaps/:id/export/md

πŸ—‚οΈ Templates

Dashboard Template Gallery with 4 blueprints: πŸš€ Startup Β· πŸ“‹ Project Β· πŸ“š Study Notes Β· πŸ’‘ Brainstorm.


πŸ“‚ Project Structure

src/
β”œβ”€β”€ app/               # Root component, routes, online/offline listeners
β”œβ”€β”€ types/             # Domain types (mindmap.ts, sync.ts, user.ts)
β”œβ”€β”€ store/
β”‚   β”œβ”€β”€ editorStore.ts           # 45-line slice orchestrator
β”‚   β”œβ”€β”€ authStore.ts             # JWT session
β”‚   β”œβ”€β”€ operationDispatcher.ts   # Queue, compress, sync operations
β”‚   β”œβ”€β”€ indexedDb.ts             # IndexedDB via idb-keyval
β”‚   β”œβ”€β”€ useSyncStore.ts          # networkStatus, syncLock
β”‚   └── slices/                  # canvasSlice Β· nodeSlice Β· collabSlice Β· versionSlice Β· commentSlice Β· activitySlice
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ editor/        # Canvas, Node, EdgeLayer, CursorLayer, Panels, Modals
β”‚   β”œβ”€β”€ dashboard/     # TemplateGallery
β”‚   └── ui/            # Toast
β”œβ”€β”€ context/           # DragContext (ref-based)
β”œβ”€β”€ engine/            # motionEngine.ts (FLIP)
β”œβ”€β”€ hooks/             # useDragEngine.ts (rAF-based)
β”œβ”€β”€ pages/             # Auth, Dashboard, Editor
β”œβ”€β”€ services/          # api.ts, socket.ts, aiService, exportService
└── styles/            # global.css (single entry point)

🧰 Tech Stack

Technology Version Purpose
React 19 UI framework
TypeScript 5.7 Type safety
Vite 7 Build tool & dev server
Zustand 5 Global state β€” slice pattern
React Router 7 Client-side routing
Socket.io-client 4.8 Real-time WebSocket layer
Axios 1.x HTTP client with JWT interceptor
idb-keyval 6 IndexedDB for offline operation queue
Framer Motion 12 Landing page scroll animations
html-to-image 1.x PNG/PDF canvas export
jsPDF 4 PDF generation
uuid 13 Unique operation IDs
Web Animations API browser-native FLIP layout animations

🚦 Getting Started

Prerequisites

1. Clone & Install

git clone https://github.com/your-username/mindmap-client.git
cd mindmap-client
npm install

2. Configure Environment

# .env
VITE_API_URL=http://localhost:5000

VITE_API_URL is the base backend URL β€” no trailing slash, no /api suffix.

3. Run

npm run dev       # β†’ http://localhost:5173
npm run build     # Production build
npm run preview   # Preview locally

⌨️ Keyboard Shortcuts

Category Action Shortcut
Navigation Pan Canvas Space + Drag
Zoom Scroll Wheel
Fit to Screen Ctrl + 0
Editing Add Child Node Tab
Edit Selected Enter or Double Click
Delete Node(s) Delete / Backspace
Undo Ctrl + Z
Redo Ctrl + Y
Deselect Escape
Layout Auto-Layout Ctrl + L

🀝 Contributing

Contributions are welcome! To get started:

# 1. Fork the repo and create your branch
git checkout -b feature/your-feature-name

# 2. Install dependencies
npm install

# 3. Run in development
npm run dev

# 4. Lint before submitting
npm run lint

Guidelines:

  • Keep components focused β€” one concern per file
  • New Zustand state belongs in the relevant slice, not scattered in components
  • All new operations must go through dispatchOperation so they're offline-safe
  • Add TypeScript types to src/types/ β€” avoid any

Open to contributions on:

  • CRDT-based conflict resolution (replacing LWW)
  • Drag-to-group / node grouping
  • Rich text node editing
  • Mobile touch support

πŸ”­ Roadmap

Priority Feature Notes
πŸ”΄ High CRDT-based sync Replace LWW with Yjs for true concurrent editing
πŸ”΄ High Mobile / touch support Pinch-to-zoom, tap-to-edit
🟠 Medium WebRTC peer sync Direct peer connections to reduce server relay load
🟠 Medium Node grouping Visual containers with drag-in/out
🟠 Medium Markdown editing Rich text in node bodies
🟑 Low Plugin system Custom node types and toolbars
🟑 Low Graph DB backend Replace MongoDB with Neo4j for complex traversals
🟑 Low Graph layout algorithms Force-directed, radial, treemap modes
🟑 Low Native mobile app React Native with shared business logic

πŸ“ˆ Scalability Considerations

Challenge Current Approach Production Scale Solution
WebSocket horizontal scaling Single Node.js process Redis pub/sub adapter (@socket.io/redis-adapter) β€” events fan out across instances
Large maps (1000+ nodes) All nodes loaded into memory Viewport culling β€” only render nodes in the current viewport bounding box
Operation queue growth Unbounded IndexedDB queue TTL on ProcessedOperation + client-side queue size cap
Cursor broadcast at scale Relay every event Throttle at 10 Hz + room size limits; move to WebRTC data channels for P2P at scale
Map sharding All maps in one MongoDB cluster Shard by mapId hash β€” each shard owns a subset of maps
Spatial queries x/y as plain numbers 2D spatial index on nodes for viewport queries ($geoWithin)
Activity log size Last 50 in-memory Paginated cursor with compound (mindMapId, createdAt) index (already in place)

πŸ”Œ API Reference Summary

Full API documentation is in the Backend README.

Group Endpoints
Auth POST /api/auth/register Β· POST /api/auth/login Β· GET /api/auth/me
Maps GET/POST /api/mindmaps Β· PATCH /:id/title Β· DELETE /:id Β· PATCH /:id/restore
Nodes GET /:id/nodes Β· POST /nodes Β· PATCH /nodes/:id Β· DELETE /nodes/:id
Sync POST /:id/sync β€” batch offline operation apply
Members GET/POST /:id/members Β· PUT/DELETE /:id/members/:memberId
Comments Nested under /:mapId/nodes/:nodeId/comments
Versions GET/POST /:id/versions Β· restore Β· delete
AI POST /api/ai/generate-mindmap
Export GET /:id/export/json Β· GET /:id/export/md

πŸ“œ License

MIT β€” free to use, modify, and distribute.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages