feat: add tenant-scoped rule and permission management

This commit is contained in:
wren
2026-05-21 22:03:08 +08:00
parent a2c2bf1969
commit 1f1bccf3b3
193 changed files with 64463 additions and 1771 deletions
@@ -0,0 +1,531 @@
# 规则域多租户方案 A 实施计划
> 适用范围:`leaudit-platform` 新平台规则配置、评查组、规则版本、评查运行结果链路
> 方案结论:采用 `方案 A = 共享业务树 + 租户规则绑定 + 租户结果快照`
> 更新日期:2026-05-21
> 文档定位:把“规则域如何接入多租户”从概念方案落成可执行的修改计划,作为后续开发、联调、数据库迁移、验收的统一基线。
---
## 1. 定案结论
规则域本轮正式采用 `方案 A`,不直接做“每租户独立整棵业务树”,也不在第一阶段引入“租户扩展节点”。
当前统一口径如下:
1. `leaudit_evaluation_point_groups` 继续作为共享业务树
2. 租户差异主要放在:
- `leaudit_rule_sets`
- `leaudit_rule_versions`
- `leaudit_rule_group_bindings`
- `leaudit_audit_runs`
- `leaudit_rule_results / leaudit_run_errors / leaudit_run_metrics`
3. 运行时规则生效顺序固定为:
- `TENANT`
- `PROVINCIAL`
- `PUBLIC`
4. `tenant_code` 是唯一真实租户边界
5. `tenant_name` 只做展示与快照
6. `area / region / default / 公共 / 省级` 只允许留在兼容层与历史清洗层
---
## 2. 当前问题复盘
规则域目前不是“功能不可用”,而是“资产归属模型仍是全局共享思路”,因此天然不满足真正多租户隔离。
当前高风险点如下:
1. `leaudit_rule_sets` 仍缺 `tenant_code`
2. `leaudit_rule_versions` 仍缺租户快照
3. `leaudit_rule_group_bindings` 仍缺租户边界
4. `leaudit_audit_runs` 仍缺租户快照,导致结果链条没有稳定归属锚点
5. `leaudit_rule_results / leaudit_run_errors / leaudit_run_metrics` 只能靠 `run_id` 间接推断租户
6. `auditServiceImpl` 运行时按 `group_id` 取规则,但没有按租户选“当前生效规则”
7. `ruleServiceImpl` 仍以全局 `rule_type -> rule_set` 为主语义
这意味着:
1. 不同租户可能共用同一个规则集与版本链
2. 一个租户发布的新版本,可能直接影响另一个租户的运行结果
3. 规则结果报表、失败诊断、运行统计无法稳定按租户回溯
---
## 3. 方案 A 的边界定义
## 3.1 保持共享的部分
以下内容第一阶段继续共享:
1. 业务树:`leaudit_evaluation_point_groups`
2. 文档类型:`leaudit_document_types`
3. 入口模块与业务树的主挂载关系
共享的含义不是“不做租户控制”,而是:
1. 树结构本身平台统一维护
2. 哪些租户能看到哪些入口/业务节点,由可见性控制解决
3. 某业务节点下到底生效哪套规则,由租户绑定解决
## 3.2 租户化的部分
以下内容必须 tenant-first
1. 规则集归属
2. 规则版本归属
3. 业务组到规则集的绑定关系
4. 评查运行记录
5. 评查结果、错误、指标等衍生记录
## 3.3 暂不纳入第一阶段的部分
本轮明确不做:
1. 每租户复制整棵业务树
2. 租户自定义树层级结构
3. 树节点级继承编辑器
4. 租户扩展节点能力
这些能力只预留扩展位,不进入本轮交付范围。
---
## 4. 目标架构
规则域的目标链路收口为:
`文档(tenant_code) -> 共享业务树 group -> 按 tenant_code 解析生效 binding -> 命中 tenant/provincial/public 规则集 -> 锁定规则版本 -> 创建带租户快照的 audit_run -> 结果/错误/指标带租户快照落库`
核心设计点:
1. 业务树是“分类锚点”
2. 规则绑定是“租户差异入口”
3. `audit_run` 是“历史快照锚点”
4. 结果表是“查询与报表加速层”,不再只靠运行时 join 推断租户
---
## 5. 数据模型修改计划
## 5.1 `leaudit_rule_sets`
### 新增字段
1. `tenant_code VARCHAR(64) NULL`
2. `scope_type VARCHAR(32) NOT NULL DEFAULT 'PROVINCIAL'`
3. `source_rule_set_id BIGINT NULL`
4. `tenant_name_snapshot VARCHAR(255) NULL`
### 约束与索引
1. 索引:`idx_leaudit_rule_sets_tenant_code`
2. 索引:`idx_leaudit_rule_sets_scope_type`
3. 唯一索引建议调整为:
- `tenant_code + rule_type + deleted_at IS NULL`
-`COALESCE(tenant_code, '') + rule_type + deleted_at IS NULL`
### 语义
1. `TENANT`:租户私有规则集
2. `PROVINCIAL`:省级统一治理规则集
3. `PUBLIC`:真正公共资源域规则集
4. `source_rule_set_id`:租户规则集如果来自省级继承/复制,记录来源
## 5.2 `leaudit_rule_versions`
### 新增字段
1. `tenant_code_snapshot VARCHAR(64) NULL`
2. `scope_type_snapshot VARCHAR(32) NULL`
3. `source_version_id BIGINT NULL`
### 原则
1. 版本归属以创建时快照固化
2. 不允许完全依赖 join `rule_set` 才知道版本属于谁
## 5.3 `leaudit_rule_group_bindings`
### 新增字段
1. `tenant_code VARCHAR(64) NULL`
2. `scope_type VARCHAR(32) NOT NULL DEFAULT 'PROVINCIAL'`
3. `tenant_name_snapshot VARCHAR(255) NULL`
### 索引与约束
1. 索引:`idx_leaudit_rule_group_bindings_group_tenant`
2. 索引:`idx_leaudit_rule_group_bindings_scope_type`
3. 唯一索引调整为:
- `group_id + rule_set_id + COALESCE(tenant_code, '') + deleted_at IS NULL`
### 语义
同一个 `group_id` 可以同时存在:
1. 一个租户私有绑定
2. 一个省级绑定
3. 一个公共绑定
运行时按优先级解析,不再只看 `priority`
## 5.4 `leaudit_rule_type_bindings`
### 第一阶段处理原则
1. 不再作为新主链路真相来源
2.`tenant_code / scope_type` 仅用于兼容老接口与迁移脚本
3. 新平台运行与配置以 `leaudit_rule_group_bindings` 为准
## 5.5 `leaudit_audit_runs`
### 必补字段
1. `tenant_code VARCHAR(64) NULL`
2. `tenant_name_snapshot VARCHAR(255) NULL`
3. `scope_type_snapshot VARCHAR(32) NULL`
4. `group_id_snapshot BIGINT NULL`
5. `rule_binding_id_snapshot BIGINT NULL`
### 原因
`audit_run` 是整个历史追溯的锚点。
没有这层快照,后续规则换绑、租户改名、共享域清洗后,历史运行会失去稳定归属。
## 5.6 `leaudit_rule_results`
### 建议新增字段
1. `tenant_code VARCHAR(64) NULL`
2. `tenant_name_snapshot VARCHAR(255) NULL`
### 原则
虽然可以通过 `run_id` 反查,但结果表是高频列表、导出、统计来源,补快照能避免后续大量 join。
## 5.7 `leaudit_run_errors`
### 建议新增字段
1. `tenant_code VARCHAR(64) NULL`
2. `tenant_name_snapshot VARCHAR(255) NULL`
## 5.8 `leaudit_run_metrics`
### 建议新增字段
1. `tenant_code VARCHAR(64) NULL`
---
## 6. 历史数据回填策略
## 6.1 回填总原则
1. 现有规则资产默认回填为 `PROVINCIAL`
2. 不把现有全局规则直接回填成 `PUBLIC`
3. 历史 `region/default/公共/省级` 只作为映射依据,不作为新模型长期值
## 6.2 回填顺序
1. 先补字段与索引
2. 再给 `rule_sets / rule_versions / group_bindings` 回填省级归属
3. 再给 `audit_runs` 补租户快照
4. 最后给 `rule_results / run_errors / run_metrics` 做快照回填
## 6.3 回填映射口径
1. 原来全局共享规则集:回填 `tenant_code='PROVINCIAL'`
2. 原来 `default / 省级 / 省局`:统一映射到 `PROVINCIAL`
3. 原来真正公共资源:才回填 `PUBLIC`
---
## 7. 运行时解析修改计划
## 7.1 目标规则
运行时解析“某文档某分组到底用哪套规则”时,必须以文档 `tenant_code` 为第一主语义。
## 7.2 生效顺序
固定解析顺序:
1. 精确租户:`tenant_code = document.tenant_code`
2. 省级继承:`tenant_code = 'PROVINCIAL'`
3. 公共继承:`tenant_code = 'PUBLIC'`
即:
`TENANT -> PROVINCIAL -> PUBLIC`
## 7.3 修改点
文件:
- [auditServiceImpl.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/services/impl/auditServiceImpl.py)
需要改造:
1. `_resolve_rule_binding_from_group`
2. `_resolve_unique_group_binding_by_doc_type`
3. `Run`
目标:
1. 查询绑定时显式带入 `tenant_code`
2. 绑定结果返回:
- `binding_id`
- `binding tenant_code`
- `binding scope_type`
- `rule_set tenant_code`
3. 创建 `audit_run` 时直接写入租户快照与绑定快照
---
## 8. 后端改造任务拆分
## 8.1 `R1` 数据库迁移脚本
涉及:
1. 新增一套规则域迁移 SQL
2. 新增预检 SQL
3. 新增回填验证 SQL
建议文件:
1. `scripts/创建sql/schema_rule_domain_tenant_phase1.sql`
2. `scripts/创建sql/precheck_rule_domain_tenant_phase1.sql`
3. `scripts/创建sql/verify_rule_domain_tenant_phase1.sql`
交付目标:
1. 字段补齐
2. 索引补齐
3. 历史数据回填
4. 验证 SQL 可重复执行
## 8.2 `R2` 规则资产服务租户化
涉及文件:
1. [ruleServiceImpl.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/services/impl/ruleServiceImpl.py)
2. [ruleController.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/controllers/ruleController.py)
改造范围:
1. `ListSets`
2. `GetVersions`
3. `GetContent`
4. `CreateVersion`
5. `PublishRuleVersion`
6. `RollbackRuleVersion`
目标:
1. 规则集列表按当前租户 + 继承层展示
2. 创建新版本时,不再按全局 `rule_type` 命中资产
3. 发布/回滚只影响当前租户生效链
## 8.3 `R3` 业务组绑定租户化
涉及文件:
1. [evaluationPointGroupServiceImpl.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/services/impl/evaluationPointGroupServiceImpl.py)
2. [ruleGroupSupport.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/services/impl/ruleGroupSupport.py)
改造范围:
1. `ListBindings`
2. `CreateBinding`
3. `UpdateBinding`
4. `DeleteBinding`
5. `GetRuleTemplate`
6. `CreateRuleDraft`
目标:
1. 绑定表支持租户归属
2. 同组可见绑定区分:
- 本租户
- 继承省级
- 继承公共
3. 后台页面能识别“当前生效绑定来自哪里”
## 8.4 `R4` 运行链路租户化
涉及文件:
1. [auditServiceImpl.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/services/impl/auditServiceImpl.py)
2. [storage_adapter.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/leaudit_bridge/storage_adapter.py)
改造范围:
1. 运行时选规则
2. 创建 `audit_run`
3. 结果、错误、指标落库
目标:
1. 运行链路 tenant-first
2. 所有衍生记录带租户快照
3. 后续报表不再依赖复杂 join 推断
## 8.5 `R5` 规则配置页聚合租户化
涉及文件:
1. [ruleConfigServiceImpl.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/services/impl/ruleConfigServiceImpl.py)
目标:
1. `ListPackSummaries``GetPack` 按当前租户解析生效规则
2. 返回新增标准字段:
- `effectiveTenantCode`
- `effectiveScopeType`
- `isInherited`
- `sourceRuleSetId`
3. 页面能区分:
- 本租户私有规则
- 继承省级规则
- 继承公共规则
## 8.6 `R6` 鉴权与权限补齐
涉及文件:
1. [ruleController.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/controllers/ruleController.py)
2. [ruleConfigController.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/controllers/ruleConfigController.py)
3. [evaluationPointGroupController.py](/home/wren-dev/Porject/leaudit-platform/fastapi_modules/fastapi_leaudit/controllers/evaluationPointGroupController.py)
目标:
1. 所有规则域接口强制登录态
2. 功能权限校验与租户上下文透传统一化
3. 杜绝“裸接口 + 全局资产”的组合风险
---
## 9. 前端改造计划
## 9.1 规则配置页
目标:
1. 展示当前规则来源
2. 展示当前租户是否继承上层规则
3. 发布/回滚操作前明确告知影响范围
应补能力:
1. “当前生效租户域”标签
2. “继承来源”标签
3. “复制省级为租户私有规则”入口
## 9.2 评查组管理页
目标:
1. 共享业务树继续展示
2. 绑定列表显式展示租户域
3. 避免让用户误以为业务树已经按租户独立
## 9.3 历史兼容口径
前端主模型不再依赖:
1. `region`
2. `default`
3. 中文共享常量
前端应统一消费:
1. `tenant_code`
2. `tenant_name`
3. `scope_type`
4. `isInherited`
---
## 10. 验收矩阵
## 10.1 规则资产
1. 租户 A 创建规则版本,不影响租户 B 当前规则
2. 省级发布规则,未覆盖的租户自动继承
3. 已有租户私有规则的组,不再被省级发布直接覆盖
## 10.2 运行链路
1. 梅州文档运行时优先命中 `MZ`
2. `MZ` 无绑定时回退 `PROVINCIAL`
3. `PROVINCIAL` 无绑定时回退 `PUBLIC`
4. `audit_run` 落库后可直接看到租户快照
## 10.3 结果与报表
1. `rule_results` 可直接按 `tenant_code` 过滤
2. `run_errors` 可直接按 `tenant_code` 过滤
3. `run_metrics` 可直接按 `tenant_code` 聚合
## 10.4 页面行为
1. 规则配置页能显示“本租户规则 / 继承省级 / 继承公共”
2. 评查组绑定页能正确显示当前生效规则来源
3. 非当前租户用户不能修改本租户规则资产
---
## 11. 执行顺序
建议按下面顺序推进,不再交叉大爆改:
1. `R1` 数据库迁移脚本
2. `R4` 运行链路租户化
3. `R2` 规则资产服务租户化
4. `R3` 业务组绑定租户化
5. `R5` 规则配置页聚合租户化
6. `R6` 鉴权与权限补齐
7. 前端联调与发布级验收
执行原则:
1. 先补“数据真相字段”
2. 再改“运行时生效逻辑”
3. 最后改“后台配置与页面展示”
---
## 12. 风险与边界
## 12.1 高风险
1. `rule_type` 当前可能被多处假定为全局唯一
2. 历史运行结果回填需要保证与旧 `document.tenant_code` 一致
3. 省级与公共域清洗口径必须先定死,不能一边跑一边改
## 12.2 中风险
1. 前端若仍只展示“当前绑定”,用户会误判租户隔离是否生效
2. `rule_type_bindings` 老兼容链路如果不断回写,容易污染新模型
## 12.3 本轮不做
1. 不做租户扩展节点
2. 不做独立业务树
3. 不做历史规则资产自动差异合并
---
## 13. 最终交付定义
当以下 6 条同时满足时,规则域多租户方案 A 才算真正落地:
1. 规则集、规则版本、组绑定都有稳定 `tenant_code`
2. 运行时规则解析已改为 `TENANT -> PROVINCIAL -> PUBLIC`
3. `audit_run` 已带完整租户快照
4. `rule_results / run_errors / run_metrics` 已能直接按租户查询
5. 规则配置页能明确展示当前规则来源与继承关系
6. 发布级验收已证明不同租户互不串规则、互不串结果