Skip to main content

How EntityFlow works

EntityFlow is built around a small set of architectural decisions that keep its behavior deterministic, testable, and identical across the web app, server, and desktop build.

Core/shell split​

All deterministic logic lives in headless, framework-free TypeScript packages. The React app, the Node server, and the Electron app are thin shells that consume them — they hold no business logic of their own.

The headless packages cover:

  • the schema IR (intermediate representation),
  • the CRDT document model,
  • geometry and edge routing,
  • SQL/DBML codegen across four dialects,
  • validation,
  • the projection (read model),
  • the canvas renderer,
  • authorization.

Because the logic is shared, what you see in the browser, what the server exports, and what the desktop app produces all come from the same code.

Dual persistence (CQRS)​

EntityFlow uses a command/query split with two representations of every diagram:

  • The authoritative write model is a Yjs CRDT, stored as a binary blob. Every edit mutates this blob.
  • A relational read-projection is derived from the blob for queries, search, and server-side export.

The flow is strictly one-way:

CRDT blob → IR → projection rows

The projection is never written back into the blob. If a projection row ever drifts or fails, it is simply re-derived from the blob — the blob is the single source of truth.

Realtime​

A Hocuspocus websocket server runs in the same Node process as the API and syncs the CRDT between connected editors. Live presence (cursors, selections, who's online) travels over Yjs awareness, which is never persisted — it exists only for the duration of a connection.

note

Because server-side export emits from the blob-derived IR, the SQL/DBML it produces is byte-for-byte identical to what the in-browser editor exports.

Horizontal scale​

A single node handles a substantial workload on its own. To run more than one server replica, enable Redis fan-out so awareness and document updates propagate across pods. Without it, replicas diverge. See Scaling & performance for details and SLO targets.