# 权限架构全面优化改造方案

> 适用范围：`leaudit-platform` 当前“角色权限 + 地区隔离”体系  
> 目标：在不推翻现有 RBAC 表结构和已落地业务逻辑的前提下，把分散的权限判断、数据范围控制、菜单兼容逻辑收敛为一套可持续演进的平台化能力。

---

## 1. 结论先行

当前项目的权限架构不是“缺权限系统”，而是已经形成了比较清晰的主干：

- 认证层：`JWT + sso_users`
- 功能权限层：`roles / user_role / permissions / role_permissions`
- 菜单权限层：`sys_routes / role_route`
- 数据隔离层：`area + role/data_scope + 业务模块自定义过滤`

从现状看，项目的真实成熟度是：

- **功能权限成熟度较高**
- **菜单权限已基本成型，但仍有兼容 fallback**
- **数据范围权限设计完整，但平台统一执行能力不足**
- **部分模块已经自行实现范围控制，但实现风格不统一**

因此，本次改造**不建议推翻现有表设计重做**，而应采取“保留模型、统一执行、逐步收敛”的路径：

1. 保留现有 `RBAC + 单地区隔离` 总体模型
2. 新增统一的“数据范围解析器 + 查询过滤构建器”
3. 将业务模块里的手写 `is_global/can_manage/area/created_by` 逻辑逐步平台化
4. 逐步取消前后端路由 fallback，最终只认数据库路由与权限点
5. 将“管理能力”从角色硬编码逐步迁移到显式权限点驱动
6. 对 legacy 模块和特殊访问模型做分层治理，而不是强行一刀切

---

## 2. 当前代码架构全景

## 2.1 认证与登录态

当前 JWT 只保留鉴权链路所需的最小字段，不把完整 `roles/permissions` 写进 token。

关键实现：

- `fastapi_common/fastapi_common_security/jwtService.py`
- `fastapi_modules/fastapi_leaudit/services/impl/authServiceImpl.py`

已确认的行为：

- JWT 中保存：`user_id`、`username`、`area`、`user_role` 等最小身份信息
- 登录响应和 `/auth/me` 返回完整 `roles`、`permissions`
- 这样避免了权限过多导致前端 session/cookie 体积膨胀

这是合理设计，应保留。

## 2.2 RBAC 核心数据模型

当前权限核心表由 `scripts/创建sql/user_rbac_schema_patch.sql` 定义，结构完整，且和现有业务实现一致：

- `sso_users`
- `roles`
- `user_role`
- `sys_routes`
- `role_route`
- `permissions`
- `role_permissions`

其中最关键的设计语义是：

- 用户地区主字段：`sso_users.area`
- 角色默认数据范围：`roles.data_scope`
- 角色-权限点级数据范围：`role_permissions.data_scope`
- 拒绝优先机制：`role_permissions.grant_type = GRANT / DENY`
- `DEPT` 在本项目语义里其实是“同地区”，不是传统组织部门

这套模型本身没有明显结构性错误，问题主要出在“平台执行层不统一”。

## 2.3 后端功能权限校验

当前后端权限判断主要分两类：

1. 通用 permission 校验
2. 某些管理域额外加角色型上下文判断

关键实现：

- `fastapi_modules/fastapi_leaudit/services/impl/permissionServiceImpl.py`
- `fastapi_modules/fastapi_leaudit/services/impl/rbacAdminServiceImpl.py`

现状特点：

- `PermissionServiceImpl` 已支持：
  - 数据库动态查权
  - `DENY` 优先
  - wildcard 权限匹配
- 但它**只返回“有没有该权限点”**，**不解析 data_scope**

这意味着：

- 平台层只完成了“功能准入”
- 没完成“数据范围落地”

## 2.4 菜单与页面权限

当前菜单权限总体是数据库驱动，但仍带兼容降级逻辑。

关键实现：

- 后端：`fastapi_modules/fastapi_leaudit/services/impl/rbacServiceImpl.py`
- 前端：`legal-platform-frontend/lib/api/legacy/auth/user-routes.ts`
- 前端侧边栏：`legal-platform-frontend/components/layout/Sidebar.tsx`

现状行为：

- 后端优先从 `role_route + sys_routes` 生成当前用户路由树
- 若数据库路由集合未达到“前端真实路径集”的预期，则回退到 `_COMPAT_ROUTE_BLUEPRINTS`
- 前端仍保留静态 fallback menu 和本地权限 map 兼容逻辑

这说明系统已经向“数据库驱动权限菜单”演进，但尚未完全完成切换。

## 2.5 数据范围控制

当前数据范围控制最关键的事实是：

- **设计层已经有 data_scope**
- **平台层没有统一数据范围执行器**
- **业务层各模块自行实现范围过滤**

已确认的代表实现：

- 文档：`fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py`
- 公文：`fastapi_modules/fastapi_leaudit/services/impl/govdocServiceImpl.py`
- 统计：`fastapi_modules/fastapi_leaudit/services/impl/usageStatsServiceImpl.py`

这些模块大量采用类似逻辑：

- `is_global` => 全量
- `can_manage + area` => 本地区
- 普通用户 => `created_by/current_user_id`

这套逻辑本身没有错，但它是“业务重复实现”，不是“权限平台统一执行”。

## 2.6 特殊模块访问模型

项目里并非所有模块都纯粹按 `area + data_scope` 控制，存在三类特殊形态：

### 2.6.1 RAG 模块

关键实现：

- `fastapi_modules/fastapi_leaudit/services/impl/ragDatasetServiceImpl.py`
- `fastapi_modules/fastapi_leaudit/services/impl/ragChatServiceImpl.py`

访问特点：

- 管理侧按 `UserRole + UserArea` 控制可管理知识库范围
- 使用侧按 `area in (user_area, '省级', '') or is_public` 控制可见应用和知识库
- 这是一种“地区 + 公共可见”混合模型

### 2.6.2 交叉评查模块

关键实现：

- `fastapi_modules/fastapi_leaudit/services/impl/crossReviewServiceImpl.py`

访问特点：

- 主要按“任务成员关系”控制
- 用户是否能看任务、提案、投票、文档，核心依赖 `task_member`
- 这不是纯 area 访问模型，而是典型 ABAC/关系型访问模型

### 2.6.3 规则与规则配置模块

关键实现：

- `fastapi_modules/fastapi_leaudit/services/impl/ruleServiceImpl.py`
- `fastapi_modules/fastapi_leaudit/services/impl/ruleConfigServiceImpl.py`

访问特点：

- 更偏“配置域”和“元数据域”
- 当前更多依赖功能权限，不强依赖 area/data_scope
- 但与评查点分组、文档类型、入口模块存在管理域耦合

---

## 3. 当前架构的优点

## 3.1 主模型已经稳定

项目已经从复杂化、多地区、多入口的旧思路收敛到：

- 一个用户一个主地区
- 少量角色
- 菜单权限和动作权限分层
- 数据权限依赖地区和用户归属

这个方向是正确的。

## 3.2 功能权限表设计足够支撑未来扩展

当前 `permissions + role_permissions` 已经具备：

- API 权限点建模
- route 关联能力
- `GRANT / DENY`
- `data_scope`
- `condition_filter`

说明现有模型不是只能做静态角色，而是具备平台化扩展空间。

## 3.3 多个业务模块已经形成真实可用的数据隔离逻辑

虽然还不统一，但文档、公文、统计等核心模块已经不是裸奔状态。

这带来两个好处：

- 当前系统并非需要从零补安全
- 可直接抽象这些已验证逻辑，作为统一执行器的来源

## 3.4 登录态瘦身思路正确

JWT 只存最小字段、详细身份通过接口返回，这一点对后续权限扩展非常重要，应保持不变。

---

## 4. 当前关键问题与风险

## 4.1 最大问题：`data_scope` 已建模，但没有平台级统一执行

这是整个权限架构当前最大的结构性缺口。

现象：

- `roles.data_scope`、`role_permissions.data_scope` 已存在
- 但 `PermissionServiceImpl` 不返回 scope
- 业务层查询时拿不到统一 scope 解析结果
- 各业务模块只能自己写过滤逻辑

后果：

- 同一权限点在不同模块中可能出现不同数据边界
- 新模块开发时容易漏加范围过滤
- 审计和排查越权时需要逐模块人工追代码
- 无法形成统一测试基线

## 4.2 第二大问题：管理能力仍部分依赖角色硬编码

典型例子：

- `documentServiceImpl.py`
- `rbacAdminServiceImpl.py`
- `ragDatasetServiceImpl.py`

这些实现大量依赖：

- `role_key in ('super_admin', 'provincial_admin')`
- `role_key in ('super_admin', 'provincial_admin', 'admin')`

风险：

- 后续若新增“某领域管理员”或更细角色，代码要到处改
- 角色含义和权限含义耦合
- 难以实现真正的“显式授权优先”

## 4.3 菜单权限仍存在 fallback 路径

这会带来两个风险：

1. 数据库配置与前端实际展示不完全一致
2. “菜单看得见/看不见”与“数据库已授权/未授权”之间可能出现认知偏差

虽然 fallback 是合理的迁移兼容机制，但不应长期存在于最终架构中。

## 4.4 数据范围规则语义未彻底统一

当前系统里至少并存以下几种语义：

- `ALL / DEPT / SELF`
- `is_global / can_manage / is_super_admin`
- `area`
- `created_by`
- `owner`
- `public`
- `task_member`

这些语义没有错，但缺少统一分类：

- 哪些属于通用 scope
- 哪些属于模块级关系规则
- 哪些属于资源属性规则

这会使平台边界越来越模糊。

## 4.5 legacy 模块治理程度不一致

评查点、规则、旧库桥接模块仍带有比较重的历史包袱，典型风险包括：

- 仍依赖旧库结构
- 通过参数而不是统一 user context 控制 area
- 控制器层做了 permission 校验，但服务层范围收口不足

这种模块最容易成为越权和维护复杂度的来源。

## 4.6 缺少统一的权限可观测性

当前系统基本没有形成统一的：

- 权限命中日志
- data_scope 解析日志
- 被拒绝原因模型
- 权限矩阵巡检工具

结果是：

- 越权排查慢
- 权限配置错误定位难
- 测试覆盖很难自动化

---

## 5. 目标架构设计

## 5.1 总体原则

目标架构不是“把所有访问控制都压成一个万能函数”，而是分三层：

1. **功能权限层**
   - 判断用户能不能调用某个动作
2. **通用数据范围层**
   - 判断该动作默认可以看到哪些数据
3. **模块关系规则层**
   - 处理 `public`、`task_member`、`owner`、`state` 这类非通用访问规则

最终形成：

- RBAC 负责“能不能做”
- Scope Resolver 负责“默认能看多少”
- Module Policy 负责“该模块的特殊访问规则”

## 5.2 建议新增的核心组件

建议在后端新增一组统一能力：

### 5.2.1 `PermissionDecisionService`

职责：

- 输入：`user_id + permission_key`
- 输出：完整授权决策对象，而不是简单布尔值

建议返回：

- `allowed`
- `grant_source_roles`
- `grant_type`
- `effective_data_scope`
- `condition_filter`
- `is_super_admin`

### 5.2.2 `DataScopeResolver`

职责：

- 解析用户当前对某权限点的最终数据范围

规则建议：

1. 汇总用户所有命中角色
2. 处理 `DENY` 优先
3. 若权限点级 `data_scope` 存在，优先使用权限点级规则
4. 若不存在，回退到角色默认 `roles.data_scope`
5. 多角色命中时，对 `GRANT` 结果按最大可见范围求并集

建议统一优先级：

- `ALL > DEPT > SELF`

`GROUP` 当前仅保留兼容，不建议作为第一阶段重点。

### 5.2.3 `ScopeContextProvider`

职责：

- 统一加载当前用户上下文

建议提供：

- `user_id`
- `area`
- `roles`
- `is_super_admin`
- `is_global_admin`
- `is_area_admin`

注意：这里的 `is_global_admin/is_area_admin` 只是兼容派生属性，不能替代显式权限本身。

### 5.2.4 `QueryScopeBuilder`

职责：

- 把 scope 结果编译成 SQLAlchemy/SQL 过滤条件

建议能力：

- `apply_area_scope(table.region)`
- `apply_creator_scope(table.created_by)`
- `apply_owner_scope(table.owner_id)`
- `apply_union_scope(...)`
- `apply_public_fallback(...)`

这样业务模块不再自己拼接“同样一套 if/else”。

### 5.2.5 `ModulePolicy`

职责：

- 承接模块级特殊规则

例如：

- `CrossReviewPolicy`：任务成员可见
- `RagDatasetPolicy`：地区可见 + 公开资源可见
- `RuleConfigPolicy`：配置域权限，不强制 area

这一步非常关键，因为它避免把所有特殊访问规则硬塞进通用 data_scope。

---

## 6. 分层改造方案

## 6.1 认证层改造

### 保留

- JWT 只存最小身份字段
- 完整角色/权限通过 `/auth/me` 和登录响应返回

### 优化项

1. 增加统一身份上下文对象
2. 登录/鉴权后将 `user_id/area/user_role/roles` 统一注入请求上下文
3. 补充权限版本号或 identity revision 字段，便于缓存失效
4. 为 `/auth/me` 增加可观测字段：
   - `roles`
   - `permissions`
   - `primary_role`
   - `area`

### 不建议做的事

- 不建议把全部权限点重新塞回 JWT
- 不建议让前端自己根据角色推导数据范围

## 6.2 RBAC 模型层改造

### 保留

- 现有 7 张核心权限表

### 优化项

1. 明确 `DEPT` 在项目中的正式定义就是“同地区”
2. 明确 `GROUP` 仅兼容保留，除非有真实业务场景再启用
3. 为 `permissions` 增加更强的治理约束：
   - 命名规范
   - route 绑定规范
   - 是否参与 data_scope 控制
4. 为 `role_permissions` 制定使用规则：
   - 默认只用 `GRANT`
   - `DENY` 只用于少数高风险覆盖场景
   - `data_scope` 必须显式说明是否覆盖角色默认范围

### 建议新增字段

如后续需要，可增量补充：

- `permissions.scope_strategy`
  - `none`
  - `area`
  - `creator`
  - `owner`
  - `module_policy`
- `permissions.resource_code`
  - 标记该权限点对应的数据资源模型

这不是第一阶段必须项，但非常利于后续平台化。

## 6.3 权限决策层改造

建议把当前 `PermissionServiceImpl` 从：

- `CheckPermission(UserId, PermissionKey) -> bool`

扩展为：

- `GetPermissionDecision(UserId, PermissionKey) -> PermissionDecision`

旧布尔接口保留，作为新决策接口的简化包装。

建议新对象至少包括：

- `allowed`
- `effective_scope`
- `granted_by_roles`
- `denied_by_roles`
- `condition_filter`

这样业务代码就不再需要：

- 先查 permission
- 再自己查角色
- 再自己推导 scope

## 6.4 数据范围执行层改造

这是本次改造优先级最高的部分。

### 第一步：沉淀统一 scope 语义

统一三类通用 scope：

- `ALL`
- `DEPT`
- `SELF`

统一基础含义：

- `ALL`：不过滤地区/用户
- `DEPT`：按 `业务表地区字段 = 当前用户.area`
- `SELF`：按 `created_by / owner_id / uploaded_by = 当前用户.id`

### 第二步：沉淀统一查询构建器

把文档、公文、统计中已经重复出现的模式抽象出来，避免每个模块重复写：

- `if is_global`
- `if can_manage`
- `else current_user`

### 第三步：支持“通用 scope + 模块 policy”组合

例如：

- 文档：scope 直接决定
- RAG：scope + `is_public`
- 交叉评查：scope 不是主轴，改由 task-member policy 主导

## 6.5 前端权限消费层改造

目标是让前端变成“消费后端权限结果”，而不是“自己做权限解释器”。

### 改造目标

1. 前端菜单只消费后端 `/rbac/user/routes`
2. 前端不再长期依赖静态 fallback menu
3. `permission_map` 只作为缓存，不作为真相源
4. 页面级和按钮级权限统一从同一权限模型读取

### 渐进策略

1. 先补齐数据库路由集合
2. 再让后端 `GetCurrentUserRoutes` 永远走数据库分支
3. 最后删除前后端 fallback 蓝图和静态菜单

## 6.6 管理后台配置层改造

当前 RBAC 管理模块已经具备较强基础，但应继续完善为“可运营权限中心”。

建议新增或加强：

1. 角色数据范围可视化
2. 权限点是否覆盖角色默认范围的展示
3. 某角色最终可见菜单、权限点、scope 的预览
4. 某用户最终权限展开页
5. 权限冲突检测
6. 未绑定 route 的 permission 提示
7. 已配置但代码未消费的 permission 提示

---

## 7. 重点模块改造建议

## 7.1 文档模块

当前状态：

- 数据范围实现较成熟
- 逻辑已具备抽象价值

建议：

1. 把 `_getCurrentUserContext` 提升为公共能力
2. 把 `_buildDocumentScopeFilters` 抽到统一 `QueryScopeBuilder`
3. 文档列表、详情、历史版本、删除、评查结果全部统一走同一 scope 解析逻辑
4. 把 `created_by`、`region`、交叉评查任务访问拆成：
   - 通用文档 scope
   - 跨任务关系访问补充

目标：

- 文档模块作为第一批标准化样板模块

## 7.2 公文模块

当前状态：

- 与文档模块类似，也已有地区/用户过滤实现

建议：

1. 复用文档统一 scope builder
2. 不再保留模块私有版本的同构过滤逻辑
3. 把差异保留在字段映射层，而不是权限判断层

## 7.3 统计模块

当前状态：

- 已有 area/user/document 维度过滤
- 对数据口径一致性要求高

建议：

1. 明确“统计可见范围必须不大于源数据可见范围”
2. 所有统计查询先通过同一 scope resolver 得到可见边界
3. 再在统计 SQL 中应用该边界
4. 对 overview/trends/by-users/by-areas/details 建立统一基线测试

## 7.4 RAG 模块

当前状态：

- 使用了 `UserArea + UserRole + is_public`
- 具备自己的可见性模型

建议：

1. 把 RAG 归类为“area + public mixed policy”
2. 通用层负责给出：
   - 当前用户是否全省
   - 当前用户地区
   - 当前 permission 的基础 scope
3. RAG 模块 policy 再补：
   - `is_public = TRUE` 时的跨区可见
   - `'省级'`、空地区默认资源的可见规则
4. 后续将“是否可管理知识库”从角色硬编码逐步迁移到显式 permission 决策

目标：

- RAG 继续保留业务特性，但不再分散复制 `UserRole` 判断

## 7.5 交叉评查模块

当前状态：

- 主要按任务成员关系控制
- 属于关系型访问控制，不应生硬纳入 `ALL/DEPT/SELF`

建议：

1. 将其定义为独立 `CrossReviewPolicy`
2. `permission_key` 只决定用户能否进入该功能域
3. 具体资源访问由：
   - `task_member`
   - `assigner`
   - `principal`
   - `proposal_owner`
   等关系决定
4. 需要补充与文档主访问边界的关系定义：
   - 交叉评查任务中的文档是否可突破原始文档 `SELF`
   - 若可突破，突破边界必须仅限任务上下文

目标：

- 把交叉评查明确定位为“关系型权限域”，而不是强行纳入普通地区 scope

## 7.6 评查点 / 规则 / legacy 模块

当前状态：

- 部分实现仍偏 legacy
- 与旧库桥接较多
- 权限收口不够彻底

建议：

1. 先做权限与数据流梳理
2. 梳理所有入口：
   - 列表
   - 详情
   - 新增
   - 更新
   - 删除
   - 导入导出
3. 对每个接口明确：
   - 只需要功能权限
   - 还是还要 data_scope
4. 对旧库访问统一增加 user context 入参约束
5. 禁止仅依赖外部传入 `area` 参数作为最终数据边界

---

## 8. 管理权限治理方案

当前系统里“能否管理”仍较多通过角色推导：

- `provincial_admin`
- `admin`
- `super_admin`

建议分两阶段治理。

## 8.1 第一阶段

保留现有角色硬编码兼容判断，但所有新功能必须同时引入显式 permission。

即：

- 角色硬编码只作为兼容 guard
- 新方案以 permission 为主

## 8.2 第二阶段

将“管理能力”全面迁移为权限点驱动：

- `system:settings:manage`
- `rbac:role_permissions:write`
- `rag:dataset:manage`
- `rules:config:manage`

最终目标：

- “你是不是 admin”不再直接等于“你能不能管理 X”
- 改成“你是否拥有该领域管理权限”

---

## 9. 硬编码角色改造专项分析

这部分必须单独拿出来，因为它不是“代码风格问题”，而是当前权限架构演进时最大的联动风险来源之一。

当前项目中的角色硬编码，至少存在 4 种不同形态：

1. **服务层派生上下文硬编码**
2. **服务层直接放行业务动作硬编码**
3. **前端展示/编辑能力硬编码**
4. **前端 guard / fallback / role mapping 硬编码**

如果不把这 4 类拆开治理，只改其中一层，会出现“后端收敛了，前端仍按旧角色逻辑放大/缩小能力”的不一致问题。

## 9.1 已确认的后端硬编码角色热点

### A. 通用上下文派生型

这些地方不是直接判断某个 permission，而是先把角色硬编码推导为：

- `is_global`
- `can_manage`
- `is_super_admin`
- `bypass_area`

代表位置：

- `documentServiceImpl.py`
- `govdocServiceImpl.py`
- `usageStatsServiceImpl.py`
- `contractTemplateServiceImpl.py`
- `rbacAdminServiceImpl.py`
- `homeServiceImpl.py`

典型模式：

- `role_key IN ('super_admin', 'provincial_admin') => is_global`
- `role_key IN ('super_admin', 'provincial_admin', 'admin') => can_manage`
- `role_key = 'super_admin' => is_super_admin / bypass_area`

问题本质：

- 这是把“角色名称”直接当成“能力模型”
- 后续新增任意领域型管理员时，所有上下文派生代码都得重复修改

### B. RAG 管理动作直判型

代表位置：

- `ragDatasetServiceImpl.py`
- `ragChatServiceImpl.py`

典型模式：

- `UserRole not in ("provincial_admin", "admin", "super_admin")`
- `user_role == "provincial_admin"`
- `UserRole == "admin"`

问题本质：

- 控制器层已经有 permission 校验
- 服务层又追加了一层角色白名单校验
- 结果是“permission 允许但角色名不在白名单”时仍会被拒绝

这会直接阻断未来“非 admin 角色但拥有 RAG 管理权限”的扩展能力。

### C. 首页和特殊入口绕过型

代表位置：

- `homeServiceImpl.py`

典型模式：

- `super_admin` 直接 `bypass_area`

问题本质：

- 首页入口可见性实际上也属于权限结果的一部分
- 不应长期依赖单角色绕过

### D. 业务规则附带角色语义型

代表位置：

- `contractTemplateServiceImpl.py`

典型模式：

- 只有“地区管理员”可上传模板
- 但实现仍由 `can_manage/is_global/is_area_admin` 这类角色派生结果承担

问题本质：

- 这是典型“业务域管理能力”
- 应转换成合同模板域显式权限，而不是继续绑死在 admin/provincial_admin 上

## 9.2 已确认的前端硬编码角色热点

### A. RAG 知识库管理 UI

代表位置：

- `components/dify-dataset-manager/index.tsx`
- `components/dify-dataset-manager/area-dataset-config.tsx`
- `hooks/use-area-dataset-config.ts`

典型模式：

- `provincial_admin` 可编辑全部
- `super_admin` 可编辑全部
- `admin` 仅可编辑本地区
- `canManageDataset = roleCanManageDataset || permissionBased`

问题本质：

- 当前前端同时混用了“角色白名单”和“权限点判断”
- 即使后端后续去角色化，前端 UI 仍会保留旧角色语义

### B. 路由 fallback 与角色映射

代表位置：

- `legal-platform-frontend/lib/auth/user-routes.ts`
- `legal-platform-frontend/lib/api/legacy/auth/user-routes.ts`

典型模式：

- `provincial_admin -> admin`
- `super_admin -> admin`
- `developer -> admin`

问题本质：

- 这是典型迁移兼容代码
- 如果长期保留，会把真实角色体系压扁成前端的少数桶位

### C. 页面 guard

代表位置：

- `legal-platform-frontend/lib/auth/guard.ts`

典型模式：

- `developer` 或 `provincial_admin` 才能进入某些设置页

问题本质：

- 这是明显的角色名授权
- 应改成 route/permission 授权，不应继续靠用户主角色字符串

### D. 特殊入口可见性辅助逻辑

代表位置：

- `legal-platform-frontend/lib/auth/cross-checking-access.ts`

典型模式：

- `provincial_admin` 自动加入“省局” area 候选

问题本质：

- 这类逻辑属于“前端对后端权限模型的二次解释”
- 如果保留过多，会持续制造边界分叉

## 9.3 为什么这些硬编码不能直接一刀删除

因为它们承担的职责并不相同。

### 第一类：可立即替换

- 服务层“动作白名单式”角色判断
- 例如 RAG 管理接口中的 `UserRole not in (...)`

这类逻辑可以优先替换为：

- 控制器层 permission 决策
- 服务层 scope/policy 决策

### 第二类：需先抽象再替换

- `is_global`
- `can_manage`
- `is_super_admin`
- `is_area_admin`

这些并不是最终目标，但当前很多模块都依赖它们构建 SQL 过滤条件。

因此正确做法不是直接删掉，而是先把它们提升为统一上下文派生结果：

- `ScopeContextProvider`
- `AdminCapabilityResolver`

之后再逐步把其实现从“角色硬编码”替换为“权限/能力决策”。

### 第三类：应保留为兼容层，但必须收缩边界

- 前端 role mapping
- fallback menu
- 部分特殊入口兼容逻辑

这些逻辑在迁移期可以保留，但必须：

1. 标记为兼容层
2. 只允许出现在前端适配层
3. 不允许继续扩散到服务层和新功能

## 9.4 推荐改造策略

### 第一阶段：建立统一能力派生层

新增统一能力对象，例如：

- `is_super_admin`
- `has_global_scope`
- `can_manage_area_resources`
- `can_manage_rbac`
- `can_manage_rag_dataset`
- `can_view_usage_stats`

这些字段应由：

- `roles`
- `permissions`
- `data_scope`
- 可选 `condition_filter`

综合解析，而不是仅看 `role_key`。

### 第二阶段：逐模块替换服务层角色直判

优先顺序建议：

1. `ragDatasetServiceImpl.py`
2. `rbacAdminServiceImpl.py`
3. `homeServiceImpl.py`
4. `contractTemplateServiceImpl.py`
5. 文档/公文/统计共用上下文派生

### 第三阶段：前端去角色化

前端改造原则：

1. UI 可见性优先使用 permission
2. 可编辑性使用后端返回的 capability 或 policy 结果
3. `user_role` 只保留展示和极少数兼容用途
4. 不再让前端自行推导“谁是管理员”

## 9.5 不同硬编码的替换目标

建议按下表理解：

- `super_admin` 全局绕过
  替换为：`is_super_admin` capability，仅在极少数系统级接口保留
- `provincial_admin => is_global`
  替换为：`effective_scope == ALL`
- `admin => can_manage`
  替换为：领域型 manage permission + `effective_scope == DEPT`
- `common => self only`
  替换为：`effective_scope == SELF`
- `provincial_admin/super_admin/admin` 共同白名单
  替换为：某领域 `manage/create/update/delete` permission

这一步很关键，因为它把“角色名语义”拆成了“能力语义”。

---

## 10. 受影响接口与联动面分析

角色硬编码改造不会只影响几个 service，而会沿着“认证 -> 控制器 -> 服务层 -> 前端 UI -> 菜单/guard”整条链路传播。

因此必须提前识别影响面。

## 10.1 高影响后端接口组

### A. 文档模块

受影响接口包括但不限于：

- `POST /api/upload`
- `GET /api/documents/list`
- `GET /api/documents/status`
- `GET /api/documents/{DocumentId}`
- `GET /api/v3/review-points/{DocumentId}`
- `PATCH /api/v3/review-points/{ReviewPointResultId}/audit`
- `PATCH /api/v3/documents/{DocumentId}/confirm`
- `POST /api/documents/{DocumentId}/attachments`
- `PUT /api/documents/{DocumentId}`
- `DELETE /api/documents/{DocumentId}`

影响原因：

- 这些接口都依赖文档服务里的用户上下文派生和范围过滤
- 一旦 `is_global/can_manage` 计算方式改变，所有文档读写边界都会联动变化

### B. 公文模块

受影响接口包括但不限于：

- `POST /api/govdoc/documents`
- `GET /api/govdoc/documents`
- `GET /api/govdoc/documents/{documentId}`
- `PATCH /api/govdoc/documents/{documentId}`
- `DELETE /api/govdoc/documents/{documentId}`
- `POST /api/govdoc/runs`
- `GET /api/govdoc/runs/{runId}`
- `GET /api/govdoc/runs/{runId}/result`
- `GET /api/govdoc/runs/{runId}/findings`
- `GET /api/govdoc/runs/{runId}/entities`
- `GET /api/govdoc/runs/{runId}/structure`
- `GET /api/govdoc/runs/{runId}/outline`
- `GET /api/govdoc/runs/{runId}/paragraphs`
- `GET /api/govdoc/runs/{runId}/report/html`
- `GET /api/govdoc/runs/{runId}/report/docx`
- `GET /api/govdoc/documents/{documentId}/original`

影响原因：

- 公文模块沿用了与文档模块相似的范围控制模型
- run/result/report 等接口如果没有统一回挂到 document scope，容易出现“知道 runId 就能读结果”的风险

### C. 统计模块

受影响接口包括：

- `GET /api/v3/usage-stats/overview`
- `GET /api/v3/usage-stats/trends`
- `GET /api/v3/usage-stats/by-users`
- `GET /api/v3/usage-stats/by-departments`
- `GET /api/v3/usage-stats/by-areas`
- `GET /api/v3/usage-stats/details`

影响原因：

- 当前统计服务对“只有管理员可看”存在上下文派生逻辑
- 如果未来改成 permission 决策，统计域会是最先受影响的读接口集合之一

### D. RAG 模块

受影响接口包括：

- `GET /api/v3/rag/apps`
- `GET /api/v3/rag/apps/default`
- `GET /api/v3/rag/datasets/my`
- `GET /api/v3/rag/datasets/admin`
- `POST /api/v3/rag/datasets/admin`
- `PUT /api/v3/rag/datasets/admin/{DatasetId}`
- `DELETE /api/v3/rag/datasets/admin/{DatasetId}`
- `GET /api/v3/rag/datasets/{DatasetId}`
- `PATCH /api/v3/rag/datasets/{DatasetId}`
- 以及数据集文档、分段、检索测试等一系列 `/datasets/{DatasetId}/...` 接口
- `POST /api/v3/rag/chat/messages`
- 会话相关接口

影响原因：

- 控制器层已经按 permission 放行
- 服务层仍按 `UserRole` 二次限流
- 这是最典型的“双轨权限模型冲突”区域

### E. RBAC 管理模块

受影响接口包括：

- `GET /api/v3/rbac/roles`
- `POST /api/v3/rbac/roles`
- `PUT /api/v3/rbac/roles/{RoleId}`
- `DELETE /api/v3/rbac/roles/{RoleId}`
- `GET /api/v3/rbac/users`
- `GET /api/admin/users/organizations/tree`
- `GET /api/v3/rbac/roles/{RoleId}/users`
- `POST /api/v3/rbac/users/{UserId}/roles`
- `DELETE /api/v3/rbac/users/{UserId}/roles/{RoleId}`
- `GET /api/v3/rbac/users/{UserId}/roles`
- `GET /api/v3/routes`
- `GET/PUT /api/rbac/roles/{RoleId}/routes`
- `GET/POST /api/v3/rbac/role-permissions`
- `POST /api/v3/rbac/roles/{RoleId}/access`
- `GET /api/v3/routes/{RouteId}/permissions`

影响原因：

- 当前先 `_assertManagePermission`，再 `_assertPermission`
- 其中 `_assertManagePermission` 仍依赖角色派生 `can_manage`
- 未来若不调整，会出现“拥有 RBAC 写权限但不是 admin 角色”仍被拒绝的问题

### F. 首页入口模块

受影响接口：

- `GET /api/home/entry-modules`

影响原因：

- 首页可见入口当前含 `super_admin` 的 area bypass 语义
- 改动后会影响首页模块展示和交叉评查入口暴露范围

### G. 合同模板模块

受影响接口包括：

- `GET /api/v3/contract-templates/categories`
- `GET /api/v3/contract-templates`
- `POST /api/v3/contract-templates`
- `GET /api/v3/contract-templates/search`
- `GET /api/v3/contract-templates/{TemplateId}`
- `DELETE /api/v3/contract-templates/{TemplateId}`

影响原因：

- 业务文案和服务层逻辑都在强调“地区管理员才能上传”
- 这类业务域权限必须显式建模，否则角色去硬编码后会发生语义漂移

## 10.2 中影响后端接口组

### A. 交叉评查控制器

控制器层目前主要通过 permission 做功能准入，再由服务层按 task-member 关系控权。

受影响点：

- 若未来新增“交叉评查协调员”等角色
- 控制器层 permission、服务层关系权限、前端入口策略三者都要同步

### B. 评查点 / 评查点分组 / 规则配置

这些模块当前更多是 permission 驱动，但仍存在：

- OR 型 permission 校验
- 路由 fallback
- 某些 legacy 行为仍按旧角色认知理解的隐患

这类模块短期不一定要先改，但必须纳入联调验证范围。

## 10.3 前端受影响面

### A. 菜单与路由

受影响位置：

- `Sidebar.tsx`
- `user-routes.ts`
- `check-route-permission.ts`
- route fallback mapping

改造后可能出现的联动：

- 某些角色映射桶失效
- fallback 菜单与真实 route-permission 不一致
- 页面可见但接口被拒绝，或页面不可见但后端已授权

### B. 知识库管理相关页面

受影响位置：

- `components/dify-dataset-manager/*`
- `hooks/use-area-dataset-config.ts`

改造后必须改为：

- 以后端返回的 permission/capability 作为真相源
- 不能继续由前端自己判定“你是不是省级管理员”

### C. 页面 guard 和 session typing

受影响位置：

- `lib/auth/guard.ts`
- `lib/auth/session-user.ts`
- `lib/auth/jwt.ts`

改造重点：

- `user_role` 类型定义不能继续隐式代表完整能力模型
- guard 逻辑要逐步转成 permission 驱动

## 10.4 最容易遗漏的影响点

有 4 类点最容易在改造时被漏掉：

1. **服务层动作二次校验**
   典型如 RAG：控制器已查 permission，但服务层又按角色拒绝
2. **只读接口的资源详情/下载接口**
   典型如公文的 report/docx/original 下载
3. **首页和入口模块可见性**
   这类功能通常不在权限改造 checklist 里，但实际也是访问控制
4. **前端本地缓存的 permission_map / user_role**
   后端改完，前端缓存解释逻辑若不改，会出现脏权限体验

## 10.5 推荐联动改造顺序

为了降低波及风险，建议按下面顺序推进：

1. 先改后端统一决策层，不动前端行为
2. 接入 RAG 服务层，消除“permission 通过但角色名拒绝”的双轨冲突
3. 接入文档/公文/统计通用 scope
4. 接入 RBAC 管理域 `_assertManagePermission`
5. 接入首页入口与合同模板这类特殊管理域
6. 最后清理前端角色映射、UI 角色判断和 guard

这样可以避免一开始就同时触碰：

- 数据边界
- 功能权限
- 菜单展示
- 页面 guard

导致联调失控。

## 10.6 额外建议：建立“角色去硬编码回归清单”

建议在实际实施时，单独维护一份回归清单，至少覆盖：

- 某用户有 permission 但主角色不是 `admin/provincial_admin` 时，是否仍可正确访问
- 某用户被赋予新领域管理角色后，是否无需改代码即可生效
- 某用户菜单、按钮、接口、详情、下载、导出是否边界一致
- 前端是否仍存在基于 `user_role` 的旧判断把能力放大或缩小

---

## 11. 数据库迁移方案

## 9.1 第一阶段可不改表，仅改执行层

这是最推荐的路径。

先做：

- 新增决策服务
- 新增 scope resolver
- 新增 query builder
- 业务模块接入

在这一步，现有表足够使用。

## 9.2 第二阶段再做增强字段

若后续希望更强平台能力，再增量考虑：

- `permissions.scope_strategy`
- `permissions.resource_code`
- `permissions.policy_code`
- `role_permissions.scope_override_reason`

这些字段用于治理和解释，不是首批必要项。

## 9.3 数据迁移原则

1. 不删除旧字段
2. 不重命名核心字段
3. 先兼容运行，再切换调用方
4. 所有新增字段默认 nullable，避免一次性大面积回填风险

---

## 12. 渐进式实施路径

## 10.1 Phase 1：统一决策能力

目标：

- 先把平台底座搭好

交付：

- `PermissionDecisionService`
- `DataScopeResolver`
- `ScopeContextProvider`
- `QueryScopeBuilder`

收益：

- 新老模块都可开始接入

## 10.2 Phase 2：样板模块接入

建议顺序：

1. 文档
2. 公文
3. 统计

原因：

- 这三类模块已经有成熟范围逻辑
- 抽象收益最高
- 改造风险相对可控

## 10.3 Phase 3：菜单权限彻底数据库化

目标：

- 删除路由 fallback
- 删除静态菜单兼容

前提：

- 数据库路由集合补齐
- 权限点-route 映射完整

## 10.4 Phase 4：特殊模块治理

建议顺序：

1. RAG
2. 交叉评查
3. 评查点/规则/legacy 桥接模块

目标：

- 形成“通用 scope + 模块 policy”模式

## 10.5 Phase 5：治理与可观测性

补齐：

- 权限命中日志
- 越权拒绝原因
- 权限矩阵导出
- 自动化巡检任务

---

## 13. 测试与验收方案

## 11.1 必做测试矩阵

每个核心权限点至少覆盖以下用户组合：

- `super_admin`
- `provincial_admin`
- `admin`
- `common`
- 多角色用户
- 无 area 用户
- 被禁用用户

每个资源至少覆盖以下数据组合：

- 同地区数据
- 异地区数据
- 自己创建数据
- 他人创建数据
- 公共数据
- 关系型共享数据

## 11.2 必做接口验收

至少覆盖：

- 登录与 `/auth/me`
- 菜单获取
- 文档列表/详情/历史/删除
- 公文列表/详情
- 统计总览/趋势/明细
- RAG 应用/知识库
- 交叉评查任务/提案/投票
- RBAC 管理台

## 11.3 必做回归断言

1. 有 permission 但无 scope 不应越权看全量
2. 菜单可见不等于接口可调用，接口仍需后端鉴权
3. 仅知道资源 ID 不应绕过数据范围校验
4. 跨模块聚合查询不能扩大原始资源可见范围
5. `DENY` 必须稳定优先于 `GRANT`

## 11.4 建议增加自动化

建议建立：

- permission fixture
- user-role fixture
- region fixture
- resource ownership fixture

让权限测试不再依赖手工造数。

---

## 14. 风险与回滚方案

## 12.1 主要风险

1. 抽象过度，导致特殊模块被错误套入通用逻辑
2. 改造过程中菜单和接口权限短期不一致
3. scope 规则切换后产生历史行为变化
4. 多角色并集规则理解不一致，导致边界扩大或缩小

## 12.2 风险控制

1. 先在样板模块试点，不直接全量切
2. 新旧逻辑并行一段时间，输出对比日志
3. 为关键接口加“旧逻辑 vs 新逻辑” shadow compare
4. 管理台提供用户最终权限预览

## 12.3 回滚策略

1. 决策服务接入采用开关控制
2. 模块级按 feature flag 切换
3. 菜单 fallback 在数据库路由完全稳定前不删除
4. 新增字段不影响旧逻辑运行

---

## 15. 推荐实施排期

## 第 1 周

- 完成权限现状盘点和权限点清单冻结
- 设计 `PermissionDecisionService` 和 `DataScopeResolver`
- 输出统一 scope 规则说明

## 第 2 周

- 落地统一决策与查询构建器
- 接入文档模块
- 建立第一批自动化权限测试

## 第 3 周

- 接入公文与统计模块
- 补齐管理台权限预览能力
- 开始新旧逻辑对比日志

## 第 4 周

- 接入 RAG
- 梳理交叉评查 policy
- 补齐数据库路由集合

## 第 5 周

- 切换菜单只走数据库路由
- 处理 legacy 规则/评查点模块
- 清理前端 fallback

## 第 6 周

- 全量回归
- 安全测试
- 观察期与灰度发布

---

## 16. 最终推荐方案

如果只给出一条最重要的改造主线，我的建议是：

**不要推翻现有 RBAC 结构，优先补齐统一的数据范围执行平台。**

更具体地说，正确的改造顺序应该是：

1. 先保留现有 `sso_users/roles/permissions/routes` 模型
2. 把 `data_scope` 从“设计字段”变成“统一可执行能力”
3. 把文档、公文、统计里的重复数据范围逻辑抽成平台底座
4. 把 RAG、交叉评查这类特殊模块归入独立 policy，而不是粗暴并表
5. 最后再清理菜单 fallback 和角色硬编码

这样做的收益最大：

- 改造风险最低
- 与现有代码最兼容
- 能最快提升一致性和安全性
- 能为后续模块扩展提供稳定底座

---

## 17. 建议立项清单

建议把后续工作拆成 8 个明确任务：

1. 建立权限决策对象与统一接口
2. 实现 data_scope 解析器
3. 实现通用查询 scope builder
4. 文档模块接入统一 scope
5. 公文与统计模块接入统一 scope
6. RAG / 交叉评查 policy 化
7. 数据库路由补齐并移除 fallback
8. 建立权限可观测性与自动化测试矩阵

这 8 项完成后，当前项目的角色权限架构就会从“可用但分散”，升级为“稳定、统一、可治理、可演进”的平台化体系。
