76853452f6
include AGENTS guidance updates, plan doc replacements, and utility script changes left in working tree
5.6 KiB
5.6 KiB
Auth UX Enhancement Design
日期: 2026-02-26 状态: 可实施(修订版)
目标
本次改动聚焦 4 个问题:
- 注册验证码页增加首次提示,降低用户困惑。
- 增加忘记密码流程(验证码模式)。
- 注册页增加邀请码输入(前端收集,后端暂不消费)。
- 修复用户名非唯一导致的用户查询问题,改为搜索接口。
非目标
- 不实现邀请码校验/入库。
- 不改动 Supabase 邮件模板基础设施(当前 self-hosted 已配置 recovery 模板 URL)。
- 不在本次引入新的认证机制(仅沿用 Supabase OTP + session)。
1. 忘记密码的可落地后端方案(对外两步)
1.1 约束说明(关键)
当前 Python SDK 的 verify_otp 参数模型不支持在验码时直接携带 new_password。因此不能走“单接口验码并改密”的实现。
1.2 可执行流程
对客户端暴露两步流程,第二步在后端内部执行两段动作:
POST /auth/password-reset:调用 Supabasereset_password_email发送 recovery 验证码。POST /auth/password-reset/confirm:接收email + token + new_password,后端内部先调用verify_otp(type="recovery"),再基于该会话调用update_user(password=...)。
这样既匹配 SDK 能力(verify_otp 不支持直接带 new_password),又保持前端体验为两步。
1.3 API 设计
POST /auth/password-reset
发送重置验证码。
Request
{
"email": "string(email)",
"redirect_to": "string(optional)"
}
Response: 204 No Content
Errors:
422参数错误429频率受限
POST /auth/password-reset/confirm
验证 recovery 验证码并完成改密。
Request
{
"email": "string(email)",
"token": "string(6 digits)",
"new_password": "string(min 6)"
}
Response: 204 No Content
Errors:
401验证码无效或过期422参数错误429频率受限
1.4 安全边界
- 用户档案更新走
users域(/users/me->UserService->Profile),仅允许公开资料字段。 - 密码修改走
auth域(Supabase Auth),不复用usersservice/repository。 POST /auth/password-reset/confirm必须在同一请求内完成“验码 + 改密”,禁止单独暴露“仅改密”接口。- 即使伪造
/users/me请求,也无法触发密码修改路径。
2. 前端忘记密码流程
流程:
登录页 -> 忘记密码页(输入邮箱) -> 验证码+新密码页 -> 返回登录并用新密码登录
关键点:
- 第二步页面一次提交
email + token + new_password到/auth/password-reset/confirm。 - 所有用户反馈统一使用
Toast(遵循apps/AGENTS.md)。 - 错误提示优先展示后端
detail。
3. 注册 UX 优化
3.1 验证码发送提示
在 register_verification_screen.dart 首次进入页面显示:
验证码已发送,如未收到请检查垃圾邮件或确认邮箱已注册
3.2 邀请码输入
在注册页新增可选字段:
- Label:
邀请码(选填) - Hint:
请输入邀请码
前端请求体可携带 invite_code,后端忽略该字段,不返回错误。
4. 用户搜索 Bug 修复
4.1 问题
GET /users/{username} 隐含“用户名唯一”假设,实际不成立。
4.2 方案
后端删除 GET /users/{username},改为 POST /users/search。
Request
{
"query": "string(1-100)"
}
Response
[
{
"id": "string",
"username": "string",
"avatar_url": "string|null",
"bio": "string|null"
}
]
查询策略:
- username: 模糊匹配(
ilike) - email: 精确匹配
- 最多返回 20 条
- 返回公开字段,不返回 email
4.3 前端联动
必须同步迁移 apps/lib/features/users/data/*(getByUsername -> searchUsers),否则删除后端旧路由后前端会直接 404。
5. 主要改动文件
后端
backend/src/v1/auth/schemas.pybackend/src/v1/auth/service.pybackend/src/v1/auth/gateway.pybackend/src/v1/auth/router.pybackend/src/v1/users/schemas.pybackend/src/v1/users/repository.pybackend/src/v1/users/service.pybackend/src/v1/users/router.pybackend/tests/integration/test_auth_routes.pybackend/tests/integration/test_users_routes.py
前端
apps/lib/features/auth/ui/screens/login_screen.dartapps/lib/features/auth/ui/screens/register_screen.dartapps/lib/features/auth/ui/screens/register_verification_screen.dartapps/lib/features/auth/ui/screens/forgot_password_screen.dart(新增)apps/lib/features/auth/ui/screens/reset_password_screen.dart(新增)apps/lib/features/auth/presentation/cubits/forgot_password_cubit.dart(新增)apps/lib/features/auth/presentation/cubits/reset_password_cubit.dart(新增)apps/lib/features/auth/data/auth_api.dartapps/lib/features/auth/data/auth_repository.dartapps/lib/features/auth/data/auth_repository_impl.dartapps/lib/features/users/data/users_api.dartapps/lib/features/users/data/users_repository.dartapps/lib/features/users/data/users_repository_impl.dartapps/lib/core/router/app_router.dart
文档
docs/runtime/runtime-route.md(按 AGENTS 规则必须同步)
6. 验收标准
- 注册验证码页首次进入显示提示。
- 登录页出现“忘记密码”入口。
- 忘记密码流程可完整走通(发码、确认改密、重新登录)。
- 注册页可输入邀请码且不影响注册。
GET /users/{username}被移除。POST /users/search可用且返回不含 email。- 后端与前端相关测试通过,文档已同步。