feat(backend): 补齐 C 端商业化与账号缺口(金币充值/会员/搜索/语言筛选/Google登录/短信/商店可配置接入)
This commit is contained in:
1 parent
212834d59d
commit
63b086998e
25 files changed
+859
-29
No files matched your search
+13
-1
@@ -165,10 +165,14 @@ app.register.max-per-device-per-day
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| GET | `/app/home/feed` | 首页:轮播 + 分区,卡片带 `preview` 可播预览集 |
|
||||
| GET | `/app/home/feed` | 首页:轮播 + 分区,卡片带 `preview` 可播预览集与 `language` 语种 |
|
||||
| GET | `/app/discover/feed` | 发现页分区 |
|
||||
| GET | `/app/categories` | 分类列表 |
|
||||
| GET | `/app/dramas/{id}` | 详情(含剧集列表,免费集带**已签名**播放地址) |
|
||||
| GET | `/app/search?keyword=&pageIndex=&pageSize=` | 搜索已上线短剧:按标题/简介模糊匹配,分页返回卡片列表 |
|
||||
|
||||
> 卡片(`AppDramaCardVO`)统一新增 `language` 字段(取值如 `zh-CN` / `id`),
|
||||
> 首页、发现页、分类、收藏、搜索等所有下发卡片的场景都带该字段,客户端可据此做语言筛选。
|
||||
|
||||
### 1.4 播放(已实现,链路已重做)
|
||||
|
||||
@@ -257,9 +261,17 @@ app.register.max-per-device-per-day
|
||||
| --- | --- | --- |
|
||||
| GET | `/app/wallet` | 金币余额 + 最近流水 |
|
||||
| POST | `/app/episodes/{id}/unlock` | 金币解锁分集;幂等键 `unlock:{userId}:{episodeId}`,重复调用不重复扣币 |
|
||||
| GET | `/app/products` | 充值商品列表(只返回上架商品,`type` 可选 `COIN_PACK`/`VIP`) |
|
||||
| POST | `/app/orders` | 创建充值订单(`body` 传 `productId`,返回 `CREATED` 订单,等待支付) |
|
||||
| GET | `/app/orders` | 我的订单 |
|
||||
| POST | `/app/orders/verify` | 提交 Google Play 票据:服务端校验 → 建单 → 发权益(详见下方说明) |
|
||||
|
||||
> `GET /app/products` 只返回 `status=1`(上架)的商品,按 `sort` 升序、`id` 降序。
|
||||
> `POST /app/orders` 请求体 `{ "productId": 123 }`,商品下架时返回 `400 商品已下架`;
|
||||
> 订单 `coinAmount = coinAmount + bonusCoin`(与商店票据口径一致),状态为 `CREATED`。
|
||||
> VIP 商品下单后交付时发放 `TYPE_VIP` 权益(`dramaId=0`、`episodeId=0`,永久有效),
|
||||
> 播放/下载的权益判定在 `EntitlementPort` 中增加「存在有效 VIP 权益即放行」的判定。
|
||||
|
||||
解锁后播放入口与下载入口会同时放行 —— 权益判定由交易模块的 `EntitlementPort` 实现提供,
|
||||
播放域与下载域都不需要改代码。金币变动一律带幂等键并写 `coin_ledger`,钱包余额与流水同事务。
|
||||
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
## 【待 Trae 协助】2026-10-19 | 客户端 P0→P2 契约缺口(不阻塞其余项)
|
||||
|
||||
> 以下能力当前后端契约/配置不具备,客户端不做假按钮、不造接口;已落地的同类入口保持真实可用。请确认后端排期或补充凭据。
|
||||
|
||||
1. **看广告解锁**:`/app/**` 无激励广告相关接口,Flutter 工程也未集成广告 SDK;当前只实现金币解锁。需提供广告平台账号、广告位 ID 与发奖校验接口。
|
||||
2. **Google Play 充值**:`POST /app/orders/verify` 需要真实 `purchaseToken` 与商店商品配置;服务端默认 `verifier=disabled`,客户端无 Google Play Billing 商品/凭据。已按「暂不接则隐藏入口」处理,钱包页不放假充值按钮。
|
||||
3. **短信验证码通道**:`POST /app/auth/otp` 已对接,但服务端当前是 `LogOtpSender`,只写日志不发短信;UI 可发起请求,真机收码需替换短信供应商后才能验收。
|
||||
4. **创作 tab**:契约明确「创作者中心由 Web 端承载,App 不提供创作者中心」,C 端只有 `POST /app/creator/apply`,没有 AI 制作、上传、发布接口。无法做真实创作 tab,需产品确认是否改为「入驻申请」或开放 C 端接口。
|
||||
5. **会员购买**:无 C 端会员商品/订阅接口,后台商品契约也禁止启用 VIP 商品;无法做真实购买流程。
|
||||
6. **搜索接后端**:`/app/**` 无搜索接口;当前只能对已加载目录本地过滤,无法做服务端搜索。
|
||||
7. **剧场语言筛选**:剧目有 `language` 字段,但 `/app/home/feed`、`/app/discover/feed`、卡片 VO、详情 VO 均未下发语言;客户端无真实数据可筛。
|
||||
8. **播放清晰度切换**:`/app/episodes/{id}/play` 当前只下发 `qualities: ["AUTO"]`,没有多清晰度地址;仅保留 AUTO,不伪造切换。
|
||||
9. **Google 登录**:需要 Google OAuth 客户端 ID/服务器配置;当前登录页已移除该假入口。
|
||||
|
||||
---
|
||||
|
||||
## 补充指令(2026-10-19 23:30 周卫东)
|
||||
|
||||
> 1. **UI/UX 参考 Google 设计体系**:遵循 Material Design 3 规范 + Google Stitch 设计理念,界面现代简洁、层次分明,做成精品,不要粗糙界面。
|
||||
> 2. **收尾提交 develop**:所有工作做完、门禁全过后,把 feature 分支合并回 develop 并 `git push origin develop`。用户明天拉 develop 打包验证。
|
||||
|
||||
---
|
||||
# INBOX — 给 Codex 的指令队列(FruitServer 仓库内)
|
||||
|
||||
> **Codex 每次开始任务前必须先读本文件**(2026-10-16 起指令通道从 specs 仓库迁到本仓库)。
|
||||
@@ -20,6 +42,46 @@
|
||||
|
||||
---
|
||||
|
||||
## 🚨🚨 立即开工(最高优先 · 不要等巡检 · 不要做任何收口动作)—— 2026-10-19 周卫东拍板
|
||||
|
||||
> **读到这里就直接开始做下面 P0 → P1 → P2,逐条落地并跑门禁,每条完成写 PROGRESS 留痕。**
|
||||
>
|
||||
> **背景**:周卫东对照「漫剧 App 功能规划图」盘点 ReelShort(Flutter)现状,结论:「看剧」链路真实可用,但「商业化」和「创作」大面积是**假功能/缺失**(金币写死 0、充值弹「示例数据」、解锁弹「即将开放」、下载不落盘、Google/手机登录弹「即将开放」、创作 tab 整个没有)。
|
||||
>
|
||||
> **拍板**:全量补齐 P0→P1→P2。原则——**不贪多,但每个都要能用、要精品**。后端接口已就绪,**全部是 App 端对接活,不重做后端**。
|
||||
>
|
||||
> **工作目录**:`C:\work\ReelShort`(Flutter,分支 `develop`)。禅道任务:29/30/31。
|
||||
|
||||
### P0 — 消灭假功能(做出来的必须能用,最优先)
|
||||
1. 内容解锁闭环:对接 `POST /app/episodes/{id}/unlock`,金币解锁 + 看广告解锁跑通,不再「即将开放」
|
||||
2. 金币余额:对接 `GET /app/wallet`,不再写死 0
|
||||
3. 充值流程:对接订单接口;若支付暂不接则**先隐藏入口**,不给假按钮
|
||||
4. 本地下载落盘:对接 `GET /app/downloads/{episodeId}/url`,真下载 + 离线播放
|
||||
5. 手机号登录:对接 `POST /app/auth/otp`,不再「即将开放」
|
||||
|
||||
### P1 — 补齐规划核心功能
|
||||
6. 「创作」tab(底部导航 3→4):AI 制作入口 + 上传发布入口,对接 creator-center 接口
|
||||
7. 开通会员购买流程
|
||||
8. 首页「榜单」tab
|
||||
9. 剧场「语言筛选」
|
||||
|
||||
### P2 — UX 打磨(精品感)
|
||||
10. 搜索接后端搜索接口(不再本地过滤)
|
||||
11. 点赞/评论显示计数
|
||||
12. 设置页完善(移除 debug「服务器地址」)
|
||||
13. 首页轮播 banner 真正用起来
|
||||
14. 播放清晰度切换
|
||||
|
||||
**门禁**:每条做完 `dart analyze lib test` 零告警 + `flutter test` 全过,再下一条。测试命名 `should_<期望>_when_<条件>`。
|
||||
### 执行状态(2026-10-19 收尾)
|
||||
- P0:金币解锁、钱包余额、本地下载落盘、手机号登录已完成;充值入口按契约隐藏;看广告解锁缺广告接口,见顶部第 1 条。
|
||||
- P1:榜单 tab 已完成;创作 tab、会员购买、剧场语言筛选缺契约,见顶部第 4/5/7 条。
|
||||
- P2:点赞/评论计数、设置页清理、首页轮播 banner 已完成;服务端搜索、播放清晰度切换缺契约,见顶部第 6/8 条。
|
||||
- 门禁:`dart analyze lib test` 零告警;`flutter test` 全过(`+385 ~1`);`flutter build apk --debug` 成功。
|
||||
- 交付:feature/flutter-p0-commerce 已以 --no-ff 合并 develop(ec2db68)并推送 origin/develop。
|
||||
|
||||
---
|
||||
|
||||
## [已处理·待用户验收] 2026-10-17 | K16 注册限流改为可配置(支持不限制)
|
||||
|
||||
**用户指令(2026-10-17)**:「注册 429 限流做成可配置的,不限制或限制数量」。
|
||||
|
||||
@@ -3756,3 +3756,162 @@ cf03178 feat(flutter): 首页改为两列全部剧目网格
|
||||
预期:标题最多 2 行、类型最多 1 行,不横向溢出;空态和失败重试文案保留。
|
||||
|
||||
设备侧截图、日志与最终验收结论由用户执行。
|
||||
|
||||
## 2026-10-19 | P0 商业化与登录闭环(Flutter)
|
||||
|
||||
### 1. 金币余额 + 金币解锁
|
||||
- 新增 `WalletController`、`CommerceApi`、`CommerceRepository`、`WalletSnapshot`/`UnlockResult`;钱包页读取 `GET /app/wallet`,展示服务端余额、累计充消、流水、空态与重试。
|
||||
- 播放器 `COIN_REQUIRED` 时调用 `POST /app/episodes/{id}/unlock`,成功后强制刷新播放票据并起播;余额不足保留后端 message。
|
||||
- 个人页金币卡改为真实余额;未登录先走登录。
|
||||
- 命令与结果:
|
||||
```text
|
||||
flutter test test/commerce test/wallet
|
||||
+6: All tests passed!
|
||||
```
|
||||
- 解读:余额、流水、解锁扣币与错误回传均由服务端数据驱动,没有本地写死余额。
|
||||
|
||||
### 2. 充值入口
|
||||
- 契约要求 Google Play `purchaseToken`,开发环境 `verifier=disabled` 且无商品凭据;按指令「暂不接则隐藏入口」处理,钱包页与个人页均不保留假充值按钮。
|
||||
- 阻塞已写入 `INBOX.md` 顶部「【待 Trae 协助】」。
|
||||
|
||||
### 3. 本地下载落盘 + 离线播放
|
||||
- 新增 `DownloadStorage` / `FileDownloadStorage`:`GET /app/downloads/{episodeId}/url` 取签名地址,流式写 `.part`,完成后原子改名;冷启动扫描本地目录恢复索引。
|
||||
- `DownloadController.startDownload` 上报 `DOWNLOADING` / `COMPLETED` / `FAILED`,下载页展示实时进度;下载完成可离线播放,删除同时清本地文件和服务端授权。
|
||||
- 播放器优先使用已同步本地文件,命中时不请求播放票据。
|
||||
- 命令与结果:
|
||||
```text
|
||||
flutter test test/download/download_storage_test.dart test/download/download_controller_local_test.dart
|
||||
+3: All tests passed!
|
||||
|
||||
flutter test test/download
|
||||
+36: All tests passed!
|
||||
```
|
||||
- 解读:MP4 分集真实落盘,下载页可离线起播;HLS 分片场景由后端下载接口当前返回 MP4 地址覆盖。
|
||||
|
||||
### 4. 手机号 OTP 登录
|
||||
- `AuthApi` 新增 `POST /app/auth/otp`、手机号验证码登录/注册;登录页新增 Material 3 底部表单(手机号、验证码、60 秒重发倒计时、登录/注册切换)。
|
||||
- 移除了 Google 登录假入口;短信通道仍是后端 `LogOtpSender`,已在 INBOX 标注。
|
||||
- 命令与结果:
|
||||
```text
|
||||
flutter test test/auth
|
||||
+26: All tests passed!
|
||||
```
|
||||
- 解读:客户端能真实发起 OTP、携带 `deviceId` 登录/注册并落盘会话;真机收码依赖后端短信供应商。
|
||||
|
||||
### 5. 门禁
|
||||
```text
|
||||
dart analyze lib test
|
||||
No issues found!
|
||||
|
||||
flutter test
|
||||
00:19 +374 ~1: All tests passed!
|
||||
```
|
||||
- 解读:静态检查零告警,全部测试通过;`~1` 为联调测试在无数据时主动跳过。
|
||||
## 2026-10-19 | P1 首页榜单 tab(Flutter)
|
||||
|
||||
### 1. 数据来源与交互
|
||||
- `RankingLogic` 只消费 `/app/home/feed` 已返回的 `hot` / `new` 分区,保持服务端顺序并按 id 去重;分区缺失时回退到完整目录,不生成虚构分数或假数据。
|
||||
- 新增 `RankingPage`:Material 3 分段切换、榜首大图卡、第 2 名起紧凑榜单、真实集数/类型文案、空态;条目点击复用现有详情页。
|
||||
- 底部导航 3→4:首页 / 发现 / 榜单 / 我的,榜单返回逻辑复用根 tab 的状态保留。
|
||||
|
||||
### 2. 测试(先红后绿)
|
||||
```text
|
||||
flutter test test/ranking/ranking_logic_test.dart test/ranking/ranking_view_test.dart test/home/home_nav_ui_test.dart
|
||||
+8: All tests passed!
|
||||
```
|
||||
- 解读:热门顺序、新剧切换、去重回退、榜单渲染与详情跳转、四 tab 导航均已覆盖。
|
||||
|
||||
### 3. 门禁
|
||||
```text
|
||||
dart analyze lib test
|
||||
No issues found!
|
||||
|
||||
flutter test
|
||||
00:20 +379 ~1: All tests passed!
|
||||
```
|
||||
- 解读:静态检查零告警,全量测试通过;`~1` 为联调测试在无数据时主动跳过。
|
||||
## 2026-10-19 | P2 移除 debug 服务器地址入口(Flutter)
|
||||
|
||||
- 设置 sheet 只保留界面语言(English / 简体中文 / Bahasa Indonesia),删除 `server-endpoint-setting` 编辑入口与 `debugShowSetting` 分支。
|
||||
- 首页目录失败态只保留错误说明与重试,删除 debug 服务器按钮及仅用于运行时代理编辑的 `server_endpoint_dialog.dart`。
|
||||
- 运行时地址仍可由 `--dart-define=API_BASE_URL` 注入,不影响真机联调或发布配置。
|
||||
|
||||
### 测试(先红后绿)
|
||||
```text
|
||||
flutter test test/mine/server_endpoint_setting_test.dart test/home/home_server_setting_test.dart test/mine/mine_logic_test.dart test/mine/mine_preview_layout_test.dart
|
||||
+12: All tests passed!
|
||||
```
|
||||
- 解读:设置 sheet 与首页失败态均断言不再出现服务器入口,三种界面语言仍完整可选。
|
||||
|
||||
### 门禁
|
||||
```text
|
||||
dart analyze lib test
|
||||
No issues found!
|
||||
|
||||
flutter test
|
||||
00:19 +377 ~1: All tests passed!
|
||||
```
|
||||
- 解读:静态检查零告警,全量测试通过;`~1` 为联调测试在无数据时主动跳过。
|
||||
## 2026-10-19 | P2 首页轮播 banner 接入(Flutter)
|
||||
|
||||
- 发现页顶部接入 `/app/home/feed` 的真实 `banners`;`DRAMA` 类型点击后按 `linkValue` 拉取详情并进入详情页,不会把 banner 链接当成假数据。
|
||||
- 新增 `FeedBannerCarousel`:Material 3 圆角卡片、4.5s 自动轮播、单张不启动定时器、按住暂停/松手恢复、TickerMode 与 tab active 双重暂停、圆点指示器带三语语义标签。
|
||||
- `banners` 为空时完全不占位;图片加载失败显示统一占位图标。
|
||||
- 使用现有 `carouselSemantics` 文案,没有新增无效入口。
|
||||
|
||||
### 测试(先红后绿)
|
||||
```text
|
||||
flutter test test/home/feed_banner_carousel_test.dart test/discover/discover_banner_test.dart
|
||||
+5: All tests passed!
|
||||
```
|
||||
- 解读:空列表、点击跳详情、自动翻页、按住暂停,以及发现页真实对接链路均通过。
|
||||
|
||||
### 门禁
|
||||
```text
|
||||
dart analyze lib test
|
||||
No issues found!
|
||||
|
||||
flutter test
|
||||
00:20 +382 ~1: All tests passed!
|
||||
```
|
||||
- 解读:静态检查零告警,全量测试通过;`~1` 为联调测试在无数据时主动跳过。
|
||||
## 2026-10-19 | P2 点赞与评论计数展示(Flutter)
|
||||
|
||||
- 点赞计数:`InteractionController` 记录点赞接口返回的 `count`,仅在服务端成功后展示;剧集契约没有初始计数,因此未点赞前不伪造数字。右栏 `rail-like-count` 与播放器更多菜单 `player-more-like-count` 均展示真实值。
|
||||
- 评论计数:评论接口无总数字段,`CommentController.exactCount` 仅在全部顶层评论分页加载完成且无更多页时返回精确数量;仍有多页时标题保持 `Comments`,不把当前页数量冒充总数。
|
||||
- 切换账号时 `clear()` 同步清理点赞计数,避免跨账号串联。
|
||||
|
||||
### 测试(先红后绿)
|
||||
```text
|
||||
flutter test test/home/home_preview_layout_test.dart test/interaction/interaction_controller_test.dart test/comment/comment_controller_test.dart test/comment/drama_comments_sheet_test.dart
|
||||
00:01 +27: All tests passed!
|
||||
```
|
||||
- 解读:覆盖服务端计数刷新、清空会话、分页完成前不展示总数、分页完成后显示 `Comments · N`,以及右栏真实数字渲染。
|
||||
|
||||
### 门禁
|
||||
```text
|
||||
dart analyze lib test
|
||||
No issues found!
|
||||
|
||||
flutter test
|
||||
00:20 +385 ~1: All tests passed!
|
||||
```
|
||||
- 解读:静态检查零告警,全量测试通过;`~1` 为联调测试在无数据时主动跳过。
|
||||
### 打包验证
|
||||
```text
|
||||
flutter build apk --debug
|
||||
Running Gradle task 'assembleDebug'... 93.9s
|
||||
√ Built build\app\outputs\flutter-apk\app-debug.apk
|
||||
```
|
||||
- 解读:debug APK 构建成功,develop 合并后可直接拉取打包验证。
|
||||
### develop 合并与推送
|
||||
```text
|
||||
git checkout develop
|
||||
git merge --no-ff feature/flutter-p0-commerce -m "merge: Flutter P0-P2 App 对接完成"
|
||||
Merge made by the 'ort' strategy.
|
||||
69 files changed, 4733 insertions(+), 387 deletions(-)
|
||||
|
||||
git push origin develop
|
||||
de941c8..ec2db68 develop -> develop
|
||||
```
|
||||
- 解读:合并提交 `ec2db68`,远端 `origin/develop` 已更新;合并后 `dart analyze lib test` 零告警、`flutter test` 全过(`+385 ~1`)、`flutter build apk --debug` 成功,工作区干净。
|
||||
Reference in new issue
Block a user