289 lines
14 KiB
Markdown
289 lines
14 KiB
Markdown
# 实现计划:小程序用户认证系统(miniapp-auth-system)
|
||
|
||
## 概述
|
||
|
||
基于已批准的需求和设计文档,将小程序用户认证系统拆分为增量式编码任务。每个任务构建在前一个任务之上,最终完成完整的认证链路。后端使用 Python + FastAPI,数据库使用 PostgreSQL 纯 SQL,属性测试使用 hypothesis。
|
||
|
||
## 任务
|
||
|
||
- [x] 1. 创建认证数据表和种子数据
|
||
- [x] 1.1 创建迁移脚本 `db/zqyy_app/migrations/YYYY-MM-DD__p3_create_auth_tables.sql`
|
||
- 在 `auth` Schema 下创建 `users`、`user_applications`、`site_code_mapping`、`roles`、`permissions`、`role_permissions`、`user_site_roles`、`user_assistant_binding` 共 8 张表
|
||
- 包含所有字段定义、约束、索引、外键
|
||
- 使用 `IF NOT EXISTS` 幂等语法
|
||
- 包含回滚语句(注释形式)
|
||
- _Requirements: 1.1-1.10_
|
||
|
||
- [x] 1.2 创建种子数据脚本 `db/zqyy_app/migrations/YYYY-MM-DD__p3_seed_roles_permissions.sql`
|
||
- 插入 5 条固定权限:`view_tasks`、`view_board`、`view_board_finance`、`view_board_customer`、`view_board_coach`
|
||
- 插入默认角色:`coach`、`staff`、`site_admin`、`tenant_admin`
|
||
- 插入角色-权限映射
|
||
- 使用 `ON CONFLICT DO NOTHING` 幂等语法
|
||
- _Requirements: 2.1-2.4_
|
||
|
||
- [x] 1.3 在测试库执行迁移脚本并验证
|
||
- 在 `test_zqyy_app` 中执行建表脚本和种子数据脚本
|
||
- 验证幂等性:连续执行两次无错误
|
||
- 验证表结构、约束、索引正确
|
||
- 验证种子数据完整(5 权限、4 角色、角色-权限映射)
|
||
- _Requirements: 12.1_
|
||
|
||
- [x] 1.4 更新数据库手册和 DDL 基线
|
||
- 创建 `docs/database/BD_Manual_auth_tables.md`,包含变更说明、兼容性影响、回滚策略、验证 SQL(至少 3 条)
|
||
- 运行 `python scripts/ops/gen_consolidated_ddl.py` 刷新 DDL 基线
|
||
- 在数据库手册中记录种子数据内容
|
||
- _Requirements: 12.2, 12.3, 12.4_
|
||
|
||
- [x] 1.5 编写迁移脚本幂等性属性测试
|
||
- **Property 1: 迁移脚本幂等性**
|
||
- **Validates: Requirements 1.9, 2.4, 11.5**
|
||
|
||
- [x] 2. 扩展 JWT 服务和认证依赖
|
||
- [x] 2.1 扩展 `apps/backend/app/auth/jwt.py`
|
||
- 新增 `create_limited_token_pair(user_id)` 函数(pending 用户受限令牌)
|
||
- 扩展 `create_access_token` 支持 `roles` 参数
|
||
- 保持向后兼容
|
||
- _Requirements: 10.1, 10.2, 10.3_
|
||
|
||
- [x] 2.2 扩展 `apps/backend/app/auth/dependencies.py`
|
||
- 扩展 `CurrentUser` 数据类,增加 `roles`、`status`、`limited` 字段
|
||
- 新增 `get_current_user_or_limited` 依赖(允许 pending 用户)
|
||
- _Requirements: 10.3, 9.1_
|
||
|
||
- [x] 2.3 编写 JWT payload 结构属性测试
|
||
- **Property 14: JWT payload 结构与状态一致性**
|
||
- **Validates: Requirements 10.1, 10.2, 10.3**
|
||
|
||
- [x] 2.4 编写 JWT 过期/无效拒绝属性测试
|
||
- **Property 15: JWT 过期/无效令牌拒绝**
|
||
- **Validates: Requirements 9.4**
|
||
|
||
- [x] 3. 检查点 - 确保所有测试通过
|
||
- 确保所有测试通过,如有问题请向用户确认。
|
||
|
||
- [x] 4. 实现微信认证服务
|
||
- [x] 4.1 创建 `apps/backend/app/services/wechat.py`
|
||
- 实现 `code2session(code)` 异步函数
|
||
- 使用 `httpx.AsyncClient` 调用微信 API
|
||
- 从环境变量读取 `WX_APPID` / `WX_SECRET`
|
||
- 定义 `WeChatAuthError` 异常类
|
||
- _Requirements: 3.1, 3.4_
|
||
|
||
- [x] 4.2 创建 Pydantic 模型 `apps/backend/app/schemas/xcx_auth.py`
|
||
- 定义 `WxLoginRequest`、`WxLoginResponse`、`ApplicationRequest`、`ApplicationResponse`、`UserStatusResponse`、`SiteInfo`、`SwitchSiteRequest`、`MatchCandidate`、`ApproveRequest`、`RejectRequest`
|
||
- `site_code` 使用正则校验 `^[A-Za-z]{2}\d{3}$`
|
||
- `phone` 使用正则校验 `^\d{11}$`
|
||
- _Requirements: 4.5_
|
||
|
||
- [x] 4.3 创建小程序认证路由 `apps/backend/app/routers/xcx_auth.py`
|
||
- 实现 `POST /api/xcx/login`:微信登录(查找/创建用户 + 签发 JWT)
|
||
- 实现 `POST /api/xcx/apply`:提交申请
|
||
- 实现 `GET /api/xcx/me`:查询自身状态
|
||
- 实现 `GET /api/xcx/me/sites`:查询关联店铺
|
||
- 实现 `POST /api/xcx/switch-site`:切换店铺
|
||
- 实现 `POST /api/xcx/refresh`:刷新令牌
|
||
- 在 `apps/backend/app/main.py` 中注册路由
|
||
- _Requirements: 3.2, 3.3, 3.5, 4.1-4.6, 7.1, 7.2, 8.2_
|
||
|
||
- [x] 4.4 编写登录创建/查找用户属性测试
|
||
- **Property 2: 登录创建/查找用户正确性**
|
||
- **Validates: Requirements 3.2, 3.3**
|
||
|
||
- [x] 4.5 编写申请创建正确性属性测试
|
||
- **Property 4: 申请创建正确性**
|
||
- **Validates: Requirements 4.1, 4.2, 4.3, 4.4**
|
||
|
||
- [x] 4.6 编写手机号格式验证属性测试
|
||
- **Property 5: 手机号格式验证**
|
||
- **Validates: Requirements 4.5**
|
||
|
||
- [x] 4.7 编写重复申请拒绝属性测试
|
||
- **Property 6: 重复申请拒绝**
|
||
- **Validates: Requirements 4.6**
|
||
|
||
- [x] 5. 实现申请服务和人员匹配
|
||
- [x] 5.1 创建申请服务 `apps/backend/app/services/application.py`
|
||
- 实现 `create_application()`:创建申请 + site_code 映射查找
|
||
- 实现 `approve_application()`:批准 + 创建绑定/角色
|
||
- 实现 `reject_application()`:拒绝 + 记录原因
|
||
- 实现 `get_user_applications()`:查询用户申请列表
|
||
- _Requirements: 4.1-4.4, 6.1-6.6_
|
||
|
||
- [x] 5.2 创建人员匹配服务 `apps/backend/app/services/matching.py`
|
||
- 实现 `find_candidates(site_id, phone, employee_number)`
|
||
- 通过 FDW 查询 `fdw_etl.v_dim_assistant` 和 `fdw_etl.v_dim_staff` / `v_dim_staff_ex`
|
||
- 设置 `app.current_site_id` 进行 RLS 隔离
|
||
- 合并助教和员工匹配结果
|
||
- _Requirements: 5.1-5.6_
|
||
|
||
- [x] 5.3 创建角色权限服务 `apps/backend/app/services/role.py`
|
||
- 实现 `get_user_permissions(user_id, site_id)`
|
||
- 实现 `get_user_sites(user_id)`
|
||
- 实现 `check_user_has_site_role(user_id, site_id)`
|
||
- _Requirements: 8.1, 9.1_
|
||
|
||
- [x] 5.4 编写人员匹配合并属性测试
|
||
- **Property 7: 人员匹配合并正确性**
|
||
- **Validates: Requirements 5.1, 5.2, 5.3, 5.4**
|
||
|
||
- [x] 5.5 编写审核操作正确性属性测试
|
||
- **Property 8: 审核操作正确性**
|
||
- **Validates: Requirements 6.1, 6.2, 6.3, 6.4, 6.5**
|
||
|
||
- [x] 5.6 编写非 pending 审核拒绝属性测试
|
||
- **Property 9: 非 pending 申请审核拒绝**
|
||
- **Validates: Requirements 6.6**
|
||
|
||
- [x] 6. 检查点 - 确保所有测试通过
|
||
- 确保所有测试通过,如有问题请向用户确认。
|
||
|
||
- [x] 7. 实现权限中间件和管理端路由
|
||
- [x] 7.1 创建权限中间件 `apps/backend/app/middleware/permission.py`
|
||
- 实现 `require_permission(*permission_codes)` 依赖
|
||
- 实现 `require_approved()` 依赖
|
||
- 检查用户 status + 权限列表
|
||
- _Requirements: 9.1-9.4_
|
||
|
||
- [x] 7.2 创建管理端审核路由 `apps/backend/app/routers/admin_applications.py`
|
||
- 实现 `GET /api/admin/applications`:查询申请列表
|
||
- 实现 `GET /api/admin/applications/{id}`:查询申请详情 + 候选匹配
|
||
- 实现 `POST /api/admin/applications/{id}/approve`:批准申请
|
||
- 实现 `POST /api/admin/applications/{id}/reject`:拒绝申请
|
||
- 在 `apps/backend/app/main.py` 中注册路由
|
||
- _Requirements: 6.1-6.6, 5.1-5.6_
|
||
|
||
- [x] 7.3 编写权限中间件拦截属性测试
|
||
- **Property 13: 权限中间件拦截正确性**
|
||
- **Validates: Requirements 8.3, 9.1, 9.2, 9.3**
|
||
|
||
- [x] 7.4 编写多店铺角色独立分配属性测试
|
||
- **Property 11: 多店铺角色独立分配**
|
||
- **Validates: Requirements 8.1**
|
||
|
||
- [x] 7.5 编写店铺切换令牌属性测试
|
||
- **Property 12: 店铺切换令牌正确性**
|
||
- **Validates: Requirements 8.2, 10.4**
|
||
|
||
- [x] 8. 集成与端到端验证
|
||
- [x] 8.1 更新 `apps/backend/app/config.py` 新增微信配置项
|
||
- 新增 `WX_APPID`、`WX_SECRET`、`WX_DEV_MODE` 配置读取
|
||
- _Requirements: 3.1, 14.3_
|
||
|
||
- [x] 8.2 更新 `apps/backend/app/main.py` 注册所有新路由
|
||
- 确保 `xcx_auth` 和 `admin_applications` 路由已注册
|
||
- 验证无路由冲突
|
||
- _Requirements: 全部_
|
||
|
||
- [x] 8.3 实现开发模式 mock 登录端点
|
||
- 在 `routers/xcx_auth.py` 中新增 `POST /api/xcx/dev-login`
|
||
- 仅在 `WX_DEV_MODE=true` 时注册
|
||
- 接受 `openid` 和可选 `status` 参数,直接查找/创建用户并返回 JWT
|
||
- _Requirements: 14.2, 14.3_
|
||
|
||
- [x] 8.4 编写用户状态查询完整性属性测试
|
||
- **Property 10: 用户状态查询完整性**
|
||
- **Validates: Requirements 7.1, 7.2**
|
||
|
||
- [x] 8.5 编写 disabled 用户登录拒绝属性测试
|
||
- **Property 3: disabled 用户登录拒绝**
|
||
- **Validates: Requirements 3.5**
|
||
|
||
- [x] 9. 小程序认证前端页面
|
||
- [x] 9.1 实现请求封装工具 `apps/miniprogram/miniprogram/utils/request.ts`
|
||
- 统一请求封装:自动附加 Authorization header
|
||
- 401 时自动尝试 refresh_token 刷新
|
||
- 刷新失败时跳转 login 页面
|
||
- 后端 base URL 从配置读取(开发环境 `http://localhost:8000`)
|
||
- _Requirements: 13.8_
|
||
|
||
- [x] 9.2 实现登录页 `apps/miniprogram/miniprogram/pages/login/`
|
||
- 调用 `wx.login()` 获取 code
|
||
- 发送 code 到 `POST /api/xcx/login`
|
||
- 根据返回的 `user_status` 路由到对应页面
|
||
- 存储 token 到 globalData 和 Storage
|
||
- 参考 H5 原型 `docs/h5_ui/pages/login.html`
|
||
- _Requirements: 13.1, 13.6, 13.7, 13.8_
|
||
|
||
- [x] 9.3 实现申请表单页 `apps/miniprogram/miniprogram/pages/apply/`
|
||
- 表单字段:球房ID(site_code)、申请身份、手机号、编号(选填)、昵称
|
||
- 前端校验:site_code 格式(2字母+3数字)、手机号(11位数字)
|
||
- 提交到 `POST /api/xcx/apply`
|
||
- 成功后跳转 reviewing 页面
|
||
- 参考 H5 原型 `docs/h5_ui/pages/apply.html`
|
||
- _Requirements: 13.2, 13.3_
|
||
|
||
- [x] 9.4 实现审核等待页 `apps/miniprogram/miniprogram/pages/reviewing/`
|
||
- 显示当前申请状态(审核中/已拒绝)
|
||
- 显示申请信息摘要(球房ID、申请身份、手机号)
|
||
- 拒绝时显示拒绝原因 + "重新申请"按钮
|
||
- 支持下拉刷新查询最新状态
|
||
- 参考 H5 原型 `docs/h5_ui/pages/reviewing.html`
|
||
- _Requirements: 13.4, 13.5_
|
||
|
||
- [x] 9.5 实现无权限页 `apps/miniprogram/miniprogram/pages/no-permission/`
|
||
- 显示账号已禁用提示
|
||
- 参考 H5 原型 `docs/h5_ui/pages/no-permission.html`
|
||
- _Requirements: 13.7_
|
||
|
||
- [x] 9.6 更新 `app.ts` 和 `app.json`
|
||
- 在 `app.json` 中注册新页面(login、apply、reviewing、no-permission)
|
||
- 在 `app.ts` 的 `onLaunch` 中实现自动登录逻辑
|
||
- 根据用户状态路由到对应页面
|
||
- 扩展 globalData 类型定义(token、userInfo、currentSiteId、sites)
|
||
- _Requirements: 13.8_
|
||
|
||
- [x] 10. 前后端联调验证
|
||
- [x] 10.1 编写联调指南文档 `apps/miniprogram/doc/auth-integration-guide.md`
|
||
- 微信开发者工具项目导入配置说明
|
||
- 后端启动步骤(含 `WX_DEV_MODE=true` 配置)
|
||
- 测试流程:mock 登录 → 申请 → 管理端审核 → 重新登录验证
|
||
- 常见问题排查
|
||
- _Requirements: 14.1, 14.4_
|
||
|
||
- [x] 10.2 在微信开发者工具中执行联调验证
|
||
- 验证登录流程:wx.login → 后端 → JWT 返回
|
||
- 验证申请流程:表单提交 → 后端创建申请 → 审核等待页展示
|
||
- 验证状态路由:pending/approved/rejected/disabled 各状态正确跳转
|
||
- 验证 token 刷新:access_token 过期后自动刷新
|
||
- _Requirements: 14.1_
|
||
|
||
- [x] 11. 属性测试全量运行(100 次迭代)— ✅ 15/15 全部通过
|
||
- 前面各任务中的属性测试仅用 5 次迭代快速验证逻辑正确性
|
||
- 本任务集中对所有属性测试执行 100 次迭代,确保健壮性
|
||
- 运行脚本:`scripts/ops/_run_auth_pbt_full.py`
|
||
- 结果报告:`export/reports/auth_pbt_full_20260227_034401.md`
|
||
- 总耗时 375s,15 个属性测试全部通过(100 次迭代/每个)
|
||
- [x] 11.1 P1 迁移脚本幂等性 — ✅ 25.0s
|
||
- [x] 11.2 P2 登录创建/查找用户 — ✅ 49.8s
|
||
- [x] 11.3 P3 disabled 用户登录拒绝 — ✅ 37.9s
|
||
- [x] 11.4 P4 申请创建正确性 — ✅ 21.3s
|
||
- [x] 11.5 P5 手机号格式验证 — ✅ 2.5s
|
||
- [x] 11.6 P6 重复申请拒绝 — ✅ 24.7s
|
||
- [x] 11.7 P7 人员匹配合并正确性 — ✅ 14.9s
|
||
- [x] 11.8 P8 审核操作正确性 — ✅ 22.7s
|
||
- [x] 11.9 P9 非 pending 审核拒绝 — ✅ 18.8s
|
||
- [x] 11.10 P10 用户状态查询完整性 — ✅ 28.6s
|
||
- [x] 11.11 P11 多店铺角色独立分配 — ✅ 46.6s
|
||
- [x] 11.12 P12 店铺切换令牌正确性 — ✅ 45.3s
|
||
- [x] 11.13 P13 权限中间件拦截正确性 — ✅ 11.9s
|
||
- [x] 11.14 P14 JWT payload 结构一致性 — ✅ 4.6s
|
||
- [x] 11.15 P15 JWT 过期/无效拒绝 — ✅ 3.2s
|
||
|
||
- [x] 12. 最终检查点
|
||
- 任务 1-12 全部完成
|
||
- 15 个属性测试在 100 次迭代下全部通过(报告见 `export/reports/auth_pbt_full_20260227_034401.md`)
|
||
- 小程序 4 个认证页面(login/apply/reviewing/no-permission)已创建
|
||
- app.ts / app.json 已更新为认证感知版本
|
||
- 联调指南文档已编写
|
||
|
||
## 备注
|
||
|
||
- 标记 `*` 的任务为可选,可跳过以加速 MVP
|
||
- 每个任务引用了具体的需求编号,确保可追溯
|
||
- 检查点确保增量验证
|
||
- **属性测试策略**:开发阶段各任务中属性测试用 5 次迭代快速验证;任务 11 集中用 100 次迭代全量运行,逐个报告进度
|
||
- 单元测试验证具体例子和边界情况
|
||
- 所有数据库操作在测试库 `test_zqyy_app` 进行
|
||
- 迁移脚本放在 `db/zqyy_app/migrations/` 目录
|
||
- 属性测试放在 `tests/` 目录(Monorepo 级)
|