Zhou Weidong
|
f05476f6db
|
docs(plans): 下发 K5 克莱因蓝主题任务
|
2026-10-17 15:51:04 +08:00 |
|
Zhou Weidong
|
61e85ab501
|
docs(plans): 合并 K3 修复回执
|
2026-10-17 15:30:07 +08:00 |
|
Zhou Weidong
|
c2bd096ef3
|
docs(plans): 补记 K3 举报错误透传修复
|
2026-10-17 15:29:59 +08:00 |
|
Zhou Weidong
|
22f458606d
|
docs(plans): 合并 K3 互动任务回执
|
2026-10-17 15:27:53 +08:00 |
|
Zhou Weidong
|
969538e6c9
|
docs(plans): 记录 K3 互动实施与验收回执
|
2026-10-17 15:27:42 +08:00 |
|
Zhou Weidong
|
a0156ee946
|
docs(plans): 下发 K3 互动任务
|
2026-10-17 15:09:12 +08:00 |
|
Zhou Weidong
|
4a658fc67e
|
docs(plans): 补齐 K2 真机验收与门禁回执
|
2026-10-17 15:02:28 +08:00 |
|
Zhou Weidong
|
698bb78aeb
|
docs(plans): 记录 K2 实施与验收回执
|
2026-10-17 14:50:51 +08:00 |
|
jianghaifeng
|
4118efd0ca
|
docs(inbox): 按 specs 补全 K2 执行规范与门禁
|
2026-10-17 14:17:17 +08:00 |
|
jianghaifeng
|
096e90c4c6
|
docs(inbox): 记录用户裁定——K2 先按现状契约执行,契约缺口后期再补
|
2026-10-17 14:12:37 +08:00 |
|
jianghaifeng
|
582453f0bd
|
docs(inbox): 下发 K2 客户端第二批(分类/记录/收藏/下载授权 + UI)
|
2026-10-17 14:11:22 +08:00 |
|
jianghaifeng
|
bad3bf4e79
|
docs: 记录 specs 只同步 main / specs 权威 / 执行前必读 INBOX 的裁定
|
2026-10-17 14:06:50 +08:00 |
|
jianghaifeng
|
7637e322ec
|
docs: 记录 2026-10-17 三库全量拉取与 main→develop 同步结果
|
2026-10-17 13:50:01 +08:00 |
|
jianghaifeng
|
2d70858887
|
docs(plans): K1-verify 回执与留痕(真机验证交回用户,标注未验证)
|
2026-10-16 18:06:02 +08:00 |
|
jianghaifeng
|
53ac5d60d1
|
docs(plans): 新增 K1-verify 条目 + 红线第 10 条(设备验证必须设备侧取证)
背景:1-3/1-4 的真机验证用了错地址 10.157.242.1(开发机 VPN 网卡、手机不可达),
且当时的证据是本机 curl 本机网卡地址返回 200 —— 假阳性,已导致真机首页加载失败。
本条目要求用正确地址(ipconfig getifaddr en0 取)重做,且证据必须产自设备侧
(首选:integration_test 在手机进程里真请求并断言),拿不到就如实标「未验证」。
红线新增第 10 条,防止再犯。
|
2026-10-16 17:54:36 +08:00 |
|
jianghaifeng
|
40e2812677
|
docs(plans): K1 回执(客户端详情+播放+续看+收藏,含真数据/假数据清单)
|
2026-10-16 17:39:36 +08:00 |
|
jianghaifeng
|
59d064f8c6
|
docs(plans): 新增 K1 条目(客户端对接:详情+播放+进度续看+收藏,含 UI 三态)
PM 勘察:客户端只调了 6 个 C 端接口(契约已实现 44 个);无 playback/watch/library
api 类;WatchHistoryRepository 仍是 SharedPreferences 本地存储、mine_logic 用 demoProfileId
假数据;EngagementRepository 亦为本地。K1 打通首页→详情→播放→续看→收藏一条链路。
|
2026-10-16 17:25:00 +08:00 |
|
jianghaifeng
|
0cab094194
|
docs(plans): J1 回执(全局 ID 字符串化 + 契约统一),标为已处理·待用户验收
|
2026-10-16 16:48:07 +08:00 |
|
jianghaifeng
|
f35db2cd3b
|
feat(framework): 全局 Long 字符串化,ID 一律以字符串下发
用户裁定方案 (a):雪花 id 精度问题全局修,统一契约。
- 新增 JacksonLongToStringConfig(fruitshorts-framework):Long/Long.TYPE → ToStringSerializer,
经 Jackson2ObjectMapperBuilderCustomizer 挂进 Spring Boot 的 ObjectMapper;admin-api 与
app-api 都是 scanBasePackages=com.fruitshorts,一处生效两端一致
- 例外:PageResult.total 是计数不是 id,用 mixin 显式保持数字(前端分页组件要数字);
Integer/int(pageIndex/pageSize/Result.code 等)不受影响
- 反序列化方向不变:请求体 'id:123'、路径变量、查询参数都接受字符串
- 契约 api-phase1.md §0 新增「ID 字段一律以字符串下发」总口径,§2.11/§2.12 改为引用 §0;
I1 里逐字段加的 @JsonSerialize 与 Result<String> 回退成自然写法,避免多套口径
- 测试:新增 LongToStringSerializationTest(普通/嵌套/List/Map/分页 + 反序列化 + 19 位路径变量),
契约测试的 standalone mapper 也挂上模块(否则测试假绿);C 端 4 条 id 断言改成 isString
- mvn test:commerce 33 / admin-api 21 / app-api 49 / worker 12 = 115 条全过
|
2026-10-16 16:44:13 +08:00 |
|
jianghaifeng
|
c503629bf9
|
docs(plans): 新增 J1 条目(全局 ID 字符串化 + 契约统一,用户裁定方案 a)
雪花 id 19 位超出 JS 安全整数,I1 期间 Codex 实测与 PM 独立复核均复现
(点下架回 200002、/admin/app-users/page 下发裸数字)。用户裁定全局修改并统一契约。
本条目给出范围:framework 全局 Long→String、契约 §0 总口径、两个前端适配、
验证要求(含 node 逐位比对证据)与门禁。
|
2026-10-16 16:36:23 +08:00 |
|
jianghaifeng
|
10264c4ef6
|
docs(plans): I1 回执补充禅道同步说明(禅道暂无 I1 任务)
|
2026-10-16 16:34:45 +08:00 |
|
jianghaifeng
|
e9877d78d8
|
docs(plans): I1 回执(商品配置 + 系统公告),标为已处理·待用户验收
|
2026-10-16 16:34:18 +08:00 |
|
jianghaifeng
|
8d19a0cc0a
|
feat(admin): 商品配置与系统公告管理接口,id 以字符串下发
- /admin/products 六个接口 + 校验(code 唯一、store_product_id 同平台唯一、
COIN_PACK 需 coin_amount>0、VIP 需 vip_days>0、VIP 只建不启)
- /admin/notices 六个接口,与 C 端 /app/notices 共用 OpsNoticeService.pageForApp 一套筛选口径
- 权限点 product:list/product:update/notice:list/notice:update + 菜单 31/32/33(sql/data-phase1.sql 幂等)
- 雪花 id 超过 JS 安全整数范围:id 以字符串下发,避免浏览器四舍五入导致回查 200002
- C 端商品查询收敛到 ProductService.findForStore,OrderService 不再自带一份
- 测试:module-commerce 33 / admin-api 16 / app-api 49 / worker 12,共 110 条全过
|
2026-10-16 16:33:15 +08:00 |
|
jianghaifeng
|
7513ac06bc
|
docs(plans): 指令通道迁入本仓库(specs 改为只拉取,由项目负责人更新)
用户口径:specs 仓库今后只拉取、由项目负责人维护,我们不再向其提交;工作留痕与
指令队列改放本仓库 docs/plans/ 下,避免本地领先提交与上游 INBOX 反复冲突。
本文件包含双 Agent 协作红线(含"验收归用户""门禁口径"),以及当前待处理条目
I1:后台管理端商品(金币包)配置 + 系统公告管理(后端接口 + ReelShortWeb 页面)。
|
2026-10-16 16:13:22 +08:00 |
|
jianghaifeng
|
5609b42dcd
|
docs: 对齐契约 §3 与 README 文档索引的进度口径
按实测修正 4 处状态描述,消除"已完成/未完成"口径不一致:
- api-phase1.md §3「契约与实现状态对照」:
04 多码率为「转码 worker(C1)已产出」;06 分享埋点标「待 C3」;
09 由"下一批"改为「Google Play 票据校验闭环已实现,Apple IAP 只留端口」;
10 由"压测与埋点 下一批"改为「C1 已实现,C2/C3/压测 未做」;
并补最后更新时间与「未完成清单见 README」的指向
- README.md 文档索引:api-phase1 的描述由"标注已实现 / 下一批"
改为"含「契约与实现状态对照」"
为什么改:契约里的状态表过期会直接误导排期与联调判断,属最容易踩的坑。
|
2026-10-16 15:32:05 +08:00 |
|
jianghaifeng
|
50ffc974db
|
docs(readme): 更新第一阶段进度:区分已完成批次与未完成清单
原进度表严重过期(仍写 06 待做、07 创作者中心待做、08 部分、09 待做),
与代码和 api-phase1.md 都不一致,容易误导排期与联调。本次按实测重写:
- 模块表 01-10 逐条核对(04/05/06/07/08 改为已实现;09/10 标部分并写明差什么)
- 新增「已完成批次」表,列出本轮冲刺 13 个批次与对应提交,便于回溯
- 新增「尚未完成」清单,分四类:后端研发 6 项、上线前必补 6 项(P0/Go-No-Go)、
基础设施 6 项、非后端范围(客户端与 Web 分工),每条标注依据文档
- 写明已作废方案:module-analytics 收敛因创作者中心改由 Web 端承载而不再需要
为什么改:README 是接手者第一眼看的文档,进度表过期会直接误导排期与联调。
|
2026-10-16 15:31:33 +08:00 |
|
jianghaifeng
|
4418a840ec
|
refactor(app-api): 按新口径撤除 App 侧创作者中心的 works / stats
为什么:用户口径变更「创作者中心是 web 端,和 app 客户端没关系」,契约已由 PM 提交 bb21920
移除两条 C 端定义;本提交把代码对齐到新契约,App 侧创作者相关只保留入驻申请。
- 删除 GET /app/creator/works、GET /app/creator/stats 两个端点及无用注入
- 删除 CreatorStatsService.java(213 行,与后台 07 看板重复的独立实现)
- 删除随之成为死代码的:CreatorAppService.requireActiveCreator / myWorks、
CreatorCenterService.pageMyDramasOf、ErrorCode.CREATOR_NOT_ACTIVE(200007)
- 删除对应测试 7 条(works/stats 契约 4 条 + requireActive 3 条);
保留 apply 幂等与协议版本校验、config 白名单、notices 空列表
- 不动 POST /app/creator/apply、GET /app/config、GET /app/notices;不改 docs/api-phase1.md
- 实测:mvn test 98 → 91 条全过;package 通过;/v3/api-docs 接口数 41 → 39,
creator 相关只剩 /app/creator/apply;两个已撤除路径对已登录客户端返回 404
|
2026-10-16 15:21:13 +08:00 |
|
jianghaifeng
|
bb219203bc
|
docs(api): 移除 /app/creator/works 与 /app/creator/stats 的 C 端定义
创作者中心(工作台 / 作品管理 / 数据看板)由 Web 端承载,创作者登录后台管理使用
(见 api-phase1.md §2.10),App 客户端不提供创作者中心。因此契约 §1.9 去掉这两条,
只保留「创作者入驻申请 + 启动配置 + 系统公告」;§1.9 标题与说明同步修正,
apply 幂等表里"已通过"一行改为指向 Web 端。
为什么要改:原定义要求 App 侧再实现一份「创作者数据看板」,虽与后台 07 看板同口径,
但代码完全独立,两份长期必然漂移(后台数字与创作者看到的数字对不上是信任问题)。
按产品口径创作者中心不上 App,这份重复实现没有存在意义,移除即从根上消除漂移风险,
也避免前端照旧契约开发后返工。
|
2026-10-16 15:14:34 +08:00 |
|
jianghaifeng
|
14b5e4137f
|
feat(app-api): E1 补全 5 个 C 端接口(创作者入驻/作品/看板 + 启动配置/公告)
为什么:联调 10-19 开始,前端照 api-phase1.md §1.9 写会 404,需要先把这 5 个补齐。
契约先行(12-上线检查清单 §一):先重写 api-phase1.md §1.9 —— 把 commerce 三条移出本节标"已实现",
补齐 5 个接口的请求/响应字段、错误码、分页口径、幂等矩阵,并新增 200007 CREATOR_NOT_ACTIVE。
- GET /app/config(匿名):硬编码白名单 6 键 + 契约默认值兜底,绝不整表下发
- GET /app/notices(匿名):ops_notice 只读分页(status/target/发布与过期时间),无数据返回空列表
- POST /app/creator/apply:幂等,防重靠 DB 唯一索引 uk_creator_user,并发冲突读回既有记录
- GET /app/creator/works:非生效创作者报 200007 + 分状态提示,不返回空数组冒充成功
- GET /app/creator/stats:与后台 07 看板同口径(字段/notes 逐条一致),null + notes 语义保留
- 冻结模块零改动:module-creator 仅新增 CreatorAppService/两个 VO 与 1 个公开方法 pageMyDramasOf,
既有 pageMyDramas 一行未动;module-system 仅新增 OpsNotice 实体与 Mapper
- Swagger 中文注解按 S1 规范补齐;白名单与 /app/notices 加进安全白名单
- 实测:mvn test 98 条全过(app-api 41→56);package 通过;端到端五接口全部符合预期
(重复 apply 同 id + created:false、pending 看 works/stats 报 200007、approved 后正常)
|
2026-10-16 14:56:44 +08:00 |
|
jianghaifeng
|
4c3d524eff
|
Merge pull request 'Feature/deploy fix local bringup' (#1) from feature/deploy-fix-local-bringup into develop
Reviewed-on: #1
|
2026-10-16 06:35:34 +00:00 |
|
Zhou Weidong
|
4c4f64323a
|
fix(worker): 补齐 prod 密钥与 CORS 映射以通过密钥校验
worker 的 application-prod.yml 没把 JWT_ADMIN_SECRET / JWT_APP_SECRET /
MEDIA_SIGNATURE_SECRET / CORS_ALLOWED_ORIGINS 映射成 fruitshorts.* 属性,
ProdSecretGuard 读到空值即拒绝启动,compose 里 worker 一直 Restarting。
按两个入口同一口径补齐映射:不写 dev 默认值,漏配仍 fail-fast;
并显式置 signature-required=true,与两个入口一致。
门禁:mvn test 全模块 BUILD SUCCESS(0 失败 0 错误,1 项 ffmpeg smoke 按用例设计跳过)。
|
2026-10-16 14:32:24 +08:00 |
|
Zhou Weidong
|
8b46e535c5
|
fix(deploy): 修正 PG18 数据卷挂载路径为 /var/lib/postgresql
docker-library/postgres 自 18 起把数据目录改成 /var/lib/postgresql/<major>/,
卷继续挂 /var/lib/postgresql/data 会被 entrypoint 判定为"残留数据"并拒绝启动;
表现为 db 容器反复 Restarting,依赖它的三个服务一起起不来。
改挂父目录后本地实测:docker compose up -d 正常,db 进入 healthy。
|
2026-10-16 14:32:24 +08:00 |
|
jianghaifeng
|
7dd4b15804
|
docs(deploy): 按 specs 约束补全部署文档(新增 DEPLOY-CHECKLIST.md)
为什么:用户要求"写好文档,一定要根据 specs 文档约束好"。把 specs 里与部署相关的
硬约束逐条对照现状后发现 9 条里有 6 条未覆盖或只写了一半,需要一次补齐并如实标注工程缺口。
- 新增 DEPLOY-CHECKLIST.md:环境映射(办公室主机 = test)、域名/HTTPS/反代(含 nginx 与证书建议)、
网络分区、发布与回滚规范(语义化 tag / release→main / 回滚演练)、备份与恢复(specs 目标 vs 现状差距)、
监控与告警现状、密钥托管与轮换、**上线检查清单对照表(docs/12 逐条 ✅⚠️❌ + 责任方)**、
风险/待确认(R1–R10)、上线前必补清单(P0–P2)
- DEPLOY.md 增加"本机属于 test 环境"与交叉引用,并单列"上线前必须补的四条"提示
- 对照表里的 ✅ 都带证据(如分区生效先实测 playback_ticket_202610 落分区、_default = 0)
- 只写文档,未改任何实现;mvn test 83 条全过、两入口 package 通过
|
2026-10-16 13:20:31 +08:00 |
|
jianghaifeng
|
cbb9961627
|
fix(deploy): 冒烟脚本与 prod Swagger 开关解耦,默认改联调口径
为什么:prod profile 下 SWAGGER_ENABLED 默认 false 会把 /doc.html 与 /v3/api-docs 一起关掉,
而 smoke.sh 硬期望这两者 200 —— 照文档默认配置部署完,冒烟必然假失败,会被误判成"部署挂了";
且联调(10-19)需要 /doc.html 在线可查。
- smoke.sh 自适应:显式 SWAGGER_ENABLED 优先;未设置则自动探测(200+openapi=开、统一信封
code=404=关、其它响应仍 FAIL);关闭时这三项打印 SKIP 而不是 FAIL,开启时照旧断言 200(断言未删)
- 新增 SWAGGER_REQUIRED 硬开关:联调环境可要求文档必须在线,不满足直接失败
- .env.example 默认改 SWAGGER_ENABLED=true,并写明该开关一次管两个端点
- DEPLOY.md 同步口径与冒烟说明
- 实测:prod+false 时 SKIP + 其余全 PASS + 退出码 0;prod+true 时两端口 /v3/api-docs 与 /doc.html 均 200;
mvn test 83 条全过、两入口 package 通过
|
2026-10-16 13:17:29 +08:00 |
|
jianghaifeng
|
b567365460
|
feat(deploy): D1 后端部署就绪(配置外置 + prod fail-fast + 自包含 Compose + 冒烟/回滚)
为什么:用户下午要部署,但全仓没有任何部署产物;且生产漏配密钥会静默使用代码里的 dev 默认值,
属上线阻塞项(04-部署架构 / 12-上线检查清单)。
- 配置外置(三件):DB_URL、JWT 双密钥(**发现 app-secret 此前没外置,一直用 dev 默认值**)、
MEDIA_SIGNATURE_SECRET、MEDIA_SIGNATURE_REQUIRED、CORS_ALLOWED_ORIGINS、MEDIA_ROOT_DIR
- 新增三份 application-prod.yml:签名强制开启、CORS 收紧、媒资指向挂载点、日志级别
- 新增 ProdSecretGuard(@Profile("prod")):密钥缺失/仍是 dev 默认值/不足 32 位、签名未开、
DB_URL 或 CORS 为空 → 一次列全并终止启动(exit 1)
- 新增 /healthz 轻量健康端点:查明 /actuator/health 的"超时"是旧 jar 未重启所致,项目本就
没有 actuator 依赖,故不引新依赖;同时把 /healthz 加进安全白名单
- Docker 化:多阶段 Dockerfile(非 root、tini、依赖层缓存、ffmpeg 只给 worker)、.dockerignore、
自包含 docker-compose.yml(含 PostgreSQL 18 + Redis + 命名卷 + 按序初始化 sql + healthcheck)
- tools/smoke.sh(失败非 0 退出)+ DEPLOY.md(Compose 主线 / 裸 jar 兜底 / 回滚 / 故障速查)
- 实测:mvn test 83 条全过;两入口 package 通过;prod 缺密钥退出码 1 且报错明确、配齐后正常启动;
冒烟脚本全 PASS;本机无 Docker,镜像与 compose 未经构建验证(已在回执如实标注)
|
2026-10-16 13:01:08 +08:00 |
|
jianghaifeng
|
9f76302e53
|
feat(media): C1 转码 worker(独立进程消费 transcode_task,产出四档 HLS + 封面)
为什么:codex-研发任务清单阶段 C 第一项要求消费 transcode_task 产出多码率 HLS + 截图;
勘察发现除 worker 外还缺两件——TranscodeService.enqueue 没有任何调用方(队列永远空)、
media_asset.hls_url/poster_url 没人回写,所以一并补齐,已有能力(条件更新认领 / 3 次重试)直接复用。
- 新增 TranscodeRunner 端口 + FfmpegTranscodeRunner(每档一条 ffmpeg 出 VOD HLS + 手写 master.m3u8 + 抽封面 + ffprobe 读时长)
- 新增 TranscodeWorker:claimNext → 转码 → 登记 media_rendition → 媒资 ready;失败记原因、第 3 次才落 FAILED 并把媒资置 failed
- 存储统一走 MediaStorageService(新增 fileFor / objectKeyOf,含目录穿越校验),worker 不自己拼磁盘路径
- 队列隔离:app-api/admin-api 默认 worker-enabled=false,新增独立模块 fruitshorts-transcode-worker(随机端口)
- MediaService 上传完成对视频素材入队并置 transcoding(图片仍直接 ready)
- 实测抓到并修掉两个真问题:① scale 未加 force_divisible_by=2 时 854x480 算出奇数宽 853,libx264 拒绝转码
② 只写 -hls_time 不强制关键帧时 8 秒片源只出 1 个分片,补 -force_key_frames 后按 6s 正确切分
- README 开发环境补 ffmpeg 9.0.2(只有 worker 需要)
- 实测:mvn test 83 条全过、0 skipped(新增 worker 12 条,含真实 ffmpeg smoke);
端到端:正常源 SUCCESS + 4 档 rendition + 媒资 ready;坏源重试 3 次后 FAILED
|
2026-10-16 12:41:48 +08:00 |
|
jianghaifeng
|
1dc97b4bf6
|
feat(commerce): B1-2 恢复购买/退款拒付回收/对账真实比对 + Apple 端口预留
为什么:风险清单 R-03 把"票据校验 + 对账打通"列为上线阻塞项。勘察发现 ReconcileService 与
/admin/reconcile 两个接口 B1 之前就已实现,真缺口是:对账没跟商店比对、差额用 0 兜底(违反
"取不到就用 null"的契约)、退款回收只有人工入口且不幂等。按实际缺口做,不重复造。
- 恢复购买:补专项测试(换设备重提同一票据 → 同一订单、原交付时间不改写、不新增流水);
补单能力沿用 B1-1 的服务端建单路径,恢复列表沿用 GET /app/orders,不新增接口
- 退款/拒付回收:GooglePlayPurchaseClient 增加 listVoidedPurchases(purchases.voidedpurchases,
带分页);新增 StoreRefundService 拉取并按 (platform, orderId) 幂等回收,本地无单计入差异;
OrderService 增加 refundByStoreCallback(已退款直接返回,不二次回收/不写第二条流水),
人工 refund() 的既有契约(已退款报错)保持不变
- 对账:reconcile_task 增 store_amount_sum(可空)与 notes 两列(幂等 ALTER);
run() 改为集合比对(本地缺票据 + 票据无本地单 + 商店已作废但本地无单),并在同一次 run 里
顺带执行退款回收;storeAmountSum 恒为 null 并在 notes 说明需从 Play Console 财务报告获取;
商店调用失败置 status=FAILED 且不写 SUCCESS+0
- Apple IAP:只留端口/枚举与明确提示,不实现真调用(B2 再实现)
- 契约同步 docs/api-phase1.md §1.8/§2.6;新增测试 17 条(commerce 14 + admin-api 3)
- 实测:mvn test 71 条全过(commerce 27 + admin-api 3 + app-api 41,B1-1 的 54 条未被打红);
两个入口 package 通过;端到端手动对账返回 storeAmountSum=null + notes 说明缺什么
|
2026-10-16 11:52:10 +08:00 |
|
Zhou Weidong
|
db897d50d6
|
feat(commerce): Google Play 票据校验闭环(校验→建单→发权益 + 幂等/防重放)
为什么:风险清单 R-03 把支付票据校验列为上线阻塞项;/app/orders/verify 此前只有 disabled
占位,且 verifyAndDeliver 要求订单事先存在——而 IAP 没有下单接口,接了校验也走不通。
- 新增 GooglePlayStoreVerifier(校验 purchaseState/productId/orderId)+ StorePlatforms(平台归一化)
- 新增 GooglePlayPurchaseClient 端口与 HttpGooglePlayPurchaseClient:JDK HttpClient + 服务账号
RS256 JWT 换 token,不引入 Google SDK 依赖;token 按过期缓存
- StoreVerifier 实现由 fruitshorts.commerce.store.verifier 选择,默认 disabled,无凭据时对外行为不变
- OrderService 补齐闭环:校验通过后按 (platform, storeProductId) 找商品建单、写 store_receipt 审计、
发金币并推进到 DELIVERED;幂等键 (platform, storeTransactionId) 与唯一索引双保险
- 防重放:重复提交同用户返回既有订单且不再发币;票据已被他人使用返回 403;校验失败不写任何数据
- 凭据只走配置/环境变量(packageName + service account JSON),不入库不提交
- 契约同步 docs/api-phase1.md §1.8;金额微单位换算与回退价有单测覆盖
- 实测:mvn test 54 条全过(commerce 13 + app-api 41,M2 的 37 条未被打红);
两个入口 package 通过;默认 disabled 端到端返回 200003 且 orders 表零行
|
2026-10-16 11:03:33 +08:00 |
|
Zhou Weidong
|
27e689c771
|
fix(config): 修复合并后 app-api 重复的 springdoc 配置键
|
2026-10-16 10:52:17 +08:00 |
|
Vicky
|
5ce6de1e3b
|
Merge remote-tracking branch 'origin/main'
|
2026-10-16 10:51:15 +08:00 |
|
Vicky
|
c6fcfcc6ea
|
docs(backend): S1 接口文档在线化——补 springdoc 配置 + 39 个 Controller 中文注解
为什么:前端联调依赖在线接口文档。S1 条目要求两个端口的 /v3/api-docs 能看、
且每个接口有中文分组与中文 summary。
诊断(与 PM 初步定位不同,有硬证据):app-api 的 /v3/api-docs、/doc.html、/、
/error 全部"挂住"(8s 超时 0 字节),根因不是 Spring Security 拦截,而是
运行中的进程握着一个被重新打包替换掉的旧 jar——spring-boot:repackage 把原 fat jar
原地改名为 .jar.original(同一 inode)再写新 jar,进程再去加载"启动后未加载过的类"
就必然 NoClassDefFoundError(日志里连 logback 的 ThrowableProxy 都加载不到),
线程直接死掉、既不响应也记不了日志。SecurityConfig.PUBLIC_PATHS 本来就包含
/doc.html、/swagger-ui/**、/v3/api-docs/**,未改任何安全配置。
- app-api 的 application.yml 补 springdoc.swagger-ui.path: /doc.html
- 39 个 Controller(app-api 10 + admin-api 29)补 @Tag(name=中文分组)
与 @Operation(summary=中文描述),共 172 个接口;描述取自 api-phase1.md 与既有 Javadoc
- 两个入口类加 @OpenAPIDefinition:文档标题 + 顶层 tags 清单(springdoc 默认顶层 tags 为空)
- 纯新增 357 行、删除 0 行:业务逻辑、路径、字段零改动
- 实测:mvn test 37 条契约测试全过;两个入口 package BUILD SUCCESS;
两端口 /v3/api-docs 中文 tags + 中文 summary,/doc.html 可打开,
非白名单路径 5ms 内返回 {"code":401,...} 不再挂住
|
2026-10-16 10:44:37 +08:00 |
|
Zhou Weidong
|
efe8af6c9b
|
docs: 补全接口契约遗漏,逐条展开系统管理与内容接口并补充 watch-history/creators 账号/media 详情
|
2026-10-16 10:23:25 +08:00 |
|
Zhou Weidong
|
66e6fc1555
|
feat: app-api 启用 Swagger 在线接口文档 (springdoc /doc.html)
|
2026-10-16 10:13:47 +08:00 |
|
Vicky
|
fafadfc6ec
|
test(backend): C 端核心链路契约测试 37 条,mvn test 不再是 No tests to run
为什么:红线第 8 条要求后端 mvn test 通过且核心接口有契约测试;此前 13 个模块全是
No tests to run.,这个"通过"是空的。按 M2 口径只补 C 端核心链路最小集。
- 接入层契约(MockMvc,真控制器 + 真全局异常处理器 + service 替身):
/app/auth 注册与登录、目录四条路由、播放票据 FREE 与 COIN_REQUIRED 的字段形态
- 业务规则(真 service + 替身 Mapper):
EMAIL 免码不走验证码且 verified=0、PHONE 必须带码、验证码错/过期被拒、
密码强度、注册频控 429、账号重复 200001、密码错误 100000、封禁 100001、
免费/已购/未解锁/无片源四个播放分支
- 依赖只加到 fruitshorts-app-api(spring-boot-starter-test,test scope),不动其它模块
- 测试放在接入层模块,避免动 01-08 冻结模块目录;只新增测试,未改业务逻辑
- 实测:mvn test BUILD SUCCESS,app-api Tests run: 37, Failures: 0, Errors: 0;
mvn -DskipTests package 仍 BUILD SUCCESS
|
2026-10-16 09:52:52 +08:00 |
|
Vicky
|
84aa0e17dd
|
fix: S0 后续——种子脚本补显式主键(去掉 identity 后新库种不进数据)
为什么:S0 把主键默认值去掉了,但 sql/data.sql 和 sql/data-phase1.sql 里有一批 INSERT
没给 id(原来靠 IDENTITY 生成),在新库上直接报
`null value in column "id" ... violates not-null constraint`,30 条菜单只种进去 14 条。
线上库因为数据早已存在所以看不出来,是"新装"这条路断了。
- 关联表(sys_role_permission / sys_role_menu / sys_admin_user_role)改用
「左键 * 1000000 + 右键」的确定性 ID,重复执行结果一致,也不会撞雪花 ID
- data-phase1 新增权限点用「1000 + sort」(1101-1156 保留区间)显式给 ID,避开早期 IDENTITY 用过的 1-251
- 商品占位行补 901-903;sys_config 补 1-2
- 删掉 data.sql 结尾"对齐 IDENTITY 序列"的收尾块(序列已不存在),改为写明种子主键约定
- 实测:新库上 schema+data 五个脚本连跑三轮零 ERROR 且行数稳定(30/48/75/51/6/3/2/5/4);
线上库跑种子前后行数不变(30/48/75/51/3/2)
|
2026-10-16 09:18:09 +08:00 |
|
Vicky
|
37c9a141d3
|
feat: S0 主键改雪花(DDL 去 identity + 实体 ASSIGN_ID + 雪花配置)
为什么:自增主键把 ID 分配锁在单库序列上,分库分表时无法横向扩展。趁线上业务数据
近零(只有系统种子表有量)先改,代价最低。
- sql/schema.sql、sql/schema-phase1.sql、sql/partition-maintenance.sql:61 处
GENERATED BY DEFAULT AS IDENTITY 去掉,主键改 BIGINT 无默认值
- 52 个实体 @TableId IdType.AUTO -> IdType.ASSIGN_ID;两个入口 id-type: assign_id,
并加 global-config.sequence.worker-id/datacenter-id(单机固定值,多实例需按实例分配)
- 新增 sql/migrate-s0-snowflake.sql:存量库幂等迁移,走 DROP IDENTITY 保留数据,不重建表
- 实测:三份建表脚本在新库连跑两遍幂等;线上 57 张表 identity 归零;
watch_history/playback_ticket/order_event 的主键与唯一索引仍含分区键
|
2026-10-16 09:00:38 +08:00 |
|
Zhou Weidong
|
35be37c193
|
style: 全量补充作者标识 // Author: fruit.com.cn
|
2026-10-16 00:01:53 +08:00 |
|
Vicky
|
6833e01e1f
|
feat: C 端 1-1 邮箱+密码注册(免码不阻塞,带风控)
为什么:客户端要做的第一件事是账号,但现状下邮箱注册走不通 —— RegisterReqVO.code 是 @NotBlank,
而 OTP 通道现在是 LogOtpSender(只写日志、发不出去),等于注册入口堵死。本轮把"邮箱+密码"打通,
同时按口径补上免码必须带的风控。
- RegisterReqVO.code 放开非必填(PHONE 仍必填,必填性按 targetType 在服务端判断)
- 邮箱注册分支:格式校验(AppIdentifier.requireEmailFormat)+ 密码强度(8-64 位且含字母数字);
传了 code 就顺手校验一次,邮箱验证能力保留但不阻塞
- 注册频控:同 IP 24h ≤5、同设备 24h ≤3(数 app_user.register_ip / register_device_id,不新建计数表),超出 429
- 顺带修一个真问题:login() 原来**无条件**把 credential 标成 verified=1,
密码登录并不证明邮箱归用户所有,会把"未验证"状态悄悄抹掉;改成只有验证码登录才置 1
- docs/api-phase1.md 补注册契约表格与残留风险(IP/设备号可伪造、OTP 只写日志、邮箱可达性未验证)
实测:免码注册成功(邮箱大小写与空格被规范化);弱密码/坏邮箱 400;重复 200001;
邮箱+密码登录成功;PHONE 不带码仍报"请先获取验证码";同设备第 4 次、同 IP 第 6 次分别 429;
免码注册后 verified=0 且经一次密码登录仍是 0。
|
2026-10-15 17:20:31 +08:00 |
|
Vicky
|
414d9fd482
|
feat: 创作者账号体系(后台开号 → 登录即进创作者中心)+ 创作者中心菜单只给创作者
为什么:创作者此前根本无法登录 —— creator.admin_user_id 只有实体字段、没有任何接口会写它,
C 端申请入驻也没做,等于整条账号链路缺入口。这批先把"后台手工建主体 → 审核 → 开号 → 登录落地"打通;
同时按用户口径收窄菜单:只要不是创作者,就不显示创作者中心。
- 手工建主体:POST /admin/creators(编号可传可自动生成 CR+日期+序号)+ 审核页「新增创作者」
- 开通账号:POST /admin/creators/{id}/account —— 仅 approved 可开(否则 200003)、已开通幂等返回
(created=false、不回明文)、用户名默认 creator.code 小写且冲突报 200001、随机 10 位初始密码一次性返回、
建 sys_admin_user + 绑 creator.admin_user_id + 授 creator 角色
- 重置密码:POST /admin/creators/{id}/account/reset-password(同样一次性明文,旧密码立即失效)
- 首登强制改密:sys_admin_user 加 must_change_password 列(幂等 ALTER;不新建表、不复用 two_factor 是因为
这个标记要能直接驱动登录响应与前端拦截),开号/重置置 1,自助改密后清 0
- 菜单收窄:26-30 从超管收回(sys_role_menu delete);另外发现超管的菜单是"全量兜底"、根本不看角色-菜单表,
光收授权无效,所以加 sys_menu.super_admin_visible,这几条置 0 —— 超管侧边栏不再出现创作者中心
(代看代码保留,只是没有入口了,见回执)
- 权限点 creator:account(只授超管);creator:list 之外的读接口未变
实测:未审核开号 200003 / 重复开号幂等 / 用户名冲突 200001 / 重置后旧密码失效新密码可登录 /
新账号只能看到自己的作品;创作者登录直接落 /creator-center/workspace 并弹出首登改密。
|
2026-10-15 16:00:42 +08:00 |
|
Vicky
|
efeb9fcfaf
|
feat: 创作者中心支持超管只读代看(未绑定不再白屏)
为什么:/creator-center 菜单同时给了超管和创作者,但接口只认"绑定了 creator.admin_user_id 的账号",
而 creator 表为空 —— 超管点进去每个接口都 403,页面全白。这是设计缺口:需要一条"超管代看"的合法路径,
且必须既能让运营排查问题,又不能变成越权入口。
- requireCurrentCreator 改三级解析:① 绑定优先(创作者角色永远走这条)② 未绑定 + creator-center:impersonate
+ 请求头 X-Creator-Id → 只读代看 ③ 其余给可识别错误码(200004 未绑定 / 200005 未选目标)
- 目标走独立请求头而不是查询参数:creator-center 接口继续"不接收 creatorId";
且只有具备 impersonate 权限的账号这个头才生效 —— 创作者自己带也不影响"只看自己的"
- 只读硬边界:代看态下作品编辑、分集增删改/排序、上传会话与产物挂载、提交/撤回、收费配置一律 200006
(写路径统一走 requireWritableDrama/requireWritable;上传会话在 MediaController 里用 ImpersonationGuard 拦)
- 代看进入写 audit_log(AuditLog 实体 + AuditLogService,同人同目标 10 分钟去重),表本来就有、之前无代码引用
- 新增 GET /admin/creator-center/impersonation/targets(仅 impersonate)供顶部下拉取数
- 权限点 creator-center:impersonate 只授予 super_admin(content_operator 第一阶段不给)
- 修掉菜单 26 的路由名冲突:它和 17 号菜单(创作者管理)都叫 CreatorCenter,Vue Router 同名路由互相覆盖,
导致超管整个 /creator-center 子树注册不上(点进去 404)。改名 CreatorWorkspace,并核对全表无重名
实测:创作者带 X-Creator-Id 仍只看自己的、仍能编辑自己的作品;代看下 9 个写操作全 403;
audit_log 有且仅有一条代看记录(12 次代看请求去重成 1 条)。
|
2026-10-15 15:25:22 +08:00 |
|