# 地区到租户编码映射清洗清单

> 适用范围：当前系统中 `area / region / 省局 / 省级 / default / 空字符串 / tenant_name` 混合使用的历史数据治理  
> 文档定位：给后续数据库清洗、兼容脚本、接口兼容层和测试验收提供一份可执行的“历史值归一清单”。

---

## 1. 结论先行

当前系统如果直接上 `tenant_code`，但不先做历史值映射清洗，会立刻出现三类问题：

1. 同一租户在不同表里仍然无法匹配
2. 首页入口、RAG、模板、文档等模块会出现“配置了但看不到”
3. 统计和权限执行器会因为历史脏值继续分裂

所以租户化改造的第一前提不是写新表，而是先收口旧值。

---

## 2. 当前确认存在的历史值类型

按目前代码和 SQL 已确认的高风险值如下。

## 2.1 地方租户值

1. `梅州`
2. `云浮`
3. `揭阳`
4. `潮州`

## 2.2 省级 / 公共语义值

1. `省局`
2. `省级`
3. `default`
4. `''`

## 2.3 展示或组织补充字段

1. `tenant_name`
2. `dep_name`
3. `ou_name`

这些值目前在部分前端逻辑里被拿来反推地区。

---

## 3. 推荐标准租户编码

建议先建立一套稳定编码：

| 现展示值 | 推荐 tenant_code | tenant_type | 说明 |
| --- | --- | --- | --- |
| 梅州 | `MZ` | `LOCAL` | 地市租户 |
| 云浮 | `YF` | `LOCAL` | 地市租户 |
| 揭阳 | `JY` | `LOCAL` | 地市租户 |
| 潮州 | `CZ` | `LOCAL` | 地市租户 |
| 省局 | `PROVINCIAL` | `HEADQUARTER` | 省局管理租户 |
| 公共资源域 | `PUBLIC` | `PUBLIC` | 跨租户公共资源，不建议继续用中文值 |

说明：

1. `PROVINCIAL` 表示省局这个租户主体
2. `PUBLIC` 表示真正公共资源域
3. 以后不要再让 `省局` 既表示租户又表示公共范围

---

## 4. 历史值映射规则

## 4.1 推荐映射表

建议如下：

| 历史值 | 归一 tenant_code | 处理说明 |
| --- | --- | --- |
| `梅州` | `MZ` | 直接映射 |
| `云浮` | `YF` | 直接映射 |
| `揭阳` | `JY` | 直接映射 |
| `潮州` | `CZ` | 直接映射 |
| `省局` | `PROVINCIAL` | 表示省局租户主体 |
| `省级` | `PUBLIC` 或 `PROVINCIAL` | 需按业务字段判定，不能一刀切 |
| `default` | `PUBLIC` | 仅限公共兜底语义，不应映射成省局主体 |
| `''` | `PUBLIC` 或 `UNKNOWN` | 需分场景处理 |
| `NULL` | `PUBLIC` 或 `UNKNOWN` | 需分场景处理 |

## 4.2 为什么 `省级` 不能一刀切

`省级` 在当前系统至少有两种含义：

1. 省局主体租户
2. 全省公共资源

例如：

1. 合同模板里的 `省级` 更接近公共模板域
2. 某些角色或用户语义里的“省级管理员”更接近省局主体

所以 `省级` 必须结合表和业务语义判断，不能直接全量更新成一个值。

---

## 5. 按表清洗策略

## 5.1 `sso_users`

重点字段：

1. `area`
2. `tenant_name`

建议：

1. 新增 `tenant_code`
2. 先根据 `area` 映射
3. `area` 为空时再尝试依据 `tenant_name`
4. 仍无法识别的写入 `UNKNOWN` 或留空待人工处理

人工复核重点：

1. `area` 为空但 `tenant_name` 不为空
2. `area` 和 `tenant_name` 语义冲突
3. 一个 `tenant_name` 对应多个 `area`

## 5.2 `leaudit_documents`

重点字段：

1. `region`

建议：

1. `default` 先归到 `PUBLIC`
2. 地方地区名直接归到对应 `tenant_code`
3. 不可识别值进入人工复核表

## 5.3 `contract_templates`

重点字段：

1. `region`

建议：

1. `省级` 默认优先解释为 `PUBLIC`
2. 如果后续明确部分模板实际是省局内部专属，再单独调整为 `PROVINCIAL`

原因：

合同模板当前更接近“公共模板库”模型。

## 5.4 `rag_dataset` / `rag_chat_app`

重点字段：

1. `area`
2. `is_public`
3. `is_default`

建议：

1. 地方地区名直接映射
2. `area=''` 且 `is_public=true` 的，映射到 `PUBLIC`
3. `area='省级'` 的记录，默认映射到 `PUBLIC`
4. `is_default=true` 不代表公共，只代表默认应用/默认知识库

## 5.5 `leaudit_entry_modules`

重点字段：

1. `areas JSONB`

建议：

1. 逐个 `area` 元素映射到标准 `tenant_code`
2. 保留原始 JSON 快照供审计
3. 后续写入迁移到关系表，不再长期依赖原 JSON

---

## 6. 代码级归一规则

## 6.1 所有输入都必须先归一

后续后端收到以下字段时，都必须先走统一归一函数：

1. `area`
2. `region`
3. `tenant_name`
4. 前端传入的入口模块租户列表
5. RAG/模板筛选条件

建议统一函数签名：

```python
resolve_tenant_code(raw_value: str | None, context: str) -> str | None
```

其中 `context` 用于区分：

1. `user_area`
2. `document_region`
3. `template_region`
4. `entry_module_area`
5. `rag_area`

## 6.2 严禁前端继续做别名猜测

当前前端 `cross-checking-access.ts` 会用：

1. `includes("梅州")`
2. `includes("省")`
3. `provincial_admin => 省局`

这种逻辑必须下线，原因是：

1. 新租户名字不一定包含旧关键字
2. 展示名称变化会导致功能失效
3. 前端无法承担主数据归一责任

---

## 7. 推荐清洗脚本步骤

## 7.1 第一步：盘点唯一值

先导出下列字段的唯一值和数量：

1. `sso_users.area`
2. `sso_users.tenant_name`
3. `leaudit_documents.region`
4. `contract_templates.region`
5. `rag_dataset.area`
6. `rag_chat_app.area`
7. `leaudit_entry_modules.areas[].area`

## 7.2 第二步：生成映射表

生成一张临时对照表：

1. `raw_value`
2. `source_table`
3. `sample_count`
4. `proposed_tenant_code`
5. `review_status`
6. `review_comment`

## 7.3 第三步：区分自动映射和人工复核

自动映射：

1. `梅州`
2. `云浮`
3. `揭阳`
4. `潮州`
5. `省局`
6. `default`

人工复核：

1. `省级`
2. 空值
3. 复合字符串
4. 未知中文别名
5. 组织名称形式的 `tenant_name`

## 7.4 第四步：回写标准字段

为业务表新增 `tenant_code` 后，按映射结果批量回写。

## 7.5 第五步：保留审计痕迹

必须保留：

1. 原始字段值
2. 映射规则版本
3. 清洗时间
4. 执行人
5. 人工修正记录

---

## 8. 重点风险清单

## 8.1 `default` 不能全量等于 `PROVINCIAL`

当前 `default` 更多是“兜底公共范围”，不是“省局租户”。

如果错误映射为 `PROVINCIAL`，会造成：

1. 公共资源被省局独占
2. 非省局租户看不到原本可见的内容

## 8.2 `省级` 不能在所有表中同义

因为它在不同业务里承担的不是同一个概念。

## 8.3 `tenant_name` 不能直接等于 `tenant_code`

`tenant_name` 是展示或组织分组名称，数据质量不一定可控。

## 8.4 入口模块 JSON 最容易残留旧值

因为它不是结构化关系表，清洗后仍可能被旧接口再次写入脏数据。

---

## 9. 推荐验收清单

清洗完成后至少要验证：

1. 每个用户都有可解析的 `tenant_code`
2. 每个入口模块的租户分配都能映射到有效主数据
3. RAG 数据集不会再出现 `''`、`省级`、`default` 混杂
4. 合同模板的公共模板不会因为映射错误被隐藏
5. 首页入口可见性在旧租户和新租户下都正确
6. 统计地区维度不会同时出现 `梅州` 和 `MZ` 两套口径

---

## 10. 本文档解决什么问题

本文档主要解决：

1. 历史地区值具体怎么映射到租户编码
2. 哪些字段必须清洗
3. 哪些旧值可以自动处理
4. 哪些旧值必须人工复核
5. 为什么租户主数据改造前必须先做这一步

建议联动阅读：

1. [租户主数据模型设计.md](/home/wren-dev/Porject/leaudit-platform/docs/权限与地区隔离/租户主数据模型设计.md)
2. [地区租户化与自定义租户扩展改造方案.md](/home/wren-dev/Porject/leaudit-platform/docs/权限与地区隔离/地区租户化与自定义租户扩展改造方案.md)
3. [自定义租户功能连带影响深度补充.md](/home/wren-dev/Porject/leaudit-platform/docs/权限与地区隔离/自定义租户功能连带影响深度补充.md)
