387 lines
11 KiB
Markdown
387 lines
11 KiB
Markdown
# 工作流平台技术文档
|
||
|
||
**项目**: 基于 Flowable 的可视化工作流平台
|
||
**版本**: v1.0
|
||
**更新日期**: 2025-01-12
|
||
|
||
---
|
||
|
||
## 📚 文档目录
|
||
|
||
### 核心设计文档
|
||
|
||
| 文档 | 说明 | 关键内容 |
|
||
|------|------|----------|
|
||
| [01-架构总览](./01-架构总览.md) | 系统整体架构设计 | 技术选型、系统架构、MVP范围、开发计划 |
|
||
| [02-后端技术设计](./02-后端技术设计.md) | 后端详细实现 | 节点注册、表达式引擎、BPMN转换、REST API |
|
||
| [03-前端技术设计](./03-前端技术设计.md) | 前端详细实现 | ReactFlow画布、字段映射选择器、状态管理 |
|
||
| [04-数据模型设计](./04-数据模型设计.md) | 数据库设计 | 业务表结构、Flowable表说明、索引优化 |
|
||
| [05-开发规范](./05-开发规范.md) | 代码和协作规范 | 命名规范、Git工作流、测试要求 |
|
||
|
||
---
|
||
|
||
## 🎯 快速导航
|
||
|
||
### 我想了解...
|
||
|
||
**整体架构**
|
||
- 👉 先看 [01-架构总览](./01-架构总览.md)
|
||
- 了解技术选型、系统架构、核心数据流
|
||
|
||
**后端开发**
|
||
- 👉 看 [02-后端技术设计](./02-后端技术设计.md)
|
||
- 节点如何注册?表达式如何解析?JSON如何转BPMN?
|
||
|
||
**前端开发**
|
||
- 👉 看 [03-前端技术设计](./03-前端技术设计.md)
|
||
- ReactFlow如何使用?字段映射选择器如何实现?
|
||
|
||
**数据库设计**
|
||
- 👉 看 [04-数据模型设计](./04-数据模型设计.md)
|
||
- 有哪些表?为什么用JSONB?如何优化查询?
|
||
|
||
**编码规范**
|
||
- 👉 看 [05-开发规范](./05-开发规范.md)
|
||
- 如何命名?如何提交代码?如何写测试?
|
||
|
||
---
|
||
|
||
## 🔑 核心设计要点
|
||
|
||
### 1. 为什么选择 Flowable?
|
||
|
||
```
|
||
✅ 开源版功能完整(不需要购买企业版)
|
||
✅ 内置审批能力(User Task)
|
||
✅ Spring Boot 集成简单
|
||
✅ 国内资料多,社区活跃
|
||
✅ 支持 BPMN 2.0 标准
|
||
|
||
vs Camunda:
|
||
- Flowable 表单引擎更强
|
||
- Flowable 开源版更完整
|
||
- Camunda 性能略优但差距不大
|
||
|
||
vs Conductor:
|
||
- Conductor 没有审批能力
|
||
- Conductor 更轻量但功能少
|
||
- 如果不需要审批,Conductor 是更好选择
|
||
```
|
||
|
||
### 2. 核心技术难点与解决方案
|
||
|
||
#### 难点1:前端如何知道上游节点输出了什么?
|
||
|
||
**解决方案**:使用静态 `outputSchema`(JSON Schema)
|
||
|
||
```typescript
|
||
// 每个节点类型定义输出结构
|
||
const httpRequestMetadata = {
|
||
id: 'http_request',
|
||
outputSchema: {
|
||
type: 'object',
|
||
properties: {
|
||
statusCode: { type: 'number' },
|
||
body: { type: 'object' },
|
||
headers: { type: 'object' },
|
||
},
|
||
},
|
||
};
|
||
|
||
// 前端根据 schema 构建字段树
|
||
// 用户可以选择: nodes.httpRequest.output.body.email
|
||
```
|
||
|
||
**优点**:
|
||
- ✅ 快速,不需要执行节点
|
||
- ✅ 类型安全
|
||
- ✅ 支持自动补全
|
||
|
||
**缺点**:
|
||
- ⚠️ 如果实际输出与 schema 不符,运行时才会发现
|
||
|
||
#### 难点2:如何实现字段映射选择器?
|
||
|
||
**核心组件**:`FieldMappingSelector.tsx`
|
||
|
||
```tsx
|
||
// 1. 计算上游节点
|
||
const upstreamNodes = edges
|
||
.filter(edge => edge.target === currentNode.id)
|
||
.map(edge => nodes.find(n => n.id === edge.source));
|
||
|
||
// 2. 根据 outputSchema 构建字段树
|
||
const fieldTree = upstreamNodes.map(node => ({
|
||
title: node.data.name,
|
||
children: buildFieldTree(nodeType.outputSchema.properties, `nodes.${node.id}.output`)
|
||
}));
|
||
|
||
// 3. 用户选择字段,生成表达式
|
||
// 用户选择: nodes.httpRequest.output.body.email
|
||
// 生成表达式: ${nodes.httpRequest.output.body.email}
|
||
```
|
||
|
||
#### 难点3:表达式解析性能
|
||
|
||
**解决方案**:
|
||
```java
|
||
// 1. 使用 JUEL 而不是完整的 JavaScript(性能更好)
|
||
// 2. 表达式编译结果缓存
|
||
private final Map<String, ValueExpression> expressionCache = new ConcurrentHashMap<>();
|
||
|
||
// 3. 快速路径:无表达式直接返回
|
||
if (!expression.contains("${")) {
|
||
return expression;
|
||
}
|
||
```
|
||
|
||
**性能测试结果**:
|
||
- JUEL: ~50000 QPS
|
||
- GraalVM JS: ~2000 QPS
|
||
- 结论:使用 JUEL,性能足够
|
||
|
||
#### 难点4:工作流定义格式
|
||
|
||
**决策**:用户层面使用 JSON,内部转换为 BPMN XML
|
||
|
||
```
|
||
前端 (JSON) ←→ 后端转换层 ←→ Flowable (BPMN XML)
|
||
|
||
理由:
|
||
✅ JSON 对前端友好
|
||
✅ JSON 易于版本控制
|
||
✅ BPMN 是 Flowable 原生格式
|
||
✅ 分层清晰,职责明确
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 技术架构图
|
||
|
||
### 整体架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ 前端 (React + ReactFlow) │
|
||
│ - 可视化编辑器 │
|
||
│ - 节点配置面板 │
|
||
│ - 字段映射选择器 ⭐⭐⭐ │
|
||
└──────────────┬──────────────────────────┘
|
||
│ REST API
|
||
┌──────────────▼──────────────────────────┐
|
||
│ Spring Boot 应用 │
|
||
│ ┌────────────────────────────────────┐ │
|
||
│ │ REST API 层 │ │
|
||
│ └────────────────────────────────────┘ │
|
||
│ ┌────────────────────────────────────┐ │
|
||
│ │ 业务逻辑层 │ │
|
||
│ │ - NodeTypeRegistry (节点注册) │ │
|
||
│ │ - ExpressionEngine (表达式解析)⭐ │ │
|
||
│ │ - WorkflowConverter (JSON→BPMN)⭐ │ │
|
||
│ └────────────────────────────────────┘ │
|
||
│ ┌────────────────────────────────────┐ │
|
||
│ │ Flowable Engine │ │
|
||
│ │ - 流程执行 │ │
|
||
│ │ - 任务管理 │ │
|
||
│ │ - 历史记录 │ │
|
||
│ └────────────────────────────────────┘ │
|
||
└──────────────┬──────────────────────────┘
|
||
│
|
||
┌──────────────▼──────────────────────────┐
|
||
│ PostgreSQL │
|
||
│ - 业务表 (workflow_definitions等) │
|
||
│ - Flowable表 (ACT_*) │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 核心数据流:工作流执行
|
||
|
||
```
|
||
1. 用户点击"执行"
|
||
↓
|
||
2. 前端调用 POST /api/workflows/{id}/execute
|
||
↓
|
||
3. 后端初始化执行上下文:
|
||
{
|
||
"workflow": { "input": {...} },
|
||
"nodes": {}, // 节点输出将保存在这里
|
||
"env": {...}
|
||
}
|
||
↓
|
||
4. Flowable 启动流程实例
|
||
↓
|
||
5. 按拓扑顺序执行节点:
|
||
a. ExpressionEngine 解析表达式
|
||
b. 调用节点实现类执行
|
||
c. 保存输出到 nodes.{nodeId}.output
|
||
↓
|
||
6. 节点间数据通过表达式传递:
|
||
${nodes.node1.output.body.email}
|
||
↓
|
||
7. 遇到 User Task(审批)时暂停
|
||
↓
|
||
8. 审批完成后继续执行
|
||
↓
|
||
9. 流程结束
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 MVP 功能清单(第一期)
|
||
|
||
### 必须有的功能
|
||
|
||
**1. 工作流编辑器**
|
||
- [x] 从左侧拖拽节点到画布
|
||
- [x] 节点之间连线
|
||
- [x] 删除节点和连线
|
||
- [x] 保存工作流
|
||
|
||
**2. 节点配置面板**
|
||
- [x] 动态表单(根据节点类型生成)
|
||
- [x] 字段映射选择器(TreeSelect 展示上游节点输出)⭐⭐⭐
|
||
- [x] 表达式输入框
|
||
|
||
**3. 节点类型(5种)**
|
||
- [x] HTTP Request
|
||
- [x] Send Email
|
||
- [x] Set Variable
|
||
- [x] Condition (IF/ELSE)
|
||
- [x] Approval (审批)
|
||
|
||
**4. 工作流执行**
|
||
- [x] 手动触发执行
|
||
- [x] 查看执行日志
|
||
- [x] 查看节点输入/输出
|
||
|
||
**5. 审批功能**
|
||
- [x] 待审批任务列表
|
||
- [x] 审批表单
|
||
- [x] 批准/拒绝
|
||
|
||
### 不做的功能(第二期)
|
||
|
||
- ❌ 定时触发(Cron)
|
||
- ❌ Webhook 触发
|
||
- ❌ 循环节点(forEach)
|
||
- ❌ 并行执行
|
||
- ❌ 工作流版本管理
|
||
- ❌ 权限管理(只做基础认证)
|
||
- ❌ 监控大盘
|
||
|
||
---
|
||
|
||
## 📅 开发计划(12周)
|
||
|
||
### Phase 1: 技术验证(Week 1-2)
|
||
- Flowable PoC
|
||
- 表达式引擎验证
|
||
- ReactFlow 画布验证
|
||
- 环境搭建
|
||
|
||
### Phase 2: 后端核心(Week 3-4)
|
||
- 节点类型注册系统
|
||
- 表达式引擎
|
||
- JSON → BPMN 转换器
|
||
- HTTP Request + Set Variable 节点
|
||
|
||
### Phase 3: 前端核心(Week 5-6)
|
||
- ReactFlow 画布
|
||
- 节点配置面板
|
||
- **字段映射选择器**(最核心)
|
||
|
||
### Phase 4: 执行引擎(Week 7-8)
|
||
- 工作流执行
|
||
- 日志记录
|
||
- 错误处理
|
||
|
||
### Phase 5: 审批功能(Week 9-10)
|
||
- User Task 集成
|
||
- 审批表单
|
||
- 任务列表
|
||
|
||
### Phase 6: 测试上线(Week 11-12)
|
||
- 集成测试
|
||
- 性能测试
|
||
- 部署上线
|
||
|
||
---
|
||
|
||
## 🎓 学习资源
|
||
|
||
### Flowable
|
||
- 官方文档: https://flowable.com/open-source/docs/
|
||
- GitHub: https://github.com/flowable/flowable-engine
|
||
- 中文教程: https://www.cnblogs.com/catcher1994/tag/Flowable/
|
||
|
||
### ReactFlow
|
||
- 官方文档: https://reactflow.dev/
|
||
- 示例: https://reactflow.dev/examples
|
||
|
||
### 表达式引擎
|
||
- JUEL 文档: https://juel.sourceforge.net/guide/index.html
|
||
- GraalVM JS: https://www.graalvm.org/javascript/
|
||
|
||
---
|
||
|
||
## ❓ 常见问题
|
||
|
||
### Q1: 为什么不直接使用 N8N?
|
||
|
||
**A**: N8N 是 Node.js 技术栈,我们需要 Java 技术栈。另外,我们需要:
|
||
- 与现有 Java 系统集成
|
||
- 自定义审批流程
|
||
- 完全掌控数据和安全
|
||
|
||
### Q2: Flowable 学习曲线陡峭吗?
|
||
|
||
**A**: 有一定学习曲线,但我们做了封装:
|
||
- 用户不需要懂 BPMN(我们用 JSON)
|
||
- 开发者只需要了解基础概念
|
||
- 提供完整的文档和示例
|
||
|
||
### Q3: 性能够吗?
|
||
|
||
**A**: 经过验证:
|
||
- 表达式解析: 50000+ QPS
|
||
- Flowable: 1000+ TPS
|
||
- 前端画布: 支持 100+ 节点不卡顿
|
||
|
||
### Q4: 如何扩展新的节点类型?
|
||
|
||
**A**: 非常简单:
|
||
1. 创建节点实现类(实现 `WorkflowNode` 接口)
|
||
2. 添加 `@Component` 注解
|
||
3. 定义元数据(字段、输出结构)
|
||
4. Spring 启动时自动注册
|
||
5. 前端自动显示
|
||
|
||
```java
|
||
@Component
|
||
public class MyCustomNode implements WorkflowNode {
|
||
@Override
|
||
public NodeTypeMetadata getMetadata() {
|
||
// 定义元数据
|
||
}
|
||
|
||
@Override
|
||
public NodeExecutionResult execute(NodeInput input, NodeExecutionContext context) {
|
||
// 执行逻辑
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📞 联系方式
|
||
|
||
- **技术负责人**: [您的名字]
|
||
- **Email**: [您的邮箱]
|
||
- **文档更新**: 如有问题或建议,请提 Issue
|
||
|
||
---
|
||
|
||
**最后更新**: 2025-01-12
|
||
**文档版本**: v1.0
|
||
|