Files
FruitServer/docs/plans/2026-10-19-K19.md

88 lines
4.1 KiB
Markdown
Raw Permalink 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.
# 2026-10-19 K19 客户端账号中心
## 基线
- ReelShort `develop`: `7d68699`
- FruitServer `develop`: `5c93ba9`
- 只改 ReelShort;不改 FruitServer 业务代码、ReelShortWeb、specs、main。
## 范围
对接 `docs/api-phase1.md` §1.2 的六个个人中心接口:
| 方法 | 路径 | 客户端用途 |
| --- | --- | --- |
| GET | `/app/me` | 资料展示 |
| PUT | `/app/me` | 修改昵称、性别、生日 |
| GET | `/app/me/devices` | 只读登录设备列表 |
| GET | `/app/me/export` | 账号数据摘要与完整 JSON 复制 |
| POST | `/app/me/deactivate` | 申请注销并进入 15 天冷静期 |
| POST | `/app/me/deactivate/cancel` | 撤销待处理注销申请 |
## 接口口径
1. 资料响应仅使用:
`uid/nickname/avatarUrl/gender/countryCode/regionCode/language/timezone/currency/status/maskedTarget/createdAt/lastLoginAt/vipLevel/vipExpireAt`。
`vipLevel` 是整数;时间字段按 `LocalDateTime` 字符串解析。
2. 资料更新只发送本次变更字段:
`nickname/avatarUrl/gender/birthday/language/timezone/regionCode`。
本页只修改 `nickname/gender/birthday`;昵称 trim 后非空且不超过 30 字符,
性别取 `male/female/unknown`,生日格式 `yyyy-MM-dd`。
3. 设备数组只解析并展示
`deviceId/platform/deviceModel/firstSeenAt/lastSeenAt/status`;
`id/userId/deleted` 不展示、不打印。页面只读。
4. 导出按实际结构解析
`{profile, credentials, consents, devices}`,展示资料摘要、凭据、授权记录数和设备数;
“复制完整 JSON”只写系统剪贴板,不写本地文件。
5. 注销请求只发送 `reason`,不采集或上送密码;成功返回 `scheduledAt`。
成功后清本地会话,不调用 logout。撤销接口成功 `data=null`,失败原样透传后端文案。
6. 所有数值和 ID 使用 `jsonToId/jsonToInt`;错误由 `ApiException` 透传到逻辑层。
## 客户端改造
- `lib/core/data/remote/account_api.dart`
- `lib/core/data/models/account_profile.dart`
- `lib/core/data/models/account_device.dart`
- `lib/core/data/models/account_export.dart`
- `lib/core/data/repositories/account_repository.dart`
- `lib/pages/account/` 下四个页面及各自的 binding/logic
- `lib/pages/mine/mine_view.dart` 登录态新增“账号”卡
- `lib/core/data/services/auth_controller.dart` 新增 `applyProfile`
- `lib/app.dart` 注册 `AccountRepository` Provider
- `lib/l10n/app_{en,zh,id}.arb` 与生成文件
- 测试新增 `test/account/`、`test/support/fake_account_repository.dart`
## TDD 顺序
1. 先写 API/模型测试:六条路径、方法、请求体、字符串/数字 ID、缺字段;
运行定向测试确认红灯。
2. 实现 AccountApi、三个模型和 AccountRepository,定向测试转绿。
3. 先写 AuthController.applyProfile 测试:保留令牌、更新昵称/头像并持久化;
再实现。
4. 先写 profile/device/export/deactivate logic 测试:
资料保存回调登录态、注销成功清会话、撤销失败透传文案、导出复制内容;
再实现逻辑层。
5. 先写 widget 测试:我的页入口登录可见、资料回填与保存、设备空态、
注销二次确认、导出加载/失败/重试;再实现页面和入口。
6. 生成 l10n,跑全量门禁;最后一次全量测试与 APK 构建。
## 门禁
```text
dart analyze lib test
flutter test
flutter build apk --debug
```
Flutter 分支:`feature/flutter-k19-account`。
## 风险与待确认
- `GET /app/me` 不返回注销申请状态,UI 不猜测状态;撤销失败展示后端文案。
- 无设备下线接口,设备页只读;`TC-ACCOUNT-10` 的“单点下线”保留为缺口。
- 无头像上传接口,头像只展示;空值使用现有占位。
- 资料响应不含 `birthday`,也没有清空入口。本批生日只能设置,无法回填或清除;
不补后端字段,页面文案明确为本次设置。
- 注销成功后服务端立即吊销全部会话,本地同步清理;撤销入口在重新登录后仍可使用。
- 真机验证由用户执行,本批不提供开发机 curl 或设备侧结果作为证据。