# 评查点分组迁移执行前检查清单

更新时间：2026-05-03

## 1. 目标

本清单用于在正式执行 `scripts/创建sql/migrate_rule_groups_to_doc_type_roots.sql` 之前，先把当前库里的旧数据、兼容态数据和潜在冲突点查清楚。

如果希望直接执行一份只读巡检 SQL，可使用：

- `scripts/创建sql/precheck_rule_group_migration.sql`

本次迁移的目标仍然是：

- 一级分组 = 业务大类
- 二级分组 = 具体业务类型
- 规则集 = 挂在二级分组下
- 入口模块 = 绑定一级分组

## 2. 当前风险结论

正式迁移前，必须先确认下面 4 类风险：

1. 是否仍存在“一级直接挂具体文档类型”的旧根数据。
2. 是否存在同一个 `document_type_id` 被多个二级分组同时承接的情况。
3. 是否存在规则集同时挂在旧一级根和旧默认子级上，导致迁移后重复。
4. `document_types.entry_module_id` 是否足够可靠，能支撑“先按入口模块粗分到一级业务大类”。

如果这 4 类风险没有检查清楚，不应直接跑迁移脚本。

## 2.1 当前已知巡检结论（2026-05-03）

基于本次实际巡检结果：

- `leaudit_document_types` 共 20 条，入口归属完整
  - 合同管理：10 条
  - 案卷智能评查：10 条
- 当前仍有 20 个旧一级根
  - 即：`一级 = 具体文档类型`
- 当前已经存在 2 个新一级业务大类根
  - `root.contract -> 合同`
  - `root.casefile -> 行政卷宗`
- 当前有 20 个默认二级分组
  - 即：`二级 = 通用 / *.default`
- 当前没有发现明显冲突：
  - 没有“同一文档类型被多个二级分组重复承接”
  - 没有“同一规则集同时挂在旧一级根和默认子级”
  - 没有“二级分组未绑定规则集”

结论：

- 当前库已经具备正式迁移的基础条件
- 但还没有完成最后的结构补齐
- 正式迁移前仍要先补 `entry_module_id`，再重跑巡检

## 3. 必查项

### 3.1 一级旧根检查

确认当前是否还有“一级 = 具体文档类型”的历史根：

```sql
SELECT
    id,
    code,
    name,
    document_type_id,
    entry_module_id,
    sort_order,
    is_enabled
FROM leaudit_evaluation_point_groups
WHERE deleted_at IS NULL
  AND COALESCE(pid, 0) = 0
  AND document_type_id IS NOT NULL
ORDER BY id;
```

判定原则：

- 查出来的这些记录，都属于兼容态旧根。
- 正式迁移后，它们不应再继续作为最终一级分组存在。

### 3.2 一级业务大类根检查

确认当前是否已经存在真正的业务大类根：

```sql
SELECT
    id,
    code,
    name,
    entry_module_id,
    sort_order,
    is_enabled
FROM leaudit_evaluation_point_groups
WHERE deleted_at IS NULL
  AND COALESCE(pid, 0) = 0
  AND document_type_id IS NULL
ORDER BY sort_order, id;
```

判定原则：

- 正常目标结构下，这里应该看到如 `合同`、`卷宗` 这类一级业务大类。
- 如果这里为空，说明当前库还没有真正切到目标结构。

### 3.3 二级分组唯一性检查

确认同一个文档类型是否被多个二级分组重复承接：

```sql
SELECT
    document_type_id,
    COUNT(*) AS child_count,
    STRING_AGG(name, ' / ' ORDER BY id) AS child_names
FROM leaudit_evaluation_point_groups
WHERE deleted_at IS NULL
  AND COALESCE(pid, 0) <> 0
  AND document_type_id IS NOT NULL
GROUP BY document_type_id
HAVING COUNT(*) > 1
ORDER BY document_type_id;
```

判定原则：

- 如果结果为空，说明每个文档类型目前最多只挂到一个二级分组，迁移最安全。
- 如果结果不为空，要逐条判断：
  - 是合理的“一个文档类型拆成多个业务子类型”
  - 还是历史脏数据

### 3.4 旧默认子级检查

确认当前是否存在旧默认子级：

```sql
SELECT
    child.id,
    child.pid,
    parent.name AS parent_name,
    child.name,
    child.code,
    child.document_type_id
FROM leaudit_evaluation_point_groups child
JOIN leaudit_evaluation_point_groups parent
  ON parent.id = child.pid
 AND parent.deleted_at IS NULL
WHERE child.deleted_at IS NULL
  AND COALESCE(child.pid, 0) <> 0
  AND (
      child.name = '通用'
      OR child.code LIKE '%.default'
  )
ORDER BY child.id;
```

判定原则：

- 这些记录多数是旧链路下的“默认子类型”兼容数据。
- 迁移时如果它们已经被真实二级业务类型替代，应考虑把规则集迁走后再停用或清理。

### 3.5 规则集重复挂载检查

确认同一个文档类型下，旧一级根和默认子级是否同时挂了相同规则集：

```sql
WITH target_groups AS (
    SELECT
        g.id,
        g.document_type_id,
        g.name,
        g.code,
        CASE
            WHEN COALESCE(g.pid, 0) = 0 THEN 'old_root'
            WHEN g.name = '通用' OR g.code LIKE '%.default' THEN 'default_child'
            ELSE 'other_child'
        END AS group_kind
    FROM leaudit_evaluation_point_groups g
    WHERE g.deleted_at IS NULL
      AND g.document_type_id IS NOT NULL
)
SELECT
    tg.document_type_id,
    rgb.rule_set_id,
    COUNT(*) AS binding_count,
    STRING_AGG(tg.group_kind || ':' || tg.name, ' / ' ORDER BY tg.id) AS group_sources
FROM leaudit_rule_group_bindings rgb
JOIN target_groups tg
  ON tg.id = rgb.group_id
WHERE rgb.deleted_at IS NULL
GROUP BY tg.document_type_id, rgb.rule_set_id
HAVING COUNT(*) > 1
ORDER BY tg.document_type_id, rgb.rule_set_id;
```

判定原则：

- 如果结果不为空，迁移脚本执行前要先确认是否允许去重。
- 否则迁移后可能出现：
  - 同一规则集被重复搬到新二级分组
  - 或者旧运行汇总结果不稳定

### 3.6 文档类型与入口模块映射检查

确认 `document_types` 是否都有稳定入口归属：

```sql
SELECT
    dt.id,
    dt.code,
    dt.name,
    dt.entry_module_id,
    em.name AS entry_module_name
FROM leaudit_document_types dt
LEFT JOIN leaudit_entry_modules em
  ON em.id = dt.entry_module_id
WHERE dt.deleted_at IS NULL
ORDER BY dt.id;
```

重点看：

- 是否存在 `entry_module_id IS NULL`
- 是否存在入口模块已被删除、停用或名称异常
- 是否存在“明明是合同类型却挂在卷宗入口”这类错误归属

### 3.7 规则集可运行性检查

迁移前需要确认二级分组绑定过去的规则集不是空壳：

```sql
SELECT
    rs.id,
    rs.rule_name,
    rs.rule_type,
    rs.current_version_id,
    rs.fallback_version_id
FROM leaudit_rule_sets rs
WHERE rs.deleted_at IS NULL
ORDER BY rs.id;
```

这一步建议再配合业务接口实际看：

- 是否有可用版本

## 4. 正式迁移推荐执行顺序

### 步骤 1：先备份

必须先备份这几张表：

- `leaudit_evaluation_point_groups`
- `leaudit_rule_group_bindings`
- `leaudit_rule_type_bindings`
- `leaudit_document_types`

### 步骤 2：先补字段，不迁数据

先补结构层缺口：

1. 给 `leaudit_evaluation_point_groups` 增加 `entry_module_id`
2. 建索引
3. 给已有一级业务大类根补入口绑定

建议值：

- `root.contract -> entry_module_id = 1`
- `root.casefile -> entry_module_id = 2`

### 步骤 3：重新跑巡检

字段补完后，重新执行：

- `scripts/创建sql/precheck_rule_group_migration.sql`

确认：

- 一级业务大类根能正确看到入口模块字段
- 巡检结果仍无重复承接、重复绑定、空壳规则集等问题

### 步骤 4：测试库执行正式迁移

再执行：

- `scripts/创建sql/migrate_rule_groups_to_business_roots.sql`

说明：

- 旧脚本 `scripts/创建sql/migrate_rule_groups_to_doc_type_roots.sql` 仅保留兼容历史引用
- 不建议继续作为正式迁移脚本使用

### 步骤 5：迁后验证 4 个页面

必须验证：

1. `/rule-groups`
2. `/files/upload`
3. `/document-types/new?id=...`
4. `/documents/list`

## 5. 迁移脚本调整口径

基于当前巡检结果，正式脚本建议继续遵守：

1. 不要再硬编码“只有合同和卷宗”
2. 优先复用已存在业务大类根，不重复新造
3. 一级根编码必须统一，例如继续沿用：
   - `root.contract`
   - `root.casefile`
- 可用规则数是否大于 0

否则迁完结构后，上传仍然会失败，只是失败原因从“结构问题”变成“规则集不可运行”。

## 4. 执行前必须人工确认的业务映射

SQL 只能粗分，业务归属必须人工确认：

### 4.1 一级业务大类清单

至少要先列清：

- 哪些文档类型归到 `合同`
- 哪些文档类型归到 `卷宗`
- 是否已经存在第 3 个业务大类，如 `内部公文`

### 4.2 二级业务类型命名规范

要确认：

- 二级显示名称是否直接用 `document_types.name`
- 还是需要改成更贴近业务的名称
  - 例如：`处罚-一般程序`
  - 而不是数据库里原始的技术名

### 4.3 默认子类型保留策略

需要人工确认：

- 哪些文档类型仍保留 `默认子类型（通用）`
- 哪些必须拆成多个真实二级业务类型

## 5. 执行顺序建议

推荐按下面顺序推进：

1. 跑本清单中的查询 SQL，导出当前状态。
2. 形成一份 `document_type -> 一级业务大类 -> 目标二级名称` 的确认表。
3. 在测试库执行迁移脚本。
4. 验证以下页面：
   - `/rule-groups`
   - `/files/upload`
   - `/document-types/new?id=...`
   - `/documents/list`
5. 验证上传链路：
   - 能否正确选择子类型
   - 上传后是否命中预期规则集
   - 合同附件追加链路是否仍正常
6. 测试通过后，再评估正式库执行窗口。

## 6. 当前不建议直接执行的情况

只要出现以下任一情况，都不建议直接执行迁移脚本：

- `document_types.entry_module_id` 还有大量空值
- 同一文档类型被多个旧组重复承接，但业务还没定论
- 规则集存在大量“可用规则数 = 0”
- 一级业务大类并不只有 `合同 / 卷宗`，但映射方案还没补
- 业务方还没确认二级命名与保留策略

## 7. 当前结论

截至当前，这套系统已经具备：

- 前端按新链路展示和解释的能力
- 后端兼容新旧结构的能力
- 新配置回写旧运行绑定表的能力

但数据库正式迁移这一步，仍然必须先做“数据盘点 + 业务确认 + 测试库演练”三件事，不能直接在正式库硬切。
