作品管理与Phaser4客户端发布闭环
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m21s
Project CI / Backend tests (pull_request) Failing after 16s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m18s
Project CI / Frontend tests (pull_request) Successful in 2m8s
Project CI / Repository checks (pull_request) Failing after 16s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m56s
Project CI / Native shell tests (pull_request) Successful in 5m47s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled

补齐 Phaser4 客户端发布前校验、阶段进度与原生幂等账本

增加 Web 作者私有作品管理、资料编辑、版本历史与软删除

增加后台作品筛选、游标分页与删除治理

同步 SpacetimeDB schema、bindings、DTO、文档与定向测试
This commit is contained in:
2026-10-01 16:30:40 +08:00
parent 1f055e9902
commit a2b70d92b8
80 changed files with 5836 additions and 676 deletions
@@ -7,14 +7,9 @@
在 10.7「陶泥儿游戏平台」上线前,把「创作者作品管理(用户侧 / 后台)+ 客户端打包上传(只保证 Phaser 4)」这条链路补齐到可用:作品能进来、能看得见状态、能管住。
## 当前事实
- 发布管道(AGC 构建打包 → 8 MiB 分片上传 → 送审 → 后台审核 → 公开可玩 → 发行网关)已实现,并有真实栈证据(见[实施计划【游戏分发阶段A领域合同】](【实施计划】游戏分发阶段A领域合同-2026-09-19.md))。
- 未通电:`game-distribution:publish` 灰度默认关闭;生产 0 个作品;dev 仅 4 条记录。
- 创作者侧缺作品管理:AGC 内没有作品列表 / 详情;`/games/mine` 不能删除作品、不能改展示资料、看不到版本历史。
- 作者点自己的「审核中 / 被驳回 / 已下架」作品只有 404:公开详情只服务已公开投影。
- 后台作品管理前端固定 50 条、无搜索无分页。
- 客户端发布没有真实进度(分片进度事件 Rust 已 emit、前端零监听);幂等键只存在于面板内存,关面板即换 key。
- 本轮已补齐:客户端 Phaser 4 + Vite 工程栈门禁、发布阶段/上传百分比、发布根幂等账本;Web 作者私有详情、状态/版本筛选、版本历史、资料编辑、软删除和作者操作;后台作品搜索、作者/状态筛选、游标分页与删除状态展示。
- 生产发布开关仍默认关闭;真实客户端 GUI 发布、生产首个作品和发布包清理策略仍需运行时取证。
## 已落地(本分支)
@@ -26,23 +21,21 @@
设计要点:不新增 SpacetimeDB 表与 procedure。详情路由的 game 走 `get_game_distribution_game`(owner 作用域,精确命中),版本沿用作者自有列表 procedure 的聚合结果。
## 计划
## 计划与落地状态
### 波 1:闭环可用
1. AGC 真机把「构建 → 打包 → 分片上传 → 送审」跑通一次(唯一还没在客户端 GUI 取证的环节)。
2. 发布进度接线:前端监听既有 `game-package-upload-progress`,渲染真实阶段与百分比。
3. 幂等键落盘:按 `gameId` + 本地项目持久化,重试复用同一 key。
4. AGC「我的作品」页:状态筛选、内联驳回理由、行内操作。
5. AGC 作品详情抽屉:展示资料、当前公开版本、版本历史、公开链接。
6. 运营开闸 + 生产发布第一个作品,走完审核 → 公开 → 游客可玩。
- [ ] AGC 真机把「构建 → 打包 → 分片上传 → 送审」跑通一次。
- [x] 发布进度接线:前端监听既有 `game-package-upload-progress`,渲染真实阶段与百分比。
- [x] 幂等键落盘:按账号、origin、本地项目和包摘要持久化根键,重试复用同一 key。
- [ ] 运营开闸 + 生产发布第一个作品,走完审核 → 公开 → 游客可玩。
### 波 2:管理完整
7. 作品资料编辑:展示资料在 `game` 级可编辑、立即生效并留审计;包仍随版本冻结。
8. 作品软删除:`game_distribution_game` 末尾追加 `deleted_at`,公开投影与列表过滤软删行,OSS 对象进入回收窗口。
9. 网页侧对齐:`/games/mine` 补删除、资料编辑、版本历史、作者看自己未公开作品。
10. 后台作品列表:分页 + 搜索 + 按作者筛选(当前前端固定 50 条)。
- [x] 作品资料编辑:展示资料在 `game` 级可编辑、立即生效并留审计;包仍随版本冻结。
- [x] 作品软删除:`game_distribution_game` 末尾追加 `deleted_at`,公开投影与列表过滤软删行。
- [x] 网页侧对齐:`/games/mine` 补删除、资料编辑、版本历史、作者查看未公开作品。
- [x] 后台作品列表:游标分页 + 搜索 + 按作者/状态筛选。
### 波 3:运营治理
@@ -51,20 +44,38 @@
13. 精选 / 推荐位(与游玩线的推荐排序定边界)。
14. 举报处理(先确认能否复用现役反馈管道)。
## 尚未完成
- AGC 真机 GUI 端到端发布取证。
- 生产环境发布第一个作品并开闸。
- 非 Phaser(Godot / Cocos / Unity)发布的主动拦截:这些工程没有 npm 构建工作区,仍只给泛化错误文案(单 HTML 项目同理)。
- 发布包清理策略的上线验收。
## 不变式
- 新增字段一律追加到 Rust 表结构体末尾并带明确默认值;不改名、不重排、不改类型。改 schema 后同步 `migration.rs`、表目录与生成绑定,并跑 `npm run check:spacetime-schema`。
- 公开投影不得携带作者私有字段(包摘要、驳回理由、文档本地路径)。作者视角走 owner 作用域路由。
- 复用现役管道与组件,不新造上传、审核、发行通道。
## 波 1 · AGC 客户端发布切片(2026-10-01 落地;自动门禁已通过,真实 GUI/生产待验收)
| 项 | 落点 | 行为 |
| --- | --- | --- |
| 发布进度接线 | `src-tauri/src/game_package_upload.rs`、`game_distribution_publish.rs`、`commands.rs`、`src/services/gamePackageUploadProgress.ts`、`src/components/game-distribution/GamePublishProgressDialog.tsx`、`GamePublishPhaseSteps.tsx`、`GameDistributionPublishPanel.tsx`、`App.tsx` | 既有 `game-package-upload-progress` 事件扩展出 `phase`(`prepare` / `upload` / `verify` / `submit`)与 `message`,上传阶段仍带 `receivedBytes` / `totalBytes`;`/complete`(重算摘要 + 展开清单)之前由上传器回调切到「校验」。渲染层在全屏进度弹窗显示「构建」步骤,在发布面板显示「构建 → 准备 → 上传 → 校验 → 送审」步骤条与上传百分比。 |
| 根幂等键落盘 | 新增 `src-tauri/src/game_publish_attempt.rs`(应用数据目录 `game-publish-attempts.json`,原子写 + 进程内锁) | 键按「账号 + origin + 本地项目 + 归一化包摘要」解析:同一份包重发、响应丢失、进程重启与分片续传复用同一根键(服务端因此只认一次尝试);送审成功后清除记录,下一次发布会新增版本。渲染层不再铸键,`publishLocalProjectGame` 只在显式传入时才带 `idempotencyKey`。账本只存账号标识、origin、本地项目标识、包摘要与根键,不含 token 与本地绝对路径。 |
| 发布前工程栈校验 | `src-tauri/src/project/export.rs`(`ensure_publish_project_stack`,导出与发布两条入口都调用) | 存在 npm 构建工作区时要求 Phaser 4 + Vite:缺 `phaser` 依赖、声明的主版本不是 4(含 `package-lock.json` 回退判定)、以及既没有 `vite` 依赖也没有 `vite.config.*` 都给出可操作中文错误(指明缺什么、当前声明、怎么修)。没有 npm 工作区的老单文件项目保持原有发布能力。 |
## 已知限制
- 作者自有游戏列表与新增的作者详情共享同一个单次条数上限(48):单作者作品数超过上限时,详情页拿不到版本记录。放量前需要补一条按 `gameId` 精确列版本的 procedure。
- 客户端不暴露 `localProjectId`:本地项目与线上作品的对应关系由客户端本地账本维护,服务端只在发布时用它复用 `gameId`。
- 发布尝试账本按「本地项目 + 包摘要」判同一尝试:改了工程或重新导出了不同内容的包就是新尝试(新建版本),旧版本的半成品包仍需走网页作者侧的恢复/重置入口。
- 发布阶段条按「本次订阅窗口」收敛(事件的 `versionId` 在命令返回前对渲染层不可知);同一窗口同一时刻只有一次发布在跑。
- 工程栈校验按首版「只支持 Phaser 4」执行:npm 工程(含 Three.js 等三维工程)未声明 `phaser` 会被拦下并提示安装 Phaser 4。若产品决定放行其它 npm 技术栈,需要在这里改成「phaser 声明存在时必须是 4,其余技术栈按白名单放行」。
## 尚未完成
- AGC 真机 GUI 端到端发布取证。
- 生产环境发布第一个作品并开闸。
- 非 Phaser(Godot / Cocos / Unity / 单 HTML)发布的主动拦截:当前只给泛化错误文案。
- 非 Phaser(Godot / Cocos / Unity)发布的主动拦截:这些工程没有 npm 构建工作区,仍只给泛化错误文案(单 HTML 项目同理)。
- 发布包清理策略的上线验收。