# 权限测试验收与回归用例清单

> 适用范围：权限架构统一改造后的联调、验收、灰度、回归阶段  
> 文档定位：把“角色、权限、地区、模块、接口、菜单、下载、导出”的测试口径一次性拉平。

---

## 1. 测试目标

本轮权限改造的核心验收目标不是“接口能用”，而是以下 6 件事同时成立：

1. 功能权限正确
2. 数据范围正确
3. 多角色合并正确
4. `DENY` 优先正确
5. 菜单、页面、按钮、接口边界一致
6. 详情、下载、导出、删除等派生接口不绕过主资源边界

---

## 2. 测试范围

本次至少覆盖以下模块：

- 文档
- 公文
- 使用统计
- RAG
- 交叉评查
- RBAC 管理
- 合同模板
- 首页入口与菜单

不作为本轮重点但要做冒烟确认：

- 规则
- 规则配置
- 评查点分组

---

## 3. 测试前置准备

## 3.1 角色准备

建议准备最少 6 类测试账号：

1. `super_admin`
2. `provincial_admin`
3. `admin`-A 地区
4. `admin`-B 地区
5. `common`-A 地区
6. `common`-B 地区

建议再补 3 类组合账号：

1. `common + admin` 同地区多角色用户
2. `admin + DENY 某权限` 用户
3. 自定义角色用户：不叫 `admin/provincial_admin`，但拥有相同 permission 与 scope

最后这类用户极关键，用于验证“去角色硬编码后系统是否仍正确工作”。

## 3.2 数据准备

建议准备以下数据：

1. A 地区文档 3 份
2. B 地区文档 3 份
3. A 地区公文 3 份
4. B 地区公文 3 份
5. A 地区合同模板 2 份
6. B 地区合同模板 2 份
7. 省级 RAG 数据集 2 个
8. A 地区 RAG 数据集 2 个
9. B 地区 RAG 数据集 2 个
10. 公共 RAG 数据集 1 个
11. 交叉评查任务至少 2 个，分别覆盖成员 A/B 差异

## 3.3 授权准备

建议为每类 permission 准备三种授权状态：

1. `GRANT + ALL`
2. `GRANT + DEPT`
3. `GRANT + SELF`

同时至少准备一个 `DENY` 用例：

- 对同一个用户，某权限被更高优先级角色 `DENY`

---

## 4. 验收口径

验收统一按三层判断：

1. `403`
   - 说明功能权限被拒绝
2. `200 + 空数据`
   - 说明功能权限有，但数据范围无命中
3. `200 + 仅返回应有数据`
   - 说明 scope 正确

不能把 `空列表` 和 `403` 混为一谈。

---

## 5. 角色矩阵用例

## 5.1 全局范围用户

用例编号：`ROLE-ALL-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `ROLE-ALL-01` | `super_admin` 查询文档列表 | 可见全部地区文档 |
| `ROLE-ALL-02` | `provincial_admin` 查询使用统计地区汇总 | 可见全部地区 |
| `ROLE-ALL-03` | `provincial_admin` 管理 RAG 数据集 | 可管理全部地区或省级数据集 |
| `ROLE-ALL-04` | 全局用户下载任意本系统有权限公文报告 | 成功 |

## 5.2 地区范围用户

用例编号：`ROLE-DEPT-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `ROLE-DEPT-01` | A 地区 `admin` 查文档列表 | 仅可见 A 地区 |
| `ROLE-DEPT-02` | A 地区 `admin` 指定 `region=B` 查文档 | 拒绝或自动收敛，不能看到 B |
| `ROLE-DEPT-03` | A 地区 `admin` 查 RBAC 用户列表 | 仅可见 A 地区用户 |
| `ROLE-DEPT-04` | A 地区 `admin` 创建 RAG 数据集并指定 B 地区 | 拒绝 |

## 5.3 自身范围用户

用例编号：`ROLE-SELF-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `ROLE-SELF-01` | `common` 查文档列表 | 仅本人上传文档 |
| `ROLE-SELF-02` | `common` 查使用统计明细 | 仅本人登录/上传/评查明细 |
| `ROLE-SELF-03` | `common` 查合同模板详情 | 仅在本人可见范围内成功 |
| `ROLE-SELF-04` | `common` 删除他人文档 | 拒绝 |

## 5.4 去角色硬编码验证

用例编号：`ROLE-DEC-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `ROLE-DEC-01` | 自定义角色用户拥有 `rag:dataset:manage + DEPT` | 应能管理本地区 RAG 数据集，即便角色名不是 `admin` |
| `ROLE-DEC-02` | 自定义角色用户拥有 `contract_template:create:write + DEPT` | 应可创建本地区模板 |
| `ROLE-DEC-03` | 自定义角色用户拥有 `rbac:user_roles:write + DEPT` | 应可管理本地区用户角色 |
| `ROLE-DEC-04` | 角色名是 `admin` 但缺少目标 permission | 应被拒绝，不能因角色名放行 |

---

## 6. 多角色与 DENY 用例

用例编号：`MERGE-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `MERGE-01` | 用户同时拥有 `documents:list:read + SELF` 与 `documents:list:read + DEPT` | 取更大范围 `DEPT` |
| `MERGE-02` | 用户同时拥有 `documents:list:read + DEPT` 与 `documents:list:read + ALL` | 取 `ALL` |
| `MERGE-03` | 用户有 `documents:list:read + ALL`，另一角色 `DENY documents:list:read` | 最终拒绝 |
| `MERGE-04` | 用户拥有 `rag:dataset:read + PUBLIC_MIXED`，另一角色 `DENY rag:dataset:update` | 可读不可改 |
| `MERGE-05` | 用户有 `rbac:users:read + DEPT` 和 `rbac:roles:read + NONE` | 用户列表仍限本地区，角色列表正常 |

---

## 7. 文档模块用例

用例编号：`DOC-*`

## 7.1 列表与详情一致性

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `DOC-01` | 列表可见文档点进详情 | 成功 |
| `DOC-02` | 列表不可见文档直接访问详情 ID | 拒绝或 404 |
| `DOC-03` | 列表不可见文档请求状态接口 | 不返回该文档状态 |
| `DOC-04` | 列表不可见文档请求评查点聚合 | 拒绝 |

## 7.2 写操作一致性

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `DOC-05` | 本人文档追加附件 | 成功 |
| `DOC-06` | 非本人、非本地区文档追加附件 | 拒绝 |
| `DOC-07` | 本地区管理员删除本地区文档 | 成功 |
| `DOC-08` | 本地区管理员删除外地区文档 | 拒绝 |
| `DOC-09` | `SELF` 用户确认他人文档评查结果 | 拒绝 |

## 7.3 上传边界

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `DOC-10` | `DEPT` 用户上传文档时指定本地区 | 成功 |
| `DOC-11` | `DEPT` 用户上传文档时指定外地区 | 拒绝或强制改写为本地区 |
| `DOC-12` | `ALL` 用户上传并指定任意地区 | 成功 |

---

## 8. 公文模块用例

用例编号：`GOV-*`

## 8.1 文档链路

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `GOV-01` | 可见公文在列表、详情均可访问 | 成功 |
| `GOV-02` | 不可见公文详情直连 | 拒绝或 404 |
| `GOV-03` | 删除可见公文 | 成功 |
| `GOV-04` | 删除不可见公文 | 拒绝 |

## 8.2 运行结果与报告链路

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `GOV-05` | 对可见公文发起 run | 成功 |
| `GOV-06` | 对不可见公文发起 run | 拒绝 |
| `GOV-07` | 通过 `runId` 查看结果，但所属公文不在 scope | 拒绝 |
| `GOV-08` | 通过 `runId` 下载 docx 报告，但所属公文不在 scope | 拒绝 |
| `GOV-09` | 下载原始公文，但所属公文不在 scope | 拒绝 |

---

## 9. 使用统计模块用例

用例编号：`STAT-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `STAT-01` | 全局用户看 `overview` | 全量数据 |
| `STAT-02` | 地区用户看 `overview` | 仅本地区 |
| `STAT-03` | `SELF` 用户看 `overview` | 仅自己相关数据或受限简版 |
| `STAT-04` | 地区用户 `areaScope=user` 指定外地区 | 拒绝或无数据 |
| `STAT-05` | 地区用户 `areaScope=document` 指定外地区 | 拒绝或无数据 |
| `STAT-06` | `by-users` 指定他人 `userId`，但不在当前 scope | 拒绝或无数据 |
| `STAT-07` | `details` 接口查看他人上传明细 | 按 scope 正确收敛 |
| `STAT-08` | `by-areas` 对 `SELF` 用户 | 建议拒绝或返回受限结果 |

---

## 10. RAG 模块用例

用例编号：`RAG-*`

## 10.1 阅读边界

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `RAG-01` | A 地区用户查看 A 地区数据集 | 成功 |
| `RAG-02` | A 地区用户查看 B 地区私有数据集 | 拒绝 |
| `RAG-03` | A 地区用户查看省级数据集 | 成功 |
| `RAG-04` | A 地区用户查看 `is_public=true` 数据集 | 成功 |
| `RAG-05` | 默认应用与应用列表展示边界一致 | 一致 |

## 10.2 管理边界

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `RAG-06` | 拥有 `rag:dataset:manage + DEPT` 的自定义角色访问 `/datasets/admin` | 成功 |
| `RAG-07` | 无 `manage` 但角色名是 `admin` 的用户访问 `/datasets/admin` | 拒绝 |
| `RAG-08` | `DEPT` 用户创建外地区数据集 | 拒绝 |
| `RAG-09` | `DEPT` 用户修改本地区数据集 | 成功 |
| `RAG-10` | `DEPT` 用户删除外地区数据集 | 拒绝 |
| `RAG-11` | 数据集文档上传、重处理、删除边界与数据集边界一致 | 一致 |

## 10.3 会话边界

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `RAG-12` | 查看自己会话 | 成功 |
| `RAG-13` | 查看他人会话 | 拒绝 |
| `RAG-14` | 删除他人会话 | 拒绝 |

---

## 11. 交叉评查模块用例

用例编号：`CR-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `CR-01` | 任务成员查询自己参与任务 | 成功 |
| `CR-02` | 非成员查询任务 | 拒绝或无数据 |
| `CR-03` | 任务成员查看任务文档 | 成功 |
| `CR-04` | 非成员查看任务文档 | 拒绝 |
| `CR-05` | 非负责角色调用 `can-confirm` | 拒绝或返回不可确认 |
| `CR-06` | 非成员上传任务文档 | 拒绝 |
| `CR-07` | 非成员追加附件 | 拒绝 |
| `CR-08` | 可投票成员投票 | 成功 |
| `CR-09` | 非可投票成员投票 | 拒绝 |
| `CR-10` | 非成员导出提案 | 拒绝 |

重点：

- 交叉评查不能按地区矩阵替代成员关系矩阵
- 这组测试必须围绕“关系模型”设计

---

## 12. RBAC 管理域用例

用例编号：`RBAC-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `RBAC-01` | 地区管理员查看用户列表 | 仅本地区 |
| `RBAC-02` | 地区管理员查询外地区用户角色 | 拒绝或无数据 |
| `RBAC-03` | 地区管理员给本地区用户分配角色 | 成功 |
| `RBAC-04` | 地区管理员给外地区用户分配角色 | 拒绝 |
| `RBAC-05` | 无 `rbac:user_roles:write` 但角色名是 `admin` | 拒绝 |
| `RBAC-06` | 角色权限配置保存后，权限即时生效或在缓存期内按预期生效 | 正确 |
| `RBAC-07` | `DENY` 权限配置后，用户访问对应接口 | 被拒绝 |

---

## 13. 合同模板模块用例

用例编号：`TPL-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `TPL-01` | 全局用户查看全部模板 | 成功 |
| `TPL-02` | 地区用户查看模板列表 | 仅本地区 + 公共/省级范围内模板 |
| `TPL-03` | `SELF` 用户查看本人模板 | 仅本人可见 |
| `TPL-04` | 拥有 `contract_template:create:write + DEPT` 的自定义角色上传模板 | 成功 |
| `TPL-05` | 前端角色名不是 `admin` 但拥有权限 | 页面上传入口应可见 |
| `TPL-06` | 无权限但前端强行调创建接口 | 后端拒绝 |
| `TPL-07` | 删除外地区模板 | 拒绝 |

---

## 14. 菜单、页面、按钮一致性用例

用例编号：`UI-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `UI-01` | 菜单可见页面，接口也应可访问 | 一致 |
| `UI-02` | 菜单不可见页面，直接输入 URL | 后端仍能防越权 |
| `UI-03` | 按钮不可见时，直调接口 | 后端仍能防越权 |
| `UI-04` | 数据库路由撤销后，前端 fallback 不应继续展示旧菜单 | 一致 |
| `UI-05` | 自定义角色用户拥有权限但不是旧硬编码角色 | 菜单、按钮按 permission 展示 |

---

## 15. 下载、导出、详情专项

用例编号：`RES-*`

这组是本轮最重要回归项。

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `RES-01` | 文档详情不可见时，评查点接口也不可见 | 一致 |
| `RES-02` | 公文详情不可见时，原文下载不可用 | 一致 |
| `RES-03` | 公文详情不可见时，报告下载不可用 | 一致 |
| `RES-04` | 交叉评查文档不可见时，提案导出不可用 | 一致 |
| `RES-05` | RAG 数据集不可见时，其文档和分段明细不可见 | 一致 |

---

## 16. 缓存与生效时效用例

用例编号：`CACHE-*`

| 编号 | 场景 | 预期 |
| --- | --- | --- |
| `CACHE-01` | 给用户新增 permission | 在预期缓存时间内生效 |
| `CACHE-02` | 给用户新增 `DENY` | 在预期缓存时间内生效，且优先于旧 `GRANT` |
| `CACHE-03` | 修改用户地区 `area` | 列表、详情、菜单能力按新地区收敛 |
| `CACHE-04` | 修改角色 `data_scope` | 对应接口边界变化符合预期 |

---

## 17. 灰度观察指标

灰度期建议至少看以下指标：

1. `403` 数量按模块趋势
2. RAG `/datasets/admin` 相关接口报错量
3. 公文 `report/docx`、`original` 下载失败量
4. 交叉评查导出失败量
5. RBAC 用户角色分配失败量
6. 前端菜单请求与接口拒绝不一致量

若出现明显上涨，应优先排查：

- scope 决策错误
- 前端仍沿用旧角色判断
- 详情/下载类接口未接统一执行器

---

## 18. 通过标准

验收通过建议满足以下门槛：

1. P0 模块用例通过率 100%
2. 所有 `DENY` 用例通过
3. 自定义角色去硬编码用例通过
4. 列表/详情/下载/导出一致性用例通过
5. 灰度期无明显越权投诉或异常日志

如果以上任一项未达标，本轮权限改造不应视为完成。
