# P3：用户认证层 — miniapp-auth-system

> 优先级：P3（依赖 P1，可与 P2 并行）
> 预估工作量：中等

---

## 需求（Requirements）

### 用户故事

1. 作为球房工作人员，我需要通过微信登录小程序，首次登录时填写申请表单（球房ID、申请身份、手机号、编号、昵称）。
2. 作为租户管理员，我需要审核用户申请，将用户关联到对应的助教/员工，并分配身份权限。
3. 作为系统，我需要通过球房ID+手机号自动建议用户与助教/员工的对应关系（同时匹配 `dwd.dim_assistant` 助教表和 `dwd.dim_staff` + `dwd.dim_staff_ex` 员工信息表）。
4. 作为用户，我需要看到自己的申请状态（审核中/通过/拒绝）。
5. 作为用户，我可以同时属于多个店铺（连锁场景），权限按店铺独立。

### 验收标准

- AC1：微信 code2Session 登录正常，返回 JWT
- AC2：新用户首次登录后进入申请页面，提交后状态为 pending
- AC3：管理员审核通过后，用户状态变为 approved，可正常访问小程序
- AC4：球房ID 不存在时，申请仍可提交，管理端显示"未找到关联信息"
- AC7：用户申请信息比对时，系统同时在助教表（`dwd.dim_assistant`）和员工信息表（`dwd.dim_staff` / `dwd.dim_staff_ex`）中匹配，返回所有匹配结果供管理员选择
- AC5：权限中间件正确拦截无权请求（如助教不能看财务看板）
- AC6：一个用户可关联多个店铺，切换店铺后数据正确隔离

---

## 设计要点

### 表结构

```
auth.users
  - id, wx_openid, wx_union_id, wx_avatar_url, nickname, phone
  - status (pending/approved/rejected/disabled)
  - created_at, updated_at

auth.user_applications
  - id, user_id, site_code (球房ID文本), applied_role_text (自由文本)
  - employee_number (选填), status, reviewer_id, review_note
  - created_at, reviewed_at

auth.site_code_mapping
  - id, site_code (2字母+3数字), site_id (ETL bigint), site_name
  - tenant_id, created_at

auth.user_site_roles
  - id, user_id, site_id, role_id
  - created_at

auth.user_assistant_binding
  - id, user_id, site_id, assistant_id (ETL dim_assistant)
  - staff_id (ETL dim_staff，可选，员工绑定时填写)
  - binding_type (assistant/staff/manager)
  - created_at
```

### 人员匹配逻辑（用户申请 → 信息比对）

用户提交申请时填写球房ID + 手机号（或编号），系统自动在以下两张表中匹配：

1. 助教表 `dwd.dim_assistant`（通过 FDW `fdw_etl.v_assistant`）：按 `site_id` + `mobile` 或 `alias_name` 匹配
2. 员工信息表 `dwd.dim_staff` + `dwd.dim_staff_ex`（通过 FDW）：按 `site_id` + `mobile` 或 `staff_name` / `alias_name` / `job_num` 匹配

匹配结果合并后返回给管理端，管理员从候选列表中选择正确的关联对象。若两张表均无匹配，显示"未找到关联信息"，管理员可手动填写。

> 员工信息表数据链路：上游 API → `ods.staff_info_master` → `dwd.dim_staff`（基础维度，SCD2）+ `dwd.dim_staff_ex`（扩展维度，SCD2）

### 权限列表（固定）

| 权限 code | 说明 |
|-----------|------|
| `view_tasks` | 任务板块可见 |
| `view_board` | 看板板块可见 |
| `view_board_finance` | 财务板块可见 |
| `view_board_customer` | 客户板块可见 |
| `view_board_coach` | 助教板块可见 |

### 租户层级

```
租户 (tenant)
  └── 店铺 (site) ← site_code 映射
        └── 用户 (user) ← 可属于多个 site
              └── 角色 (role) ← 按 site 独立分配
```

---

## 小程序前端开发强制规范

> 以下规范适用于本 SPEC 中所有小程序页面实现，具有强制约束力。

1. **原型图是唯一视觉真相**：`docs/h5_ui/pages/*.html` 中的结构、层次、元素、配色、间距、交互行为是小程序页面实现的唯一参考标准。任何偏离原型图的实现都需要明确的产品确认。
2. **WXML ≠ HTML**：严禁在小程序中使用 HTML 标签（div/span/p/a/img 等），必须使用小程序原生标签（view/text/image/navigator 等）。
3. **WXSS ≠ CSS**：使用 rpx 单位、仅支持有限选择器、无 DOM/BOM API、样式隔离机制不同。Tailwind CSS 类名必须手动转换为 WXSS。
4. **TDesign 优先**：凡 TDesign 组件库能覆盖的 UI 元素，必须使用 TDesign 组件；自定义实现仅限 TDesign 无法覆盖的场景。
5. **Power 文档优先**：实现前必须加载 `wechat-miniprogram` Power 的相关 steering 文件（`view-layer.md`、`tdesign.md`、`builtin-components.md`），确保语法和组件用法正确。
6. **项目踩坑指南必读**：实现前必须阅读 `docs/prd/MIGRATION-PLAYBOOK.md` 第六章，该文档是基于本项目实际转换经验的避坑手册，涵盖 WXML/WXSS 差异、事件系统、TDesign 用法、rpx 换算规则及新页面开发 Checklist。

---

## 任务清单

- [ ] T1：创建 `auth` Schema 下全部表（users, user_applications, site_code_mapping, user_site_roles, user_assistant_binding）
- [ ] T2：迁移现有 RBAC 表到 `auth` Schema（或保留 public 但建立关联）
- [ ] T3：实现微信 code2Session 登录 API
- [ ] T4：实现用户申请提交 API
- [ ] T5：实现 JWT 签发与刷新
- [ ] T6：实现权限中间件（基于 user_site_roles）
- [ ] T7：实现用户状态查询 API
- [ ] T8：种子数据：预置权限列表和默认角色
