feat: P1-P3 全栈集成 — 数据库基础 + DWS 扩展 + 小程序鉴权 + 工程化体系
## P1 数据库基础 - zqyy_app: 创建 auth/biz schema、FDW 连接 etl_feiqiu - etl_feiqiu: 创建 app schema RLS 视图、商品库存预警表 - 清理 assistant_abolish 残留数据 ## P2 ETL/DWS 扩展 - 新增 DWS 助教订单贡献度表 (dws.assistant_order_contribution) - 新增 assistant_order_contribution_task 任务及 RLS 视图 - member_consumption 增加充值字段、assistant_daily 增加处罚字段 - 更新 ODS/DWD/DWS 任务文档及业务规则文档 - 更新 consistency_checker、flow_runner、task_registry 等核心模块 ## P3 小程序鉴权系统 - 新增 xcx_auth 路由/schema(微信登录 + JWT) - 新增 wechat/role/matching/application 服务层 - zqyy_app 鉴权表迁移 + 角色权限种子数据 - auth/dependencies.py 支持小程序 JWT 鉴权 ## 文档与审计 - 新增 DOCUMENTATION-MAP 文档导航 - 新增 7 份 BD_Manual 数据库变更文档 - 更新 DDL 基线快照(etl_feiqiu 6 schema + zqyy_app auth) - 新增全栈集成审计记录、部署检查清单更新 - 新增 BACKLOG 路线图、FDW→Core 迁移计划 ## Kiro 工程化 - 新增 5 个 Spec(P1/P2/P3/全栈集成/核心业务) - 新增审计自动化脚本(agent_on_stop/build_audit_context/compliance_prescan) - 新增 6 个 Hook(合规检查/会话日志/提交审计等) - 新增 doc-map steering 文件 ## 运维与测试 - 新增 ops 脚本:迁移验证/API 健康检查/ETL 监控/集成报告 - 新增属性测试:test_dws_contribution / test_auth_system - 清理过期 export 报告文件 - 更新 .gitignore 排除规则
This commit is contained in:
196
.kiro/specs/03-miniapp-auth-system/requirements.md
Normal file
196
.kiro/specs/03-miniapp-auth-system/requirements.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 需求文档:小程序用户认证系统(miniapp-auth-system)
|
||||
|
||||
## 简介
|
||||
|
||||
本 SPEC 实现小程序用户认证系统,涵盖微信登录、用户申请审核、人员匹配、多店铺权限管理等完整认证链路。系统基于 P1(miniapp-db-foundation)已建立的 `auth` Schema 和 FDW 映射,在 `test_zqyy_app.auth` 中创建用户、申请、角色、绑定等业务表,并在 FastAPI 后端实现对应的 API 端点和权限中间件。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **Auth_System**:小程序用户认证系统,负责微信登录、用户管理、申请审核、权限控制的完整后端服务
|
||||
- **WeChat_Auth_Service**:微信认证服务模块,负责调用微信 `code2Session` 接口换取 `openid` 和 `session_key`
|
||||
- **Application_Service**:用户申请服务模块,负责处理用户提交的入驻申请、状态流转和审核操作
|
||||
- **Matching_Service**:人员匹配服务模块,负责根据球房ID和手机号/编号在助教表和员工表中查找候选匹配
|
||||
- **Permission_Middleware**:权限中间件,基于用户的 `site_id` + `role` 拦截无权请求
|
||||
- **JWT_Service**:JWT 令牌服务,负责签发和刷新 access_token / refresh_token(已有实现,本 SPEC 扩展)
|
||||
- **site_code**:球房ID,格式为 2 字母 + 3 数字(如 `AB123`),与 `site_id` 一一映射
|
||||
- **site_id**:门店标识符,类型为 `BIGINT`,用于多门店数据隔离
|
||||
- **user_status**:用户状态枚举,取值为 `pending`(审核中)/ `approved`(已通过)/ `rejected`(已拒绝)/ `disabled`(已禁用)
|
||||
- **binding_type**:绑定类型枚举,取值为 `assistant`(助教)/ `staff`(员工)/ `manager`(管理员)
|
||||
- **FDW**:`postgres_fdw` 外部数据包装器,通过 `fdw_etl` Schema 读取 ETL 库数据
|
||||
- **Migration_Script**:存放在 `db/zqyy_app/migrations/` 中的纯 SQL 迁移脚本,以日期前缀命名
|
||||
- **BD_Manual**:数据库手册文档,存放在 `docs/database/` 中,记录表结构变更、兼容性影响、回滚策略和验证 SQL
|
||||
- **DDL_Baseline**:DDL 基线文件,存放在 `docs/database/ddl/` 中,由 `gen_consolidated_ddl.py` 自动生成
|
||||
- **Miniprogram_Auth_Pages**:小程序认证相关前端页面,包括登录页、申请表单页、审核等待页、无权限页
|
||||
- **Dev_Login**:开发模式下的 mock 登录端点,绕过微信 code2Session 调用,用于联调测试
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:认证数据表创建
|
||||
|
||||
**用户故事:** 作为后端开发者,我需要在 `auth` Schema 中创建用户认证相关的数据表,以便支撑完整的认证和权限管理功能。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `users` 表,包含 `id`(SERIAL PK)、`wx_openid`(UNIQUE)、`wx_union_id`、`wx_avatar_url`、`nickname`、`phone`、`status`(默认 `pending`)、`created_at`、`updated_at` 字段
|
||||
2. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `user_applications` 表,包含 `id`(SERIAL PK)、`user_id`(FK → users)、`site_code`、`applied_role_text`、`employee_number`(可选)、`phone`、`status`(默认 `pending`)、`reviewer_id`、`review_note`、`created_at`、`reviewed_at` 字段
|
||||
3. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `site_code_mapping` 表,包含 `id`(SERIAL PK)、`site_code`(UNIQUE,格式 2 字母 + 3 数字)、`site_id`(BIGINT UNIQUE)、`site_name`、`tenant_id`、`created_at` 字段
|
||||
4. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `user_site_roles` 表,包含 `id`(SERIAL PK)、`user_id`(FK → users)、`site_id`(BIGINT)、`role_id`(FK → roles)、`created_at` 字段,并对 `(user_id, site_id, role_id)` 建立唯一约束
|
||||
5. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `user_assistant_binding` 表,包含 `id`(SERIAL PK)、`user_id`(FK → users)、`site_id`(BIGINT)、`assistant_id`(BIGINT,可选)、`staff_id`(BIGINT,可选)、`binding_type`、`created_at` 字段
|
||||
6. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `roles` 表,包含 `id`(SERIAL PK)、`code`(UNIQUE)、`name`、`description`、`created_at` 字段
|
||||
7. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `permissions` 表,包含 `id`(SERIAL PK)、`code`(UNIQUE)、`name`、`description`、`created_at` 字段
|
||||
8. WHEN Migration_Script 执行完成, THE Auth_System SHALL 在 `auth` Schema 中创建 `role_permissions` 表,包含 `role_id`(FK → roles)、`permission_id`(FK → permissions)字段,并以 `(role_id, permission_id)` 为联合主键
|
||||
9. THE Migration_Script SHALL 使用 `IF NOT EXISTS` / `OR REPLACE` 等幂等语法,确保重复执行不会报错
|
||||
10. THE Migration_Script SHALL 在脚本中包含回滚语句(以注释形式)
|
||||
|
||||
### 需求 2:种子数据预置
|
||||
|
||||
**用户故事:** 作为系统管理员,我需要系统预置固定的权限列表和默认角色,以便审核时可直接分配。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 种子数据脚本执行完成, THE Auth_System SHALL 在 `auth.permissions` 表中插入 5 条固定权限记录:`view_tasks`、`view_board`、`view_board_finance`、`view_board_customer`、`view_board_coach`
|
||||
2. WHEN 种子数据脚本执行完成, THE Auth_System SHALL 在 `auth.roles` 表中插入默认角色(至少包含 `coach`(助教)、`staff`(员工)、`site_admin`(店铺管理员)、`tenant_admin`(租户管理员))
|
||||
3. WHEN 种子数据脚本执行完成, THE Auth_System SHALL 在 `auth.role_permissions` 表中为每个默认角色分配对应的权限组合
|
||||
4. THE 种子数据脚本 SHALL 使用 `ON CONFLICT DO NOTHING` 语法,确保重复执行不会产生重复数据
|
||||
|
||||
### 需求 3:微信登录
|
||||
|
||||
**用户故事:** 作为球房工作人员,我需要通过微信登录小程序,以便快速进入系统。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 小程序端发送微信临时登录凭证(`code`), THE WeChat_Auth_Service SHALL 调用微信 `code2Session` 接口换取 `openid` 和 `session_key`
|
||||
2. WHEN `code2Session` 返回有效 `openid` 且该 `openid` 已存在于 `auth.users` 表中, THE Auth_System SHALL 返回该用户的 JWT 令牌对(access_token + refresh_token)和用户状态信息
|
||||
3. WHEN `code2Session` 返回有效 `openid` 且该 `openid` 不存在于 `auth.users` 表中, THE Auth_System SHALL 创建新用户记录(status 为 `pending`),返回 JWT 令牌对和 `pending` 状态标识
|
||||
4. IF `code2Session` 接口调用失败或返回错误码, THEN THE WeChat_Auth_Service SHALL 返回 HTTP 401 错误,包含具体的错误描述
|
||||
5. WHEN 用户状态为 `disabled`, THE Auth_System SHALL 返回 HTTP 403 错误,拒绝登录
|
||||
|
||||
### 需求 4:用户申请提交
|
||||
|
||||
**用户故事:** 作为球房工作人员,我需要在首次登录后填写申请表单(球房ID、申请身份、手机号、编号、昵称),以便管理员审核我的身份。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 用户提交申请表单(包含 `site_code`、`applied_role_text`、`phone`,可选 `employee_number`), THE Application_Service SHALL 在 `auth.user_applications` 表中创建一条 status 为 `pending` 的申请记录
|
||||
2. WHEN 用户提交的 `site_code` 在 `auth.site_code_mapping` 中存在映射, THE Application_Service SHALL 将申请记录关联到对应的 `site_id`
|
||||
3. WHEN 用户提交的 `site_code` 在 `auth.site_code_mapping` 中不存在映射, THE Application_Service SHALL 仍然接受申请,申请记录中保留 `site_code` 文本,管理端显示"未找到关联信息"
|
||||
4. WHEN 用户提交申请时提供了 `nickname`, THE Auth_System SHALL 更新 `auth.users` 表中该用户的 `nickname` 字段
|
||||
5. IF 用户提交的 `phone` 为空或格式无效(非 11 位数字), THEN THE Application_Service SHALL 返回 HTTP 422 错误,包含具体的校验失败信息
|
||||
6. WHEN 用户已有一条 `pending` 状态的申请, THE Application_Service SHALL 拒绝重复提交,返回 HTTP 409 错误
|
||||
|
||||
### 需求 5:人员匹配
|
||||
|
||||
**用户故事:** 作为系统,我需要根据球房ID和手机号自动建议用户与助教/员工的对应关系,以便管理员快速审核。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 管理员查看某条申请详情时, THE Matching_Service SHALL 根据申请中的 `site_id` 和 `phone` 在 `fdw_etl.v_dim_assistant` 中按 `site_id` + `mobile` 匹配助教记录
|
||||
2. WHEN 管理员查看某条申请详情时, THE Matching_Service SHALL 根据申请中的 `site_id` 和 `phone` 在 `fdw_etl.v_dim_staff` 和 `fdw_etl.v_dim_staff_ex` 中按 `site_id` + `mobile` 匹配员工记录
|
||||
3. WHEN 申请中包含 `employee_number`, THE Matching_Service SHALL 额外按 `job_num` 字段匹配员工记录
|
||||
4. THE Matching_Service SHALL 将助教匹配结果和员工匹配结果合并为统一的候选列表返回,每条候选包含来源类型(`assistant` / `staff`)、姓名、手机号、编号
|
||||
5. WHEN 助教表和员工表均无匹配结果, THE Matching_Service SHALL 返回空候选列表,管理端显示"未找到关联信息"
|
||||
6. WHEN 申请的 `site_code` 无法映射到 `site_id`, THE Matching_Service SHALL 跳过匹配,返回空候选列表
|
||||
|
||||
### 需求 6:申请审核
|
||||
|
||||
**用户故事:** 作为租户管理员,我需要审核用户申请,将用户关联到对应的助教/员工,并分配身份权限。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 管理员批准申请并选择了候选匹配对象, THE Application_Service SHALL 将申请状态更新为 `approved`,在 `auth.user_assistant_binding` 中创建绑定记录,在 `auth.user_site_roles` 中分配角色
|
||||
2. WHEN 管理员批准申请但无候选匹配(手动审核), THE Application_Service SHALL 将申请状态更新为 `approved`,仅在 `auth.user_site_roles` 中分配角色,不创建绑定记录
|
||||
3. WHEN 管理员拒绝申请, THE Application_Service SHALL 将申请状态更新为 `rejected`,记录 `review_note`(拒绝原因)
|
||||
4. WHEN 申请审核通过后, THE Auth_System SHALL 将 `auth.users` 表中该用户的 `status` 更新为 `approved`
|
||||
5. WHEN 审核操作完成, THE Application_Service SHALL 记录 `reviewer_id` 和 `reviewed_at` 时间戳
|
||||
6. IF 审核目标申请的状态不是 `pending`, THEN THE Application_Service SHALL 返回 HTTP 409 错误,拒绝重复审核
|
||||
|
||||
### 需求 7:用户状态查询
|
||||
|
||||
**用户故事:** 作为用户,我需要看到自己的申请状态(审核中/通过/拒绝),以便了解审核进度。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 用户查询自身状态, THE Auth_System SHALL 返回用户的 `status`、所有申请记录列表(含每条申请的 `site_code`、`applied_role_text`、`status`、`review_note`)
|
||||
2. WHEN 用户状态为 `approved`, THE Auth_System SHALL 同时返回用户已关联的店铺列表和对应角色
|
||||
|
||||
### 需求 8:多店铺支持与店铺切换
|
||||
|
||||
**用户故事:** 作为用户,我可以同时属于多个店铺(连锁场景),切换店铺后数据正确隔离。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Auth_System SHALL 允许一个用户通过多次申请关联到多个不同的 `site_id`,每个 `site_id` 独立分配角色
|
||||
2. WHEN 用户切换当前店铺, THE JWT_Service SHALL 签发包含新 `site_id` 的 JWT 令牌对
|
||||
3. WHEN 用户携带某 `site_id` 的 JWT 访问 API, THE Permission_Middleware SHALL 仅允许访问该 `site_id` 下用户拥有权限的资源
|
||||
|
||||
### 需求 9:权限中间件
|
||||
|
||||
**用户故事:** 作为系统,我需要权限中间件正确拦截无权请求,确保数据安全。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 用户携带有效 JWT 访问受保护端点, THE Permission_Middleware SHALL 从 JWT 中提取 `user_id` 和 `site_id`,查询 `auth.user_site_roles` 和 `auth.role_permissions` 获取用户在该店铺下的权限列表
|
||||
2. WHEN 用户的权限列表不包含端点所需的权限 code, THE Permission_Middleware SHALL 返回 HTTP 403 错误
|
||||
3. WHEN 用户的 `status` 不是 `approved`, THE Permission_Middleware SHALL 返回 HTTP 403 错误,拒绝访问受保护端点
|
||||
4. WHEN JWT 令牌过期或无效, THE Permission_Middleware SHALL 返回 HTTP 401 错误
|
||||
|
||||
### 需求 10:JWT 令牌扩展
|
||||
|
||||
**用户故事:** 作为后端开发者,我需要扩展现有 JWT 服务以支持微信登录场景和多店铺切换。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE JWT_Service SHALL 在 JWT payload 中包含 `user_id`(sub)、`site_id`、`roles`(角色 code 列表)、`type`(access/refresh)、`exp` 字段
|
||||
2. WHEN 用户通过微信登录且状态为 `approved`, THE JWT_Service SHALL 使用用户默认店铺(第一个关联的 site_id)签发令牌
|
||||
3. WHEN 用户通过微信登录且状态为 `pending`, THE JWT_Service SHALL 签发不含 `site_id` 和 `roles` 的受限令牌,仅允许访问申请提交和状态查询端点
|
||||
4. WHEN 用户请求切换店铺, THE JWT_Service SHALL 验证用户在目标 `site_id` 下有角色绑定后签发新令牌
|
||||
|
||||
### 需求 11:迁移脚本管理
|
||||
|
||||
**用户故事:** 作为后端开发者,我需要所有数据库变更都有对应的迁移脚本,以便变更可追溯、可重放。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Migration_Script SHALL 将所有认证相关表的 DDL 存放在 `db/zqyy_app/migrations/` 目录中
|
||||
2. THE Migration_Script SHALL 使用日期前缀命名(格式:`YYYY-MM-DD__<描述>.sql`)
|
||||
3. THE Migration_Script SHALL 使用 UTF-8 编码,纯 SQL(非 ORM)
|
||||
4. THE Migration_Script SHALL 在每个脚本中包含回滚语句(以注释形式)
|
||||
5. THE Migration_Script SHALL 使用幂等语法(`IF NOT EXISTS`、`ON CONFLICT DO NOTHING`),确保重复执行不会报错
|
||||
|
||||
### 需求 12:DDL 测试库落库与文档同步
|
||||
|
||||
**用户故事:** 作为后端开发者,我需要所有 DDL 变更在测试库(`test_zqyy_app`)中实际执行验证,并同步更新数据库手册和 DDL 基线,确保文档与实际 Schema 一致。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 迁移脚本编写完成, THE Auth_System SHALL 在 `test_zqyy_app` 测试库中执行迁移脚本,验证无错误
|
||||
2. WHEN 迁移脚本执行成功, THE Auth_System SHALL 创建或更新 `docs/database/BD_Manual_auth_tables.md` 数据库手册,包含变更说明、兼容性影响、回滚策略、验证 SQL(至少 3 条)
|
||||
3. WHEN 迁移脚本执行成功, THE Auth_System SHALL 运行 `python scripts/ops/gen_consolidated_ddl.py` 重新生成 DDL 基线文件 `docs/database/ddl/zqyy_app__auth.sql`
|
||||
4. WHEN 种子数据脚本执行成功, THE Auth_System SHALL 在数据库手册中记录种子数据内容(角色、权限、角色-权限映射)
|
||||
|
||||
### 需求 13:小程序认证前端页面
|
||||
|
||||
**用户故事:** 作为球房工作人员,我需要在小程序中看到登录页、申请表单页、审核状态页,以便完成从微信登录到正式使用的完整流程。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 用户首次打开小程序, THE Auth_System SHALL 展示登录页面,调用 `wx.login()` 获取 code 并发送到后端 `/api/xcx/login`
|
||||
2. WHEN 后端返回 `user_status=pending` 且用户无 pending 申请, THE Auth_System SHALL 跳转到申请表单页面,包含球房ID(`site_code`)、申请身份、手机号、编号(选填)、昵称输入框
|
||||
3. WHEN 用户提交申请表单, THE Auth_System SHALL 调用 `/api/xcx/apply` 提交申请,成功后跳转到审核等待页面
|
||||
4. WHEN 用户状态为 `pending` 且已有 pending 申请, THE Auth_System SHALL 展示审核等待页面,显示"审核中"状态和申请信息摘要
|
||||
5. WHEN 用户状态为 `rejected`, THE Auth_System SHALL 在审核等待页面显示拒绝原因,并提供"重新申请"按钮
|
||||
6. WHEN 用户状态为 `approved`, THE Auth_System SHALL 跳转到小程序主页(任务列表)
|
||||
7. WHEN 用户状态为 `disabled`, THE Auth_System SHALL 展示无权限页面,提示账号已被禁用
|
||||
8. THE Auth_System SHALL 在小程序 `app.ts` 的 `onLaunch` 中实现自动登录逻辑,根据用户状态路由到对应页面
|
||||
9. WHEN 用户拥有多个店铺, THE Auth_System SHALL 在主页提供店铺切换入口
|
||||
|
||||
### 需求 14:前后端联调验证
|
||||
|
||||
**用户故事:** 作为开发者,我需要在微信开发者工具中验证完整的认证流程(登录→申请→审核→进入主页),确保前后端接口对接正确。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE Auth_System SHALL 提供联调验证脚本或文档,说明如何在微信开发者工具中测试完整认证流程
|
||||
2. THE Auth_System SHALL 在后端提供开发模式下的 mock 登录端点(`POST /api/xcx/dev-login`),接受任意 openid 直接返回 JWT,绕过微信 code2Session 调用
|
||||
3. WHEN 开发模式启用时, THE Auth_System SHALL 允许通过环境变量 `WX_DEV_MODE=true` 切换到 mock 模式
|
||||
4. THE Auth_System SHALL 在 `apps/miniprogram/doc/` 中提供联调指南文档,包含微信开发者工具配置、后端启动步骤、测试账号说明
|
||||
Reference in New Issue
Block a user