Files
social-app/docs/plans/2026-02-26-auth-ux-enhancement-design.md
T
qzl 76853452f6 chore: commit remaining workspace updates
include AGENTS guidance updates, plan doc replacements, and utility script changes left in working tree
2026-02-26 17:59:30 +08:00

205 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Auth UX Enhancement Design
**日期**: 2026-02-26
**状态**: 可实施(修订版)
## 目标
本次改动聚焦 4 个问题:
1. 注册验证码页增加首次提示,降低用户困惑。
2. 增加忘记密码流程(验证码模式)。
3. 注册页增加邀请码输入(前端收集,后端暂不消费)。
4. 修复用户名非唯一导致的用户查询问题,改为搜索接口。
## 非目标
- 不实现邀请码校验/入库。
- 不改动 Supabase 邮件模板基础设施(当前 self-hosted 已配置 recovery 模板 URL)。
- 不在本次引入新的认证机制(仅沿用 Supabase OTP + session)。
---
## 1. 忘记密码的可落地后端方案(对外两步)
### 1.1 约束说明(关键)
当前 Python SDK 的 `verify_otp` 参数模型不支持在验码时直接携带 `new_password`。因此不能走“单接口验码并改密”的实现。
### 1.2 可执行流程
对客户端暴露两步流程,第二步在后端内部执行两段动作:
1. `POST /auth/password-reset`:调用 Supabase `reset_password_email` 发送 recovery 验证码。
2. `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
```json
{
"email": "string(email)",
"redirect_to": "string(optional)"
}
```
Response: `204 No Content`
Errors:
- `422` 参数错误
- `429` 频率受限
#### POST /auth/password-reset/confirm
验证 recovery 验证码并完成改密。
Request
```json
{
"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),不复用 `users` service/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
```json
{
"query": "string(1-100)"
}
```
Response
```json
[
{
"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.py`
- `backend/src/v1/auth/service.py`
- `backend/src/v1/auth/gateway.py`
- `backend/src/v1/auth/router.py`
- `backend/src/v1/users/schemas.py`
- `backend/src/v1/users/repository.py`
- `backend/src/v1/users/service.py`
- `backend/src/v1/users/router.py`
- `backend/tests/integration/test_auth_routes.py`
- `backend/tests/integration/test_users_routes.py`
### 前端
- `apps/lib/features/auth/ui/screens/login_screen.dart`
- `apps/lib/features/auth/ui/screens/register_screen.dart`
- `apps/lib/features/auth/ui/screens/register_verification_screen.dart`
- `apps/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.dart`
- `apps/lib/features/auth/data/auth_repository.dart`
- `apps/lib/features/auth/data/auth_repository_impl.dart`
- `apps/lib/features/users/data/users_api.dart`
- `apps/lib/features/users/data/users_repository.dart`
- `apps/lib/features/users/data/users_repository_impl.dart`
- `apps/lib/core/router/app_router.dart`
### 文档
- `docs/runtime/runtime-route.md`(按 AGENTS 规则必须同步)
---
## 6. 验收标准
- [ ] 注册验证码页首次进入显示提示。
- [ ] 登录页出现“忘记密码”入口。
- [ ] 忘记密码流程可完整走通(发码、确认改密、重新登录)。
- [ ] 注册页可输入邀请码且不影响注册。
- [ ] `GET /users/{username}` 被移除。
- [ ] `POST /users/search` 可用且返回不含 email。
- [ ] 后端与前端相关测试通过,文档已同步。