Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 69 additions & 50 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pnpm run dev:app-pc
### Frontend Structure

- **apps/app-pc** - PC client application
- **apps/app-mobile** - Mobile client application
- **packages/flow-design** - Flow designer component
- **packages/flow-pc** - PC display components
- **packages/flow-mobile** - Mobile display components
Expand All @@ -68,102 +69,120 @@ The workflow engine is organized into 8 layers:
- `WorkflowBuilder` - Builder pattern for workflow construction

2. **Node Layer** (`com.codingapi.flow.node`)
- `IFlowNode` - Interface defining node lifecycle methods (including `strategyManager()`)
- `BaseFlowNode` - Abstract base for all nodes, manages both `actions` and `strategies`
- `BaseAuditNode` - Abstract base for audit nodes (ApprovalNode, HandleNode), simplified to use strategies for all configurations
- `IFlowNode` - Interface defining node lifecycle methods
- `BaseFlowNode` - Abstract base for all nodes, manages actions and strategies
- `BaseAuditNode` - Abstract base for audit nodes (ApprovalNode, HandleNode)
- 11 node types: StartNode, EndNode, ApprovalNode, HandleNode, NotifyNode, ConditionBranchNode, ParallelBranchNode, RouterBranchNode, InclusiveBranchNode, DelayNode, TriggerNode, SubProcessNode

3. **Action Layer** (`com.codingapi.flow.action`, `com.codingapi.flow.action.actions`)
- `IFlowAction` - Interface for node actions (including `copy()` method)
- `BaseAction` - Abstract base with `triggerNode()` for recursive node traversal
- 9 action types: DefaultAction, PassAction, RejectAction, SaveAction, ReturnAction, TransferAction, AddAuditAction, DelegateAction, CustomAction
- `IFlowAction` - Interface for node actions with `copy()` method
- `BaseAction` - Abstract base with `triggerNode()` for recursive traversal
- 8 action types: DefaultAction, PassAction, RejectAction, SaveAction, ReturnAction, TransferAction, AddAuditAction, DelegateAction, CustomAction

4. **Record Layer** (`com.codingapi.flow.record`)
- `FlowRecord` - Execution record with states (TODO/DONE, RUNNING/FINISH/ERROR/DELETE)
- Tracks processId, nodeId, currentOperatorId, formData, parallel branch info

5. **Session Layer** (`com.codingapi.flow.session`)
- `FlowSession` - Execution context with currentOperator, workflow, currentNode, currentAction, currentRecord, formData, advice
- `FlowAdvice` - Encapsulates approval parameters (advice, signKey, backNode, transferOperators)
- `FlowSession` - Execution context (currentOperator, workflow, currentNode, currentAction, currentRecord, formData, advice)
- `FlowAdvice` - Approval parameters (advice, signKey, backNode, transferOperators)

6. **Manager Layer** (`com.codingapi.flow.node.manager`)
- `ActionManager` - Manages node actions (including `getAction(Class)`, `verifySession()`)
- `ActionManager` - Manages node actions, provides `getAction(Class)`, `verifySession()`
- `OperatorManager` - Manages node operators
- `StrategyManager` - Manages node strategies (including `loadOperators()`, `generateTitle()`, `verifySession()`)
- `StrategyManager` - Manages node strategies, provides `loadOperators()`, `generateTitle()`, `verifySession()`

7. **Strategy Layer** (`com.codingapi.flow.strategy`)
- `INodeStrategy` - Interface for node strategies (including `copy()`, `getId()`)
- `INodeStrategy` - Interface with `copy()`, `getId()`, `strategyType()`
- 10 strategy types: MultiOperatorAuditStrategy, TimeoutStrategy, SameOperatorAuditStrategy, RecordMergeStrategy, ResubmitStrategy, AdviceStrategy, OperatorLoadStrategy, ErrorTriggerStrategy, NodeTitleStrategy, FormFieldPermissionStrategy

8. **Script Layer** (`com.codingapi.flow.script.runtime`)
- `ScriptRuntimeContext` - Groovy script execution environment
- OperatorMatchScript, OperatorLoadScript, NodeTitleScript, ConditionScript, ErrorTriggerScript, RejectActionScript
- `ScriptRuntimeContext` - Groovy script execution with thread-safe design and auto-cleanup
- Script types: OperatorMatchScript, OperatorLoadScript, NodeTitleScript, ConditionScript, ErrorTriggerScript, RejectActionScript

### Node Lifecycle (Critical for Understanding Flow)

When a node is executed, methods are called in this order:
1. `verifySession(session)` - Delegates to ActionManager and StrategyManager for validation
2. `continueTrigger(session)` - Returns true to continue to next node, false to generate records
3. `generateCurrentRecords(session)` - Generate FlowRecords for current node (uses StrategyManager.loadOperators() for audit nodes)
4. `fillNewRecord(session, record)` - Fill new record data (uses StrategyManager for audit nodes)
5. `isDone(session)` - Check if node is complete (uses StrategyManager for multi-person approval progress)
1. `verifySession(session)` - Delegates to ActionManager and StrategyManager
2. `continueTrigger(session)` - Returns true to continue, false to generate records
3. `generateCurrentRecords(session)` - Generate FlowRecords (uses StrategyManager.loadOperators() for audit nodes)
4. `fillNewRecord(session, record)` - Fill record data (uses StrategyManager for audit nodes)
5. `isDone(session)` - Check if complete (uses StrategyManager for multi-person approval)

### Flow Execution Lifecycle

**FlowCreateService** (starting a workflow):
1. Validate request → Get workflow definition → Verify workflow → Create/get backup → Validate creator → Build form data → Create start session → Verify session → Generate records → Save records → Push events
1. Validate request → Get workflow → Verify workflow → Create backup → Validate creator → Build form data → Create start session → Verify session → Generate records → Save records → Push events

**FlowActionService** (executing an action):
1. Validate request → Validate operator → Get record → Validate record state → Load workflow → Get current node → Get action → Build form data → Create session → Verify session → Execute action
1. Validate request → Validate operator → Get record → Validate state → Load workflow → Get current node → Get action → Build form data → Create session → Verify session → Execute action

**PassAction.run()** (typical action execution):
1. Check if node is done (via StrategyManager) → Update current record → Generate subsequent records → Trigger next nodes → Save records → Push events
**PassAction.run()** (typical action):
1. Check if node done (StrategyManager) → Update current record → Generate subsequent records → Trigger next nodes → Save records → Push events

### Parallel Branch Execution

When encountering `ParallelBranchNode`:
1. `filterBranches()` analyzes and finds the convergence end node
1. `filterBranches()` finds the convergence end node
2. Record parallel info (parallelBranchNodeId, parallelBranchTotal, parallelId) in FlowRecord
3. Execute all branches simultaneously (generate records for each)
4. At convergence node, `isWaitParallelRecord()` checks if all branches have arrived
3. Execute all branches simultaneously
4. At convergence, `isWaitParallelRecord()` checks if all branches arrived
5. Once all arrive, clear parallel info and continue

### Key Design Patterns

- **Builder Pattern**: `WorkflowBuilder`, `BaseNodeBuilder`, `ActionBuilder` with singleton `builder()` method
- **Factory Pattern**: `NodeFactory.getInstance()` (uses reflection to call static `formMap()` methods), `NodeStrategyFactory`, `FlowActionFactory`
- **Strategy Pattern**: `INodeStrategy` with `StrategyManager` - strategy-driven node configuration (operators, titles, timeouts, permissions all via strategies)
- **Template Method**: `BaseFlowNode` defines node lifecycle, `BaseAction` defines action execution, `BaseStrategy` defines strategy template
- **Singleton**: `NodeFactory`, `ScriptRuntimeContext`, `RepositoryContext`, `GatewayContext` use static final instance
- **Chain of Responsibility**: `triggerNode()` recursively traverses subsequent nodes, `StrategyManager` iterates strategies to find matches
- **Composite Pattern**: Nodes contain multiple strategies and actions
- **Copy Pattern**: `INodeStrategy.copy()`, `IFlowAction.copy()`, `BaseFlowNode.setActions()`, `BaseFlowNode.setStrategies()` for incremental updates
- **Builder**: `WorkflowBuilder`, `BaseNodeBuilder` with singleton `builder()` method
- **Factory**: `NodeFactory.getInstance()` (reflection + static `formMap()`), `NodeStrategyFactory`, `FlowActionFactory`
- **Strategy**: `INodeStrategy` with `StrategyManager` - strategy-driven configuration
- **Template Method**: `BaseFlowNode` (node lifecycle), `BaseAction` (action execution), `BaseStrategy` (strategy template)
- **Singleton**: `NodeFactory`, `ScriptRuntimeContext`, `RepositoryContext`, `GatewayContext` (static final instance)
- **Chain of Responsibility**: `triggerNode()` recursive traversal, `StrategyManager` strategy iteration
- **Composite**: Nodes contain multiple strategies and actions
- **Copy Pattern**: `INodeStrategy.copy()`, `IFlowAction.copy()`, `BaseFlowNode.setActions()`, `BaseFlowNode.setStrategies()`

### Strategy-Driven Node Configuration (Critical Architecture Change)
### Strategy-Driven Node Configuration (Critical Architecture)

All node configurations are now implemented through strategies rather than direct properties:
All node configurations are implemented through strategies:
- **Operator loading**: `OperatorLoadStrategy` with Groovy script
- **Node title**: `NodeTitleStrategy` with Groovy script
- **Timeout**: `TimeoutStrategy` with timeout value
- **Permissions**: `FormFieldPermissionStrategy` with field permission list
- **Permissions**: `FormFieldPermissionStrategy` with field permissions
- **Error handling**: `ErrorTriggerStrategy` with Groovy script
- **Multi-person approval**: `MultiOperatorAuditStrategy` with type (SEQUENCE/MERGE/ANY/RANDOM_ONE)

The `StrategyManager` provides unified access to all strategies:
- `loadOperators(session)` - Load operators via OperatorLoadStrategy
- `generateTitle(session)` - Generate title via NodeTitleStrategy
- `getTimeoutTime()` - Get timeout via TimeoutStrategy
- `verifySession(session)` - Verify via various strategies
`StrategyManager` provides unified access: `loadOperators()`, `generateTitle()`, `getTimeoutTime()`, `verifySession()`

### Multi-Person Approval Implementation
### Multi-Person Approval Modes

The `MultiOperatorAuditStrategy.Type` enum defines four approval modes:
- **SEQUENCE**: Sequential approval, hides subsequent records until previous is done
- **MERGE**: Concurrent approval, requires percentage completion (configurable via `percent` property)
- **ANY**: Any one person approval, completes immediately when first person approves
- **RANDOM_ONE**: Random one person approval, randomly selects one person from the list
`MultiOperatorAuditStrategy.Type` enum:
- **SEQUENCE**: Sequential, hides subsequent records
- **MERGE**: Concurrent, requires percentage completion
- **ANY**: Any one person, completes on first approval
- **RANDOM_ONE**: Randomly selects one person

The `BaseAuditNode.isDone()` method implements the completion logic for each mode.
Implemented in `BaseAuditNode.isDone()`.

### ScriptRuntimeContext Auto-Cleanup

Thread-safe Groovy script execution with dual auto-cleanup:
- **Threshold-based**: Triggers when `SCRIPT_LOCKS.size() > maxLockCacheSize` (default 1000)
- **Scheduled**: Periodic cleanup every `CLEANUP_INTERVAL_SECONDS` (default 300s)
- **Configuration**: JVM property `-Dflow.script.cleanup.interval`, or `setMaxLockCacheSize(int)`
- **Lifecycle**: Auto-starts on singleton init, registers shutdown hook, supports runtime enable/disable

Thread safety: Each execution creates independent GroovyClassLoader/GroovyShell. Fine-grained synchronization using script hashCode as lock key - same script serializes, different scripts run concurrently.

### Framework Exception Hierarchy

All framework exceptions extend `FlowException` (RuntimeException):
- `FlowValidationException` - Parameter validation (required, notEmpty)
- `FlowNotFoundException` - Resource not found (workflow, record, node, operator, action)
- `FlowStateException` - Invalid state (recordAlreadyDone, operatorNotMatch, workflowAlreadyFinished)
- `FlowPermissionException` - Permission issues (fieldReadOnly, fieldNotFound, accessDenied)
- `FlowConfigException` - Configuration errors (strategiesNotNull, actionsNotNull, parallelEndNodeNotNull)
- `FlowExecutionException` - Execution errors (scriptExecutionError, nodeExecutionError, actionExecutionError)

Use framework exceptions instead of generic exceptions (IllegalArgumentException, etc.) when working with flow engine code.

## Code Conventions

Expand All @@ -184,9 +203,9 @@ The `BaseAuditNode.isDone()` method implements the completion logic for each mod

## Documentation References

- **flow-engine-framework/src/test/Design.md** - Comprehensive architecture documentation with updated class design, lifecycle diagrams, design patterns, and key implementation details
- **Design.md** (root) - Comprehensive architecture documentation with class design, lifecycle diagrams, design patterns, and key implementation details
- **AGENTS.md** - Detailed coding guidelines and patterns
- **frontend/packages/flow-design/AGENTS.md** - Frontend library development
- **frontend/apps/app-pc/AGENTS.md** - Frontend app development
- **frontend/packages/flow-design/AGENTS.md** - Frontend library development
- **Rsbuild**: https://rsbuild.rs/llms.txt
- **Rspack**: https://rspack.rs/llms.txt
77 changes: 75 additions & 2 deletions Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,66 @@

#### ScriptRuntimeContext
- **位置**: `com.codingapi.flow.script.runtime.ScriptRuntimeContext`
- **职责**: Groovy脚本运行时环境
- **核心方法**: `execute(String method, String script, ...)`
- **职责**: Groovy脚本运行时环境,支持线程安全的脚本执行和自动资源清理
- **设计特点**:
- **线程安全**: 使用脚本哈希值进行细粒度同步,不同脚本可并发执行
- **自动清理**: 双重清理机制(阈值触发 + 定时清理)
- **资源管理**: 单例自动管理定时任务生命周期,注册JVM关闭钩子
- **核心属性**:
- `SCRIPT_LOCKS`: 脚本锁映射表(ConcurrentHashMap),键为脚本哈希值
- `EXECUTION_COUNTER`: 脚本执行计数器(AtomicInteger)
- `maxLockCacheSize`: 最大锁缓存阈值(默认1000)
- `CLEANUP_INTERVAL_SECONDS`: 定时清理间隔(默认300秒,可通过系统属性`flow.script.cleanup.interval`覆盖)
- **核心方法**:
- `run(String script, Class<T> returnType, Object... args)`: 执行脚本
- `execute(String method, String script, Class<T> returnType, Object... args)`: 执行指定方法
- `clearLockCache()`: 手动清理锁缓存
- `setMaxLockCacheSize(int)`: 设置最大锁缓存阈值
- `getLockCacheSize()`: 获取当前锁缓存大小
- `getExecutionCount()`: 获取脚本执行总次数
- `enableAutoCleanup()`: 启用自动清理
- `disableAutoCleanup()`: 禁用自动清理
- `getCleanupIntervalSeconds()`: 获取清理间隔

#### 自动清理机制

```
┌─────────────────────────────────────────────────────────────────┐
│ ScriptRuntimeContext │
│ 自动清理双重机制 │
└─────────────────────────────────────────────────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ 阈值触发清理 │ │ 定时清理任务 │
│ (Threshold-based) │ │ (Scheduled) │
└─────────────────────────┘ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ 触发条件: │ │ 触发条件: │
│ SCRIPT_LOCKS.size() > │ │ 每隔 CLEANUP_INTERVAL_ │
│ maxLockCacheSize │ │ SECONDS 秒执行一次 │
└─────────────────────────┘ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ 清理动作: │ │ 清理动作: │
│ SCRIPT_LOCKS.clear() │ │ SCRIPT_LOCKS.clear() │
│ EXECUTION_COUNTER.set(0)│ │ EXECUTION_COUNTER.set(0)│
└─────────────────────────┘ └─────────────────────────┘
```

**配置方式**:
- **阈值配置**: `ScriptRuntimeContext.setMaxLockCacheSize(500)`
- **定时配置**: JVM启动参数 `-Dflow.script.cleanup.interval=300`
- **动态控制**: `enableAutoCleanup()` / `disableAutoCleanup()`

**生命周期管理**:
1. 单例初始化时自动启动定时清理任务(守护线程)
2. 注册JVM关闭钩子确保资源释放
3. 支持运行时动态启用/禁用自动清理

#### 脚本类型

Expand Down Expand Up @@ -693,3 +751,18 @@
- 节点的`setActions()`和`setStrategies()`方法支持增量更新
- 根据类型匹配现有对象,调用`copy()`方法复制属性
- `CustomAction`特殊处理,支持动态添加

### 5. 脚本运行时线程安全设计
- **问题**: GroovyShell和GroovyClassLoader都不是线程安全的
- **方案**: 每次执行创建独立的GroovyClassLoader和GroovyShell实例
- **细粒度同步**: 使用脚本哈希值作为锁键,相同脚本串行执行,不同脚本并发执行
- **自动清理**: 阈值触发 + 定时清理双重机制,避免内存泄漏

### 6. 框架异常体系
- `FlowException`: 所有框架异常的基类(RuntimeException)
- `FlowValidationException`: 参数验证异常(required、notEmpty)
- `FlowNotFoundException`: 资源未找到异常(workflow、record、node等)
- `FlowStateException`: 状态异常(recordAlreadyDone、operatorNotMatch等)
- `FlowPermissionException`: 权限异常(fieldReadOnly、accessDenied等)
- `FlowConfigException`: 配置异常(strategiesNotNull、actionsNotNull等)
- `FlowExecutionException`: 执行异常(scriptExecutionError、nodeExecutionError等)
Loading