Architecture Design
# Overall Architecture
RuleGo-Editor is built on Vue 3 Composition API + LogicFlow + Element Plus, adopting a layered architecture design. The core idea is to decouple graphical editing capabilities (LogicFlow) from business logic (RuleGo rule chains) through an adapter layer, enabling the editor to run independently or flexibly connect to backend services.
+---------------------------------------------------------------+
| RuleGoEditor.vue |
| (Main Component - Composition & Orchestration Layer) |
+---------------------------------------------------------------+
| |
| +------------------+ +------------------+ +--------------+ |
| | Canvas Area | | AI Chat Panel | | Debug Console| |
| | (LogicFlow) | | (ChatPanel) | |(DebugConsole)| |
| +------------------+ +------------------+ +--------------+ |
| |
| +------------------+ +------------------+ +--------------+ |
| | Node Property | | Edge Property | | Sidebar | |
| | Panel | | Panel | | (Sidebar) | |
| |(NodeProperty*) | |(EdgeProperty*) | | | |
| +------------------+ +------------------+ +--------------+ |
+---------------------------------------------------------------+
| | |
+-------v----------------------v---------------------v----------+
| Hooks Layer |
| |
| useLogicFlow useGraphData useGraphEvent |
| useEditorSelection useEditorContext useCanvasDebug |
| useDebugWebSocket |
+---------------------------------------------------------------+
| | |
+-------v----------------------v---------------------v----------+
| Data Adapter Layer |
| |
| RuleGoAdapter NodeAdapter GraphUtils |
+---------------------------------------------------------------+
| | |
+-------v----------------------v---------------------v----------+
| Extension Layer |
| |
| NodeRedExtension (lf-node) ControlExtension (toolbar) |
| Custom node registration Toolbar rendering |
+---------------------------------------------------------------+
| | |
+-------v----------------------v---------------------v----------+
| Infrastructure |
| |
| LogicFlow Element Plus i18n API Layer |
+---------------------------------------------------------------+
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Core Modules
# 1. Main Component RuleGoEditor.vue
The main component is the entry point and orchestration center of the entire editor, responsible for:
- Layout Management: Contains the canvas area, property panels (Drawers and Dialogs for nodes/edges), AI chat panel, and debug console
- Instantiating Core Objects: Creates instances of I18n, NodeAdapter, RuleGoAdapter, etc.
- Hook Composition: Combines capabilities of various modules through useLogicFlow, useGraphData, useGraphEvent, etc.
- Context Injection: Shares editor state with child components and Hooks via provide/inject
- Keyboard Shortcuts: Configures shortcuts like Delete, Ctrl+C/V, etc.
- Lifecycle Management: Loads components and initializes on mount, cleans up event listeners on unmount
The main component exposes the following methods to the outside via defineExpose:
| Method | Description |
|---|---|
| render | Renders rule chain data to the canvas |
| save | Triggers a save operation |
| getData | Gets the current canvas rule chain data |
| setLocales | Sets the i18n language pack |
| reloadComponents | Reloads the component list |
# 2. Data Adapter Layer
# RuleGoAdapter.js
Responsible for bidirectional conversion between RuleGo data format and LogicFlow graph data format. It is the bridge between the editor and the RuleGo backend.
adapterIn (Input Adapter): Converts RuleGo format data to the { nodes, edges } format that LogicFlow can render.
RuleGo Data Format:
{
ruleChain: { id, name, additionalInfo },
metadata: {
nodes: [...],
endpoints: [...],
connections: [...]
}
}
+-------------------+
| RuleGoAdapter |
| .adapterIn() |
+--------+----------+
|
v
LogicFlow Data Format:
{
nodes: [{ id, type, x, y, text, properties }],
edges: [{ id, type, sourceNodeId, targetNodeId, text, properties }]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
During the conversion process, it will:
- Automatically add a default input node (start-node)
- Determine the canvas type of each node based on component definitions (simple-node, endpoint-node, group-node, etc.)
- Read node coordinates from additionalInfo.layoutX/layoutY
- Merge endpoint connections and regular node connections
- Handle label concatenation for edges with multiple relation types
adapterOut (Output Adapter): Converts LogicFlow graph data back to RuleGo format.
During the conversion process, it will:
- Map from lfId back to the business ID (model.id)
- Write canvas coordinates to additionalInfo.layoutX/layoutY
- Handle routing paths for endpoint nodes (router.to.path)
- Write parentGroupId for group nodes
- Arrange node order according to rules (first node placed at the front)
# NodeAdapter.js
Responsible for node component adaptation, including:
- i18n Injection: Reads Chinese names, descriptions, and relation type labels from i18n language packs
- Group Classification: Groups components by category into different sidebar groups
- Form Validation Rules: Automatically adds numeric validation rules for int/float type fields
- Built-in Option Injection: Handles dropdown option data in builtins (such as nodePool shared node pool)
- AI Provider Injection: Automatically injects AI provider selection dropdowns for components with url+model fields
- Input Node Injection: Automatically injects start-node into the endpoints group
# GraphUtils.js
A collection of graphic utility functions, providing:
genId()- Generates unique IDs (based on nanoid)createEdge()- Creates edge data with automatic left/right anchor bindinggetNodeSeq()- Extracts sequence number from node IDgetRelationTypeOptionsFromNode()- Dynamically gets connection type options from node configurationgetEndpointConnections()- Parses routing connection relationships for endpoint nodesupdateEndpointRouterToPath()- Writes endpoint edge connections to routing pathsvalidator- Canvas data validator
# 3. Hooks Layer
The Hooks layer uses the Vue 3 Composition API pattern, splitting different concerns of the editor into independent reusable functions.
# useLogicFlow.js - LogicFlow Instance Management
Responsibilities:
- Creating and destroying LogicFlow instances
- Registering plugins (SelectionSelect, Snapshot, MiniMap, DynamicGroup, NodeRedExtension, ControlExtension)
- Merging externally passed options configuration
- Mounting compatibility methods (getRuleChain, getEditorSetting, rulegoEditor)
- Initializing group event listeners
Initialization Flow:
options (Default Configuration)
|
v
Merge inputOptions (External Configuration)
|
v
new LogicFlow(options)
|
v
Mount compatibility methods + rulegoEditor namespace
|
v
Return lf (shallowRef)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# useGraphData.js - Graph Data Management
Responsibilities:
- Component list loading (built-in components + API dynamic components)
- Canvas rendering (render) and clearing (clear)
- Save operations (save), including business validation and API calls
- Operation snapshot management (undos/redos)
- Dirty data marking (isDirty)
- Component hot-reloading (reloadComponents)
Component loading flow:
1. Check if options.components already has data
|
+-- Yes --> Adapt directly
|
+-- No --> Initialize with defaultComponents
|
2. Call adapterComponents() for i18n and group adaptation
|
3. toComponentList() converts to flat mapping { [type]: componentDef }
|
4. initLfCallback() initializes LogicFlow instance
|
5. If loadComponentsFromApi=true, asynchronously load API components
|
6. After API data returns, re-adapt and rebuild LF instance
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# useGraphEvent.js - Graph Event Management
Responsibilities:
- Registering canvas interaction events (node click/double-click, edge click/double-click, blank click, DND drag-in, node drag)
- Registering custom business events (NEW, OPEN, UPDATE, SAVE, SETTING, etc.)
- Handling history changes (history:change), maintaining undos/redos and isDirty state
- Alt+drag: Allows dragging nodes out of groups
- Group collapse state detection to avoid accidental edge-add events during collapse
# useEditorSelection.js - Selection Logic Management
Responsibilities:
- Maintaining currently selected node/edge and their model data
- Managing property panel display state (Drawer/Dialog open/close)
- Node property submit and cancel logic
- Edge property submit and cancel logic
- Deleting selected elements (includes business rule validation: at least one endpoint must remain)
- Node cloning (supports clipboard and in-canvas copy)
# useEditorContext.js - Editor Context
Implements state sharing across components and Hooks through Vue's provide/inject mechanism.
provideEditorContext({
i18n, // i18n instance
nodeAdapter, // Node adapter
adapter, // RuleGo adapter
lf, // LogicFlow instance (shallowRef)
container, // Canvas container DOM reference
ruleChain, // Current rule chain data (ref)
nodeComponents, // Node component mapping (ref)
settingOptions, // Editor settings (ref)
options, // Editor configuration (reactive)
initData, // Initialization data (reactive)
emit, // Event emitter
})
2
3
4
5
6
7
8
9
10
11
12
13
Any child component or Hook can simply call useEditorContext() to obtain all the above context, without the need to pass props layer by layer.
# useCanvasDebug.js - Canvas Debug Visualization
Responsibilities:
- Listening to debug data events (DEBUG_DATA), setting node status styles based on flowType
- processing state: blue highlighted border
- success state: green highlighted border
- error state: red highlighted border
- Setting
_debugHighlightingflag during debugging to prevent history:change from incorrectly triggering isDirty - Providing clearHighlight method to clear all debug highlights
# useDebugWebSocket.js - WebSocket Debug Connection
Responsibilities:
- Establishing WebSocket connection with the backend to receive real-time debug logs
- Supporting automatic reconnection (exponential backoff, max 10 retries)
- Authentication via JWT token
- Maintaining connection state (connecting / connected / disconnected / error)
- Data buffering (retains up to 500 entries, trims when exceeded)
# 4. Extension Layer
# lf-node/index.js - NodeRedExtension
A LogicFlow plugin that registers all custom node types and edge types in the constructor:
Registered Node Types:
start-node --> StartNode (Default input node)
endpoint-node --> EndpointNode (Endpoint node)
simple-node --> SimpleNode (General business node)
chain-node --> ChainNode (Sub-rule chain node)
group-node --> GroupNode (Group node)
agent-node --> AgentNode (AI Agent node)
comment-node --> CommentNode (Comment node)
Registered Edge Types:
flow-link --> FlowLink (Bezier curve edge)
Sets default edge type to flow-link
2
3
4
5
6
7
8
9
10
11
12
13
In the render method, it creates an independent Vue application instance to render the sidebar (Sidebar.vue) and registers Element Plus.
# toolbar/index.js - ControlExtension
A LogicFlow plugin that creates an independent Vue application instance in the constructor to render the toolbar (Toolbar.vue) and registers Element Plus.
# 5. Custom Nodes
All custom nodes inherit from BaseNode, following LogicFlow's model/view separation pattern.
# BaseNode.js - Base Node
Provides common capabilities for all nodes:
Model Layer (RedNodeModel):
- Default size 120x30, corner radius 5px
- Defines left/right anchors (left for incoming, right for outgoing)
- Connection validation rules: only allows right-side outgoing, left-side incoming, forbids duplicate connections, forbids connecting to input-type nodes, forbids cross-group connections
- Automatic text truncation with ellipsis for long text
- Debug status styles (processing/success/error highlight)
View Layer (RedNode):
- Renders rectangular node + left icon area + separator line
- Custom anchor shapes (rectangular)
# Node Type Inheritance
BaseNode (BaseNode.js)
|
+-- SimpleNode (simple-node) General business node with icon
+-- StartNode (start-node) Default input node, right anchor only
+-- EndNode (end-node) End node
+-- EndpointNode (endpoint-node) Endpoint node, right anchor only
+-- AgentNode (agent-node) AI Agent node
+-- CommentNode (comment-node) Comment node
dynamicGroup (LogicFlow Extension)
|
+-- GroupNode (group-node) Group node, supports collapse/expand/resize
2
3
4
5
6
7
8
9
10
11
12
# GroupNode.js - Group Node
Based on LogicFlow's DynamicGroup extension, additionally providing:
- Collapsible/expandable, collapsed size 120x30
- Resizable, supports dragging borders
- Child node restrictions: forbids endpoint-node and start-node from joining groups
- Dynamic anchor updates: real-time adjustment of left/right anchor positions during collapse/expand
- Edge redirection: forces update of connected edges' start/end points after collapse/expand
- Alt+drag: Hold Alt to drag nodes out of groups
# FlowLink.js - Edge
Based on LogicFlow's BezierEdge (Bezier curve), additionally providing:
- Debug highlight styles (blue bold)
- Selected/hover styles (orange bold)
- Text label auto-wrap and background frame
# 6. Configuration and Internationalization
# config/config.js
Global configuration management, including:
- AI multi-turn conversation configuration (message history limit, context window, storage key prefix, etc.)
- AI provider list (Gitee AI, DeepSeek, Tongyi Qianwen, Zhipu AI, OpenAI, Ollama)
- Editor configuration persistence (localStorage)
- Configuration URL updates
Configuration priority: window.rulegoEditorConfig > localStorage > default values
# constants/events.js
Editor custom event constants for LogicFlow eventCenter event communication:
Command Events (Toolbar --> Core):
rulego-editor:new New rule chain
rulego-editor:open Open rule chain
rulego-editor:update Update rule chain properties
rulego-editor:save Save
rulego-editor:setting Update settings
rulego-editor:reset Reset
rulego-editor:deleteSelects Delete selected elements
rulego-editor:showEditPanel Show edit panel
rulego-editor:loadComponents Load components
Notification Events (Core --> Toolbar/Sidebar):
rulego-editor:saveOk Save successful
rulego-editor:componentOk Component loading complete
rulego-editor:sidebarOk Sidebar ready
rulego-editor:deleted Element deleted
Debug Events:
rulego-editor:toggleDebugConsole Toggle debug console
rulego-editor:clearDebugHighlight Clear debug highlight
rulego-editor:debugData Debug data arrived
rulego-editor:toggleRuleChainChat Toggle AI chat panel
rulego-editor:openNodeDetail Open node detail (debug tab)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# i18n/
Internationalization files, organized by module:
i18n/
zh/
index.js Main entry, exports locales object
ai.js AI-related text
endpoint.js Endpoint node text
extend.js Extension node text
locales_registry.js Extension language pack registration
2
3
4
5
6
7
The I18n class supports dynamic language pack registration, allowing custom i18n text injection through options.locales or extensions.
# Data Flow
# Data Input Flow (RuleGo --> Canvas)
External data prop passed in
|
v
RuleGoAdapter.adapterIn(data)
|
+-- Read ruleChain metadata (id, name, additionalInfo)
+-- Add default input node (start-node)
+-- Iterate metadata.nodes, convert to LF nodes
+-- Iterate metadata.endpoints, convert to endpoint-nodes
+-- Iterate metadata.connections, convert to edges
+-- Handle label merging for edges with multiple relation types
|
v
{ nodes: [...], edges: [...] }
|
v
lf.render(data) Render to canvas
|
v
restoreParentGroup() Restore group relationships
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Data Output Flow (Canvas --> RuleGo)
lf.getGraphData()
|
v
RuleGoAdapter.adapterOut(lf, logicFlowData)
|
+-- Iterate edges, map from lfId back to business ID
+-- Handle endpoint routing paths
+-- Iterate nodes, write coordinates to additionalInfo
+-- Write parentGroupId for groups
+-- Arrange node order
|
v
{ ruleChain: {...}, metadata: { nodes, endpoints, connections } }
|
v
GraphUtils.validator.validate(data) Validate
|
v
saveWorkflow(id, data) Call API to save
|
v
emit('saveOk', data) Notify external
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Component Loading Flow
1. loadComponentsAndInitLf()
|
v
2. Check if options.components already has data
|
+-- Yes --> adapterComponents(options.components)
+-- No --> adapterComponents(defaultComponents)
|
v
3. NodeAdapter.adapterComponents()
|
+-- Register i18n language pack
+-- Iterate nodes and endpoints
+-- adapterComponentsLocal(): Inject Chinese labels, descriptions
+-- adapterBuiltins(): Inject dropdown options
+-- adapterRules(): Add form validation rules
+-- Group by category
|
v
4. toComponentList() converts to flat mapping
|
v
5. initLfCallback() creates LogicFlow instance
|
v
6. (Optional) Asynchronously load components from API
|
+-- GET /api/v1/components
+-- Re-adapt
+-- Rebuild LF instance
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Event Communication Mechanism
The editor internally uses two sets of event communication mechanisms:
# 1. Vue Events (emit)
Used for communication between the main component and the parent component:
RuleGoEditor (Child Component)
|
+-- emit('saveOk', data) Save successful
+-- emit('saveError', data) Save failed
+-- emit('reset', data) Reset
|
v
Parent Component (Host Application)
2
3
4
5
6
7
8
# 2. LogicFlow eventCenter
Used for communication between internal modules of the editor. Since the toolbar and sidebar are independent Vue application instances (created via createApp), they cannot directly share state through Vue's provide/inject. Therefore, LogicFlow's eventCenter is used as an event bus.
Toolbar (Independent Vue Application)
|
+-- lf.graphModel.eventCenter.emit(EDITOR_EVENTS.SAVE)
|
v
useGraphEvent (Event Listener)
|
+-- lf.on(EDITOR_EVENTS.SAVE, () => save())
|
v
useGraphData.save()
2
3
4
5
6
7
8
9
10
11
# 3. provide/inject Context
Used for state sharing between Hooks and child components within the main component, obtained uniformly through useEditorContext().
# Extension Mechanism
# 1. Component Extension
Pass custom component definitions through options.components, or load dynamically via API. See Node Components documentation for component definition format.
# 2. Internationalization Extension
Inject custom language packs through options.locales or extensions, supporting overriding default component names, descriptions, relation type labels, etc.
# 3. Toolbar Extension
Configure show/hide for each button through options.toolbar. The toolbar renders as an independent Vue application and communicates with core logic through LogicFlow eventCenter.
# 4. LogicFlow Plugin Extension
Pass LogicFlow plugin list through options.plugins to register custom node types, edge types, and extension features.
# 5. Token Management Extension
Inject custom token management functions through options.getToken and options.clearToken for connecting to the host application's authentication system.
# Technical Highlights
# shallowRef and LogicFlow Instance
The LogicFlow instance is wrapped with shallowRef instead of ref, because LogicFlow is a complex class instance. Deep reactive proxies would cause performance issues and unexpected behavior.
# Independent Vue Application Instances
The sidebar and toolbar are created as independent Vue application instances via createApp, each registering Element Plus. This is because LogicFlow's plugin render method needs to mount to a DOM overlay and cannot directly reuse the main application's Vue instance.
# Dirty Data Tracking
Automatically marks isDirty by listening to the history:change event, and resets after render and save succeed. When the browser is closed, it prompts the user to save via the beforeunload event.
# Debug Highlight Isolation
During debug highlighting, the _debugHighlighting flag is set to prevent node style changes from triggering history:change and incorrectly setting isDirty to true.