This document is a current high-level map of the codebase. It is intentionally narrower than a full design spec and should stay aligned with the implementation in src/.
OpenFlowKit is a local-first diagram editor built with:
- React 19
- TypeScript 5
- React Flow / XYFlow
- Zustand
- ELK.js
The main application lives in src/. Additional repo surfaces include:
docs-site/for canonical public docs content and site generationdocs/for repo-only notes and operational markdownweb/for the marketing site
Main app shape:
src/
app/ Route state helpers
components/ UI surfaces and editor shells
config/ Rollout flags and provider config
context/ React context providers
diagram-types/ Diagram family plugins and property panel registration
hooks/ Feature and editor hooks
i18n/ Localization
lib/ Shared types, parsers, compat helpers, utilities
services/ Domain services
store/ Zustand state, actions, defaults, persistence
Route composition is currently centered in src/App.tsx, not in a dedicated pages/ directory.
The repository contains three main product/runtime surfaces:
The browser editor and related in-app experiences.
Key areas:
src/App.tsxsrc/components/FlowEditor.tsxsrc/components/home/*
The public docs site built with Astro/Starlight.
Key area:
docs-site/
The public landing/marketing site.
Key area:
web/
The app uses a single public Zustand store exported from src/store.ts.
The runtime store is now bootstrapped through:
src/store/createFlowStore.tssrc/store/createFlowStoreState.tssrc/store/createFlowStorePersistOptions.ts
This keeps the public entry stable while moving composition, persistence, and hydration concerns behind explicit seams.
The store is still monolithic at runtime, but it is now partitioned more clearly through slice-typed hooks, selectors, and internal slice factories in src/store/.
Current store-facing hook files include:
canvasHooks.tstabHooks.tshistoryHooks.tsdesignSystemHooks.tsviewHooks.tsselectionHooks.ts
Supporting files:
defaults.tstypes.tsselectors.tsslices/createCanvasEditorSlice.tsslices/createExperienceSlice.tsslices/createWorkspaceSlice.tspersistence.tsaiSettings.ts
There is no current top-level brandHooks.ts slice in src/store/.
Persistence is coordinated through:
src/store/persistence.tssrc/services/storage/flowPersistStorage.tssrc/services/storage/storageRuntime.tssrc/services/storage/indexedDbStateStorage.ts
Current behavior at a high level:
- document/tab state is persisted through Zustand persistence
- IndexedDB-backed storage is used where available
- localStorage remains part of the compatibility and fallback story
- persisted nodes/edges are sanitized before storage
- ephemeral UI fields are excluded from persisted state
- browser storage detection and IndexedDB schema readiness are now funneled through a shared storage runtime helper instead of each storage surface bootstrapping itself independently
- IndexedDB store and index definitions are now declared in one schema manifest in
src/services/storage/indexedDbSchema.ts - schema migration markers now live in a dedicated IndexedDB schema metadata store instead of sharing the persisted Zustand state store
- local-first chat persistence now uses document-scoped IndexedDB indexes instead of full chat-message store scans
- user images/icons can be stored by content-hash ref in the IndexedDB
assetsstore (assetStoreV1rollout flag) instead of embedding multi-MB data URLs into every document/history/snapshot copy; nodes holdimageAssetId/iconAssetIdand resolve display URLs at render time
Important constraint:
- persisted storage keys should not be renamed without a migration path
The editor now follows a clearer four-layer composition path:
src/components/FlowEditor.tsxrender shell onlysrc/components/flow-editor/useFlowEditorScreenModel.tsscreen-level composition of store state, domain hooks, and refssrc/components/flow-editor/buildFlowEditorScreenControllerParams.tspure assembly of controller config from screen-model statesrc/components/flow-editor/useFlowEditorController.tsadaptation into shell, studio, panel, and chrome controller surfaces
Key editor concerns composed through that path include:
- tabs and active document selection
- node and edge operations
- history and snapshots
- AI generation
- export/import
- playback
- collaboration
- command bar and studio mode surfaces
- selection and keyboard bindings
This is still the main integration hotspot in the architecture, but it is now bounded more explicitly:
FlowEditor.tsxshould stay render-onlyuseFlowEditorScreenModel.tsshould gather state and domain hooks, not render UIbuildFlowEditorScreenControllerParams.tsshould stay pure and only map grouped screen state into controller inputuseFlowEditorController.tsshould adapt grouped inputs into UI-facing shell/panel/chrome props
If future work bypasses those boundaries, editor maintainability will regress quickly.
The app uses hooks to compose store state and service logic into editor-facing behaviors.
Examples:
useFlowHistoryuseFlowOperationsuseAIGenerationuseFlowExportusePlaybackuseFlowEditorCollaborationuseFlowEditorActionsuseFlowEditorCallbacks
The architecture intent is:
- services own domain logic
- hooks compose state and side effects
- components render and delegate
src/services/ contains most of the domain-heavy logic.
Notable service areas:
ai/architectureLint/collaboration/diagramDiff/export/figma/infraSync/mermaid/playback/shapeLibrary/storage/templateLibrary/
This is one of the stronger structural parts of the codebase: a significant amount of non-UI logic lives outside React components.
Built-in diagram families and property panel registration live under:
src/diagram-types/
Examples include:
- architecture
- class diagram
- ER diagram
- journey
- mindmap
- state diagram
These plugins and registrations allow the app to support multiple structured diagram behaviors without collapsing all logic into the base canvas layer.
Built-in diagram capabilities are now bootstrapped through a shared runtime initialization path instead of scattered one-off registration calls:
src/diagram-types/bootstrap.tssrc/diagram-types/builtInPlugins.tssrc/diagram-types/builtInPropertyPanels.ts
The repo currently has two documentation buckets:
- canonical content and runtime in
docs-site/
- operational and setup markdown in
docs/
Collaboration currently lives under:
src/hooks/useFlowEditorCollaboration.tssrc/services/collaboration/*
Current implementation notes:
- collaboration runtime construction now flows through
src/services/collaboration/bootstrap.ts - realtime transport is built around peer-oriented collaboration
- the current stack includes WebRTC-style transport concerns and signaling configuration
- fallback behavior exists for unsupported environments
This area is functional but still evolving and should be treated as active infrastructure rather than fully settled architecture.
Export logic is primarily coordinated through:
src/hooks/useFlowExport.tssrc/services/export/*
Current formats and related capabilities include:
- raster image export
- SVG export
- JSON export
- Mermaid export
- OpenFlow DSL export
- animated export / playback-related export
Testing is split across:
- Vitest unit and component tests in
src/ - Playwright end-to-end tests in
e2e/
Useful commands:
npm run lint
npm test -- --run
npm run e2e:ciFor current repo-health status and phased remediation, see AUDIT_FIX_LOG.md.