# BD_Manual：auth Schema 认证业务表

> 目标库：`test_zqyy_app`（通过 `APP_DB_DSN` 连接）
> 迁移脚本：
>   - `db/zqyy_app/migrations/2026-02-25__p3_create_auth_tables.sql`（建表）
>   - `db/zqyy_app/migrations/2026-02-25__p3_seed_roles_permissions.sql`（种子数据）
> 关联 SPEC：`miniapp-auth-system`（P3 小程序用户认证系统）

---

## 1. 变更说明

### 新增表（8 张）

| # | 表名 | 用途 | 主要字段 |
|---|------|------|---------|
| 1 | `auth.users` | 微信用户主表 | `id`(PK), `wx_openid`(UK), `wx_union_id`, `wx_avatar_url`, `nickname`, `phone`, `status`(默认 `pending`), `created_at`, `updated_at` |
| 2 | `auth.user_applications` | 用户入驻申请表 | `id`(PK), `user_id`(FK→users), `site_code`, `site_id`, `applied_role_text`, `employee_number`, `phone`, `status`(默认 `pending`), `reviewer_id`, `review_note`, `created_at`, `reviewed_at` |
| 3 | `auth.site_code_mapping` | 球房ID与门店映射表 | `id`(PK), `site_code`(UK), `site_id`(UK), `site_name`, `tenant_id`, `created_at` |
| 4 | `auth.roles` | 角色定义表 | `id`(PK), `code`(UK), `name`, `description`, `created_at` |
| 5 | `auth.permissions` | 权限定义表 | `id`(PK), `code`(UK), `name`, `description`, `created_at` |
| 6 | `auth.role_permissions` | 角色-权限关联表 | `role_id`(FK→roles), `permission_id`(FK→permissions)，联合主键 |
| 7 | `auth.user_site_roles` | 用户-门店-角色关联表 | `id`(PK), `user_id`(FK→users), `site_id`, `role_id`(FK→roles), `created_at`，`(user_id, site_id, role_id)` 唯一约束 |
| 8 | `auth.user_assistant_binding` | 用户-人员绑定表 | `id`(PK), `user_id`(FK→users), `site_id`, `assistant_id`(可空), `staff_id`(可空), `binding_type`, `created_at` |

### 约束与索引

| 表 | 约束/索引名 | 类型 | 说明 |
|----|-----------|------|------|
| `users` | `uq_users_wx_openid` | UNIQUE | 微信 openid 唯一 |
| `users` | `ix_users_wx_openid` | INDEX | openid 查询加速 |
| `site_code_mapping` | `uq_site_code_mapping_site_code` | UNIQUE | 球房ID 唯一 |
| `site_code_mapping` | `uq_site_code_mapping_site_id` | UNIQUE | site_id 唯一映射 |
| `site_code_mapping` | `ix_site_code_mapping_site_code` | INDEX | site_code 查询加速 |
| `roles` | `uq_roles_code` | UNIQUE | 角色 code 唯一 |
| `permissions` | `uq_permissions_code` | UNIQUE | 权限 code 唯一 |
| `role_permissions` | PK `(role_id, permission_id)` | PRIMARY KEY | 联合主键 |
| `role_permissions` | `fk_role_permissions_role_id` | FK | → `auth.roles(id)` CASCADE |
| `role_permissions` | `fk_role_permissions_permission_id` | FK | → `auth.permissions(id)` CASCADE |
| `user_applications` | `fk_user_applications_user_id` | FK | → `auth.users(id)` CASCADE |
| `user_applications` | `ix_user_applications_user_id` | INDEX | user_id 查询加速 |
| `user_applications` | `ix_user_applications_status` | INDEX | status 过滤加速 |
| `user_site_roles` | `uq_user_site_roles_user_site_role` | UNIQUE | 防止重复分配 |
| `user_site_roles` | `fk_user_site_roles_user_id` | FK | → `auth.users(id)` CASCADE |
| `user_site_roles` | `fk_user_site_roles_role_id` | FK | → `auth.roles(id)` CASCADE |
| `user_site_roles` | `ix_user_site_roles_user_site` | INDEX | (user_id, site_id) 查询加速 |
| `user_assistant_binding` | `fk_user_assistant_binding_user_id` | FK | → `auth.users(id)` CASCADE |


### 种子数据

#### 权限（5 条）

| code | name | description |
|------|------|-------------|
| `view_tasks` | 查看任务 | 允许查看任务列表和任务详情 |
| `view_board` | 查看看板 | 允许查看数据看板概览 |
| `view_board_finance` | 查看财务看板 | 允许查看财务相关的数据看板 |
| `view_board_customer` | 查看客户看板 | 允许查看客户相关的数据看板 |
| `view_board_coach` | 查看助教看板 | 允许查看助教相关的数据看板 |

#### 角色（4 条）

| code | name | description |
|------|------|-------------|
| `coach` | 助教 | 球房助教，可查看任务和助教看板 |
| `staff` | 员工 | 球房员工，可查看任务和数据看板 |
| `site_admin` | 店铺管理员 | 单店管理员，可查看所有看板 |
| `tenant_admin` | 租户管理员 | 租户级管理员，拥有全部权限 |

#### 角色-权限映射（14 条）

| 角色 | 权限列表 | 权限数 |
|------|---------|--------|
| `coach` | `view_tasks`, `view_board_coach` | 2 |
| `staff` | `view_tasks`, `view_board` | 2 |
| `site_admin` | `view_tasks`, `view_board`, `view_board_finance`, `view_board_customer`, `view_board_coach` | 5 |
| `tenant_admin` | `view_tasks`, `view_board`, `view_board_finance`, `view_board_customer`, `view_board_coach` | 5 |

---

## 2. 兼容性影响

| 组件 | 影响 |
|------|------|
| ETL 任务 | 无影响。本次变更仅操作业务库 `auth` Schema，不涉及 ETL 库 |
| 后端 API | 直接依赖。FastAPI 后端将基于这些表实现微信登录、用户申请、审核、权限中间件等认证功能 |
| 小程序 | 间接依赖。小程序通过后端 API 间接使用这些表（登录、申请、状态查询） |
| 管理后台 | 间接依赖。管理端通过后端 API 进行申请审核操作 |
| FDW 配置 | 无影响。`fdw_etl` Schema 独立于 `auth`，但人员匹配服务会通过 FDW 查询 ETL 库的助教/员工表 |
| `public` Schema | 无影响。脚本不包含任何对 `public` 的操作 |
| 现有 `auth` Schema | 兼容。`auth` Schema 已由 P1 迁移脚本创建，本次仅在其中新增表，不修改已有对象 |

---

## 3. 回滚策略

按逆序 `DROP TABLE IF EXISTS CASCADE`（迁移脚本末尾已包含注释形式的回滚语句）：

```sql
-- 先删除种子数据（如需保留表结构）
DELETE FROM auth.role_permissions
WHERE role_id IN (SELECT id FROM auth.roles WHERE code IN ('coach', 'staff', 'site_admin', 'tenant_admin'))
  AND permission_id IN (SELECT id FROM auth.permissions WHERE code IN ('view_tasks', 'view_board', 'view_board_finance', 'view_board_customer', 'view_board_coach'));

DELETE FROM auth.roles WHERE code IN ('coach', 'staff', 'site_admin', 'tenant_admin');
DELETE FROM auth.permissions WHERE code IN ('view_tasks', 'view_board', 'view_board_finance', 'view_board_customer', 'view_board_coach');

-- 删除表（按逆序，CASCADE 处理外键依赖）
DROP TABLE IF EXISTS auth.user_assistant_binding CASCADE;
DROP TABLE IF EXISTS auth.user_site_roles CASCADE;
DROP TABLE IF EXISTS auth.user_applications CASCADE;
DROP TABLE IF EXISTS auth.role_permissions CASCADE;
DROP TABLE IF EXISTS auth.permissions CASCADE;
DROP TABLE IF EXISTS auth.roles CASCADE;
DROP TABLE IF EXISTS auth.site_code_mapping CASCADE;
DROP TABLE IF EXISTS auth.users CASCADE;
```

注意：`CASCADE` 会级联删除依赖对象。如果表中已有业务数据，需先备份再执行回滚。

---

## 4. 验证 SQL

```sql
-- 1. 验证 auth Schema 下 8 张认证表全部存在
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'auth'
  AND table_name IN (
    'users', 'user_applications', 'site_code_mapping',
    'roles', 'permissions', 'role_permissions',
    'user_site_roles', 'user_assistant_binding'
  )
ORDER BY table_name;
-- 预期：返回 8 行

-- 2. 验证种子数据：5 条权限
SELECT COUNT(*) AS perm_count
FROM auth.permissions
WHERE code IN ('view_tasks', 'view_board', 'view_board_finance', 'view_board_customer', 'view_board_coach');
-- 预期：5

-- 3. 验证种子数据：4 条角色
SELECT COUNT(*) AS role_count
FROM auth.roles
WHERE code IN ('coach', 'staff', 'site_admin', 'tenant_admin');
-- 预期：4

-- 4. 验证角色-权限映射数量
SELECT r.code AS role_code, COUNT(rp.permission_id) AS perm_count
FROM auth.roles r
JOIN auth.role_permissions rp ON r.id = rp.role_id
GROUP BY r.code
ORDER BY r.code;
-- 预期：coach=2, site_admin=5, staff=2, tenant_admin=5（共 14 条映射）

-- 5. 验证关键约束存在
SELECT conname, contype
FROM pg_constraint
WHERE conrelid IN (
    'auth.users'::regclass,
    'auth.site_code_mapping'::regclass,
    'auth.user_site_roles'::regclass
)
ORDER BY conrelid::regclass::text, conname;
-- 预期：包含 uq_users_wx_openid、uq_site_code_mapping_site_code、uq_site_code_mapping_site_id、uq_user_site_roles_user_site_role 等
```
