- 为多个端点添加权限控制,包括文件操作、工作流任务、群组管理和表单相关功能 - 重构ChatAgentService以支持从数据库读取AI模型配置,并提供回退到应用设置的功能 - 在DatabaseInitializer中添加ai_models表的建表脚本,确保表结构存在 - 更新Directory.Build.props以抑制EF1002和NU1605警告 - 为FileDbContext添加Settings实体集合和文件设置实体 - 优化FileDbContextDesignTimeFactory的配置文件查找逻辑,支持多种目录结构 - 修复EF迁移快照中的命名空间引用错误 - 为多个工作流和IM相关端点添加相应的权限验证
693 lines
40 KiB
Markdown
693 lines
40 KiB
Markdown
# X6 工作流前后端对接标准
|
||
|
||
| 项目 | 内容 |
|
||
|---|---|
|
||
| 文档状态 | 评审稿(P0),未实现 |
|
||
| 适用范围 | BuildFlow 审批流自定义流程设计器(前端 + 后端) |
|
||
| 技术栈 | 前端 Vue 3 + Vben Admin v5 + AntV X6;后端 .NET 10 + FastEndpoints + MediatR + EF Core |
|
||
| 关键决策 | ① 传统审批流(非 AI 编排)② 后端 X6 JSON 单一事实源 ③ X6 自建路线 |
|
||
|
||
> 本文是**标准/契约**文档,不是实现教程。所有事实陈述标注「基于现有代码:`路径`」。实现细节另起任务。
|
||
|
||
---
|
||
|
||
## 第 1 章 背景与现状
|
||
|
||
### 1.1 目标场景
|
||
|
||
BuildFlow 需要一个**审批流自定义流程设计器**:业务用户在前端通过拖拽节点、连线的方式编排审批流程(开始 → 审批 → 抄送 → 条件分支 → 并行 → 子流程 → 定时 → 结束),保存后由后端 `ProcessEngine` 执行。
|
||
|
||
**明确不做**:AI 智能体编排(LLM/代码/MCP/知识库节点)。
|
||
|
||
### 1.2 前端现状
|
||
|
||
基于现有代码:`build-flow.web/apps/web-antdv-next/src/`
|
||
|
||
- 技术栈:Vue 3 + TypeScript + Vue Vben Admin v5 + antdv-next + pnpm workspace。
|
||
- **当前无任何流程相关页面**(`src/views/` 下只有 dashboard / system / file-manager / im / share / demos / _core,无 workflow 目录)。
|
||
- **当前无 X6 依赖**,需全新引入 `@antv/x6` + `@antv/x6-vue-shape`。
|
||
- API 客户端约定:基于现有代码 `src/api/request.ts`,统一 `requestClient`(`responseReturn: 'data'`),后端响应信封由前端层自动解包。
|
||
|
||
### 1.3 后端现状(关系表事实源)
|
||
|
||
基于现有代码:`build-flow.api/src/modules/workflow/`
|
||
|
||
#### 1.3.1 三张关系表为唯一事实源
|
||
|
||
| 表名 | 实体 | 配置文件 |
|
||
|---|---|---|
|
||
| `wf_workflow_definitions` | `WorkflowDefinition` | `Infrastructure/Persistence/Configurations/WorkflowDefinitionConfiguration.cs` |
|
||
| `wf_workflow_nodes` | `WorkflowNode` | `WorkflowNodeConfiguration.cs` |
|
||
| `wf_workflow_edges` | `WorkflowEdge` | `WorkflowEdgeConfiguration.cs` |
|
||
|
||
**`DefinitionJson` 是冗余空壳字段**:
|
||
|
||
- 基于现有代码 `Domain/Entities/WorkflowDefinition.cs:21`:字段注释为「完整流程图的 JSON 快照(节点+边),便于导出/导入与前端渲染」。
|
||
- 基于现有代码 `UpdateWorkflowDefinitionCommandHandler.cs`:Handler 仅做 `entity.DefinitionJson = request.DefinitionJson;` 字符串覆盖,**不与 nodes/edges 表同步**,无任何一致性校验。
|
||
- 基于 `SeedData.cs`:种子数据只构造 Node/Edge 实体,**未写 DefinitionJson**。
|
||
|
||
#### 1.3.2 `ProcessEngine` 运行时只读关系表
|
||
|
||
基于现有代码 `Application/Engine/ProcessEngine.cs`(约 1191 行,方法名定位,行号会漂移):
|
||
|
||
- 节点查找 `FindNodeAsync`:`_dbContext.WorkflowNodes.FindAsync(nodeId)`。
|
||
- 出边查找 `GetOutgoingEdgesAsync`:`_dbContext.WorkflowEdges.Where(e => e.SourceNodeId == nodeId)`。
|
||
- 入边查找 `GetIncomingEdgesAsync`:`_dbContext.WorkflowEdges.Where(e => e.TargetNodeId == nodeId)`。
|
||
- 启动时加载定义全部节点(`StartAsync` 内):`_dbContext.WorkflowNodes.Where(n => n.DefinitionId == ...)`。
|
||
- Config 解析统一走 `NodeConfigParser.Parse(node.Config)`。
|
||
- **`DefinitionJson` 在引擎路径中一次都未被读取**(grep 零命中)。
|
||
|
||
#### 1.3.3 引擎对实体字段的精确依赖(迁移影响面)
|
||
|
||
| 实体 | 引擎使用的字段 | 是否影响迁移 |
|
||
|---|---|---|
|
||
| `WorkflowNode` | `Id`, `DefinitionId`, `NodeType`, `Name`, `Config` | ✅ 必须从 JSON 等价读取 |
|
||
| `WorkflowNode` | `PositionX`, `PositionY` | ❌ 引擎不读(纯画布字段) |
|
||
| `WorkflowNode` | `FormDefinitionId` | ⚠️ 引擎不直接读,但 DTO 层有 |
|
||
| `WorkflowEdge` | `SourceNodeId`, `TargetNodeId` | ✅ 拓扑遍历核心 |
|
||
| `WorkflowEdge` | `EdgeType` | ✅ `CompleteTaskAsync` 选边(Approved 优先 / Normal 回退 / Rejected 独立) |
|
||
| `WorkflowEdge` | `Condition` | ✅ Condition/ExclusiveGateway 节点条件评估 |
|
||
| `WorkflowEdge` | `Order` | ✅ Condition/ExclusiveGateway 分支评估顺序(first-match-wins) |
|
||
| `WorkflowEdge` | `Label` | ❌ 引擎不读 |
|
||
|
||
#### 1.3.4 现有接口割裂(7 套)
|
||
|
||
基于现有代码 `src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/`(24 个文件):
|
||
|
||
- 定义级:Create / Update / Delete / Publish / Disable / GetById / GetList(7 个)
|
||
- 节点级:`CreateNode` / `UpdateNode` / `DeleteNode`(3 个,路由 `/workflow-definitions/{DefinitionId}/nodes[/{NodeId}]`)
|
||
- 边级:`CreateEdge` / `UpdateEdge` / `DeleteEdge`(3 个)
|
||
|
||
**问题**:前端维护画布需对每个节点/边单独发请求,与 X6「整图 `toJSON()` 保存」模型不匹配。
|
||
|
||
#### 1.3.5 响应信封
|
||
|
||
基于现有代码 `shared/BuildFlow.Shared/Api/ApiResponse.cs` + `ApiResponseMiddleware.cs`:
|
||
|
||
```
|
||
{ "code": 0, "data": <业务对象>, "message": "ok" }
|
||
```
|
||
|
||
- `code = 0` 表示成功;前端 `requestClient` 配 `responseReturn: 'data'` 自动解包。
|
||
- 时间统一序列化为 **UTC 毫秒时间戳**(`TimestampDateTimeConverter`)。
|
||
- 命名 CamelCase。
|
||
|
||
#### 1.3.6 现有枚举(本契约复用,不改)
|
||
|
||
基于现有代码 `Domain/Enums/`:
|
||
|
||
```csharp
|
||
// NodeType(int):Start=0, End=1, Approval=2, Cc=3, Condition=4,
|
||
// Parallel=5, SubProcess=6, Timer=7, ExclusiveGateway=8
|
||
// EdgeType(int):Normal=0, Approved=1, Rejected=2
|
||
// DefinitionStatus(int):Draft=0, Published=1, Disabled=2
|
||
```
|
||
|
||
---
|
||
|
||
## 第 2 章 目标与边界
|
||
|
||
### 2.1 目标
|
||
|
||
1. 定义**与 X6 `toJSON()`/`fromJSON()` 原生兼容**的 `definition_json` schema,作为前后端唯一对接契约。
|
||
2. 让 `definition_json` 升级为后端**唯一事实源**,`ProcessEngine` 改读 JSON。
|
||
3. 简化接口:废弃逐 Node/Edge CRUD,改为**整图保存**。
|
||
4. 前端用 X6 实现可视化设计器,`graph.toJSON()` → 直接落库,`graph.fromJSON()` → 直接渲染。
|
||
|
||
### 2.2 边界
|
||
|
||
- **本文档只定标准,不实现**。后续实现按第 8 章阶段推进。
|
||
- 不改变现有 `NodeType` / `EdgeType` / `DefinitionStatus` 枚举语义。
|
||
- 不改变响应信封、认证、权限体系。
|
||
- 不涉及流程实例运行时(`WorkflowInstance` / `WorkflowTask` / `WorkflowToken`)的存储改造——它们引用的是已发布流程定义的快照,迁移策略见第 7 章。
|
||
|
||
---
|
||
|
||
## 第 3 章 组件选型结论
|
||
|
||
### 3.1 结论:X6 自建路线
|
||
|
||
| 候选 | 结论 | 依据 |
|
||
|---|---|---|
|
||
| `@antv/xflow`(X6 官方应用级方案) | ❌ 不可用 | 仓库已声明停止维护;**仅支持 React**,Vben 是 Vue3 无法集成 |
|
||
| X6 官方审批流成品 | ❌ 不存在 | 官方 showcase 无审批流成品,无审批/抄送/条件分支节点预制模板 |
|
||
| Vue3 审批流成品(StavinLi/Workflow-Vue3 等) | ❌ 偏离方向 | 均为仿钉钉 DOM 树渲染,**不用 X6 画布**,与「引入 X6」目标冲突 |
|
||
| **X6 自建(BPMN/流程图示例 + x6-vue-shape)** | ✅ 采纳 | 贴合「引入 X6」目标;官方有 BPMN/流程图示例可参照;审批节点需自写但有参照 |
|
||
|
||
### 3.2 依赖包
|
||
|
||
| 包 | 用途 | 版本约束 |
|
||
|---|---|---|
|
||
| `@antv/x6` | X6 主包(**3.x 起插件已合并进主包**,Snapline/Stencil/Transform 等无需单独安装) | `^3.x`(X6 当前稳定主版本,遵循仓库 pnpm catalog 规则) |
|
||
| `@antv/x6-vue-shape` | Vue 组件渲染节点注册 | 与 `@antv/x6` 3.x 对齐(同主版本) |
|
||
|
||
> ⚠️ 必须用 **X6 3.x**,2.x 的插件需单独安装且 API 有差异。实现时以 `@antv/x6` 当前发布的稳定主版本为准,并加入仓库 catalog,不要固定死小版本。安装走 `build-flow.web` 的 pnpm workspace,禁止 npm/yarn。
|
||
|
||
### 3.3 参照起点
|
||
|
||
- X6 官方 BPMN 示例、流程图示例:源码位于 antvis/X6 仓库 `site/examples/showcase/practices/demo/`。
|
||
- X6 Vue 节点文档:`https://x6.antv.antgroup.com/tutorial/intermediate/vue`。
|
||
- 连接桩文档:`https://x6.antv.antgroup.com/tutorial/basic/port`。
|
||
- 旧版审批 demo(请假/人事审批,X6 1.x,仅作节点样式参考):`https://x6.antv.vision/zh/examples/showcase/practices/`。
|
||
|
||
---
|
||
|
||
## 第 4 章 前端方案(设计层面)
|
||
|
||
### 4.1 目录落点
|
||
|
||
遵循 `rag-coding-web` 技能约定,全部落在 `apps/web-antdv-next/src/`:
|
||
|
||
```
|
||
src/
|
||
├── api/core/workflow.ts # API 定义
|
||
├── router/routes/modules/workflow.ts # 路由 module
|
||
└── views/workflow/
|
||
├── list/index.vue # 流程定义列表/发布/启停
|
||
└── designer/
|
||
├── index.vue # 设计器主页面(容器)
|
||
├── graph/ # X6 Graph 初始化与配置
|
||
│ ├── createGraph.ts # Graph 工厂(grid/snapline/connecting)
|
||
│ └── ports.ts # 端口 groups/items 预设
|
||
├── shapes/ # 节点注册(每个 NodeType 一个)
|
||
│ ├── register.ts # 集中 register 所有 shape
|
||
│ ├── StartNode.vue
|
||
│ ├── ApprovalNode.vue
|
||
│ ├── ConditionNode.vue
|
||
│ └── ... # 详见 4.4
|
||
├── components/ # 设计器 UI 组件
|
||
│ ├── StencilPanel.vue # 拖拽节点面板
|
||
│ ├── Toolbar.vue # 保存/撤销/缩放/校验
|
||
│ └── NodeConfigDrawer.vue # 节点配置抽屉
|
||
└── composables/
|
||
├── useGraph.ts # Graph 生命周期管理
|
||
└── useGraphPersistence.ts # 加载/保存(toJSON/fromJSON)
|
||
```
|
||
|
||
> 上述是设计目标结构,实现时可在遵循「模块内聚」前提下调整。`packages/@core`、`packages/effects` 不改。
|
||
|
||
### 4.2 设计器能力清单
|
||
|
||
| 能力 | X6 机制 | 说明 |
|
||
|---|---|---|
|
||
| 拖拽创建节点 | `Stencil` 插件 | 分组面板,拖入后 `addNode` |
|
||
| 画布缩放 | `mousewheel` + `minScale/maxScale` | 0.5 ~ 3 |
|
||
| 对齐线 | `Snapline` 插件 | X6 3.x 内置 |
|
||
| 连线 | `connecting` 配置 | `connector: 'smooth'`、`allowLoop: false`、`validateConnection` |
|
||
| 端口显隐 | `node:mouseenter/mouseleave` 事件 | 默认隐藏,hover 显示,连接后常显 |
|
||
| 节点删除 | 卡片内删除按钮 + `node.remove()` | Start/End 节点禁止删除 |
|
||
| 边删除 | `edge:mouseenter` 显示 `button-remove` 工具 | |
|
||
| 整图保存 | `graph.toJSON()` | 一次请求覆盖整张图 |
|
||
| 整图加载 | `graph.fromJSON({nodes, edges})` | 详情接口返回的 `definitionJson` 直接喂入 |
|
||
|
||
### 4.3 端口预设(所有节点统一)
|
||
|
||
四向端口,默认隐藏,hover 显示:
|
||
|
||
```ts
|
||
const PORT_GROUPS = {
|
||
top: { position: 'top', attrs: { circle: { r: 3, magnet: true, fill: '#C2C8D5', stroke: '#C2C8D5' } } },
|
||
right: { position: 'right', attrs: { circle: { r: 3, magnet: true, fill: '#C2C8D5', stroke: '#C2C8D5' } } },
|
||
bottom: { position: 'bottom', attrs: { circle: { r: 3, magnet: true, fill: '#C2C8D5', stroke: '#C2C8D5' } } },
|
||
left: { position: 'left', attrs: { circle: { r: 3, magnet: true, fill: '#C2C8D5', stroke: '#C2C8D5' } } },
|
||
};
|
||
const PORT_ITEMS = [
|
||
{ id: 'top', group: 'top' }, { id: 'right', group: 'right' },
|
||
{ id: 'bottom', group: 'bottom' }, { id: 'left', group: 'left' },
|
||
];
|
||
```
|
||
|
||
### 4.4 节点形态
|
||
|
||
用 `@antv/x6-vue-shape` 注册 Vue 组件渲染。每个 `NodeType` 对应一个 shape 名和一个 `.vue` 组件,业务配置通过 `node.data` 承载,组件内 `node.getData()` 读取。详见第 5 章 5.5 的 shape 映射表。
|
||
|
||
> 交互复杂的节点配置(审批人规则编辑器、条件表达式编辑器)需独立子方案,本文不展开。
|
||
|
||
---
|
||
|
||
## 第 5 章 后端数据契约(★ 核心)
|
||
|
||
### 5.1 顶层结构
|
||
|
||
`definition_json` 列存 X6 原生格式。后端统一**接收/返回 `{nodes, edges}` 形式**(X6 的 `fromJSON`/`parseJSON` 同时支持 `{cells}` 和 `{nodes, edges}` 两种等价形式,本契约选用前者更易读写):
|
||
|
||
```json
|
||
{
|
||
"nodes": [ /* Node 对象数组 */ ],
|
||
"edges": [ /* Edge 对象数组 */ ]
|
||
}
|
||
```
|
||
|
||
> 空图(仅有定义壳、无节点)合法,值为 `{"nodes":[],"edges":[]}`。
|
||
|
||
### 5.2 节点标准字段表
|
||
|
||
| 字段 | 类型 | 必填 | 用途 | 后端是否消费 |
|
||
|---|---|---|---|---|
|
||
| `id` | string | ✅ | 节点唯一标识,格式见 5.7 | ✅ 拓扑遍历 |
|
||
| `shape` | string | ✅ | 节点形状名,决定渲染器,见 5.5 | ✅ 反推 NodeType |
|
||
| `x` | number | ✅ | 画布 X 坐标(左上角) | ❌ 仅渲染 |
|
||
| `y` | number | ✅ | 画布 Y 坐标(左上角) | ❌ 仅渲染 |
|
||
| `width` | number | ❌ | 宽度(注册时默认) | ❌ 仅渲染 |
|
||
| `height` | number | ❌ | 高度(注册时默认) | ❌ 仅渲染 |
|
||
| `angle` | number | ❌ | 旋转角度 | ❌ 仅渲染 |
|
||
| `visible` | boolean | ❌ | 是否可见,默认 true | ❌ 仅渲染 |
|
||
| `data` | object | ✅ | **业务数据**,见 5.5 | ✅ 引擎读取 |
|
||
| `ports` | object | ❌ | 连接桩,见 5.4 | ❌ 仅渲染(边引用 port) |
|
||
| `attrs` | object | ❌ | SVG 样式 | ❌ 仅渲染 |
|
||
| `markup` | array | ❌ | SVG 结构 | ❌ 仅渲染 |
|
||
| `label` | string\|object | ❌ | 文本标签 | ❌ 仅渲染 |
|
||
|
||
**后端消费原则**:引擎只读 `id` / `shape`(反推 NodeType)/ `data`;几何/样式字段透传不解释。
|
||
|
||
### 5.3 边标准字段表
|
||
|
||
| 字段 | 类型 | 必填 | 用途 | 后端是否消费 |
|
||
|---|---|---|---|---|
|
||
| `id` | string | ✅ | 边唯一标识 | ✅ 标识 |
|
||
| `shape` | string | ❌ | 边类型,默认 `wf-edge` | ❌ |
|
||
| `source` | `{cell, port}` | ✅ | 起点 `{cell: nodeId, port: portId}` | ✅ 取 `cell` 作 SourceNodeId |
|
||
| `target` | `{cell, port}` | ✅ | 终点 `{cell: nodeId, port: portId}` | ✅ 取 `cell` 作 TargetNodeId |
|
||
| `data` | object | ❌ | 业务数据,见 5.6 | ✅ 引擎读取 |
|
||
| `label` | string\|object | ❌ | 边标签 | ❌ 仅渲染(引擎不读) |
|
||
| `vertices` | `[{x,y}]` | ❌ | 路径控制点(弯折点) | ❌ 仅渲染 |
|
||
| `router` | string\|object | ❌ | 路由算法(normal/orth/manhattan) | ❌ 仅渲染 |
|
||
| `connector` | string\|object | ❌ | 连接器(normal/smooth/rounded) | ❌ 仅渲染 |
|
||
| `attrs` | object | ❌ | 样式 | ❌ 仅渲染 |
|
||
| `zIndex` | number | ❌ | 层级 | ❌ 仅渲染 |
|
||
|
||
**source/target 规则**:必须用 `{cell, port}` 结构;`cell` 是节点 id(对应 5.2 的 `node.id`),`port` 是端口 id(默认 `top/right/bottom/left`)。后端只取 `cell` 做拓扑,`port` 仅前端连线校验用。
|
||
|
||
### 5.4 端口 port 结构(与 4.3 一致)
|
||
|
||
```json
|
||
"ports": {
|
||
"groups": { /* top/right/bottom/left 组定义,见 4.3 */ },
|
||
"items": [
|
||
{ "id": "top", "group": "top" },
|
||
{ "id": "right", "group": "right" },
|
||
{ "id": "bottom", "group": "bottom" },
|
||
{ "id": "left", "group": "left" }
|
||
]
|
||
}
|
||
```
|
||
|
||
> 后端不解释 ports 结构,但边的 `source.port` / `target.port` 必须命中节点 `ports.items[].id`。校验在发布时做(见第 6 章)。
|
||
|
||
### 5.5 节点 data 业务契约(关键映射)
|
||
|
||
`node.shape` 决定渲染器,同时**反推 `NodeType` 枚举**。业务配置统一进 `node.data`,替代旧的 `WorkflowNode.Config`(jsonb 字符串)。
|
||
|
||
| NodeType | 枚举值 | shape 名 | `data` 业务字段(替代旧 Config) |
|
||
|---|---|---|---|
|
||
| `Start` | 0 | `wf-start` | 无(`data` 可存 `title`) |
|
||
| `End` | 1 | `wf-end` | 无(`data` 可存 `title`) |
|
||
| `Approval` | 2 | `wf-approval` | `approvalMode`(single/countersign/any), `assigneeRule`, `assigneeRules`(数组), `minApprovals`, `timeoutMinutes`, `onEnter`, `onApproved`, `onRejected`, `formDefinitionId` |
|
||
| `Cc` | 3 | `wf-cc` | `recipients`(数组), `formDefinitionId` |
|
||
| `Condition` | 4 | `wf-condition` | 无(条件表达式与顺序放在**出边**的 `data` 上,见 5.6) |
|
||
| `Parallel` | 5 | `wf-parallel` | 无 |
|
||
| `SubProcess` | 6 | `wf-subprocess` | `definitionId`(子流程 GUID 字符串) |
|
||
| `Timer` | 7 | `wf-timer` | `delayMinutes`, `targetTime`(ISO8601) |
|
||
| `ExclusiveGateway` | 8 | `wf-exclusive` | 无(同 Condition,分支信息在出边) |
|
||
|
||
> `data.title`(节点显示名,对应旧 `WorkflowNode.Name`)所有节点通用,建议必填。
|
||
|
||
**shape → NodeType 反推规则**:后端维护一张常量映射表,`shape` 缺失时拒绝发布。
|
||
|
||
### 5.6 边 data 业务契约
|
||
|
||
| `data` 字段 | 类型 | 对应旧字段 | 用途 |
|
||
|---|---|---|---|
|
||
| `edgeType` | int (枚举值 0/1/2) | `WorkflowEdge.EdgeType` | Normal=0 / Approved=1 / Rejected=2;影响 Approval 节点选边 |
|
||
| `condition` | string | `WorkflowEdge.Condition` | Condition/ExclusiveGateway 出边的条件表达式(简单文本或 JSON 树) |
|
||
| `order` | int | `WorkflowEdge.Order` | 分支评估顺序,值小优先(first-match-wins) |
|
||
|
||
> 几何信息(`vertices` / `router` / `connector`)放边**顶层**,不放 `data`;这些字段后端透传不读。
|
||
|
||
### 5.7 ID 规则
|
||
|
||
| 元素 | id 格式 | 生成方 |
|
||
|---|---|---|
|
||
| 节点 | `node_<guid>` | 前端生成(拖入时),后端保存时校验唯一 |
|
||
| 边 | `edge_<guid>` | 前端生成(连线时),后端保存时校验唯一 |
|
||
| 端口 | `top` / `right` / `bottom` / `left`(固定) | 由 shape 注册预设,不单独生成 |
|
||
|
||
> **待决项**(见第 9 章):是否允许后端在保存时重写 id。当前建议前端生成、后端透传,保证 `source.cell`/`target.cell` 引用稳定。
|
||
|
||
### 5.8 引擎字段对应表(迁移映射)
|
||
|
||
`ProcessEngine` 当前读实体字段 → 改造后从 JSON 路径读取:
|
||
|
||
| 当前实体字段 | JSON 路径 | 说明 |
|
||
|---|---|---|
|
||
| `node.Id` | `nodes[].id` | 字符串 ↔ Guid(需类型转换) |
|
||
| `node.NodeType` | 由 `nodes[].shape` 反推 | 见 5.5 映射 |
|
||
| `node.Name` | `nodes[].data.title` | |
|
||
| `node.Config`(jsonb 字符串) | `nodes[].data`(对象) | 直接是对象,免去 `NodeConfigParser` 字符串反序列化 |
|
||
| `node.DefinitionId` | 外层(图所属定义) | 加载时由 Definition 上下文注入 |
|
||
| `node.PositionX/Y` | `nodes[].x/y` | 引擎不读,仅迁移脚本用 |
|
||
| `edge.SourceNodeId` | `edges[].source.cell` | |
|
||
| `edge.TargetNodeId` | `edges[].target.cell` | |
|
||
| `edge.EdgeType` | `edges[].data.edgeType` | |
|
||
| `edge.Condition` | `edges[].data.condition` | |
|
||
| `edge.Order` | `edges[].data.order` | |
|
||
| `edge.Label` | `edges[].label` | 引擎不读 |
|
||
|
||
### 5.9 完整示例(最小可运行图)
|
||
|
||
```json
|
||
{
|
||
"nodes": [
|
||
{
|
||
"id": "node_start_001",
|
||
"shape": "wf-start",
|
||
"x": 120, "y": 120,
|
||
"data": { "title": "开始" },
|
||
"ports": { "groups": { "...": "见 5.4" }, "items": [ "..." ] }
|
||
},
|
||
{
|
||
"id": "node_approval_001",
|
||
"shape": "wf-approval",
|
||
"x": 120, "y": 280,
|
||
"data": {
|
||
"title": "部门经理审批",
|
||
"approvalMode": "single",
|
||
"assigneeRule": "role:dept-manager",
|
||
"timeoutMinutes": 1440,
|
||
"formDefinitionId": null
|
||
},
|
||
"ports": { "...": "..." }
|
||
},
|
||
{
|
||
"id": "node_end_001",
|
||
"shape": "wf-end",
|
||
"x": 120, "y": 440,
|
||
"data": { "title": "结束" },
|
||
"ports": { "...": "..." }
|
||
}
|
||
],
|
||
"edges": [
|
||
{
|
||
"id": "edge_001",
|
||
"shape": "wf-edge",
|
||
"source": { "cell": "node_start_001", "port": "bottom" },
|
||
"target": { "cell": "node_approval_001", "port": "top" },
|
||
"data": { "edgeType": 0 }
|
||
},
|
||
{
|
||
"id": "edge_002",
|
||
"shape": "wf-edge",
|
||
"source": { "cell": "node_approval_001", "port": "bottom" },
|
||
"target": { "cell": "node_end_001", "port": "top" },
|
||
"data": { "edgeType": 1 }
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 第 6 章 API 契约(简化接口)
|
||
|
||
### 6.1 改造后接口(最小集)
|
||
|
||
遵循现有 FastEndpoints + MediatR + 资源式路由风格(基于现有代码 `Endpoints/workflow/WorkflowDefinition/`):
|
||
|
||
| 方法 | 路由 | 说明 | 请求要点 | 响应 |
|
||
|---|---|---|---|---|
|
||
| `GET` | `/workflow-definitions` | 列表 | 分页/筛选 | `WorkflowDefinitionDto[]`(**不含** nodes/edges,含 definitionJson 摘要状态) |
|
||
| `GET` | `/workflow-definitions/{Id}` | 详情 | — | `WorkflowDefinitionDetailDto`(含完整 `definitionJson`,前端 `graph.fromJSON` 直接渲染) |
|
||
| `POST` | `/workflow-definitions` | 创建 | name, code, formDefinitionId | 初始空图 `{"nodes":[],"edges":[]}` |
|
||
| `PUT` | `/workflow-definitions/{Id}` | **整图保存** | name, description, **definitionJson**, formDefinitionId | `WorkflowDefinitionDto` |
|
||
| `POST` | `/workflow-definitions/{Id}/publish` | 发布 | — | 发布时做**图校验**(见 6.3) |
|
||
| `DELETE` | `/workflow-definitions/{Id}` | 删除 | — | 空对象(沿用现有写回 `"{}"` 约定) |
|
||
|
||
**关键变化**:`PUT` 整图保存——请求体 `definitionJson` 即 X6 `graph.toJSON()` 输出,**一次请求覆盖整张图**,后端不再做增量 Node/Edge 同步。
|
||
|
||
**DTO 字段去向(基于现有代码 `DTOs/WorkflowDefinitionDetailDto.cs`)**:
|
||
|
||
现有 `WorkflowDefinitionDetailDto` 含 `List<WorkflowNodeDto> Nodes` + `List<WorkflowEdgeDto> Edges` 两个集合字段,是「关系表事实源」时代的产物。JSON 单一事实源后这两个集合变为冗余,处理方式:
|
||
|
||
- **`Nodes` / `Edges` 集合**:置为 `null`(或空集合),**不再由后端填充**。前端设计器统一从 `DefinitionJson` 经 `graph.fromJSON()` 渲染,不读这两个集合。
|
||
- **`DefinitionJson`**:成为详情接口的**唯一权威负载**,前端拿它直接喂 `graph.fromJSON`。
|
||
- **是否删除 `Nodes`/`Edges` 字段**:为避免破坏存量前端调用,P1 阶段**保留字段置空**,P4 关系表清理时一并从 DTO 移除。
|
||
- `WorkflowNodeDto` / `WorkflowEdgeDto`:P4 阶段随关系表废弃而废弃。
|
||
|
||
### 6.2 废弃接口(过渡期保留)
|
||
|
||
以下 6 套接口标 `[Obsolete]`,过渡期内不删(避免破坏存量调用),最终在 P4 阶段移除:
|
||
|
||
- `POST/PUT/DELETE /workflow-definitions/{DefinitionId}/nodes[/{NodeId}]`
|
||
- `POST/PUT/DELETE /workflow-definitions/{DefinitionId}/edges[/{EdgeId}]`
|
||
|
||
> 过渡期:这些接口只操作关系表(旧事实源),不写 `definition_json`。一旦 P1 完成 ProcessEngine 切换,关系表不再是事实源,这些接口失去意义。
|
||
|
||
### 6.3 发布时图校验规则
|
||
|
||
`POST /publish` 在状态机 `Draft → Published` 前,对 `definition_json` 做以下校验(失败返回 `ValidationErrorResponse`)。
|
||
|
||
> 校验规则依据现有 `ProcessEngine` 的运行时强约束(基于现有代码 `Application/Engine/ProcessEngine.cs`:边选择在 `CompleteTaskAsync` 内、Condition 评估在 `ProcessConditionNodeAsync`、无匹配分支抛 `"No condition branch matched"`)。**发布期校验必须覆盖引擎运行时会抛异常的所有情形**,避免发布出运行即崩溃的流程。
|
||
|
||
**结构校验:**
|
||
|
||
1. **唯一 Start**:有且仅有一个 `shape === "wf-start"` 节点。
|
||
2. **至少一个 End**:存在 `shape === "wf-end"` 节点。
|
||
3. **无悬空边**:每条边的 `source.cell` / `target.cell` 都能在 `nodes[].id` 中找到。
|
||
4. **可达性**:从 Start 节点出发,所有 End 节点可达(DFS/BFS)。
|
||
5. **shape 合法**:所有 `shape` 在 5.5 映射表内。
|
||
6. **id 唯一**:节点 id、边 id 全局唯一;边的 `source.cell`/`target.cell` 引用有效。
|
||
|
||
**引擎强约束校验(必须,否则运行时抛 BusinessException):**
|
||
|
||
7. **Approval 节点出边完备性**:每个 `wf-approval` 节点必须至少有一条 `data.edgeType=Approved` 或 `data.edgeType=Normal` 的出边(通过路径);若业务允许驳回,还必须有一条 `data.edgeType=Rejected` 的出边。否则审批任务完成时引擎找不到匹配边直接异常。
|
||
8. **Condition / ExclusiveGateway 节点分支评估**:每个 `wf-condition` / `wf-exclusive` 节点的所有出边必须带 `data.condition` 和 `data.order`;**强烈建议提供一条兜底边**(condition 为 `true` 或空),否则当所有分支都不匹配时引擎抛 `"No condition branch matched"`。
|
||
9. **SubProcess 节点引用有效**:`wf-subprocess` 节点的 `data.definitionId` 必须指向一个已发布(`Published`)的流程定义。
|
||
|
||
> 校验失败统一返回 `ValidationErrorResponse`(沿用现有 `BuildFlow.Shared/Api/` 的校验失败信封)。
|
||
|
||
---
|
||
|
||
## 第 7 章 迁移策略(关系表 → JSON)
|
||
|
||
### 7.1 核心难点:已发布定义的不可变性与运行实例的版本隔离
|
||
|
||
> ⚠️ **本节是整个迁移方案的关键,直接决定方案是否可行。**
|
||
|
||
**现有代码的事实缺陷(必须先正视)**:
|
||
|
||
1. **WorkflowInstance 没有 Version 字段**(基于现有代码 `Domain/Entities/WorkflowInstance.cs`):实例仅存 `DefinitionId`。
|
||
2. **ProcessEngine 按 DefinitionId 实时读图**(基于现有代码 `Application/Engine/ProcessEngine.cs` 的 `StartAsync`):`WorkflowNodes.Where(n => n.DefinitionId == instance.DefinitionId)`,无版本隔离。
|
||
3. **Update 没有状态校验**(基于现有代码 `UpdateWorkflowDefinitionCommandHandler.cs`):注释说「仅 Draft 可改」,但 Handler **未强制**——`Published` 状态的定义仍可被 PUT 覆盖。
|
||
|
||
**后果**:在关系表时代,这三点就已构成隐患(发布后改节点会污染运行中实例);**迁移到 JSON 单一事实源、且 PUT 改为整图覆盖后,隐患被放大**——一个 PUT 即可让所有运行中实例读到不一致的图。
|
||
|
||
**结论**:JSON 单一事实源方案**必须配套解决版本隔离**,否则不可上线。
|
||
|
||
### 7.2 版本隔离方案:发布快照表(参照仓库已有先例 `FormDefinitionVersion`)
|
||
|
||
> 本方案沿用仓库**已有的** `FormDefinitionVersion`(`wf_form_definition_versions`)版本快照范式,命名/分层/审计接口完全对齐,不引入新模式。
|
||
|
||
**新增实体 `WorkflowDefinitionSnapshot`**(基于现有先例 `Domain/Entities/FormDefinitionVersion.cs` 的结构):
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `Id` | Guid | 主键 |
|
||
| `DefinitionId` | Guid | 所属流程定义 ID |
|
||
| `Version` | int | 版本号(与发布时 `WorkflowDefinition.Version` 对应) |
|
||
| `DefinitionJson` | string? (jsonb) | 该版本的完整 X6 graph JSON 快照(**不可变**) |
|
||
| `Source` | string | 触发来源:`Publish`(仅发布写入,区别于 FormDefinitionVersion 的 Update/Publish 双源) |
|
||
| `ChangeSummary` | string? | 变更摘要(可选) |
|
||
| 审计 | IAuditable | CreatedBy/CreatedAt/UpdatedBy/UpdatedAt/IsDeleted/OperatorIP |
|
||
|
||
**EF 配置**(基于现有先例 `FormDefinitionVersionConfiguration.cs`):
|
||
- 表名 `wf_workflow_definition_snapshots`(对齐 `wf_form_definition_versions` 命名)。
|
||
- `DefinitionJson` → `HasColumnType("jsonb")`。
|
||
- 复合唯一索引 `HasIndex(e => new { e.DefinitionId, e.Version })`。
|
||
- 索引 `HasIndex(e => e.DefinitionId)`。
|
||
|
||
**写入时机(发布流程)**:
|
||
1. `PublishWorkflowDefinitionCommandHandler`(基于现有代码)在做 `Status=Published; Version++` **之前**,先做 6.3 全部校验。
|
||
2. 校验通过后,把当前 `definition_json` 复制成一条 `WorkflowDefinitionSnapshot` 记录(Version = 新版本号)。
|
||
3. 快照写入后,引擎运行实例只读快照表,Draft 编辑主表的 `definition_json` 不影响已发布版本。
|
||
|
||
**读取规则(ProcessEngine 改造后)**:
|
||
- 引擎不再用 `instance.DefinitionId` 查 `wf_workflow_definitions.definition_json`。
|
||
- 改为:用 `instance.DefinitionId` + **实例绑定的 Version** 定位 `wf_workflow_definition_snapshots` 的不可变快照。
|
||
- ⚠️ 这要求 `WorkflowInstance` **新增一个 `DefinitionVersion`(int)字段**,在 `StartInstance` 时从当时的 `WorkflowDefinition.Version` 拷贝写入实例(实例一旦启动版本即冻结)。
|
||
|
||
> 实体字段新增属侵入式改动,但 `WorkflowInstance.DefinitionVersion` 是方案成立的最小必要条件,无法绕开。EF Migration 需加此列并回填存量实例(用对应定义当前 Version)。
|
||
|
||
### 7.3 Draft 编辑的 Published 锁定(修复现有 Update 漏洞)
|
||
|
||
在 `UpdateWorkflowDefinitionCommandHandler` 增加状态校验(基于现有代码,当前缺失):
|
||
|
||
```csharp
|
||
// 仅 Draft 可编辑定义内容;Published/Disabled 状态拒绝整图 PUT
|
||
if (entity.Status != DefinitionStatus.Draft)
|
||
{
|
||
throw new BusinessException("Only draft workflow definitions can be edited.");
|
||
}
|
||
```
|
||
|
||
> 已发布的定义如需修改,走「复制为新 Draft → 编辑 → 重新发布」流程(产出新 Version + 新快照),原 Version 快照不变,存量实例不受影响。
|
||
|
||
### 7.4 四步迁移路线
|
||
|
||
**第一步(P1 核心):实现 JSON 读取层 + 快照机制**
|
||
- 新建 `WorkflowGraph` 领域值对象 + 解析器(`Application/Engine/WorkflowGraphParser.cs`),从 X6 JSON 解析出:节点列表、边列表、出边拓扑、节点 data。
|
||
- 新建 `WorkflowDefinitionSnapshot` 实体 + EF 配置 + Migration。
|
||
- `WorkflowInstance` 新增 `DefinitionVersion` 字段 + Migration + 回填。
|
||
- `PublishWorkflowDefinitionCommandHandler` 增加 6.3 校验 + 写快照。
|
||
- `UpdateWorkflowDefinitionCommandHandler` 增加 Draft 锁定(7.3)。
|
||
|
||
**第二步(P1):ProcessEngine 切换为读快照**
|
||
- 引擎启动实例时:按 `instance.DefinitionId + instance.DefinitionVersion` 从 `wf_workflow_definition_snapshots` 加载不可变 JSON 到内存 `WorkflowGraph`。
|
||
- 改造影响面见 7.5。
|
||
- 此阶段起,Draft 编辑主表 `definition_json` 与运行实例彻底解耦。
|
||
|
||
**第三步(P1):存量数据迁移脚本(支持 dry-run + 回滚,见 7.6)**
|
||
- 遍历 `wf_workflow_definitions`,对 `definition_json` 为空的记录,从 `wf_workflow_nodes` + `wf_workflow_edges` 序列化生成 X6 JSON:
|
||
- `PositionX/Y` → `x/y`
|
||
- 补默认 `width/height/ports`(按 shape 预设)
|
||
- `node.Config`(字符串)→ `node.data`(对象),并按 NodeType 补 `data.title = node.Name`
|
||
- `edge.SourceNodeId/TargetNodeId` → `edge.source.cell/target.cell`
|
||
- `edge.EdgeType/Condition/Order` → `edge.data.edgeType/condition/order`
|
||
- 节点/边 id 统一为 `node_<guid>` / `edge_<guid>`
|
||
- 为每个已 `Published` 的定义补写一条 `WorkflowDefinitionSnapshot` 快照(Version 取定义当前 Version)。
|
||
- 为每个运行中的 `WorkflowInstance` 回填 `DefinitionVersion`(取其定义当前 Version)。
|
||
|
||
**第四步(P4):关系表降级 → 最终移除**
|
||
- 关系表降级为只读快照(过渡期)。
|
||
- 新版本:移除 `WorkflowNodes` / `WorkflowEdges` DbSet、EF Configuration,加 Migration drop 表。
|
||
|
||
### 7.5 ProcessEngine 改造影响面(以方法名为准)
|
||
|
||
基于现有代码 `Application/Engine/ProcessEngine.cs`。下表**以方法名为准**(行号会随代码漂移,仅作辅助定位):
|
||
|
||
| 当前方法 | 当前实现(关系表) | 改造后(读 WorkflowGraph) |
|
||
|---|---|---|
|
||
| `StartAsync` 加载节点 | `_dbContext.WorkflowNodes.Where(DefinitionId==instance.DefinitionId)` | 从快照 JSON 加载 `WorkflowGraph`,找 `shape==="wf-start"` |
|
||
| `FindNodeAsync` | `_dbContext.WorkflowNodes.FindAsync(nodeId)` | 从内存 `WorkflowGraph.Nodes` 按 id 查 |
|
||
| `GetOutgoingEdgesAsync` | `_dbContext.WorkflowEdges.Where(SourceNodeId==)` | 从内存 `WorkflowGraph.Edges` 按 source.cell 过滤 |
|
||
| `GetIncomingEdgesAsync` | `_dbContext.WorkflowEdges.Where(TargetNodeId==)` | 从内存 `WorkflowGraph.Edges` 按 target.cell 过滤 |
|
||
| `ParseConfig` 包装 | 入参 `node.Config`(字符串) | 入参改为 `node.data`(对象),`NodeConfigParser` 适配 |
|
||
| Timer 节点内联查边(位于 `ProcessTimerNodeAsync` 内) | `db.WorkflowEdges.Where(SourceNodeId==)` | 同上,改读 `WorkflowGraph` |
|
||
|
||
> 改造后引擎从「每步查库」变为「启动时一次加载快照 JSON 到内存 `WorkflowGraph`,后续内存遍历」,性能与一致性都更优;且天然实现版本隔离(实例绑定 Version)。
|
||
|
||
### 7.6 迁移回滚预案
|
||
|
||
生产数据迁移必须有回滚方案:
|
||
|
||
1. **迁移前备份**:迁移脚本执行前,对 `wf_workflow_definitions.definition_json` 原值、`wf_workflow_nodes`、`wf_workflow_edges` 做全表 SQL 备份(`pg_dump` 相关表)。
|
||
2. **dry-run 模式**:脚本支持 `--dry-run`,仅输出迁移报告(将生成多少条 JSON、多少条快照、回填多少实例),不写库。
|
||
3. **分批 + 可重入**:按 `DefinitionId` 分批处理,每批独立事务;脚本可重复执行(幂等:`definition_json` 已非空则跳过)。
|
||
4. **回滚**:若迁移后引擎异常,回滚步骤:
|
||
- 恢复 `definition_json` 原值(备份还原);
|
||
- 保留关系表数据(P4 之前关系表不 drop,是安全网);
|
||
- ProcessEngine 通过特性开关回退到读关系表的旧路径(P1 改造时即应保留双读开关,详见 9.1)。
|
||
5. **关系表保留期**:`wf_workflow_nodes` / `wf_workflow_edges` 在 P4 之前**禁止 drop**,作为整个迁移期的最终回滚保障。
|
||
|
||
---
|
||
|
||
## 第 8 章 分阶段实施路线
|
||
|
||
| 阶段 | 内容 | 交付物 |
|
||
|---|---|---|
|
||
| **P0** | 文档评审(本文) | 本文档定稿 |
|
||
| **P1** | 后端契约改造 | `WorkflowGraph` 解析层、`WorkflowDefinitionSnapshot` 快照表、`WorkflowInstance.DefinitionVersion` 字段、Published 锁定、ProcessEngine 切换读快照、整图保存接口、发布校验、存量迁移脚本(含 dry-run + 回滚) |
|
||
| **P2** | 前端设计器骨架 | X6 画布 + Stencil 拖拽 + 连线 + 整图保存/加载闭环(能跑通「画图→保存→重新加载」) |
|
||
| **P3** | 节点配置弹窗 | 审批人规则编辑器、条件表达式编辑器、抄送人选择、子流程选择 |
|
||
| **P4** | 收尾 | 列表/发布/启停页、关系表废弃清理、6 套废弃接口移除 |
|
||
|
||
---
|
||
|
||
## 第 9 章 风险与待决项
|
||
|
||
### 9.1 风险
|
||
|
||
| 风险 | 说明 | 应对 |
|
||
|---|---|---|
|
||
| **运行实例无版本隔离(现有缺陷,致命)** | `WorkflowInstance` 无 Version 字段,引擎按 DefinitionId 实时读图;发布后改图会污染运行中实例 | **7.2 方案强制实施**:新增 `DefinitionVersion` 字段 + 发布快照表,引擎读不可变快照 |
|
||
| **Published 后可被 PUT 覆盖(现有漏洞)** | `UpdateWorkflowDefinitionCommandHandler` 无状态校验,已发布定义可被改 | **7.3 方案强制实施**:Update Handler 增加 Draft 状态校验 |
|
||
| **双源一致性(迁移期)** | P1 期间 JSON 与关系表并存 | ProcessEngine 保留特性开关(双读),默认读快照,异常可切回关系表;Draft 编辑只走 JSON |
|
||
| **存量已运行实例的 Version 回填** | 迁移期已运行的实例无 DefinitionVersion,按什么值回填? | 取其定义当前 Version 回填(接受「存量实例绑定到当前版本」的近似;P1 切换前应停止新发起,迁移完再恢复) |
|
||
| **整图 JSON 体积** | 复杂图可能较大 | 监控单图大小,必要时拆分子流程(已有 SubProcess 节点) |
|
||
| **前端节点交互复杂度** | 多人会签、条件表达式编辑器工作量大 | P3 独立子方案,工作量预期见 9.3 |
|
||
| **`NodeConfigParser` 兼容** | 当前解析字符串,改造后是对象 | 适配层兼容,或迁移完成后简化 |
|
||
|
||
### 9.2 待决项(需评审拍板)
|
||
|
||
1. **节点/边 ID 生成方**:当前建议前端生成 `node_<guid>` / `edge_<guid>`,后端透传。是否允许后端保存时重写 id?(影响 `source.cell` 引用稳定性)
|
||
2. **Published 流程的派生编辑**:7.3 锁定 Published 后,是否提供「复制已发布流程 → 新 Draft」的派生编辑能力?(建议提供,作为修改已发布流程的标准路径)
|
||
3. **shape ↔ NodeType 映射表存放位置**:建议放 Domain 层 `WorkflowShapeMap` 静态类。
|
||
4. **`WorkflowGraph` 是否强类型化**:建议实现 `WorkflowGraph`/`GraphNode`/`GraphEdge` 强类型模型(record),避免裸 `JsonDocument` 散落。是否纳入本次标准?(建议纳入 P1)
|
||
5. **P1 切换窗口**:存量实例 Version 回填存在近似(9.1),是否接受「P1 切换前暂停新发起、迁移完恢复」的停机窗口?还是要求零停机(零停机需更复杂的双写过渡)?
|
||
|
||
### 9.3 工作量预期(诚实声明,避免评审低估)
|
||
|
||
「X6 自建」意味着审批相关节点 UI **全部自写**(基于现有代码,仓库无任何 X6 前端代码可复用):
|
||
|
||
- P2 设计器骨架(画布/拖拽/连线/保存):~1-2 周
|
||
- **P3 节点配置弹窗是工作量重头**,尤其:
|
||
- 审批人规则编辑器(单人/会签/或签、角色/部门/指定人、加签)—— 复杂,~1-2 周
|
||
- 条件表达式编辑器(变量选择 + 比较 + 与/或组合)—— 复杂,~1 周
|
||
- 抄送人选择、子流程选择、定时配置 —— 较简单,~3-5 天
|
||
- P1 后端改造(含快照表/Version 字段/Migration/引擎切换/迁移脚本):~1-1.5 周
|
||
|
||
> P3 的复杂子项(审批人规则、条件表达式)建议在 P2 闭环验证后,另起详细子方案再实现,不在本文展开。
|
||
|
||
---
|
||
|
||
## 附录 A:关键文件路径清单
|
||
|
||
### 后端(`build-flow.api/`)
|
||
|
||
**Domain**
|
||
- `src/modules/workflow/Domain/Entities/WorkflowDefinition.cs` — 定义实体(DefinitionJson 字段在此)
|
||
- `src/modules/workflow/Domain/Entities/WorkflowNode.cs` — 节点实体(迁移源)
|
||
- `src/modules/workflow/Domain/Entities/WorkflowEdge.cs` — 边实体(迁移源)
|
||
- `src/modules/workflow/Domain/Entities/WorkflowInstance.cs` — **实例实体(待新增 DefinitionVersion 字段)**
|
||
- `src/modules/workflow/Domain/Entities/FormDefinitionVersion.cs` — **版本快照先例(wf_workflow_definition_snapshots 照此范式新建)**
|
||
- `WorkflowDefinitionSnapshot`(**待新增**) — 发布快照实体,参照 `FormDefinitionVersion`
|
||
- `src/modules/workflow/Domain/Enums/NodeType.cs` — 节点类型枚举(复用)
|
||
- `src/modules/workflow/Domain/Enums/EdgeType.cs` — 边类型枚举(复用)
|
||
- `src/modules/workflow/Domain/Enums/DefinitionStatus.cs` — 定义状态枚举(复用)
|
||
|
||
**Application**
|
||
- `src/modules/workflow/Application/Engine/ProcessEngine.cs` — 流程引擎(改造核心,~1191 行)
|
||
- `src/modules/workflow/Application/Engine/NodeConfigParser.cs` — Config 解析器(需适配)
|
||
- `src/modules/workflow/Application/Features/WorkflowDefinitions/Commands/UpdateWorkflowDefinitionCommand.cs` — 更新命令
|
||
- `src/modules/workflow/Application/Features/WorkflowDefinitions/Handlers/UpdateWorkflowDefinitionCommandHandler.cs` — 更新处理器(仅覆盖字符串)
|
||
- `src/modules/workflow/Application/Features/WorkflowDefinitions/DTOs/WorkflowDefinitionDto.cs`
|
||
- `src/modules/workflow/Application/Features/WorkflowDefinitions/DTOs/WorkflowDefinitionDetailDto.cs`
|
||
- `src/modules/workflow/Application/Features/WorkflowDefinitions/DTOs/WorkflowNodeDto.cs`
|
||
- `src/modules/workflow/Application/Features/WorkflowDefinitions/DTOs/WorkflowEdgeDto.cs`
|
||
|
||
**Infrastructure**
|
||
- `src/modules/workflow/Infrastructure/Persistence/WorkflowDbContext.cs` — DbSet 定义(WorkflowNodes/WorkflowEdges)
|
||
- `src/modules/workflow/Infrastructure/Persistence/Configurations/WorkflowDefinitionConfiguration.cs`
|
||
- `src/modules/workflow/Infrastructure/Persistence/Configurations/WorkflowNodeConfiguration.cs`
|
||
- `src/modules/workflow/Infrastructure/Persistence/Configurations/WorkflowEdgeConfiguration.cs`
|
||
- `src/modules/workflow/Infrastructure/Persistence/SeedData.cs` — 种子数据
|
||
|
||
**Host**
|
||
- `src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/` — 24 个 Endpoint/Request 文件(含 6 套待废弃 Node/Edge 接口)
|
||
|
||
**Shared**
|
||
- `src/shared/BuildFlow.Shared/Api/ApiResponse.cs` — 响应信封
|
||
- `src/shared/BuildFlow.Shared/Api/ApiResponseMiddleware.cs` — 响应包裹中间件
|
||
|
||
### 前端(`build-flow.web/apps/web-antdv-next/`)
|
||
|
||
- `src/api/request.ts` — API 客户端(`requestClient`)
|
||
- `src/router/routes/modules/` — 路由 module 目录(待新增 `workflow.ts`)
|
||
- `src/views/` — 页面目录(待新增 `workflow/`)
|
||
- `src/api/core/` — API 模块目录(待新增 `workflow.ts`)
|
||
|
||
### 参考文档
|
||
- X6 官方文档:`https://x6.antv.antgroup.com/`
|
||
- X6 Vue 节点:`https://x6.antv.antgroup.com/tutorial/intermediate/vue`
|
||
- X6 连接桩:`https://x6.antv.antgroup.com/tutorial/basic/port`
|
||
- rag-coding-web 技能:BuildFlow 管理端前端开发约定
|