You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

64 lines
4.2 KiB

4 weeks ago
# 01 · 模块注册模型:模块怎么存、表怎么归属到模块
Type: grilling
Status: resolved
## Question
数据权限的「业务模块」(线索/商机/客户/项目,可扩展)在系统里以什么形式存在,
受控表(`OwnedEntity` + `@DataScope`)又如何归属到某个模块?
要定的点:
- 模块本身存哪:新建字典/注册表(如 `sys_data_scope_module`:id, code, name, sort),
还是复用 `crm-dict`,还是别的?「可扩展」要求它数据驱动,不能把四个模块写死在枚举里。
- 表→模块的关联方向:
- A:`@DataScope` 注解上加 `module` 属性,实体自报家门;
- B:模块注册表里登记「本模块含哪些表名」;
- C:其他。
- 一个模块含多张表(如「客户」含客户+联系人+跟进记录)共享同一档——关联模型要支持一对多。
- 未标模块 / 未接入模块的受控表如何处理(沿用某默认档?不过滤?拒绝启动?)。
这是整张地图的地基,后续存储/计算/上下文/拦截器都依赖它先定。
## Answer
### 1. 模块注册表:专用注册表 `sys_data_scope_module`
新建表,字段:`id` / `code`(全局唯一,稳定标识,如 `lead`/`opportunity`/`customer`/`project`)/ `name`(展示名)/ `sort` / `status`(enabled/disabled)/ `builtin`(boolean,内置模块不可删除)。
- 模块列表数据驱动,管理员通过端点 CRUD,不写死在枚举/代码里。
- `code` 是稳定标识——注解和角色配置都引用 `code`,不引用 `id`
- `builtin=true` 的模块由初始化脚本导入,不可删除(可改 name/sort/启停),与 `SysRole.builtin` 语义一致。
### 2. 表→模块关联:`@DataScope` 注解加 `module` 属性(实体自报)
注解新增 `String module()`,**无默认值(必填)**:
```java
@DataScope(module = "customer", ownerColumn = "owner_id", deptColumn = "dept_id")
public class Customer extends OwnedEntity { ... }
```
- 启动扫描时 `PermissionConfig` 建表 table→(moduleCode, ownerColumn, deptColumn) 映射。
- 与 ownerColumn/deptColumn 同源,不引入第二处事实来源。
- 一个模块含多张表(如「客户」含客户+联系人+跟进记录):多个实体标同一 `module` code 即可,拦截器按表名查到模块后取同一份 `VisibilityScope`。无需额外机制。
### 3. 未标模块 / 注册表查不到:module 必填 + 拒绝启动
- `@DataScope``module` 属性为必填(编译期无默认值)。
- 启动扫描时 `PermissionConfig` 校验:每个 `@DataScope` 注解的 `module` code 必须在 `sys_data_scope_module` 注册表里存在。
- 校验失败 → 抛异常,拒绝启动(与 ADR-0006「不存在设了一半」一致)。
### 对下游工单的影响
- **02(存储)**:角色对每个模块的档位建议存 `sys_role_data_scope(role_id, module_code, data_scope)`——module 用 `code`(string)引用而非 `id`,与 crm-dict「业务数据只存字典编码」的约定一致。角色对某模块未配档位时的默认语义、CUSTOM(5) 是否保留等由 02 定。
- **04(上下文值对象)**:`DataVisibilityContext` 从放一份 `DataVisibility` 变为放 `module code → DataVisibility` 的映射。部门集合/子树展开只算一次、各模块档位复用(部门集合不随模块变)。
- **05(拦截器)**:`DataScopeInterceptor` 查表名 → 拿 module code → 从上下文取该模块的 `VisibilityScope` → 注入 SQL。`PermissionResolverImpl.resolve` 对每个模块各自在所有角色的该模块档位里取最宽。
- **03(迁移)**:现有 `sys_role.data_scope` 单列需迁移到新存储(具体规则由 03 定,依赖 02)。
- **06(写侧)**:写侧 owner/dept 填充与档位无关,不受模块概念影响,待 06 票确认。
### 新增域术语
- **数据权限模块**:数据权限按业务模块分别配置时的「业务模块」概念,存在于 `sys_data_scope_module` 注册表中,用 `code` 标识。一个角色对每个模块各有一档数据范围档位,多角色对每个模块各自取最宽。模块可由管理员扩展(数据驱动),受控实体通过 `@DataScope(module = "...")` 注解声明所属模块。