docs(plans): 下发 K19 账号中心接口对接任务

This commit is contained in:
Zhou Weidong authored and trae-solo-agent committed 2026-10-19 09:44:41 +08:00
1 parent d3b347aa09
commit 5c93ba9131
1 file changed
+105
+105
View File
@@ -20,6 +20,111 @@
---
## [待处理] 2026-10-19 | K19 客户端账号中心:资料 / 设备 / 数据导出 / 注销
**用户指令(2026-10-19)**:「先写 K19 任务书并派单」。
> 只改客户端 `ReelShort`。后端、`ReelShortWeb`、`specs`、`main` 一律不动。
### 一、背景与缺口
后端 `/app` 共 45 个接口,客户端已接 26 个。本轮对接账号中心 6 个(`api-phase1.md` §1.2,第 157–162 行;实现见
`fruitshorts-app-api/.../AppMeController.java`):
| 方法 | 路径 | 客户端现状 |
| --- | --- | --- |
| GET | `/app/me` | 未对接 |
| PUT | `/app/me` | 未对接 |
| GET | `/app/me/devices` | 未对接 |
| GET | `/app/me/export` | 未对接 |
| POST | `/app/me/deactivate` | 未对接 |
| POST | `/app/me/deactivate/cancel` | 未对接 |
### 二、接口与字段口径(以后端代码为准确认,勿臆造)
1. **GET `/app/me`** → `AppUserRespVO`:`uid, nickname, avatarUrl, gender, countryCode, regionCode,
language, timezone, currency, status, maskedTarget, createdAt, lastLoginAt, vipLevel(Integer),
vipExpireAt`。`vipLevel` 是数字,其余时间字段是 `LocalDateTime` 字符串。
2. **PUT `/app/me`** → 请求 `ProfileUpdateReqVO`,全部字段可选,**只传本次改动的字段**:
`nickname, avatarUrl, gender, birthday(yyyy-MM-dd), language, timezone, regionCode`。
`nickname` 为空串时后端忽略;`gender` 取值按 `schema-phase1.sql` 注释用小写
`male / female / unknown`;`birthday` 后端只能设置、不能清空。响应同 `AppUserRespVO`。
3. **GET `/app/me/devices`** → **直接返回 `AppUserDevice` 实体数组**(不是专用 VO):
`id, userId, deviceId, platform, deviceModel, firstSeenAt, lastSeenAt, status, createdAt, updatedAt, deleted`。
按契约 §0,`Long` 字段以字符串下发。客户端**只展示** `deviceId/platform/deviceModel/firstSeenAt/lastSeenAt/status`,
`userId`、`deleted` 一律忽略、不落日志、不上屏。
4. **GET `/app/me/export`** → `{profile: AppUserRespVO, credentials: [{type, masked, verified}], consents: [...], devices: [...]}`
(以 `AppUserService.exportAccount` 实际结构为准)。
5. **POST `/app/me/deactivate`** → 请求 `{reason}`(`password` 后端当前不校验,**客户端不采集、不上送**);
成功返回 `scheduledAt`(15 天冷静期截止时间,`LocalDateTime`)。后端同时吊销全部会话。
已有申请时返回业务错误,文案「注销申请已在处理中」。
6. **POST `/app/me/deactivate/cancel`** → 成功 `data = null`;无待处理申请时错误文案「没有待处理的注销申请」。
**契约缺口(本批如实标注,不得自行补后端)**:
- `GET /app/me` 不返回「注销申请中」状态 → UI 不能做状态判断,只能把后端错误文案原样透传;
「撤销注销」入口常驻,无申请时展示后端返回的文案。
- 无「设备下线 / 踢出」接口 → 设备页**只读**;`TC-ACCOUNT-10` 中「单点下线」记为缺口,留待后续批次。
- 无头像上传接口 → 头像**只展示**(`avatarUrl` 为空用现有占位图标),本批不做上传、不做 URL 输入框。
### 三、客户端改造范围
1. **remote**:新增 `lib/core/data/remote/account_api.dart`,六个方法,路径与请求体严格按上表;
错误一律抛现有 `ApiException`(禁止吞异常、禁止空 catch)。
2. **models**:新增 `account_profile.dart`、`account_device.dart`、`account_export.dart`。
数值/ID 解析用 `json_numbers.dart` 的 `jsonToId` / `jsonToInt`,兼容字符串与数字两种下发形式。
3. **repository**:新增 `account_repository.dart`(接口 + `HttpAccountRepository`);
在 `app.dart` 的 Provider 树注册,供页面与测试注入(`FakeAccountRepository` 放 `test/support/`)。
4. **页面**(建议 `lib/pages/account/`,沿用 provider binding/logic/view 三层):
- **个人资料**:进入时 `GET /app/me`;可改 `nickname`(去空格后非空、≤30 字符,客户端校验)、
`gender`(male/female/unknown,本地化文案)、`birthday`(日期选择,`yyyy-MM-dd`);
`uid / maskedTarget / countryCode / currency / status` 只读展示;`language / timezone / regionCode` 只读。
保存调 `PUT /app/me`,成功后用响应刷新页面,并**同步本地登录态**(见第 6 条)。
- **登录设备**:`GET /app/me/devices`,列表展示平台、机型、设备号(脱敏显示,保留首尾各 4 位)、
首次/最近活跃时间、状态;空态用现有 `EmptyState`;本页只读。
- **数据导出**:`GET /app/me/export`,展示资料摘要、凭据(`type/masked/verified`)、授权记录数、设备数;
提供「复制完整 JSON」到剪贴板(`Clipboard.setData`)+ SnackBar 提示;不写本地文件。
- **注销账号**:15 天冷静期与「申请后立即登出全部设备」的显著提示;可选注销原因(≤200 字);
「申请注销」必须二次确认弹窗 → 成功后展示 `scheduledAt` 并清空本地会话(服务端已吊销全部会话,
用 `AuthController.clear()`,不要再调 logout),回到未登录态;
「撤销注销申请」常驻,成功/失败均以后端文案提示。
5. **入口**:`lib/pages/mine/mine_view.dart` 在已登录态新增「账号」卡(置于钱包卡之后、菜单卡之前):
个人资料 / 登录设备 / 数据导出 / 注销账号,四项带图标与分隔线;未登录不显示。样式沿用现有 `_menuCard`。
6. **登录态同步**:`AuthController` 增加公开方法(如 `applyProfile(AuthUser)`),资料保存成功后更新
内存 session 的 `uid/nickname/avatarUrl` 并持久化,使「我的」页昵称即时生效;不改令牌与刷新逻辑。
7. **l10n**:新增文案必须同时写入 `app_en.arb / app_zh.arb / app_id.arb` 并重新生成;
印尼语为印尼市场主语言,禁止留英文占位。
8. **测试(TDD,先红后绿)**:
- API/模型:六接口路径与请求体、`Long` 字符串/数字两种解析、缺字段容错、错误文案透传;
- logic:资料保存成功后回调登录态、注销成功后清会话、撤销失败展示后端文案、导出复制内容;
- widget:我的页四个入口仅登录态可见、资料页字段回填与保存、设备空态、注销二次确认、
数据导出页加载/失败/重试。
- 既有测试不得改断言;如需适配只改注入的 Fake。
### 四、约束与门禁
- 代码规模红线:函数 ≤50 行、参数 ≤5、类 ≤300 行、文件 ≤500 行、嵌套 ≤4、圈复杂度 ≤10;禁止魔法值。
- public 类/方法必须有文档注释,文件首行统一 `// Author: fruit.com.cn`;禁止裸 `then()`、空 catch。
- 门禁(不达标不提交):`dart analyze lib test` 零告警;`flutter test` 全过;
`flutter build apk --debug` 构建通过。
- 真机验证由用户执行,Codex **不得**自行做设备侧验证,也不得用本机 curl 充当设备证据。
### 五、Git 与交接
- 从干净 `develop`(基线 `7d68699`)拉 `feature/flutter-k19-account`;小步提交,
`type(scope): 描述`(≤50 字符),只 `git add` 本次文件。
- 完成后 `git checkout develop && git merge --no-ff feature/flutter-k19-account && git push origin develop`;
**不动 `main`**;提交作者与提交者统一 `Zhou Weidong <502333560@qq.com>`。
- 任务书与留痕属于 FruitServer 仓库:`docs/plans/PROGRESS.md` 追加命令 + 原始输出 + 解读,
单独提交到 FruitServer `develop`(`docs(plans): ...`),不夹带客户端代码。
### 六、回执要求
完成后停住并回执:分支与提交号、六个接口的调用位置、测试条数与结果、`dart analyze` / `flutter test` /
`flutter build apk --debug` 原始结论、已知缺口(设备下线 / 头像上传 / 注销状态查询),
以及「用户可照做的真机验证步骤 + 每步预期结果」。
---
## [已处理·待用户验收] 2026-10-17 | K16 注册限流改为可配置(支持不限制)
**用户指令(2026-10-17)**:「注册 429 限流做成可配置的,不限制或限制数量」。