Files
lingxi/docs/adr/ADR-001-权限点目录与六类数据范围.md
T
Stev_Wang 7fb458f62f
ci / 质量门禁 (push) Canceled after 0s
docs(plan): 回写 A2 完成状态并记录 H1 权限门决策
背景:A2 角色权限与数据范围已完成,需回写计划状态、实施报告与架构决策记录。

改动:
- 新增 docs/adr/ADR-001-权限点目录与六类数据范围.md 及 ADR 索引,记录 H1 权限门六项决策。
- 新增 A2 实施报告(范围、交付、门禁、遗留、回滚、下一步)。
- 更新开发计划 §5.2 / §6.3 / 文档状态,并同步根 README 文档索引。
2026-11-03 12:27:15 +08:00

105 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-001 角色权限模型:权限点目录、特殊权限、SoD 与六类数据范围
| 项 | 内容 |
| --- | --- |
| 状态 | 已接受(2026-11-03,H1 权限门用户确认) |
| 决策人 | 产品 / 技术负责人(用户) |
| 记录人 | 工程 Lead |
| 关联 | 开发计划 V0.1 §3.4 H1 门、§6.3 A2、§7.2、§10.3、§13 DP-14;技术架构 V0.4 §5.5 / §6.1–6.3 / §7.1 / §8.7;PRD V1.6 §5.4.3、R-16~R-18 |
| 影响范围 | `packages/shared` 权限点与数据范围契约、`identity` 模块、`prisma` 迁移与种子、`apps/web` 角色管理页、A3 客户模块、后续所有受保护端点 |
## 背景
A2「角色权限与数据范围」开卡前必须完成 H1 权限门(开发计划 §3.4):确认权限点目录、六类数据范围、SoD 互斥对、特殊权限授予规则,否则权限模型返工会影响全部页面。
现状与文档存在差异:
- `packages/shared/src/permissions.ts` 是 A0 骨架,共 25 个 `read/write` 风格编码;缺少 `role:view`、`customer_field:apply`、`customer:transfer`、`customer_group:manage`、`asset:delete`。
- 开发计划附录 B 使用 `view/manage` 风格并列出更多编码;但其自身注明「最终以 `packages/shared` 为准」。
- PRD §5.4.3 的权限粒度更细(如图片生成 / 视频生成拆开),完整实现会显著增加权限点数量与配置成本。
- A3 客户模块尚未开发,而六类数据范围中的「指定客户组 / 负责客户 / 本人创建」依赖客户与客户组数据。
## 决策
### D1 权限点目录:保留现有编码,只增不改
以 `packages/shared` 现有 25 个编码为基线,补齐 A2 必需的 5 个编码:
`role:view`、`customer_field:apply`、`customer:transfer`、`customer_group:manage`、`asset:delete`。
合计 **30 个权限点 / 10 个模块**。命名保持 `<模块>:<动作>` 与 `read/write` 动作词;后续新增权限点通过代码目录注册并同步 `permissions` 表,**不手写迁移**。
### D2 特殊权限:M0 五项 6 编码
| 特殊权限 | 编码 |
| --- | --- |
| 导出 | `delivery:export` |
| AI 配置 | `ai:configure` |
| 审计查看 | `audit:read` |
| 审计导出 | `audit:export` |
| 行业包发布 | `industry:publish` |
| 字段审批 | `customer_field:approve` |
规则:默认关闭、单独授予、不随角色复制带入、授予与撤销二次确认并写入审计。PRD 中的「跨客户复用授权」「批量删除」按开发计划 DP-14 留到 M2/M3,届时先回写技术架构并补编码,**A2 不实现**。
### D3 SoD 三对互斥:按现有编码映射
| 互斥对 | 编码 |
| --- | --- |
| 脚本生成与审核 | `script:write` × `script:review` |
| 行业包编辑与发布 | `industry:manage` × `industry:publish` |
| 字段申请与审批 | `customer_field:apply` × `customer_field:approve` |
保存角色时校验,命中返回 `40304`;仅角色级校验(同一角色不可同时持有),超级管理员豁免。用户通过多个角色组合持有的情况不在 A2 校验范围(PRD 表述为「不可同属一个角色」)。
### D4 六类数据范围:全链路实现,客户集合通过端口隔离
A2 建立 `data_scopes` 表、六类范围解析引擎、`ScopeContext` 注入链路与 Repository 客户维度强制参数;角色保存时持久化范围类型与目标(指定客户组可多个)。
客户集合解析通过 `CustomerDirectory` 端口完成:
- A2 实现 `EmptyCustomerDirectory`,在 A3 客户模块落地前返回空集;
- 测试使用 fake 客户目录覆盖非空场景;
- A3 接入真实 `customers` / `customer_groups` 后替换实现,`ScopeContext` 与 Repository 契约不变。
失败处理:数据范围解析失败一律 403,**不降级为「全部客户」**。多角色取并集;任一角色为「全部客户」则结果为全部。
### D5 超级管理员:隐式全集
`is_system = true` 的角色自动拥有全部权限点、全部特殊权限与全部数据范围,不依赖、也不可编辑 `role_permissions` / `data_scopes` 记录;仅显示名可改,不可删除、不可停用。
角色数量 > 20、超管人数 > 2 仅做非阻断提示(PRD 为「建议值」)。相关建议值当前以共享常量表达,A4 系统配置落地后迁入 `system_configs`(R-26 单一存放处)。
### D6 变更审计:A2 结构化日志,A5 落库
角色变更(新建 / 编辑 / 复制 / 停用 / 删除 / 特殊权限授予)记录结构化日志:操作人、账号、IP、trace_id、目标角色、权限点前后值、特殊权限前后值、影响用户数。
同时写 `outbox_events`(`role.permissions.changed`,payload 含受影响用户 ID)作为「受影响用户通知」占位,消费方随 A5/A6 接入。审计表落库、检索与导出由 A5 完成;`@Audit` 装饰器签名保持不变。
## 后果
### 正面
- A1 已实现代码零迁移,A2 可在现有 25 编码上平滑扩展。
- 六类范围与 ScopeContext 一次建好,A3 只需实现 `CustomerDirectory` 与客户表,避免范围逻辑二次返工。
- 超管隐式全集避免新增权限点后超管缺权,减少权限事故。
- 权限目录代码化 + 启动同步,新增权限点无需手写迁移。
### 代价与约束
- 权限点命名保留 `read/write`,与开发计划附录 B 的 `view/manage` 不一致;后续文档引用以 `packages/shared` 为准,附录 B 需在下一版修订时对齐(不改语义)。
- A2 的 `客户组 / 负责客户 / 本人创建` 三类范围在 A3 前无可选目标,UI 需提供空态;A2 验收以解析引擎与 fake 客户目录单测为准,不等同于真实客户隔离验收。
- 「审计查看」作为特殊权限后,普通角色默认无法查看审计;符合 PRD「审计单独授权」原则。
- 权限点数(30)与 PRD 操作级粒度仍有差距,图片 / 视频生成等细分待 M1 前按需补充,遵循「只增不改」。
## 待办 / 回写
| 项 | 责任 | 时点 |
| --- | --- | --- |
| 开发计划附录 B 权限点表与 ADR-001 对齐(命名/增补) | 产品 / 架构 | A2 收口时 |
| 技术架构 §6.3 补 `role:view`、`customer_field:apply` 等编码说明 | 架构 | A2 收口时 |
| A3 实现 `CustomerDirectory` 真实客户目录并补范围验收 | 研发 | A3 |
| DP-14 两项特殊权限编码与架构回写 | 架构 | M2/M3 前 |
| 角色数量 / 超管数量建议值迁入 `system_configs` | 研发 | A4 |
| 审计落库、检索、导出 | 研发 | A5 |