docs(plans): 下发 K19 账号中心接口对接任务
This commit is contained in:
1 parent
d3b347aa09
commit
5c93ba9131
1 file changed
+105
@@ -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 限流做成可配置的,不限制或限制数量」。
|
||||
|
||||
Reference in new issue
Block a user