# 表单管理 PRD

> 产品需求文档 - 定义表单管理应用的功能需求和验收标准

---

## 📋 背景与目标

### 背景

表单管理是一个业务应用层模块，基于表单引擎和审批引擎构建，为管理员和表单设计者提供统一的表单设计与流程配置界面。

### 目标

1. **统一管理界面** - 在一个界面中完成表单设计和流程配置
2. **可视化设计** - 拖拽式表单设计 + 钉钉风格流程设计
3. **版本控制** - 表单和流程的版本管理与审核发布
4. **发布快照** - 发布时绑定表单版本与流程版本，确保运行时一致性
5. **模板系统** - 提供常用表单模板，快速创建
6. **多区域支持** - 支持多区域部署，数据完全隔离

### 多区域需求

> 表单管理模块从设计之初即支持多区域（大区级）部署。

#### 支持的区域

| 区域 | regionId | 说明 |
|------|----------|------|
| 中国 | `CN` | 中国区数据中心 |
| 美国 | `US` | 美国区数据中心 |
| 中东 | `ME` | 中东区数据中心 |

#### 包含 regionId 的实体

| 实体 | 说明 |
|------|------|
| `FormDefinition` | 表单定义 |
| `FormVersion` | 表单版本 |
| `ReleaseSnapshot` | 发布快照 |
| `FormInstance` | 表单实例 |
| `ProcessDefinition` | 流程定义 |
| `ProcessVersion` | 流程版本 |
| `ProcessInstance` | 流程实例 |

#### 核心原则

**区域设计说明**：

实际实现采用了更灵活的区域设计方案：
- ✅ `FormDefinition` 使用 `regionScope` + `allowedRegions` 支持全局和区域两种模式
- ✅ `ReleaseSnapshot` 和 `FormInstance` 包含 `regionId` 必填字段
- ✅ 不同区域的快照和实例数据完全隔离，互不影响
- ✅ 同一 `formDefinitionId` 在不同区域可以各有一个 ACTIVE 快照
- ✅ 查询快照和实例时必须指定区域

#### 模板的特殊处理

> **模板是全局共享的，不区分 region**，用于设计参考。

| 实体 | regionId | 说明 |
|------|----------|------|
| `FormTemplate` | ❌ 无 | 全局共享，所有区域可见 |
| `FormDefinition` | ✅ 必填 | 从模板创建时，必须指定目标 region |

**流程**：
```
模板库（全局）
    │
    │ 选择模板
    ▼
从模板创建表单
    │
    │ 必须选择 regionId（CN / US / ME）
    ▼
FormDefinition（属于特定区域）
```

**说明**：
- 模板只是设计参考，本身不属于任何区域
- 从模板创建 `FormDefinition` 时，必须指定 `regionId`
- 同一模板可以在不同区域分别创建表单定义

#### regionId 从哪里来

> 用户当前所在区域由**登录态 / 用户配置**决定（`user.regionId`）。

```
用户登录 → 获取 user.regionId (如 CN)
         ↓
前端调用 API 时始终带上区域标识:
  - HTTP Header: X-Region-Id: CN
  - 或 Query 参数: ?regionId=CN
         ↓
后端校验 regionId，隔离数据访问
```

**说明**：
- 用户**不需要手动选择区域**，由系统根据用户归属自动确定
- 管理员可以在用户管理中配置用户的 `regionId`
- 跨区域操作（如模板同步）需要特殊权限

### 边界声明

| 模块 | 职责 | 用户群体 | 前端路径 |
|------|------|----------|----------|
| **表单管理** | 表单定义、流程配置、版本管理、发布快照 | 管理员/设计者 | `/forms` |
| **审批中心** | 表单填写、审批任务、流程跟踪、**我的申请** | 普通用户 | `/approvals` |
| **表单引擎** | JSON Schema、字段类型、数据验证、渲染 | 内部服务 | - |
| **审批引擎** | 流程编排、任务调度、Temporal 集成 | 内部服务 | - |

> **⚠️ 重要**：用户发起的表单实例（"我的申请"）在**审批中心**展示和管理，而非表单管理模块。
> 表单管理模块专注于"设计态"，审批中心专注于"运行态"。

---

## 🔄 核心概念：发布快照

### 什么是发布快照

发布快照（Release Snapshot）是表单定义发布时创建的**不可变记录**，绑定了：

- **表单版本** (FormVersion) - 表单结构的 JSON Schema
- **流程版本** (ProcessVersion) - 审批流程的节点和路由定义

```
┌─────────────────────────────────────────────────────────────────┐
│                        发布快照 (Snapshot)                       │
├─────────────────────────────────────────────────────────────────┤
│  snapshotId: "snap_20251207_001"                                │
│  regionId: "CN"                 ←── 区域隔离（大区级）            │
│  formDefinitionId: "fd_001"                                     │
│  formVersionId: "fv_003"        ←── 绑定的表单版本               │
│  processVersionId: "pv_002"     ←── 绑定的流程版本               │
│  publishedAt: "2025-12-07T10:00:00Z"                            │
│  publishedBy: "admin_001"                                       │
│  status: "ACTIVE"                                               │
└─────────────────────────────────────────────────────────────────┘
```

### 为什么需要发布快照

```
场景：用户 A 在 12月1日 发起报销申请（使用 v1.0 流程）
      管理员在 12月5日 更新了流程（v2.0 新增审批节点）
      
问题：用户 A 的申请应该走 v1.0 还是 v2.0？

答案：走 v1.0！因为用户发起时绑定的是 v1.0 的发布快照
```

**核心原则**：
- ✅ 用户发起申请时，始终基于**发布快照**创建实例
- ✅ 运行中的实例不受后续版本更新影响
- ✅ 历史实例可追溯到具体的表单和流程版本

**⚠️ 与审批中心的依赖关系**：

> 审批中心在发起申请时，**必须**通过 `/form-management` 获取 ACTIVE 快照，而不允许直接绑定某个 FormVersion / ProcessVersion。

```
[审批中心]                              [表单管理]
     │                                       │
     │ GET /form-management/forms/{id}/active-snapshot
     │ ─────────────────────────────────────>│
     │                                       │
     │ <─────── { snapshotId, formVersionId, processVersionId }
     │                                       │
     │ POST /form-management/forms/{id}/instances
     │ { snapshotId, formData }
     │ ─────────────────────────────────────>│
     │                                       │
```

### 快照生命周期

```
┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  DRAFT   │ ──> │ PENDING  │ ──> │  ACTIVE  │ ──> │ ARCHIVED │
│  草稿    │     │ 待审核   │     │  激活    │     │  归档    │
└──────────┘     └──────────┘     └──────────┘     └──────────┘
                      │                │
                      │                └── 新版本发布时，旧版本自动归档
                      └── 审核驳回时，回到草稿
```

### 快照与默认版本

> **每个区域的每个表单定义在任一时刻最多只有一个 ACTIVE 快照，作为"当前默认对外版本"。**

- 发布新版本时，系统自动将旧的 ACTIVE 快照归档为 ARCHIVED
- 用户发起申请时，始终使用当前区域的 ACTIVE 快照
- 数据库层面通过唯一约束保证：`UNIQUE(regionId, formDefinitionId) WHERE status = 'ACTIVE'`

### 快照状态唯一性约束

> 为确保发布目标明确，对快照状态数量进行限制。

| 状态 | 每个 (regionId, formDefinitionId) 的数量限制 | 说明 |
|------|---------------------------------------------|------|
| `DRAFT` | **最多 1 个** | 一次只能准备一个草稿 |
| `PENDING` | **最多 1 个** | 提交审核后从 DRAFT 转换 |
| `ACTIVE` | **最多 1 个** | 当前对外发布版本 |
| `ARCHIVED` | 无限制 | 历史版本 |
| `SUSPENDED` | 无限制 | 暂停版本 |

**为什么 DRAFT 只能有一个？**

```
场景：v2 已发布，v3 正在写，想并行准备 v4？

问题：如果允许多个 DRAFT，发布时不知道发布哪个版本。

解决：必须先处理 v3（发布或丢弃），再创建 v4 草稿。
```

### 表单与流程的绑定关系

> **当前版本**: 一个表单定义对应一个流程定义（1:1）。

```
FormDefinition ──1:1──> ProcessDefinition
```

**未来扩展（预留）**: 一个表单可能需要支持多个流程（如请假：国内流程、国外流程）。

---

## 📊 状态机

### 表单定义状态（FormDefinition）

> FormDefinition 本身有独立的状态，表示该表单是否可用。

```
┌──────────┐     ┌──────────┐     ┌──────────┐
│  DRAFT   │ ──> │  ACTIVE  │ ──> │ ARCHIVED │
│  草稿    │     │  已激活  │     │  已归档  │
└──────────┘     └──────────┘     └──────────┘
     │                │                 ▲
     │                │                 │
     │                ▼                 │
     │           ┌──────────┐           │
     └─────────> │ DISABLED │ ──────────┘
                 │  已禁用  │
                 └──────────┘
```

| 状态 | 说明 | 允许操作 |
|------|------|----------|
| `DRAFT` | 新建的表单，从未发布过 | 编辑、删除、发布（首次） |
| `ACTIVE` | 至少发布过一次，当前可用 | 编辑、禁用、归档 |
| `DISABLED` | 暂停使用，不再接受新申请 | 启用（回到 ACTIVE）、归档 |
| `ARCHIVED` | 已归档，不再使用 | 仅查看（只读） |

**状态转换规则**：

| 当前状态 | 目标状态 | 触发动作 | 说明 |
|----------|----------|----------|------|
| DRAFT | ACTIVE | 首次发布 | 发布 ReleaseSnapshot 后自动转换 |
| ACTIVE | DISABLED | 禁用 | 暂停接受新申请，运行中实例不受影响 |
| DISABLED | ACTIVE | 启用 | 恢复接受新申请 |
| ACTIVE | ARCHIVED | 归档 | 不再使用，无法恢复 |
| DISABLED | ARCHIVED | 归档 | 从禁用状态直接归档 |
| DRAFT | 删除 | 删除 | 从未发布的草稿可直接删除 |

**注意**：
- `DISABLED` 状态下，已有的 ACTIVE 快照仍然存在，但用户无法发起新申请
- `ARCHIVED` 状态下，历史实例数据保留，仅供查看和审计

### 表单版本状态（FormVersion）

> **简化流程**：审核通过即发布，无需额外的发布步骤。

```
┌──────────┐     ┌────────────────┐     ┌──────────┐
│  DRAFT   │ ──> │ PENDING_REVIEW │ ──> │PUBLISHED │
│  草稿    │     │    待审核      │     │ 已发布   │
└──────────┘     └────────────────┘     └──────────┘
     │                   │                    │
     │                   │                    │
     │                   ▼                    ▼
     │              ┌──────────┐        ┌──────────┐
     └────────────> │ REJECTED │        │DEPRECATED│
                    │ 已驳回   │        │ 已废弃   │
                    └──────────┘        └──────────┘
```

| 状态 | 说明 | 允许操作 |
|------|------|----------|
| `DRAFT` | 草稿，设计中 | 编辑、提交审核、删除 |
| `PENDING_REVIEW` | 待审核 | 审核通过、审核驳回 |
| `PUBLISHED` | 已发布，对外可用 | 废弃、创建新版本 |
| `REJECTED` | 已驳回 | 编辑（回到草稿）、删除 |
| `DEPRECATED` | 已废弃，不推荐使用 | 查看（只读） |

**核心设计决策**：
- ✅ **审核通过 = 发布**：管理员审核通过后，版本立即变为 `PUBLISHED` 并自动设为默认版本
- ✅ 无需额外的"发布"步骤，简化操作流程
- ✅ 旧版本自动变为 `DEPRECATED`（如果有）

### 状态转换规则

| 当前状态 | 目标状态 | 触发动作 | 执行者 |
|----------|----------|----------|--------|
| DRAFT | PENDING_REVIEW | 提交审核 | 设计者 |
| PENDING_REVIEW | PUBLISHED | 审核通过 | 管理员 |
| PENDING_REVIEW | REJECTED | 审核驳回 | 管理员 |
| PUBLISHED | DEPRECATED | 新版本发布 | 系统自动 |
| REJECTED | DRAFT | 修改后重新编辑 | 设计者 |

### 版本名称与发布说明

> 为便于版本管理和追溯，增加版本名称和发布说明字段。

#### 版本名称（versionName）

| 实体 | 字段 | 示例 |
|------|------|------|
| `FormVersion` | `versionName` | "v1.0 初版"、"v2.0 增加附件字段" |
| `ProcessVersion` | `versionName` | "v1.0 两级审批"、"v2.0 增加财务节点" |

**使用场景**：
- 版本列表显示
- 版本对比时快速识别
- 审核/发布时的备注

#### 发布说明（releaseNote）

| 实体 | 字段 | 说明 |
|------|------|------|
| `ReleaseSnapshot` | `releaseNote` | 发布时填写的说明/备注 |
| `ReleaseSnapshot` | `reviewComment` | 审核时填写的意见 |

**示例**：
```
releaseNote: "修复金额校验问题，增加附件上传功能"
reviewComment: "审核通过，符合规范要求"
```

### 表单实例生命周期

> 表单实例（FormInstance）由表单管理模块创建，审批流程由审批引擎驱动。

| 状态 | 说明 | 触发条件 | 行为主体 |
|------|------|----------|----------|
| `DRAFT` | 草稿 | 用户保存未提交 | 用户 |
| `PENDING_APPROVAL` | 审批中 | 用户提交申请，审批流程启动 | 用户 |
| `APPROVED` | 已通过 | 所有审批节点通过 | 审批人 |
| `REJECTED` | 已拒绝 | 任一审批节点拒绝 | 审批人 |
| `WITHDRAWN` | 已撤回 | 发起人主动撤回 | 用户（发起人） |
| `CANCELLED` | 已取消 | 管理员强制取消或系统超时 | 管理员/系统 |

```
用户发起                    审批处理                       最终状态
┌────────┐               ┌──────────────────┐         ┌────────────────┐
│ DRAFT  │ ─提交────────>│ PENDING_APPROVAL │ ─通过──>│   APPROVED     │
│ 草稿   │               │     审批中        │         │    已通过      │
└────────┘               └──────────────────┘         └────────────────┘
                                  │                         
                                  ├─拒绝────────> REJECTED (已拒绝)
                                  ├─用户撤回────> WITHDRAWN (已撤回)  ← 用户行为
                                  └─管理员取消──> CANCELLED (已取消)  ← 管理员/系统行为
```

**WITHDRAWN vs CANCELLED 的区别**：

| 属性 | WITHDRAWN（撤回） | CANCELLED（取消） |
|------|-------------------|-------------------|
| **行为主体** | 发起人自己 | 管理员或系统 |
| **触发时机** | 审批完成前任意时刻 | 管理员介入或超时 |
| **权限要求** | `form:use`（仅限发起人） | `form:admin` |
| **业务含义** | 用户改变主意，主动放弃 | 被动终止（违规、超时等） |
| **可恢复性** | 用户可基于此重新提交 | 通常不可恢复 |

**两阶段提交模式**：
1. **创建草稿** - 调用 `POST /instances` 创建 DRAFT 状态的实例，可多次编辑
2. **提交审批** - 调用 `POST /instances/:id/submit` 提交，状态变为 PENDING_APPROVAL

**关键约束**：每个实例创建时绑定一个发布快照（snapshotId），整个生命周期内使用该快照的表单结构和流程定义。

---

## 🔧 流程设计器节点规范

### 节点类型列表

| 节点类型 | 类型标识 | 说明 | 图标 | 颜色 |
|----------|----------|------|------|------|
| 开始节点 | `START` | 流程起点，自动生成 | Circle | `#52c41a` |
| 结束节点 | `END` | 流程终点，自动生成 | CircleCheck | `#8c8c8c` |
| 审批人 | `USER_TASK` | 需要人工审批的节点 | UserCheck | `#1677ff` |
| 执行人 | `EXECUTOR` | 需要人工执行的节点 | UserCog | `#52c41a` |
| 抄送人 | `CC` | 知会节点，不阻塞流程 | Users | `#722ed1` |
| 条件分支 | `EXCLUSIVE_GATEWAY` | 基于条件选择分支 | GitBranch | `#fa8c16` |
| 并行分支 | `PARALLEL_GATEWAY` | 多分支并行执行 | GitMerge | `#13c2c2` |

### 节点配置结构

```typescript
interface ProcessNode {
  id: string;                    // 节点唯一标识
  type: NodeType;                // 节点类型
  name: string;                  // 节点名称
  position: { x: number; y: number }; // 画布位置
  config: ProcessNodeConfig;     // 节点配置
}

interface ProcessNodeConfig {
  // 审批人配置
  approverType?: ApproverType;   // 审批人类型
  approvers?: string[];          // 指定审批人 ID 列表
  roles?: string[];              // 指定角色 ID 列表
  
  // 多人审批配置
  approvalMode?: ApprovalMode;   // 会签/或签/依次审批
  
  // 连续主管配置
  chainConfig?: {
    maxLevels: number;           // 最大审批层级
    stopCondition: string;       // 终止条件
    autoApprove: 'none' | 'initiator' | 'duplicate' | 'both';
  };
  
  // 字段权限配置（与表单字段联动）
  editableFields?: string[];     // 在该节点可编辑的字段列表
  requiredFields?: string[];     // 在该节点必填的字段列表
  hiddenFields?: string[];       // 在该节点隐藏的字段列表
  
  // 条件分支配置
  conditions?: ConditionConfig[];
  
  // 超时配置
  timeout?: {
    hours: number;
    action: 'remind' | 'auto_approve' | 'auto_reject';
  };
  
  // 允许的操作
  allowedActions?: string[];     // APPROVE, REJECT, RETURN, FORWARD, ADD_SIGN
}
```

### 审批人类型

| 类型 | 标识 | 说明 |
|------|------|------|
| 指定成员 | `FIXED_USER` | 选择固定用户 |
| 指定角色 | `ROLE` | 具有特定角色的用户 |
| 部门主管 | `DEPARTMENT` | 发起人所在部门主管 |
| 直属主管 | `INITIATOR_MANAGER` | 发起人的直接上级 |
| 多级主管 | `MANAGER_CHAIN` | 逐级向上审批 |
| 表单字段 | `FORM_FIELD` | 从表单字段获取审批人 |
| 发起人自选 | `SELF_SELECT` | 发起时选择审批人 |

### 多人审批方式

| 方式 | 标识 | 说明 |
|------|------|------|
| 会签 | `AND` | 所有审批人都需同意 |
| 或签 | `OR` | 任一审批人同意即可 |
| 依次审批 | `SEQUENTIAL` | 按顺序依次审批 |

### 字段权限与审批节点联动

在流程设计 Tab，支持为每个审批/执行节点配置字段权限：

| 配置项 | 说明 |
|--------|------|
| `editableFields` | 在该节点可编辑的字段列表 |
| `requiredFields` | 在该节点必填的字段列表 |
| `hiddenFields` | 在该节点隐藏的字段列表 |

**渲染时行为**：表单引擎在渲染时，根据当前审批节点的字段权限配置，控制字段的只读/可写/隐藏状态。

```
示例：报销申请表
├── 发起人填写：金额、说明、附件（可编辑）
├── 部门经理审批：金额、说明（只读），审批意见（可编辑）
└── 财务审核：所有字段（只读），付款账号（可编辑、必填）
```

---

## 📐 表单 JSON Schema 存储结构

### 表单版本数据结构

```typescript
interface FormVersion {
  id: string;
  formDefinitionId: string;
  version: number;                // 版本号，如 1, 2, 3
  status: VersionStatus;
  
  // 核心数据
  schema: JSONSchema;             // 表单结构定义
  uiSchema: UISchema;             // UI 布局配置
  
  // 元数据
  createdBy: string;
  createdAt: Date;
  updatedAt: Date;
  
  // 审核信息
  reviewedBy?: string;
  reviewedAt?: Date;
  reviewComment?: string;
}
```

### JSON Schema 结构

```json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "报销申请表",
  "properties": {
    "expenseType": {
      "type": "string",
      "title": "报销类型",
      "enum": ["交通费", "餐饮费", "住宿费", "办公用品"],
      "x-component": "select",
      "x-required": true
    },
    "amount": {
      "type": "number",
      "title": "报销金额",
      "minimum": 0,
      "x-component": "number",
      "x-required": true,
      "x-props": {
        "precision": 2,
        "suffix": "元"
      }
    },
    "date": {
      "type": "string",
      "title": "发生日期",
      "format": "date",
      "x-component": "date-picker",
      "x-required": true
    },
    "description": {
      "type": "string",
      "title": "费用说明",
      "x-component": "textarea",
      "x-props": {
        "rows": 3,
        "maxLength": 500
      }
    },
    "attachments": {
      "type": "array",
      "title": "附件",
      "items": {
        "type": "object",
        "properties": {
          "fileId": { "type": "string" },
          "fileName": { "type": "string" },
          "fileUrl": { "type": "string" }
        }
      },
      "x-component": "file-upload",
      "x-props": {
        "accept": ".jpg,.png,.pdf",
        "maxCount": 5,
        "maxSize": 10485760
      }
    }
  },
  "required": ["expenseType", "amount", "date"]
}
```

### UI Schema 结构

```json
{
  "ui:order": ["expenseType", "amount", "date", "description", "attachments"],
  "ui:layout": {
    "type": "vertical",
    "gutter": 16
  },
  "expenseType": {
    "ui:width": "50%",
    "ui:placeholder": "请选择报销类型"
  },
  "amount": {
    "ui:width": "50%",
    "ui:placeholder": "请输入金额"
  },
  "date": {
    "ui:width": "50%"
  },
  "description": {
    "ui:width": "100%"
  },
  "attachments": {
    "ui:width": "100%",
    "ui:help": "支持 jpg、png、pdf 格式，单个文件不超过 10MB"
  }
}
```

### 扩展属性说明 (x-*)

| 属性 | 说明 |
|------|------|
| `x-component` | 渲染组件类型 |
| `x-required` | 是否必填（业务层） |
| `x-props` | 组件特有属性 |
| `x-rules` | 自定义验证规则 |
| `x-reactions` | 联动规则 |
| `x-visible` | 显示条件 |
| `x-disabled` | 禁用条件 |

---

## 🔐 权限模型

### 权限定义

| 权限标识 | 说明 | 包含操作 |
|----------|------|----------|
| `form:read` | 查看表单 | 查看表单列表、详情、版本 |
| `form:design` | 设计表单 | 创建、编辑表单和流程设计 |
| `form:review` | 审核表单 | 审核版本、通过/驳回 |
| `form:publish` | 发布表单 | 发布、归档表单 |
| `form:delete` | 删除表单 | 删除表单定义 |
| `form:admin` | 管理员 | 包含以上所有权限 + 系统设置 |

### 角色权限矩阵

| 角色 | read | design | review | publish | delete | admin |
|------|------|--------|--------|---------|--------|-------|
| 普通用户 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| 表单设计者 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| 表单审核员 | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| 表单管理员 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

### 数据权限

| 场景 | 规则 |
|------|------|
| 表单列表 | 设计者看自己创建的 + 已发布的；管理员看所有 |
| 表单编辑 | 仅创建者或管理员 |
| 版本审核 | 仅审核员或管理员 |
| 发布操作 | 仅管理员 |

---

## 📤 发布策略

### 发布流程

```
┌──────────────────────────────────────────────────────────────────┐
│                         发布流程                                  │
└──────────────────────────────────────────────────────────────────┘

1. 设计完成
   ├── 表单设计完成 (FormVersion: DRAFT)
   └── 流程设计完成 (ProcessVersion: DRAFT)
              │
              ▼
2. 提交审核
   ├── 表单版本状态 → PENDING_REVIEW
   └── 流程版本状态 → PENDING_REVIEW
              │
              ▼
3. 管理员审核（审核通过 = 发布）
   ├── 审核通过：
   │   ├── 表单版本状态 → PUBLISHED
   │   ├── 流程版本状态 → PUBLISHED
   │   ├── 自动设为默认版本 (isDefault = true)
   │   └── 旧版本状态 → DEPRECATED (如果有)
   └── 审核驳回：
       └── 状态 → REJECTED (设计者可修改后重新提交)
              │
              ▼
4. 用户可用
   └── 用户在审批中心可见该表单
```

### 发布策略选项

| 策略 | 说明 | 适用场景 |
|------|------|----------|
| **立即生效** | 发布后立即对所有用户生效 | 新表单、紧急修复 |
| **定时发布** | 指定时间自动发布 | 计划性更新 |
| **灰度发布** | 先对部分用户生效 | 重大变更、风险控制 |

### 版本兼容性策略

| 场景 | 处理方式 |
|------|----------|
| 新增字段 | 设置默认值，历史实例不受影响 |
| 删除字段 | 历史实例保留该字段数据 |
| 修改字段类型 | 需要数据迁移脚本 |
| 修改流程节点 | 运行中实例继续走旧流程 |

### 回滚策略

```
场景：新版本发布后发现问题，需要回滚

操作步骤：
1. 将当前快照状态设为 SUSPENDED（暂停）
2. 将历史快照状态恢复为 ACTIVE
3. 新发起的申请将使用历史版本
4. 运行中的实例不受影响

注意：回滚不影响运行中的实例，仅影响新发起的申请
```

---

## 👤 用户角色与故事

### 角色定义

| 角色 | 权限 | 说明 |
|------|------|------|
| 表单设计者 | `form:design` | 可设计表单、配置流程、提交审核 |
| 表单审核员 | `form:review` | 可审核表单版本 |
| 表单管理员 | `form:admin` | 可审核、发布、归档、系统设置 |
| 普通用户 | `form:read` | 可查看已发布表单、在审批中心使用 |

### 用户故事

#### 表单设计者

```
作为 表单设计者
我希望 通过拖拽方式设计表单结构
以便 无需开发人员介入即可创建新表单
```

```
作为 表单设计者
我希望 在同一界面配置审批流程
以便 表单和流程一起设计，保持一致性
```

```
作为 表单设计者
我希望 从模板快速创建表单
以便 提高设计效率
```

#### 表单管理员

```
作为 表单管理员
我希望 审核设计者提交的表单版本
以便 确保表单符合业务规范后再发布
```

```
作为 表单管理员
我希望 管理表单的多个版本
以便 可以回滚或查看历史版本
```

```
作为 表单管理员
我希望 发布时创建快照绑定表单和流程版本
以便 确保运行中的实例不受后续更新影响
```

#### 普通用户

> **注意**：普通用户的表单填写、我的申请、审批跟踪等功能都在**审批中心**完成，不在表单管理模块。

```
作为 普通用户
我希望 在审批中心查看可用的表单列表
以便 选择需要填写的表单
```

```
作为 普通用户
我希望 在审批中心填写和提交表单
以便 发起业务申请
```

```
作为 普通用户
我希望 在审批中心查看"我的申请"
以便 跟踪我发起的所有申请状态
```

```
作为 普通用户
我希望 在审批中心撤回审批中的申请
以便 在发现问题时可以主动撤回重新提交
```

---

## 📦 功能需求

### F1: 表单定义管理

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F1.1 表单列表 | P0 | ✅ | 查看所有表单定义 |
| F1.2 创建表单 | P0 | ✅ | 创建新的表单定义 |
| F1.3 编辑表单 | P0 | ✅ | 修改表单基本信息 |
| F1.4 删除表单 | P1 | ✅ | 软删除表单定义 |
| F1.5 归档表单 | P1 | ✅ | 下线不再使用的表单 |
| F1.6 搜索筛选 | P1 | ✅ | 按名称、状态筛选 |
| F1.7 禁用/启用 | P1 | 📋 | 暂停或恢复表单使用 |

**表单定义状态**：

| 状态 | 说明 | UI 展示 |
|------|------|---------|
| `DRAFT` | 新建，从未发布 | 灰色标签 |
| `ACTIVE` | 已发布，当前可用 | 绿色标签 |
| `DISABLED` | 已禁用，暂停使用 | 橙色标签 |
| `ARCHIVED` | 已归档，不再使用 | 灰色标签 |

### F2: 表单设计器

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F2.1 字段面板 | P0 | ✅ | 拖拽字段到画布 |
| F2.2 设计画布 | P0 | ✅ | 可视化布局设计 |
| F2.3 属性面板 | P0 | ✅ | 配置字段属性 |
| F2.4 实时预览 | P0 | ✅ | 预览表单效果 |
| F2.5 撤销重做 | P1 | ✅ | 操作历史管理 |
| F2.6 保存草稿 | P0 | ✅ | 保存为草稿版本 |

### F3: 流程设计器（钉钉风格）

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F3.1 审批人节点 | P0 | ✅ | 配置审批人 |
| F3.2 执行人节点 | P0 | ✅ | 配置执行人 |
| F3.3 抄送人节点 | P1 | ✅ | 配置抄送人 |
| F3.4 条件分支 | P0 | ✅ | 基于条件的分支路由 |
| F3.5 并行分支 | P1 | ✅ | 并行执行的分支 |
| F3.6 节点属性配置 | P0 | ✅ | 审批人类型、多人审批方式 |
| F3.7 撤销重做 | P1 | ✅ | 操作历史管理 |

### F4: 版本管理

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F4.1 版本列表 | P0 | ✅ | 查看所有版本 |
| F4.2 创建版本 | P0 | ✅ | 保存为新版本 |
| F4.3 版本对比 | P2 | 📋 | 对比两个版本差异 |
| F4.4 版本回滚 | P1 | 📋 | 回滚到历史版本 |
| F4.5 设置默认版本 | P0 | ✅ | 指定发布版本 |
| F4.6 版本名称 | P1 | 📋 | 为版本设置名称（如 "v1.0 初版"） |
| F4.7 版本说明 | P1 | 📋 | 记录版本变更说明 |

**版本命名**：
- 每个版本（FormVersion / ProcessVersion）可配置 `versionName`
- 示例："v1.0 初版"、"v2.0 增加附件字段"、"v3.0 优化审批流程"
- 用于版本列表展示和版本对比时快速识别

### F5: 版本审核与发布

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F5.1 提交审核 | P0 | ✅ | 设计者提交版本审核 |
| F5.2 待审核列表 | P0 | ✅ | 管理员查看待审核 |
| F5.3 审核通过 | P0 | ✅ | 通过后可发布 |
| F5.4 审核驳回 | P0 | ✅ | 驳回并说明原因 |
| F5.5 发布快照 | P0 | 📋 | 创建发布快照 |
| F5.6 审核记录 | P1 | 📋 | 查看历史审核记录 |
| F5.7 发布说明 | P1 | 📋 | 发布时填写发布说明 |

**发布说明**：
- 发布时可填写 `releaseNote`，记录本次发布的变更内容
- 示例："修复金额校验问题"、"增加附件上传功能"
- 用于审计、版本列表展示和问题追溯

### F6: 表单模板

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F6.1 模板列表 | P0 | ✅ | 浏览可用模板 |
| F6.2 从模板创建 | P0 | ✅ | 基于模板创建表单 |
| F6.3 保存为模板 | P1 | 📋 | 将表单保存为模板 |
| F6.4 模板分类 | P2 | 📋 | 按类型分类模板 |

### F7: 多语言支持

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F7.1 翻译管理 | P1 | ✅ | 管理表单翻译 |
| F7.2 导入导出 | P2 | 📋 | 批量导入导出翻译 |

### F8: 统计分析

| 功能点 | 优先级 | 状态 | 说明 |
|--------|--------|------|------|
| F8.1 使用统计 | P2 | 🚧 | 表单使用次数统计 |
| F8.2 趋势分析 | P2 | 📋 | 使用趋势图表 |

---

## 🎨 界面设计

### 模块布局

```
┌─────────────────────────────────────────────────────────────────┐
│                          顶部导航栏                              │
├───────────┬─────────────────────────────────────────────────────┤
│           │                                                     │
│   左侧    │                    主内容区                          │
│   导航    │                                                     │
│           │                                                     │
│  • 概览   │                                                     │
│  • 表单   │                                                     │
│  • 我的   │                                                     │
│  • 审核   │                                                     │
│  • 模板   │                                                     │
│  • 翻译   │                                                     │
│  • 统计   │                                                     │
│           │                                                     │
└───────────┴─────────────────────────────────────────────────────┘
```

### 设计器布局

```
┌─────────────────────────────────────────────────────────────────┐
│  ← 返回  │  表单名称  │  表单设计  │  流程设计  │  预览  │  保存 │
├─────────────────────────────────────────────────────────────────┤
│           │                              │                      │
│  字段     │         设计画布             │      属性面板        │
│  面板     │                              │                      │
│           │    ┌──────────────────┐      │   ┌────────────────┐ │
│  基础     │    │                  │      │   │  节点名称      │ │
│  ├ 文本   │    │  [表单/流程内容]  │      │   │  审批人设置    │ │
│  ├ 数字   │    │                  │      │   │  多人审批方式  │ │
│  ├ 日期   │    └──────────────────┘      │   │  高级设置      │ │
│           │                              │   └────────────────┘ │
│  高级     │                              │                      │
│  ├ 附件   │                              │                      │
│  ├ 表格   │                              │                      │
│           │                              │                      │
└───────────┴──────────────────────────────┴──────────────────────┘
```

---

## ✅ 验收标准

### 表单设计

- [ ] 可通过拖拽添加所有支持的字段类型
- [ ] 字段属性可正确配置和保存
- [ ] 预览功能正确显示表单效果
- [ ] 支持撤销/重做操作
- [ ] JSON Schema 正确生成并可验证

### 流程设计

- [ ] 可添加审批人、执行人、抄送人节点
- [ ] 可配置条件分支和并行分支
- [ ] 节点属性（审批人类型、多人审批方式）可正确配置
- [ ] 流程设计可保存和加载

### 版本管理

- [x] 可创建新版本并保存
- [x] 可查看版本历史
- [x] 版本状态机正确流转（DRAFT → PENDING_REVIEW → PUBLISHED）
- [x] 可提交版本审核
- [x] 管理员可审核通过/驳回（审核通过=发布）

### 发布快照

- [x] 发布时正确创建快照（ReleaseSnapshot 表）
- [x] 快照绑定表单版本和流程版本
- [x] 运行中实例不受新版本影响
- [x] 历史实例可追溯到具体版本（snapshotId 关联）

### 权限控制

- [ ] 不同角色看到不同的菜单和操作
- [ ] 数据权限正确隔离
- [ ] 操作权限正确校验

### 多区域（Region）行为

- [ ] 同一 `formDefinitionId` 在不同 `regionId` 下可以各有一个 ACTIVE 快照（CN 有一个，US 有一个）
- [ ] 查询 ACTIVE 表单时，必须传入 `regionId`，不同区域看到的可用表单列表不同
- [ ] 在 CN 区创建的 `FormInstance` 不会出现在 US 审批中心
- [ ] 涉及定义/快照/实例的 API，如果缺少 `regionId` 参数，应返回 `REGION_REQUIRED` 错误
- [ ] 创建实体时自动注入当前用户的 `regionId`
- [ ] **模板 API 不需要 `regionId`**（模板全局共享）
- [ ] 从模板创建表单定义时，**必须指定目标 `regionId`**
- [ ] 跨区域操作（如模板同步到多区域）需要 `form:admin` 权限

### 错误码校验

| 错误码 | 触发条件 | HTTP 状态码 |
|--------|----------|-------------|
| `REGION_REQUIRED` | 缺少 `regionId` 参数 | 400 |
| `INVALID_REGION` | `regionId` 不在支持列表中（CN/US/ME） | 400 |
| `REGION_MISMATCH` | 资源的 `regionId` 与请求的 `regionId` 不一致 | 403 |
| `FORM_DEFINITION_DISABLED` | 表单已禁用，不允许新发起 | 403 |
| `FORM_DEFINITION_ARCHIVED` | 表单已归档，不允许任何操作 | 403 |
| `NO_ACTIVE_SNAPSHOT` | 该区域没有可用的 ACTIVE 快照 | 404 |
| `DRAFT_ALREADY_EXISTS` | 已有 DRAFT 快照，不能创建新草稿 | 409 |
| `PENDING_ALREADY_EXISTS` | 已有 PENDING 快照正在审核中 | 409 |

---

## 📅 里程碑

| 阶段 | 内容 | 状态 |
|------|------|------|
| Phase 1 | 表单定义管理 + 基础设计器 | ✅ |
| Phase 2 | 钉钉风格流程设计器 | ✅ |
| Phase 3 | 版本管理 + 审核流程 | ✅ |
| Phase 4 | 发布快照 + 多区域隔离 | ✅ |
| Phase 5 | 权限模型 + 模板系统 | 📋 |
| Phase 6 | 统计分析 + 跨区域同步 | 📋 |

---

**最后更新**: 2025-12-11
