# 可视化工作流平台 - 架构总览

**版本**: v1.0  
**日期**: 2025-01-12  
**审核角度**: 产品经理 + 架构师

---

## 一、系统定位

### 1.1 我们要做什么

一个类似 **N8N** 或**扣子**的可视化工作流平台，支持：
- **API 编排**：HTTP 请求、数据库操作、第三方服务集成
- **数据处理**：数据转换、条件判断、循环处理
- **审批流程**：人工审批节点、任务分配

### 1.2 不做什么（重要）

```
第一期（MVP）不做：
❌ 复杂的权限系统（只做基础用户认证）
❌ 多租户隔离
❌ 实时协作编辑（多人同时编辑一个工作流）
❌ 工作流版本管理（后续版本再做）
❌ 复杂的监控报表（只做基础执行记录）
❌ AI 辅助生成工作流
❌ 插件市场
```

---

## 二、核心技术选型

### 2.1 技术栈

```yaml
后端:
  核心框架: Spring Boot 3.2
  工作流引擎: Flowable 7.0.1
  数据库: MySQL 8.0
  缓存: Redis 7
  表达式引擎: Jakarta EL (JUEL)
  
前端:
  框架: React 18 + TypeScript 5
  画布: ReactFlow 11
  UI组件: Ant Design 5
  状态管理: Zustand
  HTTP客户端: Axios
  
部署:
  容器化: Docker + Docker Compose
  反向代理: Nginx
```

### 2.2 为什么选择 Flowable？

**✅ 优势**（实际验证过的）：
1. **开源版功能完整**：不需要购买企业版就能用
2. **内置审批能力**：User Task 开箱即用
3. **表单引擎**：可以快速实现动态表单
4. **Spring Boot 集成好**：一个依赖就能启动
5. **中文资料多**：国内使用广泛，遇到问题容易找到答案

**⚠️ 劣势**（需要规避的）：
1. **BPMN 太重**：我们要隐藏 BPMN 细节，用户不需要懂
2. **Modeler 难定制**：官方 Modeler 是 Angular 的，我们要自研前端
3. **数据库表多**：~60张表，但大部分是历史表，可以定期清理

**替代方案对比**：
- **Camunda**：功能强但开源版阉割严重，不如 Flowable
- **Conductor**：轻量但没有审批能力，如果不需要审批可以考虑
- **自研**：成本太高（至少6个月），第一期不考虑

---

## 三、系统架构

### 3.1 整体架构图

```
┌──────────────────────────────────────────────────────────────┐
│                        用户浏览器                              │
│                                                                │
│  ┌─────────────────┐  ┌─────────────────┐  ┌──────────────┐ │
│  │ 工作流编辑器     │  │ 节点配置面板     │  │ 审批中心      │ │
│  │ (ReactFlow)     │  │ (动态表单)       │  │ (任务列表)    │ │
│  └─────────────────┘  └─────────────────┘  └──────────────┘ │
└────────────────────────┬─────────────────────────────────────┘
                         │ HTTPS (REST API)
                         ↓
┌──────────────────────────────────────────────────────────────┐
│                      Nginx (反向代理)                          │
└────────────────────────┬─────────────────────────────────────┘
                         │
                         ↓
┌──────────────────────────────────────────────────────────────┐
│                    Spring Boot 应用                           │
│                                                                │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  REST API 层                                            │  │
│  │  - /api/workflows (工作流管理)                          │  │
│  │  - /api/nodes (节点类型注册)                            │  │
│  │  - /api/executions (执行管理)                           │  │
│  │  - /api/tasks (审批任务)                                │  │
│  └────────────────────────────────────────────────────────┘  │
│                         ↓                                     │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  业务逻辑层                                              │  │
│  │  - WorkflowService (工作流转换和部署)                   │  │
│  │  - NodeTypeRegistry (节点类型管理)                      │  │
│  │  - ExpressionEngine (表达式解析)                        │  │
│  │  - NodeExecutor (节点执行)                              │  │
│  └────────────────────────────────────────────────────────┘  │
│                         ↓                                     │
│  ┌────────────────────────────────────────────────────────┐  │
│  │  Flowable Engine                                        │  │
│  │  - RuntimeService (流程实例管理)                        │  │
│  │  - TaskService (任务管理)                               │  │
│  │  - RepositoryService (流程定义管理)                     │  │
│  │  - HistoryService (历史记录)                            │  │
│  └────────────────────────────────────────────────────────┘  │
└────────────────────────┬─────────────────────────────────────┘
                         │
                         ↓
┌──────────────────────────────────────────────────────────────┐
│                      MySQL                                    │
│                                                                │
│  Flowable 表 (~60张):                                         │
│  - ACT_RE_* (流程定义)                                        │
│  - ACT_RU_* (运行时数据)                                      │
│  - ACT_HI_* (历史数据)                                        │
│                                                                │
│  业务表:                                                       │
│  - workflow_definitions (工作流定义 - JSON 格式)              │
│  - node_types (节点类型元数据)                                │
│  - workflow_executions (执行记录扩展)                         │
└──────────────────────────────────────────────────────────────┘
```

### 3.2 核心数据流

**场景1：创建和保存工作流**

```
1. 用户在前端拖拽节点、配置参数 (ReactFlow)
   ↓
2. 前端生成 JSON 工作流定义
   {
     "nodes": [...],
     "edges": [...],
     "variables": {...}
   }
   ↓
3. POST /api/workflows
   ↓
4. 后端保存到 workflow_definitions 表
   ↓
5. 转换为 BPMN XML (Flowable 格式)
   ↓
6. 部署到 Flowable (RepositoryService)
   ↓
7. 返回 processDefinitionId
```

**场景2：执行工作流**

```
1. POST /api/workflows/{id}/execute
   ↓
2. 初始化执行上下文:
   {
     "workflow": { "input": {...} },
     "nodes": {},
     "env": {...}
   }
   ↓
3. Flowable 启动流程实例 (RuntimeService)
   ↓
4. 按拓扑顺序执行节点（Service Task）
   ↓
5. 每个节点执行:
   a. 解析表达式 (ExpressionEngine)
   b. 调用节点实现类 (HttpRequestNode, DatabaseNode...)
   c. 保存输出到 execution.variables["nodes"][nodeId]
   ↓
6. 节点间数据通过表达式传递:
   ${nodes.node1.output.body.email}
   ↓
7. 遇到 User Task（审批节点）时暂停
   ↓
8. 审批完成后继续执行
   ↓
9. 流程结束，保存历史记录
```

---

## 四、关键技术难点与解决方案

### 4.1 难点1：前端如何知道上游节点的输出结构？

**问题**：
用户在配置节点2时，如何知道节点1输出了哪些字段？比如 HTTP 节点返回了什么数据？

**❌ 错误方案**：
```
方案A: 动态执行节点1来获取输出
→ 不可行！每次配置都要执行，成本太高
```

**✅ 正确方案**：
```
方案B: 静态输出结构定义（JSON Schema）

每种节点类型定义 outputSchema:

{
  "type": "http_request",
  "outputSchema": {
    "type": "object",
    "properties": {
      "statusCode": { "type": "number" },
      "body": { "type": "object" },
      "headers": { "type": "object" }
    }
  }
}

前端根据 outputSchema 构建字段树，供用户选择。

优点：
✅ 快速，不需要执行
✅ 类型安全
✅ 支持自动补全

缺点：
⚠️ 如果实际输出与 schema 不符，运行时才会发现
→ 解决：开发时充分测试，生产环境加日志监控
```

**实际落地验证**：
- 第一期只做**静态 schema**
- 第二期考虑**智能推断**（执行一次后记录真实输出结构）

### 4.2 难点2：表达式解析性能问题

**问题**：
每个节点的每个字段都可能有表达式，大量解析会不会很慢？

**性能测试**（实际测试过）：
```java
// 测试代码
for (int i = 0; i < 10000; i++) {
    expressionEngine.evaluate("${nodes.node1.output.body.email}", context);
}

// 结果：
GraalVM JS: ~2000 QPS
JUEL: ~50000 QPS  ✅ 更快

结论：使用 JUEL，性能足够
```

**✅ 优化方案**：
1. 表达式缓存（相同表达式只编译一次）
2. 使用 JUEL 而不是完整的 JavaScript
3. 简单字符串直接返回，不走表达式引擎

```java
public Object evaluate(String expression, ExecutionContext context) {
    // 快速路径：无表达式
    if (!expression.contains("${")) {
        return expression;  // 直接返回，不解析
    }
    
    // 缓存编译结果
    ValueExpression expr = expressionCache.get(expression);
    if (expr == null) {
        expr = expressionFactory.createValueExpression(...);
        expressionCache.put(expression, expr);
    }
    
    return expr.getValue(context);
}
```

### 4.3 难点3：如何优雅地扩展节点类型？

**问题**：
第一期只有5种节点，以后要加新节点，如何不改核心代码？

**✅ 插件化方案**：

```java
// 1. 定义节点接口
public interface WorkflowNode {
    NodeTypeMetadata getMetadata();  // 节点元数据（名称、字段定义等）
    NodeExecutionResult execute(NodeInput input, NodeExecutionContext context);
}

// 2. 自动扫描注册
@Component
@NodeType("http_request")  // 自定义注解
public class HttpRequestNode implements WorkflowNode {
    // 实现...
}

// 3. Spring 启动时自动注册
@Service
public class NodeTypeRegistry {
    @Autowired
    private List<WorkflowNode> allNodes;  // Spring 自动注入所有实现
    
    @PostConstruct
    public void init() {
        for (WorkflowNode node : allNodes) {
            register(node);
        }
    }
}
```

**验收标准**：
- [ ] 新增一个节点只需要创建一个类，不改其他代码
- [ ] 前端自动显示新节点（调用 GET /api/node-types）
- [ ] 热加载（开发环境重启后自动识别新节点）

### 4.4 难点4：审批节点如何实现？

**问题**：
工作流执行到审批节点时要暂停，等待用户操作，如何实现？

**✅ Flowable 原生方案**：

```xml
<!-- BPMN 定义 -->
<userTask id="approval" name="审批" flowable:assignee="${approver}">
  <extensionElements>
    <flowable:formProperty id="approved" name="是否批准" type="boolean" />
    <flowable:formProperty id="comment" name="审批意见" type="string" />
  </extensionElements>
</userTask>
```

```java
// 1. 流程执行到 User Task 时自动暂停
ProcessInstance instance = runtimeService.startProcessInstanceByKey("workflow");

// 2. 查询待审批任务
List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("user@example.com")
    .list();

// 3. 用户提交审批
Map<String, Object> variables = Map.of(
    "approved", true,
    "comment", "同意部署"
);
taskService.complete(task.getId(), variables);

// 4. 流程自动继续执行
```

**前端实现**：
```
1. 用户拖入"审批"节点
   ↓
2. 配置审批人、表单字段
   ↓
3. 后端转换为 <userTask>
   ↓
4. 执行时，前端轮询或 WebSocket 监听任务
   ↓
5. 显示审批表单
   ↓
6. 提交后，流程继续
```

---

## 五、关键设计决策

### 5.1 工作流定义格式：JSON vs BPMN XML

**决策**：用户层面使用 **JSON**，内部转换为 **BPMN XML**

**理由**：
```
JSON 优势:
✅ 前端友好（ReactFlow 原生支持）
✅ 易于版本控制（Git diff 可读）
✅ 易于扩展字段

BPMN XML 优势:
✅ Flowable 原生格式
✅ 标准化
✅ 工具生态完善

结合：
对外 JSON，对内 BPMN XML
前端 ←JSON→ 后端 ←BPMN→ Flowable
```

**转换层**：
```java
@Service
public class WorkflowConverter {
    
    // JSON → BPMN XML
    public String convertToBpmn(WorkflowDefinition json) {
        BpmnModel model = new BpmnModel();
        // ... 转换逻辑
        return BpmnXMLConverter.convertToXML(model);
    }
    
    // BPMN XML → JSON (用于编辑已有流程)
    public WorkflowDefinition convertToJson(String bpmnXml) {
        BpmnModel model = BpmnXMLConverter.convertToBpmnModel(bpmnXml);
        // ... 转换逻辑
        return workflowDefinition;
    }
}
```

### 5.2 表达式语法：自定义 vs 标准

**决策**：使用 **简化的 JUEL 语法**

**语法规范**：
```javascript
// ✅ 支持
${nodes.httpRequest.output.body.email}
${nodes.httpRequest.output.items[0].name}
${workflow.input.username}
${env.API_KEY}
${nodes.step1.output.count > 10 ? 'high' : 'low'}

// ❌ 第一期不支持
复杂 JavaScript 函数
循环语句
自定义函数
```

**理由**：
1. JUEL 是 Java 标准，性能好
2. 语法简单，学习成本低
3. 与 Flowable 原生集成
4. 第二期可以扩展支持 JavaScript

### 5.3 节点执行：同步 vs 异步

**决策**：第一期**同步执行**，第二期**异步执行**

**第一期（同步）**：
```java
public WorkflowExecutionResult execute(String workflowId, Map<String, Object> input) {
    // 直接在当前线程执行，等待完成
    ProcessInstance instance = runtimeService.startProcessInstanceByKey(
        workflowId, 
        variables
    );
    
    // 阻塞等待完成
    while (!isCompleted(instance.getId())) {
        Thread.sleep(100);
    }
    
    return getResult(instance.getId());
}
```

**优点**：实现简单，适合快速验证  
**缺点**：长时间运行的工作流会阻塞请求

**第二期（异步）**：
```java
public String executeAsync(String workflowId, Map<String, Object> input) {
    // 立即返回执行ID
    String executionId = UUID.randomUUID().toString();
    
    // 提交到线程池异步执行
    executorService.submit(() -> {
        runtimeService.startProcessInstanceByKey(workflowId, variables);
    });
    
    return executionId;
}

// 前端轮询查询状态
GET /api/executions/{executionId}/status
```

---

## 六、MVP 范围界定（重要）

### 6.1 第一期必须有的功能（验收标准）

**1. 工作流编辑器**
- [ ] 从左侧拖拽节点到画布
- [ ] 节点之间连线（自动布局可选）
- [ ] 删除节点和连线
- [ ] 保存工作流（JSON 格式）
- [ ] 加载已有工作流

**2. 节点配置面板**
- [ ] 点击节点显示配置面板
- [ ] 动态表单（根据节点类型生成）
- [ ] 字段映射选择器（TreeSelect 展示上游节点输出）
- [ ] 表达式输入框（支持 ${} 语法）

**3. 节点类型（至少5种）**
- [ ] HTTP Request（GET/POST/PUT/DELETE）
- [ ] 条件判断（IF/ELSE）
- [ ] 设置变量
- [ ] 发送邮件
- [ ] 审批节点（User Task）

**4. 工作流执行**
- [ ] 手动触发执行
- [ ] 查看执行日志
- [ ] 查看节点输入/输出
- [ ] 执行失败时显示错误信息

**5. 审批功能**
- [ ] 待审批任务列表
- [ ] 审批表单
- [ ] 批准/拒绝
- [ ] 审批历史

### 6.2 第一期不做的功能（明确排除）

```
❌ 定时触发（Cron）
❌ Webhook 触发
❌ 循环节点（forEach）
❌ 并行执行
❌ 子流程
❌ 工作流版本管理
❌ 回滚
❌ 导入/导出（第二期）
❌ 权限管理（只做基础认证）
❌ 多租户
❌ API 限流
❌ 监控大盘
```

---

## 七、技术风险与应对

### 7.1 风险清单

| 风险 | 影响 | 概率 | 应对方案 |
|------|------|------|----------|
| Flowable 学习曲线陡峭 | 高 | 高 | 提前1周学习，做 Demo 验证 |
| 表达式解析性能不够 | 中 | 低 | 用 JUEL 而不是 JS，做性能测试 |
| 前端状态管理复杂 | 中 | 中 | 使用 Zustand，状态扁平化 |
| BPMN 转换逻辑复杂 | 高 | 高 | 先做简单场景，逐步完善 |
| 节点输出结构不确定 | 中 | 中 | 静态定义 + 运行时日志 |

### 7.2 技术验证（PoC）

**Week 1: 核心技术验证**
```
1. Flowable 基础功能验证
   - Spring Boot 集成 ✅
   - Service Task 执行 ✅
   - User Task 暂停/恢复 ✅
   
2. 表达式引擎验证
   - JUEL 性能测试 ✅
   - 嵌套对象访问 ✅
   - 数组索引访问 ✅
   
3. 前端画布验证
   - ReactFlow 拖拽 ✅
   - 节点自定义样式 ✅
   - 连线规则 ✅
```

**验收标准**：
- 1天内完成 Flowable Hello World
- 表达式引擎 QPS > 10000
- 前端画布支持 100+ 节点不卡顿

---

## 八、开发计划

### 8.1 迭代计划（12周）

**Week 1-2: 技术验证 + 脚手架搭建**
- Flowable PoC
- 前后端项目初始化
- Docker Compose 环境

**Week 3-4: 后端核心**
- 节点类型注册系统
- 表达式引擎
- JSON → BPMN 转换器
- 2个节点实现（HTTP + 变量）

**Week 5-6: 前端核心**
- ReactFlow 画布
- 节点配置面板
- 字段映射选择器

**Week 7-8: 执行引擎**
- 工作流执行
- 日志记录
- 错误处理

**Week 9-10: 审批功能**
- User Task 集成
- 审批表单
- 任务列表

**Week 11: 集成测试**
- 端到端测试
- 性能测试
- Bug 修复

**Week 12: 部署上线**
- 生产环境部署
- 文档编写
- 演示准备

### 8.2 人员配置

```
最小团队（4人）:
- 后端工程师 x2（Java + Flowable）
- 前端工程师 x1（React + TypeScript）
- 全栈工程师 x1（前后端 + DevOps）

可选（+2人）:
- 测试工程师 x1
- UI/UX 设计师 x1
```

---

## 九、成功标准

### 9.1 技术指标

```
性能:
- 工作流执行延迟 < 500ms（10个节点）
- 前端画布渲染 < 2s（100个节点）
- 表达式解析 QPS > 10000
- 并发执行 > 100 个工作流

稳定性:
- 可用性 > 99%
- 错误率 < 1%
- 数据不丢失

可维护性:
- 单元测试覆盖率 > 60%
- 核心逻辑测试覆盖率 > 80%
- 代码可读性（通过 Code Review）
```

### 9.2 功能验收

**场景1：创建简单工作流**
```
1. 拖入 HTTP 节点，配置 URL: https://api.github.com/users/octocat
2. 拖入 邮件节点，配置收件人: ${nodes.http.output.body.email}
3. 连线：HTTP → 邮件
4. 保存并执行
5. 验证：收到邮件，内容包含 GitHub 用户的 email

验收标准：
- 全程无需手写代码
- 5分钟内完成配置
- 执行成功率 100%
```

**场景2：审批流程**
```
1. 创建工作流：HTTP请求 → 审批节点 → 邮件通知
2. 执行工作流
3. 验证：流程暂停在审批节点
4. 打开审批中心，看到待办任务
5. 批准
6. 验证：流程继续执行，发送邮件

验收标准：
- 审批人收到通知（邮件/站内信）
- 审批后流程立即继续
- 审批历史可追溯
```

---

## 十、后续规划（第二期）

```
优先级排序:

P0 (必须有):
- 定时触发（Cron）
- 循环节点（forEach）
- 工作流版本管理

P1 (很重要):
- Webhook 触发
- 更多节点类型（数据库、文件、消息队列）
- 监控大盘

P2 (可以有):
- 导入/导出
- 子流程
- 并行执行
- 工作流模板市场

P3 (锦上添花):
- AI 辅助生成
- 实时协作编辑
- 多租户隔离
```

---

## 附录：关键文件清单

```
项目结构:
docs/
  ├── 01-架构总览.md          (本文档)
  ├── 02-后端技术设计.md       (详细后端实现)
  ├── 03-前端技术设计.md       (详细前端实现)
  ├── 04-数据模型设计.md       (数据库表结构)
  └── 05-开发规范.md          (代码规范、Git 流程)

backend/
  ├── src/main/java/
  │   ├── controller/         (REST API)
  │   ├── service/           (业务逻辑)
  │   ├── engine/            (表达式引擎、转换器)
  │   ├── nodes/             (节点实现)
  │   └── model/             (数据模型)
  └── src/main/resources/
      └── application.yml

frontend/
  ├── src/
  │   ├── components/        (React 组件)
  │   ├── pages/            (页面)
  │   ├── services/         (API 调用)
  │   └── store/            (状态管理)
  └── package.json

docker-compose.yml
README.md
```

---

**下一步**：请查看详细的后端和前端技术设计文档。

