Files
Neo-ZQYY/docs/database/BD_manual_biz_registry_tables.md
Neo 70324d8542 chore: 文档与 IDE 配置整理
- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro)
- CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/
- 新增 /spec-close、/pre-change 两个工作流命令
- DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表)
- BD_Manual → BD_manual 命名统一(48 个文件)
- 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数)
- 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表)
- 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档)
- docs/database/README.md 索引更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:02:37 +08:00

255 lines
9.9 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.
# BD 手册biz 注册体系表NS4.1 registry
## 概述
NS4.1 注册体系新增 4 张表,全部位于 `biz` Schema建立「连接器 → 租户 → 店铺」三级注册体系。合并原 `auth.site_code_mapping`,统一管理上游 SaaS 系统、租户和店铺的关系并为简写ID 提供归属和变更历史。
所有表位于 `zqyy_app` / `test_zqyy_app` 数据库。
## 变更原因
- NS4.1 注册体系设计,建立项目级「连接器 → 租户 → 店铺」三级结构
- 合并原 `auth.site_code_mapping``biz.sites`增加租户关联和简写ID 变更历史管理
- 数据来源:种子数据从 `auth.site_code_mapping` 迁移ETL 增量同步从 `dwd.dim_site`
## 变更说明
| 库 | Schema | 表 | 变更类型 | 说明 |
|----|--------|---|---------|------|
| zqyy_app | biz | connectors | 新建 | 连接器注册表 |
| zqyy_app | biz | tenants | 新建 | 租户注册表 |
| zqyy_app | biz | sites | 新建 | 店铺注册表(合并原 auth.site_code_mapping |
| zqyy_app | biz | site_code_history | 新建 | 简写ID 变更历史表 |
| zqyy_app | auth | site_code_mapping | 废弃重命名 | → `auth._archived_site_code_mapping` |
---
## 1. biz.connectors — 连接器注册表
记录本项目接入的上游 SaaS 系统。当前仅有飞球feiqiu一个连接器预留多连接器扩展能力。
### 表结构
| 列名 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | SERIAL | PRIMARY KEY | 自增主键 |
| connector_key | VARCHAR(50) | UNIQUE NOT NULL | 连接器标识(如 `'feiqiu'` |
| display_name | VARCHAR(100) | NOT NULL | 显示名称 |
| is_active | BOOLEAN | NOT NULL DEFAULT true | 是否启用 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 创建时间 |
### 约束与索引
| 名称 | 类型 | 列 | 说明 |
|------|------|---|------|
| connectors_pkey | PRIMARY KEY | id | 主键 |
| connectors_connector_key_key | UNIQUE | connector_key | 连接器标识唯一 |
### 种子数据
```sql
INSERT INTO biz.connectors (connector_key, display_name) VALUES ('feiqiu', '飞球');
```
---
## 2. biz.tenants — 租户注册表
连接器下的租户,`tenant_id` 来自上游系统。同一连接器下 `tenant_id` 唯一。
### 表结构
| 列名 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | SERIAL | PRIMARY KEY | 自增主键 |
| connector_id | INTEGER | NOT NULL FK → biz.connectors(id) | 所属连接器 |
| tenant_id | BIGINT | NOT NULL | 上游系统租户 ID |
| tenant_name | VARCHAR(200) | — | 租户名称 |
| is_active | BOOLEAN | NOT NULL DEFAULT true | 是否启用 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 创建时间 |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 更新时间 |
### 约束与索引
| 名称 | 类型 | 列 | 说明 |
|------|------|---|------|
| tenants_pkey | PRIMARY KEY | id | 主键 |
| tenants_connector_id_tenant_id_key | UNIQUE | (connector_id, tenant_id) | 同一连接器下租户唯一 |
| tenants_connector_id_fkey | FOREIGN KEY | connector_id → biz.connectors(id) | 外键关联连接器 |
### 种子数据
```sql
INSERT INTO biz.tenants (connector_id, tenant_id, tenant_name)
VALUES (1, 2790683160709957, '朗朗桌球');
```
---
## 3. biz.sites — 店铺注册表
合并原 `auth.site_code_mapping`增加租户关联和简写ID 管理。`site_id` 来自上游系统,全局唯一。`site_code` 为当前生效的简写ID6 位字符3+3 格式),全局唯一。
### 表结构
| 列名 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | SERIAL | PRIMARY KEY | 自增主键 |
| tenant_id | INTEGER | NOT NULL FK → biz.tenants(id) | 所属租户 |
| site_id | BIGINT | NOT NULL UNIQUE | 上游系统门店 ID |
| site_name | VARCHAR(200) | — | 门店名称 |
| site_code | VARCHAR(6) | UNIQUE | 当前生效的简写ID3+3 格式,如 `LLQ001` |
| site_label | VARCHAR(50) | — | 门店标签 |
| is_active | BOOLEAN | NOT NULL DEFAULT true | 是否启用 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 创建时间 |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 更新时间 |
### 约束与索引
| 名称 | 类型 | 列 | 说明 |
|------|------|---|------|
| sites_pkey | PRIMARY KEY | id | 主键 |
| sites_site_id_key | UNIQUE | site_id | 上游门店 ID 唯一 |
| sites_site_code_key | UNIQUE | site_code | 简写ID 全局唯一 |
| sites_tenant_id_fkey | FOREIGN KEY | tenant_id → biz.tenants(id) | 外键关联租户 |
### 数据迁移
```sql
-- 从 auth.site_code_mapping 迁移真实数据
INSERT INTO biz.sites (tenant_id, site_id, site_name, site_code)
SELECT t.id, scm.site_id, scm.site_name, scm.site_code
FROM auth.site_code_mapping scm
JOIN biz.tenants t ON t.tenant_id = scm.tenant_id
WHERE scm.tenant_id IS NOT NULL;
-- ETL 增量同步补充:通过 FDW 读取 dwd.dim_sitescd2_is_current=1
-- 补充 auth.site_code_mapping 中没有但 dwd.dim_site 中有的店铺
```
---
## 4. biz.site_code_history — 简写ID 变更历史表
增量记录所有使用过的简写ID。`site_code` 全局唯一(含历史),确保已退役的 code 不会被重新分配。每个 `site_id` 最多一条 `is_current=true` 记录。
### 表结构
| 列名 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | SERIAL | PRIMARY KEY | 自增主键 |
| site_id | BIGINT | NOT NULL | 关联 biz.sites.site_id |
| site_code | VARCHAR(6) | NOT NULL UNIQUE | 简写ID全局唯一含历史 |
| is_current | BOOLEAN | NOT NULL DEFAULT false | true=当前生效,每个 site_id 最多一条 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 创建时间 |
| retired_at | TIMESTAMPTZ | — | 退役时间is_current=false 时设置) |
### 约束与索引
| 名称 | 类型 | 列 | 说明 |
|------|------|---|------|
| site_code_history_pkey | PRIMARY KEY | id | 主键 |
| site_code_history_site_code_key | UNIQUE | site_code | 简写ID 全局唯一(含历史) |
### 初始数据
```sql
-- 为已有 site_code 的店铺创建历史记录
INSERT INTO biz.site_code_history (site_id, site_code, is_current)
SELECT site_id, site_code, true
FROM biz.sites
WHERE site_code IS NOT NULL;
```
---
## 兼容性
| 组件 | 影响 |
|------|------|
| 后端 API | 全部切换到 `biz.sites` + `biz.site_code_history`。新增 `admin_registry` 路由模块租户列表、店铺列表、简写ID 管理)。`admin_tenant_admins` 路由中 `tenant_id``biz.tenants` 选择。`tenant_users` 路由中 site_code 查询从 `auth.site_code_mapping` 切换到 `biz.sites` |
| ETL | 无直接影响。店铺同步通过 FDW 只读访问 ETL 库 `dwd.dim_site`,写入 `biz.sites`。ETL 流程本身不变 |
| 小程序 | 无需改动。用户申请时的 site_code 验证由后端 API 透明切换到 `biz.sites` + `biz.site_code_history` |
| 管理后台admin-web | 新增注册体系 API 调用(`src/api/registry.ts`),租户管理员创建流程从 `biz.tenants`/`biz.sites` 选择 |
| 原 auth.site_code_mapping | 迁移完成后重命名为 `auth._archived_site_code_mapping`,保留供回滚 |
## 回滚策略
### 完整回滚(逆序 DROP + 恢复原表)
```sql
BEGIN;
-- 1. 逆序删除注册体系表
DROP TABLE IF EXISTS biz.site_code_history CASCADE;
DROP TABLE IF EXISTS biz.sites CASCADE;
DROP TABLE IF EXISTS biz.tenants CASCADE;
DROP TABLE IF EXISTS biz.connectors CASCADE;
-- 2. 恢复原表(如已重命名)
ALTER TABLE IF EXISTS auth._archived_site_code_mapping
RENAME TO site_code_mapping;
COMMENT ON TABLE auth.site_code_mapping IS '店铺简写ID 映射表(已恢复)';
COMMIT;
```
注意:
- 回滚前需确认后端代码已切换回 `auth.site_code_mapping` 查询
- `CASCADE` 会级联删除依赖对象
- 如果 `biz.sites` 中已有新增店铺ETL 同步补充的),回滚后这些数据将丢失
## 验证 SQL
```sql
-- 1. 验证 biz.sites 中已有 site_code 的店铺数量
SELECT COUNT(*) FROM biz.sites WHERE site_code IS NOT NULL;
-- 预期:与原 auth.site_code_mapping 中有 site_code 的行数一致
-- 2. 验证 sites 与 site_code_history 的一致性
SELECT s.site_id, s.site_code, h.is_current
FROM biz.sites s
LEFT JOIN biz.site_code_history h
ON h.site_id = s.site_id AND h.site_code = s.site_code
WHERE s.site_code IS NOT NULL;
-- 预期:所有行的 h.is_current = true每个有 code 的店铺在历史表中有对应的当前记录)
-- 3. 验证三级注册体系关联完整性
SELECT c.connector_key, t.tenant_name, COUNT(s.id) AS site_count
FROM biz.connectors c
JOIN biz.tenants t ON t.connector_id = c.id
LEFT JOIN biz.sites s ON s.tenant_id = t.id
GROUP BY c.connector_key, t.tenant_name;
-- 预期:至少 1 行feiqiu / 朗朗桌球 / Nsite_count > 0
-- 4. 验证 4 张注册体系表全部存在
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'biz'
AND table_name IN ('connectors', 'tenants', 'sites', 'site_code_history')
ORDER BY table_name;
-- 预期:返回 4 行
-- 5. 验证 site_code 全局唯一性sites + history 无冲突)
SELECT site_code, COUNT(*) AS cnt
FROM biz.site_code_history
GROUP BY site_code
HAVING COUNT(*) > 1;
-- 预期:返回 0 行(每个 site_code 在历史表中最多出现一次)
-- 6. 验证种子数据
SELECT connector_key, display_name FROM biz.connectors WHERE connector_key = 'feiqiu';
-- 预期1 行feiqiu / 飞球)
SELECT tenant_id, tenant_name FROM biz.tenants WHERE tenant_id = 2790683160709957;
-- 预期1 行2790683160709957 / 朗朗桌球)
```
## 关联文件
- DDL 基线biz`docs/database/ddl/zqyy_app__biz.sql`
- 迁移脚本:`db/zqyy_app/migrations/2026-03-22__ns41_registry_tables.sql`
- 后端路由:`apps/backend/app/routers/admin_registry.py`
- 后端 Schema`apps/backend/app/schemas/admin_registry.py`
- 管理员路由:`apps/backend/app/routers/admin_tenant_admins.py`
- 前端 API`apps/admin-web/src/api/registry.ts`
- Spec`.kiro/specs/admin-web-enhancement/`
- PRD`docs/prd/Neo_Specs/NS4.1-tenant-admin-redesign.md`