MC Modeler is a 100% client-side Single Page Application — there is no server-side rendering. This is a hard constraint: bpmn-js requires a real DOM to mount its canvas, making SSR impossible. Every feature, from state management to persistence, runs entirely in the browser.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Aston2710/mc-modeler/llms.txt
Use this file to discover all available pages before exploring further.
The architecture is designed around one central rule: XML lives in bpmn-js, not in Zustand. The BPMN diagram is only extracted from the engine when it needs to be persisted or exported — never stored in React state.
Tech Stack
React 19 + TypeScript
Functional components only.
strict: true in tsconfig. No any types.Vite 6
Build tool. Instant HMR in development, optimized production bundles.
bpmn-js v18
BPMN 2.0 engine by Camunda. Certified OMG-standard, MIT-licensed.
Zustand v5 + Immer
Global state management. Lightweight, no boilerplate, ideal for canvas state.
Tailwind CSS v4
Utility-first styling. No conflicts with bpmn-js’s internal
.djs-* classes.Supabase + Yjs
Cloud backend for multi-user persistence. Yjs (CRDT) for real-time collaboration.
package.json):
Six Architectural Layers
The codebase is divided into six layers with strict directional dependencies. Lower layers never import from higher ones.Layer 1 — Presentation (/src/components)
Layer 1 — Presentation (/src/components)
React UI components. They contain no business logic and never access bpmn-js directly. Components read from Zustand stores and call store actions. They never import
localforage, IDiagramRepository, or bpmn-js modules.Sub-directories: layout/, canvas/, palette/, properties/, diagrams/, modals/, ui/.Layer 2 — Orchestration (/src/hooks)
Layer 2 — Orchestration (/src/hooks)
Custom React hooks that wire the UI to both the bpmn-js engine and Zustand state. This is the only layer allowed to bridge these two systems.Key hooks:
useBpmnModeler— main integration point with the bpmn-js engine (import, export, undo/redo, zoom, element manipulation)useAutoSave— debounced persistence triggered by canvas changesuseExport— PDF, PNG, SVG export logicuseKeyboard— global keyboard shortcutsuseValidation— BPMN validation rules
Layer 3 — BPMN Engine (/src/bpmn)
Layer 3 — BPMN Engine (/src/bpmn)
Everything bpmn-js-specific: initialization configuration, custom modules (palette, renderer, context pad), and event adapters that translate bpmn-js events into Zustand actions.This is as close to bpmn-js internals as the codebase gets. No other layer imports bpmn-js directly.
config.ts— modeler options and custom module declarationsmodules/CustomPalette.ts— categorized element palettemodules/CustomRenderer.ts— custom visual stylesmodules/CustomContextPad.ts— right-click/hover element menuadapters/eventAdapter.ts— bpmn-js events → store actions
Layer 4 — State (/src/store)
Layer 4 — State (/src/store)
Zustand stores using the Immer middleware for immutable updates. State is split across focused stores:
| Store | Responsibility |
|---|---|
diagramStore | Diagram list, tabs, active diagram, projects, trash |
uiStore | Panel visibility, modals, toasts, zoom, selected elements |
preferencesStore | Language, theme, grid settings, palette mode |
collabStore | Real-time collaboration session state |
commentStore | Inline diagram comments |
notificationStore | In-app notification inbox |
authStore | Supabase authentication session |
imageStore | Image library management |
presenceStore | Collaborator cursor/presence state |
Layer 5 — Persistence (/src/persistence)
Layer 5 — Persistence (/src/persistence)
The repository pattern abstracts all storage behind
IDiagramRepository. No store, hook, or component imports localforage directly or references LocalRepository/SupabaseRepository by name. Everything goes through diagramRepository exported from /src/persistence/index.ts.Two implementations exist: LocalRepository (IndexedDB, offline) and SupabaseRepository (cloud). The binding is decided at startup by a single isSupabaseConfigured check.Layer 6 — Domain (/src/domain)
Layer 6 — Domain (/src/domain)
Pure TypeScript: interface definitions, type aliases, and validation logic. No dependencies on React, bpmn-js, or any runtime library. This layer can be tested in isolation with zero setup.
types.ts— all domain interfacesvalidation.ts— BPMN business rule validatorsbpmnElements.ts— catalogue of all supported BPMN elements
Data Flow
Every user interaction follows the same path through the layers:bpmn-js Lifecycle
Understanding the engine lifecycle is critical for contributing to this codebase.Single instance per session
BpmnModeler is instantiated once per active editing session. The DOM container ref is passed at construction time. The instance is stored in modelerRef inside useBpmnModeler.Switching diagrams uses importXML
When the user opens a different diagram (tab change),
modeler.importXML(newXml) is called on the existing instance. The modeler is never destroyed and recreated to switch diagrams — that would lose the undo stack and cause visible flash.Optional per-tab cache
When the tabs cache flag is enabled, each diagram gets its own modeler instance that is kept alive and re-attached to the DOM on tab switches. This preserves zoom level, selection, and undo history per tab without re-importing.
Directory Structure
Key Design Rules
These rules are enforced across the entire codebase and must be respected by contributors:XML stays in bpmn-js
BPMN XML is never stored in Zustand. It is extracted via
modeler.saveXML() only when saving to persistence.Repository is the only storage API
Nothing imports
localforage directly. Nothing imports LocalRepository or SupabaseRepository by name outside of persistence/index.ts.No SSR, ever
The app is a pure SPA. bpmn-js requires a real DOM — server rendering is impossible.
One binding point
Switching from local to cloud storage only requires changing one line in
/src/persistence/index.ts. No stores, hooks, or components need to change.Further Reading
Data Model
All TypeScript domain interfaces: Diagram, Project, Folder, LibraryImage, and more.
Persistence Layer
Repository pattern, LocalRepository, SupabaseRepository, auto-save, CAS conflict handling, and soft delete.
BPMN Engine
bpmn-js initialization, custom modules, and the event adapter pattern.
Collaboration & Sync
Yjs CRDT integration, presence, and real-time conflict resolution.