包含多个会话的累积代码变更: - backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔 - admin-web: ETL 状态页、任务管理、调度配置、登录优化 - miniprogram: 看板页面、聊天集成、UI 组件、导航更新 - etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强 - tenant-admin: 项目初始化 - db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8) - packages/shared: 枚举和工具函数更新 - tools: 数据库工具、报表生成、健康检查 - docs: PRD/架构/部署/合约文档更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
513 lines
20 KiB
Markdown
513 lines
20 KiB
Markdown
# NS4.1:租户管理员页面重构 — 项目级注册体系 + 简写ID管理
|
||
|
||
> 优先级:高(NS4 后续迭代,依赖 NS4 基础设施已就绪)
|
||
> 预估工作量:中
|
||
> 前置条件:NS4(租户管理后台基础设施)、P3(用户认证体系)
|
||
> 关联页面:`http://localhost:5173/tenant-admins`(admin-web 系统管理后台)
|
||
|
||
---
|
||
|
||
## 一、背景与目标
|
||
|
||
### 1.1 现状问题
|
||
|
||
当前 `admin-web` 的租户管理员页面(NS4 需求 14)仅支持基础 CRUD:
|
||
- 创建时手动输入 `tenant_id` 和 `managed_site_ids`(无下拉选项,无名称参考)
|
||
- 无法删除管理员记录
|
||
- 无法管理简写ID(site_code),简写ID 的创建和修改散落在数据库手动操作中
|
||
- 缺少项目级的「连接器 → 租户 → 店铺」注册体系,租户名称无处存储
|
||
|
||
### 1.2 目标
|
||
|
||
1. 建立项目级注册体系:`biz.connectors` → `biz.tenants` → `biz.sites`,统一管理连接器、租户、店铺三级关系
|
||
2. 将 `auth.site_code_mapping` 合并迁移至 `biz.sites`,简写ID 成为店铺属性
|
||
3. 简写ID 变更增量记录(`biz.site_code_history`),保护已提交但未审核的用户申请
|
||
4. 重构租户管理员页面:支持删除(软删除)、2 步创建流程、简写ID 管理
|
||
5. 新增 ETL 增量同步任务:从 `dwd.dim_site` 同步店铺信息到业务库
|
||
|
||
---
|
||
|
||
## 二、数据模型设计
|
||
|
||
### 2.1 新建表
|
||
|
||
#### 表 1:`biz.connectors` — 连接器注册表
|
||
|
||
记录本项目接入的上游 SaaS 系统。当前仅「飞球」一个连接器,预留多连接器扩展。
|
||
|
||
```sql
|
||
CREATE TABLE biz.connectors (
|
||
id SERIAL PRIMARY KEY,
|
||
connector_key VARCHAR(50) NOT NULL UNIQUE, -- 连接器标识(如 'feiqiu')
|
||
display_name VARCHAR(100) NOT NULL, -- 显示名称(如 '飞球')
|
||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||
);
|
||
|
||
COMMENT ON TABLE biz.connectors IS '连接器注册表:记录本项目接入的上游 SaaS 系统';
|
||
```
|
||
|
||
初始数据:
|
||
|
||
```sql
|
||
INSERT INTO biz.connectors (connector_key, display_name)
|
||
VALUES ('feiqiu', '飞球');
|
||
```
|
||
|
||
#### 表 2:`biz.tenants` — 租户注册表
|
||
|
||
记录每个连接器下的租户信息。`tenant_id` 来自上游系统(飞球的 `tenant_id`)。
|
||
|
||
```sql
|
||
CREATE TABLE biz.tenants (
|
||
id SERIAL PRIMARY KEY,
|
||
connector_id INTEGER NOT NULL REFERENCES 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(),
|
||
UNIQUE (connector_id, tenant_id) -- 同一连接器下 tenant_id 唯一
|
||
);
|
||
|
||
COMMENT ON TABLE biz.tenants IS '租户注册表:连接器下的租户,tenant_id 来自上游系统';
|
||
```
|
||
|
||
初始数据(从 ETL 库 `dwd.dim_site` 提取当前唯一租户):
|
||
|
||
```sql
|
||
INSERT INTO biz.tenants (connector_id, tenant_id, tenant_name)
|
||
VALUES (1, 2790683160709957, '朗朗桌球');
|
||
-- tenant_name 暂用店铺名,后续可由管理员修改或从上游同步
|
||
```
|
||
|
||
#### 表 3:`biz.sites` — 店铺注册表(合并 `auth.site_code_mapping`)
|
||
|
||
将 `auth.site_code_mapping` 的功能合并到此表,增加 `tenant_id` 外键关联。
|
||
`site_code` 为当前生效的简写ID(6 位,3+3 格式)。
|
||
|
||
```sql
|
||
CREATE TABLE biz.sites (
|
||
id SERIAL PRIMARY KEY,
|
||
tenant_id INTEGER NOT NULL REFERENCES biz.tenants(id),
|
||
site_id BIGINT NOT NULL UNIQUE, -- 上游系统的店铺 ID
|
||
site_name VARCHAR(200), -- 店铺名称(从 dwd.dim_site 同步)
|
||
site_code VARCHAR(6) UNIQUE, -- 当前生效的简写ID(如 'LLQ001')
|
||
site_label VARCHAR(50), -- 店铺标签(从 dwd.dim_site 同步)
|
||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||
);
|
||
|
||
COMMENT ON TABLE biz.sites IS '店铺注册表:合并原 auth.site_code_mapping,增加租户关联和简写ID管理';
|
||
COMMENT ON COLUMN biz.sites.site_code IS '当前生效的简写ID,6位字符(3+3格式),全局唯一';
|
||
```
|
||
|
||
初始数据(从 `auth.site_code_mapping` 迁移):
|
||
|
||
```sql
|
||
-- 仅迁移真实数据(排除测试数据 tenant_id IS NULL)
|
||
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;
|
||
```
|
||
|
||
#### 表 4:`biz.site_code_history` — 简写ID 变更历史表
|
||
|
||
增量记录所有使用过的简写ID,用于保护已提交但未审核的用户申请。
|
||
|
||
```sql
|
||
CREATE TABLE biz.site_code_history (
|
||
id SERIAL PRIMARY KEY,
|
||
site_id BIGINT NOT NULL, -- 关联 biz.sites.site_id
|
||
site_code VARCHAR(6) NOT NULL, -- 历史简写ID
|
||
is_current BOOLEAN NOT NULL DEFAULT false, -- 是否为当前生效
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- 该 code 生效时间
|
||
retired_at TIMESTAMPTZ, -- 该 code 失效时间(NULL=当前生效)
|
||
UNIQUE (site_code) -- 简写ID 全局唯一(含历史)
|
||
);
|
||
|
||
COMMENT ON TABLE biz.site_code_history IS '简写ID变更历史:增量记录所有使用过的简写ID';
|
||
COMMENT ON COLUMN biz.site_code_history.is_current IS 'true=当前生效的简写ID,每个 site_id 最多一条 is_current=true';
|
||
```
|
||
|
||
### 2.2 表关系
|
||
|
||
```
|
||
biz.connectors (1)
|
||
└── biz.tenants (N) -- 一个连接器下多个租户
|
||
└── biz.sites (N) -- 一个租户下多个店铺
|
||
└── biz.site_code_history (N) -- 一个店铺的简写ID变更历史
|
||
|
||
auth.tenant_admins.tenant_id → biz.tenants.tenant_id(逻辑关联,不加 FK)
|
||
auth.user_applications.site_code → biz.site_code_history.site_code(逻辑关联)
|
||
```
|
||
|
||
### 2.3 废弃表处理
|
||
|
||
`auth.site_code_mapping` 在数据迁移完成并验证后标记为废弃:
|
||
1. 迁移期间保留原表,新旧并行
|
||
2. 后端代码切换到 `biz.sites` 读取
|
||
3. 验证无误后,原表重命名为 `auth._archived_site_code_mapping`
|
||
|
||
### 2.4 `dwd.dim_site` 提升为项目级
|
||
|
||
当前 `dwd.dim_site` 位于 ETL 连接器级别(`apps/etl/connectors/feiqiu/`)。
|
||
本次不做物理迁移(表仍在 `dwd` schema),但在语义上将其视为项目级维度表。
|
||
后续如有多连接器场景,再考虑拆分为项目级 `dim` schema。
|
||
|
||
---
|
||
|
||
## 三、功能详细设计
|
||
|
||
### 3.1 租户管理员列表页
|
||
|
||
#### 现有功能保留
|
||
- 分页 + 关键词搜索
|
||
- 编辑(显示名称、管辖门店、账号状态)
|
||
- 重置密码
|
||
|
||
#### 新增功能
|
||
|
||
##### 3.1.1 删除管理员(软删除)
|
||
|
||
- 操作:点击「删除」按钮 → 二次确认弹窗 → 确认后设置 `is_active = false`
|
||
- 列表默认只显示 `is_active = true` 的记录
|
||
- 可选:增加「显示已禁用」开关,查看所有记录
|
||
- 已禁用的记录不可再次删除,但可以重新启用
|
||
|
||
##### 3.1.2 创建管理员(2 步流程)
|
||
|
||
**第 1 步:创建账号**
|
||
- 选择租户:下拉选择 `biz.tenants` 中的租户(显示 `tenant_name`,值为 `tenant_id`)
|
||
- 输入用户名
|
||
- 输入初始密码
|
||
- 输入显示名称
|
||
- 选择管辖门店:根据所选租户,加载该租户下所有店铺(`biz.sites`),多选
|
||
|
||
**第 2 步:设置简写ID**
|
||
- 展示所选租户下所有店铺列表
|
||
- 每个店铺显示:店铺名称、当前简写ID(如有)
|
||
- 可为每个店铺设置/修改简写ID
|
||
- 简写ID 格式:6 位字符数字(3+3 模式,如 `LLQ001`)
|
||
- 校验:全局唯一(含历史记录中的 code)
|
||
|
||
> 第 2 步可跳过(简写ID 后续可在编辑时设置)
|
||
|
||
##### 3.1.3 编辑管理员
|
||
|
||
- 不可修改所属租户(`tenant_id` 只读)
|
||
- 可修改:用户名、密码(重置)、显示名称、管辖门店、简写ID
|
||
- 简写ID 编辑入口:在编辑弹窗中增加「管理简写ID」区域,展示该租户下所有店铺及其当前 code
|
||
|
||
### 3.2 简写ID 管理逻辑
|
||
|
||
#### 3.2.1 设置/修改简写ID
|
||
|
||
```
|
||
用户在管理后台修改某店铺的简写ID(old_code → new_code)
|
||
→ 校验 new_code 格式(6位,3+3)
|
||
→ 校验 new_code 全局唯一(biz.sites.site_code + biz.site_code_history.site_code)
|
||
→ 事务内执行:
|
||
1. 将 old_code 在 site_code_history 中标记 is_current=false, retired_at=NOW()
|
||
2. 插入 new_code 到 site_code_history(is_current=true)
|
||
3. 更新 biz.sites.site_code = new_code
|
||
4. 清理无引用的历史记录(见 3.2.2)
|
||
```
|
||
|
||
#### 3.2.2 历史记录清理
|
||
|
||
每次修改简写ID 时,检查被替换的旧 code 是否有关联的用户申请:
|
||
|
||
```sql
|
||
-- 检查旧 code 是否有未审核的申请引用
|
||
SELECT COUNT(*) FROM auth.user_applications
|
||
WHERE site_code = :old_code AND status = 'pending';
|
||
```
|
||
|
||
- 如果有未审核申请引用 → 保留历史记录(`is_current=false`,但不删除)
|
||
- 如果无任何申请引用 → 从 `biz.site_code_history` 中删除该条记录
|
||
|
||
> 目的:防止用户已用旧 code 提交申请但尚未审核时,映射关系丢失
|
||
|
||
#### 3.2.3 简写ID 格式规范
|
||
|
||
- 总长度:6 位
|
||
- 格式:3 位字母/数字 + 3 位数字(如 `LLQ001`、`ABC123`)
|
||
- 大小写:统一存储为大写
|
||
- 全局唯一:同一时刻不允许两个店铺使用相同 code(含历史未清理的 code)
|
||
|
||
### 3.3 租户/店铺信息展示
|
||
|
||
#### 3.3.1 租户下拉选项
|
||
|
||
创建管理员时,租户下拉数据来源:
|
||
|
||
```
|
||
GET /api/admin/tenants → biz.tenants (is_active=true)
|
||
返回:[{ id, tenantId, tenantName, connectorName }]
|
||
```
|
||
|
||
#### 3.3.2 店铺列表
|
||
|
||
选择租户后,加载该租户下所有店铺:
|
||
|
||
```
|
||
GET /api/admin/tenants/{tenant_id}/sites → biz.sites (tenant_id=?, is_active=true)
|
||
返回:[{ id, siteId, siteName, siteCode, siteLabel }]
|
||
```
|
||
|
||
---
|
||
|
||
## 四、接口设计
|
||
|
||
### 4.1 新增接口
|
||
|
||
| 接口 | 方法 | 路径 | 说明 |
|
||
|------|------|------|------|
|
||
| 租户列表 | GET | `/api/admin/tenants` | 所有活跃租户(含连接器名称) |
|
||
| 租户下店铺列表 | GET | `/api/admin/tenants/{tenant_id}/sites` | 指定租户下所有店铺(含当前 site_code) |
|
||
| 删除管理员 | DELETE | `/api/admin/tenant-admins/{id}` | 软删除(is_active=false) |
|
||
| 设置简写ID | PUT | `/api/admin/sites/{site_id}/site-code` | 设置/修改店铺简写ID |
|
||
| 简写ID历史 | GET | `/api/admin/sites/{site_id}/site-code-history` | 查看某店铺的简写ID变更历史 |
|
||
|
||
### 4.2 修改接口
|
||
|
||
| 接口 | 变更内容 |
|
||
|------|----------|
|
||
| `POST /api/admin/tenant-admins` | 创建时 `tenant_id` 改为从 `biz.tenants` 选择;`managed_site_ids` 从 `biz.sites` 选择 |
|
||
| `PATCH /api/admin/tenant-admins/{id}` | 增加 `username` 可修改(需校验唯一性) |
|
||
| `GET /api/admin/tenant-admins` | 默认只返回 `is_active=true`;增加 `include_inactive` 参数 |
|
||
|
||
---
|
||
|
||
## 五、ETL 同步任务
|
||
|
||
### 5.1 店铺信息增量同步
|
||
|
||
新增 ETL 任务:从 `dwd.dim_site`(ETL 库)增量同步到 `biz.sites`(业务库)。
|
||
|
||
#### 同步逻辑
|
||
|
||
```
|
||
1. 读取 dwd.dim_site WHERE scd2_is_current = 1
|
||
2. 对比 biz.sites 中已有记录:
|
||
- 新增店铺(site_id 不存在)→ INSERT(site_code 留空,待管理员设置)
|
||
- 店铺名称变更 → UPDATE site_name
|
||
- 店铺标签变更 → UPDATE site_label
|
||
3. 不删除已有记录(即使上游标记为关闭)
|
||
```
|
||
|
||
#### 触发方式
|
||
|
||
- 手动触发:管理后台按钮或 CLI 命令
|
||
- 定时触发:随 ETL 日常调度(DWD 层完成后)
|
||
|
||
#### 租户信息
|
||
|
||
- `biz.tenants` 中的 `tenant_name` 暂不自动同步(上游无 tenant_name 字段)
|
||
- 首次由迁移脚本写入,后续由管理员在管理后台手动修改
|
||
|
||
---
|
||
|
||
## 六、数据迁移计划
|
||
|
||
### 6.1 迁移步骤
|
||
|
||
```
|
||
1. 创建新表:biz.connectors → biz.tenants → biz.sites → biz.site_code_history
|
||
2. 写入种子数据:connectors(飞球)、tenants(从 dim_site 提取)
|
||
3. 迁移 auth.site_code_mapping → biz.sites(仅真实数据,排除 tenant_id IS NULL 的测试数据)
|
||
4. 为已有 site_code 创建 site_code_history 记录(is_current=true)
|
||
5. 运行 ETL 同步任务,补充 biz.sites 中缺失的店铺(dim_site 中有但 site_code_mapping 中没有的)
|
||
6. 后端代码切换:所有读取 auth.site_code_mapping 的地方改为读取 biz.sites
|
||
7. 验证:对比新旧表数据一致性
|
||
8. 废弃原表:重命名为 auth._archived_site_code_mapping
|
||
```
|
||
|
||
### 6.2 回滚策略
|
||
|
||
- 迁移期间保留原表不动
|
||
- 如需回滚:删除 biz.sites/tenants/connectors/site_code_history,恢复后端代码指向 auth.site_code_mapping
|
||
|
||
---
|
||
|
||
## 七、前端页面设计
|
||
|
||
### 7.1 页面布局
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ 租户管理员 │
|
||
│ [搜索框] [显示已禁用 ☐] [+ 创建管理员] │
|
||
├─────────────────────────────────────────────────────┤
|
||
│ 用户名 │ 显示名称 │ 租户 │ 管辖门店 │ 状态 │ 操作 │
|
||
│ admin1 │ 张三 │ 朗朗 │ 朗朗桌球 │ 启用 │ 编辑 │
|
||
│ │ │ │ │ │ 重置 │
|
||
│ │ │ │ │ │ 简写ID │
|
||
│ │ │ │ │ │ 删除 │
|
||
└─────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 7.2 创建弹窗(2 步)
|
||
|
||
```
|
||
步骤 1/2:创建账号
|
||
┌──────────────────────────────┐
|
||
│ 租户: [▼ 朗朗桌球 ] │
|
||
│ 用户名: [ ] │
|
||
│ 初始密码:[ ] │
|
||
│ 显示名称:[ ] │
|
||
│ 管辖门店:[☑ 朗朗桌球 ] │
|
||
│ │
|
||
│ [下一步] [取消] │
|
||
└──────────────────────────────┘
|
||
|
||
步骤 2/2:设置简写ID
|
||
┌──────────────────────────────┐
|
||
│ 店铺 当前简写ID │
|
||
│ 朗朗桌球 [LLQ001 ] │
|
||
│ │
|
||
│ 格式:6位(3字母+3数字) │
|
||
│ │
|
||
│ [跳过] [完成创建] [上一步]│
|
||
└──────────────────────────────┘
|
||
```
|
||
|
||
### 7.3 简写ID 管理弹窗
|
||
|
||
```
|
||
管理简写ID — 朗朗桌球(租户)
|
||
┌──────────────────────────────────────┐
|
||
│ 店铺 当前ID 操作 │
|
||
│ 朗朗桌球 LLQ001 [修改] │
|
||
│ │
|
||
│ 修改简写ID: │
|
||
│ 新ID:[ ] [保存] [取消] │
|
||
│ │
|
||
│ 变更历史: │
|
||
│ LLQ001 当前生效 2026-03-22 │
|
||
│ LL001 已失效 2026-02-25 (保留) │
|
||
│ │
|
||
│ [关闭] │
|
||
└──────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 八、影响范围
|
||
|
||
### 8.1 后端
|
||
|
||
| 文件 | 变更类型 | 说明 |
|
||
|------|----------|------|
|
||
| `app/routers/admin_tenant_admins.py` | 修改 | 增加 DELETE 端点、修改 CREATE/EDIT 逻辑 |
|
||
| `app/schemas/admin_tenant_admins.py` | 修改 | 新增/修改请求响应 Schema |
|
||
| `app/routers/admin_registry.py` | 新建 | 租户/店铺/简写ID 管理接口 |
|
||
| `app/schemas/admin_registry.py` | 新建 | 注册体系 Schema |
|
||
|
||
### 8.2 前端(admin-web)
|
||
|
||
| 文件 | 变更类型 | 说明 |
|
||
|------|----------|------|
|
||
| `src/pages/TenantAdmins/index.tsx` | 重构 | 2 步创建、删除、简写ID 管理 |
|
||
| `src/api/tenantAdmins.ts` | 修改 | 新增 API 调用 |
|
||
| `src/api/registry.ts` | 新建 | 租户/店铺列表 API |
|
||
|
||
### 8.3 数据库
|
||
|
||
| 操作 | 对象 | 说明 |
|
||
|------|------|------|
|
||
| 新建 | `biz.connectors` | 连接器注册表 |
|
||
| 新建 | `biz.tenants` | 租户注册表 |
|
||
| 新建 | `biz.sites` | 店铺注册表(合并 site_code_mapping) |
|
||
| 新建 | `biz.site_code_history` | 简写ID 变更历史 |
|
||
| 废弃 | `auth.site_code_mapping` | 迁移完成后废弃 |
|
||
|
||
### 8.4 ETL
|
||
|
||
| 变更 | 说明 |
|
||
|------|------|
|
||
| 新增同步任务 | `dwd.dim_site` → `biz.sites` 增量同步 |
|
||
|
||
### 8.5 小程序端
|
||
|
||
| 变更 | 说明 |
|
||
|------|------|
|
||
| 用户申请时的 site_code 查询 | 从 `auth.site_code_mapping` 切换到 `biz.sites` + `biz.site_code_history` |
|
||
|
||
---
|
||
|
||
## 九、约束与边界条件
|
||
|
||
1. 一个租户只有一个管理员(软限制,不加 DB 约束)
|
||
2. 简写ID 全局唯一(含历史记录),通过 UNIQUE 约束保证
|
||
3. 删除管理员为软删除(`is_active = false`),不物理删除
|
||
4. 编辑时不可修改所属租户
|
||
5. 简写ID 格式:6 位,3+3 模式,统一大写存储
|
||
6. 历史简写ID 仅在无未审核申请引用时才可清理
|
||
7. ETL 同步不删除已有店铺记录(即使上游关闭)
|
||
8. `biz.tenants.tenant_name` 暂不自动同步,由管理员手动维护
|
||
|
||
---
|
||
|
||
## 十、不做的事情(明确排除)
|
||
|
||
1. 不做多连接器支持的完整实现(仅预留 `biz.connectors` 表结构)
|
||
2. 不做 `dwd.dim_site` 的物理迁移(保留在 `dwd` schema)
|
||
3. 不做租户管理员的自助注册功能
|
||
4. 不做店铺管理员的管理(本 PRD 仅涉及租户管理员)
|
||
5. 不做 `auth.site_code_mapping` 的立即删除(迁移后保留为 `_archived`)
|
||
6. 不做简写ID 的自动生成(由管理员手动设置)
|
||
|
||
---
|
||
|
||
## 十一、数据库现状参考
|
||
|
||
### ETL 库 `dwd.dim_site`(当前数据)
|
||
|
||
| site_id | tenant_id | shop_name | site_label |
|
||
|---------|-----------|-----------|------------|
|
||
| 2790685415443269 | 2790683160709957 | 朗朗桌球 | A |
|
||
|
||
### 业务库 `auth.site_code_mapping`(当前数据)
|
||
|
||
| id | site_code | site_id | site_name | tenant_id |
|
||
|----|-----------|---------|-----------|-----------|
|
||
| 1 | LL001 | 2790685415443269 | 朗朗桌球 | 2790683160709957 |
|
||
| 1448 | PT952 | 857189 | 测试球房_PT952 | NULL |
|
||
| 1470 | PT118 | 819193 | 测试球房_PT118 | NULL |
|
||
| 1471 | PT607 | 899675 | 测试球房_PT607 | NULL |
|
||
|
||
> 仅 id=1 为真实数据,其余为属性测试生成的测试数据(`tenant_id IS NULL`)
|
||
|
||
### 业务库 `auth.tenant_admins`(现有结构)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | BIGSERIAL | 主键 |
|
||
| username | VARCHAR(50) | 登录用户名,UNIQUE |
|
||
| password_hash | VARCHAR(255) | bcrypt 哈希 |
|
||
| display_name | VARCHAR(100) | 显示名称 |
|
||
| tenant_id | BIGINT | 所属租户 |
|
||
| managed_site_ids | BIGINT[] | 管辖门店 ID 列表 |
|
||
| is_active | BOOLEAN | 账号状态 |
|
||
| created_by | BIGINT | 创建者 |
|
||
| created_at | TIMESTAMPTZ | 创建时间 |
|
||
| last_login_at | TIMESTAMPTZ | 最后登录时间 |
|
||
|
||
> `tenant_admins` 表结构不变,仅后端逻辑调整(创建时从 `biz.tenants` 选择租户)
|
||
|
||
---
|
||
|
||
## 十二、参考文档
|
||
|
||
| 文档 | 路径 | 用途 |
|
||
|------|------|------|
|
||
| NS4 原始 PRD | `docs/prd/Neo_Specs/NS4-tenant-admin-web.md` | 租户管理后台完整需求 |
|
||
| P3 认证体系 | `docs/prd/specs/P3-miniapp-auth-system.md` | site_code / user_applications 设计 |
|
||
| BD 手册-认证表 | `docs/database/BD_Manual_auth_tables.md` | auth schema 表结构 |
|
||
| BD 手册-业务表 | `docs/database/BD_Manual_biz_tables.md` | biz schema 表结构 |
|