flowable-devops/backend/docs/README.md
dengqichen d42166d2c0 提交
2025-10-13 16:25:13 +08:00

387 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 工作流平台技术文档
**项目**: 基于 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