小程序可在 Go 上完成微信手机号登录、测评、预约和下单,不再反代 Java。 Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
5.8 KiB
Markdown
165 lines
5.8 KiB
Markdown
# Feature Spec: 账号登录
|
||
|
||
> Status: `Active` · Map: `5.x 账号 [P1+]` · Phase: `P1`
|
||
> 规范:[../feature-design.md](../feature-design.md)
|
||
> 关联:[profile-bootstrap.md](profile-bootstrap.md)
|
||
|
||
---
|
||
|
||
## 1. 功能定义
|
||
|
||
| 字段 | 内容 |
|
||
|---|---|
|
||
| Name | 账号登录(小程序微信;H5 过渡账密) |
|
||
| Purpose | 跨设备持久用户身份;未登录不可生成/查看生日衍生结果 |
|
||
| Business Goal | 数据归属清晰;咨询与魔方同一人;为会员与深度版付费打底 |
|
||
|
||
| In | Out |
|
||
|---|---|
|
||
| 小程序微信登录 / 登出 / me | 短信 OTP |
|
||
| 设备身份绑定到已注册账号 | 游客可看完整报告 |
|
||
| Bearer Session | 运营 Admin 登录(独立) |
|
||
|
||
---
|
||
|
||
## 2. 用户价值
|
||
|
||
1. 换手机后仍能看到自己的档案与报告。
|
||
2. 登录后输入生日一次生成、各页直读。
|
||
3. N/A(登录本身免费)。
|
||
|
||
---
|
||
|
||
## 3. 用户角色
|
||
|
||
| Actor | 能力 |
|
||
|---|---|
|
||
| Visitor | 仅设备身份;可打开登录页;**不可**建档出结果 |
|
||
| User(已注册) | CRUD 本人档案与 TA;读已生成报告 |
|
||
| VIP / DeepAccess | 同前,权益不变 |
|
||
|
||
---
|
||
|
||
## 4. 用户流程
|
||
|
||
```text
|
||
进入结果页或建档
|
||
↓
|
||
未登录? → 小程序 login-pop(微信)或 H5 /login(过渡账密)
|
||
↓
|
||
Device 绑定到账号 User
|
||
↓
|
||
进入档案 / 结果页(读缓存报告)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 页面设计
|
||
|
||
| 路由 | 页面 |
|
||
|---|---|
|
||
| `/login` | H5 LoginPage(过渡账密;小程序已删除此页) |
|
||
| 小程序 `login-pop` | 微信手机号授权(唯一 C 端登录) |
|
||
| `/mine` | 展示账号手机号尾号 + 退出 |
|
||
|
||
---
|
||
|
||
## 6. 页面状态规范
|
||
|
||
| 状态 | UI |
|
||
|---|---|
|
||
| Loading | 登录中 |
|
||
| Error | 密码错误 / 手机号已注册 |
|
||
| Normal | 跳转 redirect 或 /mine |
|
||
|
||
---
|
||
|
||
## 7. Business Rules
|
||
|
||
| ID | Rule |
|
||
|---|---|
|
||
| R1 | **小程序:** 微信 `code` + 手机号授权登录;按 `wx_openid` 命中,否则按手机号合并历史账密账号;未命中则建号 |
|
||
| R2 | **H5 过渡:** OpenLogin(任意非空手机号+密码)仍可用,避免 H5 断服;小程序不再提供账密页。正式关掉账密须另改本 Spec |
|
||
| R3 | 登录成功后:签发 session;device_identities.user_id 改绑到账号 |
|
||
| R4 | 生成/查看档案与报告 API 必须已注册(users.phone 非空)且有效 session 或已绑设备账号 |
|
||
| R5 | 登出作废 session;设备可再登录其他账号 |
|
||
| R6 | 正式环境恢复校验前须改回本 Spec |
|
||
| R7 | 新账号未填昵称时,服务端用「意象词+场景词」词库(100×100)随机生成,如心语岛、微光谷 |
|
||
| R8 | 账号昵称可在个人档案页修改(PATCH `/auth/me`);首页与各页「自己」展示位统一用昵称(合盘/问答/星座/档案卡) |
|
||
| R9 | 账号头像可在「我的」页更换:相册或拍照上传;服务端持久化;GET `/auth/me` 返回 `avatar_url`;未设置时 UI 用愈心小人正面默认头像(`public/default-avatar.png`,源图 `public/logo/愈心小人1.png`) |
|
||
|
||
---
|
||
|
||
## 8. 数据模型影响
|
||
|
||
- `users.phone` UNIQUE · `users.wx_openid` UNIQUE · `users.wx_unionid` · `users.java_platform_user_id` · `users.password_hash` · `users.nickname` · `users.avatar_url`
|
||
- `user_sessions(token, user_id, expires_at)`
|
||
- 本地文件:`data/avatars/{user_id}.{jpg|png|webp}`(进程相对路径)
|
||
|
||
---
|
||
|
||
## 9. API 需求
|
||
|
||
| Method | Path | 说明 |
|
||
|---|---|---|
|
||
| POST | `/api/v1/auth/wechat` | 小程序微信登录 `{ code, encryptedData, iv }` |
|
||
| POST | `/api/v1/auth/register` | H5 过渡注册(可带 nickname) |
|
||
| POST | `/api/v1/auth/login` | H5 过渡登录 |
|
||
| POST | `/api/v1/auth/logout` | 登出 |
|
||
| GET | `/api/v1/auth/me` | 当前账号(含 avatar_url) |
|
||
| PATCH | `/api/v1/auth/me` | 更新昵称 `{ nickname }` |
|
||
| POST | `/api/v1/auth/me/avatar` | multipart `file`;jpeg/png/webp;≤2MB → 更新 avatar_url |
|
||
| GET | `/api/v1/media/avatars/:file` | 公开读头像文件 |
|
||
|
||
---
|
||
|
||
## 10. 权限设计
|
||
|
||
| 能力 | Visitor | User |
|
||
|---|---|---|
|
||
| register/login | ✓ | ✓ |
|
||
| profiles / reports 写读 | ✗ | ✓ |
|
||
| 上传头像 | ✗ | ✓ |
|
||
| 读头像媒体 | ✓ | ✓ |
|
||
|
||
---
|
||
|
||
## 11. 埋点
|
||
|
||
经统一 `track()`(见 [analytics.md](analytics.md) · [ops-analytics.md](ops-analytics.md))。
|
||
**非** P1 核心漏斗 5 事件;接入后走自有 `POST /analytics/events`(及可选 GA)。
|
||
禁止参数含手机号、明文密码、头像绝对 URL / `user_id`。
|
||
|
||
| Event | 触发 | 可选 params |
|
||
|---|---|---|
|
||
| `auth_register` | 账号新建成功(含 OpenLogin 自动建号,`is_new=true`) | `source`: login_page |
|
||
| `auth_login` | 已有账号登录成功(`is_new=false`) | `source`: login_page |
|
||
| `auth_logout` | 用户在「我的」点退出且本地 session 已清 | `surface`: mine |
|
||
| `avatar_sheet_opened` | 「我的」打开更换头像 sheet | `surface`: mine |
|
||
| `avatar_upload_succeeded` | 头像上传 API 成功且 UI 刷新为新图 | `source`: album \| camera |
|
||
| `avatar_upload_failed` | 头像上传失败(校验/网络/服务端) | `source`: album \| camera · `reason`: too_large \| bad_type \| network \| server \| unknown |
|
||
| `nickname_updated` | PATCH 昵称成功 | `surface`: profile |
|
||
|
||
`page_view` 对 `/login` · `/mine` 由路由自动采集,本 Spec 不重复定义。
|
||
|
||
**实现状态:** 事件名以本表为准;H5 已挂 Login / Mine / Profile(`track` → 自有 ingest + 可选 GA)。
|
||
|
||
---
|
||
|
||
## 12. 测试验收标准
|
||
|
||
| Given | When | Then |
|
||
|---|---|---|
|
||
| 新设备 | 未登录 POST portrait | 401 |
|
||
| 注册成功 | 建档 | 200 且生成报告包 |
|
||
| 登录另一设备 | list profiles | 见同一账号数据 |
|
||
| 已登录设备 | POST logout 后无 Bearer 再 GET /auth/me | 401(设备已解绑,刷新不再显示登录态) |
|
||
|
||
---
|
||
|
||
## 13. AI 开发前检查
|
||
|
||
- [x] lexicon:登录/注册/账号
|
||
- [x] 不碰 Admin Auth
|
||
- [x] 咨询域见 Spec `consult-miniprogram`(ECR-050)
|