补充游戏共创与作品 Fork 的产品设计与技术方案

- 新增【技术方案】游戏共创与作品Fork-2026-10-03.md:用户视角入口、授权三态与状态流转、数据模型、接口契约、验收标准、未决问题
- 新增里程碑规范:游戏共创授权与血缘 M1、成品包改造闭环 M2a、作品工程源包与一键改造 M2b、创作族谱与衍生列表 M3
- 新增 M1 实施计划,明确修改边界、顺序、验证命令、风险与回滚点
- 记录与 PR #565(作品管理与 Phaser4 客户端发布)的重叠面与软删除语义影响
- docs/README.md 登记主规范索引
This commit is contained in:
2026-10-04 19:08:41 +08:00
parent 6c95660588
commit 87b306daa2
7 changed files with 771 additions and 0 deletions
@@ -0,0 +1,98 @@
# 【实施计划】游戏共创授权与血缘
| 字段 | 值 |
| ------------- | ------------------------------------------------------------------------ |
| Version | 1.0 |
| Status | implemented-local(代码与静态门禁已过;运行时端到端与浏览器验证待补) |
| Date | 2026-10-04 |
| Parent Spec | `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md` |
| Milestone | `docs/project-memory/plans/【里程碑】游戏共创授权与血缘-2026-10-03.md` |
| 授权默认值 | `forbidden`(保守取值,与需求文档一致;如需改默认允许,改一个常量即可) |
| 分支 / 工作树 | `feat/game-fork` / `.worktrees/feat/game-fork` |
## 修改边界(逐文件)
### 1. `server-rs/crates/spacetime-module/src/game_distribution.rs`
- `GameDistributionGame` 表尾追加 `fork_authorization: String`,`#[default("forbidden".to_string())]`。
- 新增表 `GameDistributionLineage`(accessor `game_distribution_lineage`):
- `game_id` PK;`owner_user_id` / `parent_game_id` / `root_game_id` 三个 btree 索引。
- 字段:`game_id, owner_user_id, parent_game_id, parent_version_id, root_game_id, generation, created_at`。
- 新常量:`GAME_DISTRIBUTION_FORK_AUTHORIZATION_{FORBIDDEN,NON_COMMERCIAL,FULL}`、`GAME_DISTRIBUTION_ACTION_SET_FORK_AUTHORIZATION`。
- `GameDistributionCreateGameInput` 追加 `forked_from_game_id: Option<String>`、`forked_from_version_id: Option<String>`。
- 新增 `GameDistributionSetForkAuthorizationInput { game_id, owner_user_id, fork_authorization, expected_fork_authorization, idempotency_key, request_digest, now_micros }`。
- `create_game_distribution_game_tx`:在「新建分支」写 game 之后、写收据之前校验并写血缘行(幂等回放分支与 `local_project_id` 复用分支都不写血缘;复用分支带血缘直接报错)。
- 新增 `set_game_distribution_fork_authorization_tx` + procedure `set_game_distribution_fork_authorization_and_return`。
- 快照:`GameDistributionGameSnapshot` 加 `fork_authorization`;公开快照加 `fork_authorization` / `fork_count` / `lineage`(父作品摘要 + 代际 + 根);后台快照加 `fork_authorization` / `generation` / `forked_from_game_id` / `derived_count`。
- 血缘校验函数 `validate_game_distribution_fork_declaration_tx(ctx, owner, parent_game_id, parent_version_id) -> Result<(root, generation, parent_owner), String>`。
### 2. `server-rs/crates/spacetime-module/src/migration.rs`
- 在 `game_distribution_game` 之后追加 `game_distribution_lineage`,并补一行注释说明它是业务事实、随迁移导出。
### 3. `server-rs/crates/module-game-distribution/src/{domain,errors,lib}.rs`
- 授权阶梯规则(只升不降)与错误:`FORK_AUTHORIZATION_DOWNGRADE_NOT_ALLOWED`、`FORK_AUTHORIZATION_UNKNOWN`、`FORK_NOT_AUTHORIZED`、`FORK_SOURCE_NOT_AVAILABLE`、`FORK_SOURCE_VERSION_MISMATCH`、`FORK_DECLARATION_ON_EXISTING_GAME`(展示文案中文,错误码进 details)。
- 代际计算:`next_generation(parent_generation) = parent_generation + 1`;根判定。
- 配套单测。
### 4. `server-rs/crates/spacetime-client/src/**`
- `game_distribution.rs`:创建输入 record 加血缘字段;新增 `set_game_distribution_fork_authorization`。
- `active/mapper/game_distribution.rs`:`GameDistributionGameRecord` 加 `fork_authorization`;公开 record 加 `fork_count`/`lineage`;admin record 加 `generation`/`forked_from_game_id`/`derived_count`;新增血缘 record 与映射。
- `module_bindings/**` 由 `npm run spacetime:generate` 生成,禁止手改。
### 5. `server-rs/crates/shared-contracts/src/game_distribution.rs`
- `GameDistributionCreateGameRequest` 追加 `fork: Option<GameDistributionForkDeclaration>`(`parentGameId` / `parentVersionId`)。
- 新增 `GameDistributionSetForkAuthorizationRequest { expectedForkAuthorization, forkAuthorization }`。
- 游戏响应加 `forkAuthorization`,公开响应加 `forkCount` / `lineage` / `forkSourceAvailable`。
### 6. `server-rs/crates/api-server/src/modules/game_distribution.rs`
- `protected` 路由新增 `PUT /api/game-distribution/games/{game_id}/fork-authorization`。
- `create_game` 校验并传递血缘声明。
- `public_game_payload` / `game_payload` / `admin_game_payload` 增量字段。
- `map_spacetime_error` 增加血缘/授权关键字的映射分支(放在 `不匹配` 分支之前,避免子串碰撞)。
- 定向测试(沿用 `app.rs` 里的分发测试 harness)。
### 7. 网页端
- `packages/shared/src/contracts/gameDistribution.ts`:`GameDistributionGame` / 创建请求 / 新授权请求类型。
- `src/services/gameDistributionClient.ts`:`updateGameForkAuthorization`(照 `unpublishGame` 写)。
- `src/components/game-distribution/GameDetailPage.tsx`:授权徽章、溯源卡、代际。
- `src/components/game-distribution/MyGamesPage.tsx`:卡片内授权设置(行内两段式确认,复用现有 `PlatformActionButton` 视觉),只升不降。
- 定向测试:`GameDistributionPages.test.tsx` / `MyGamesPage.test.tsx` 增量用例。
### 8. 文档
- 主规范 `<u>§5 验收证据</u>` 回填、里程碑验收勾选;`docs/README.md` 索引已登记。
## 顺序
1. schema(表 + 列 + 迁移登记)→ `npm run spacetime:generate` → `npm run check:spacetime-schema`。
2. 领域规则与单测(`module-game-distribution`)。
3. module tx/procedure + client facade + mapper。
4. shared-contracts DTO + api-server handler/payload/错误映射 + 后端定向测试。
5. 网页端类型、服务层、详情页、我的作品页 + 定向测试。
6. 运行时 smoke:真实栈走「设置授权 → 提升 → 拒绝降级 → 声明血缘 → 详情页展示 → 父作品下架后新声明被拒」。
## 验证命令
```bash
npm run spacetime:generate
npm run check:spacetime-schema
cargo test -p module-game-distribution
cargo test -p api-server
npx tsc --noEmit
npx vitest run src/components/game-distribution
npm run check:encoding
git diff --check
```
## 风险与回滚点
- **回滚点 1(schema)**:新列与新表只做追加,旧行默认 `forbidden`;回滚只需还原表定义并重新发布(新表直接删表定义)。
- **风险**:`map_spacetime_error` 靠子串匹配,新错误文案若含「不匹配」「已存在」「状态」会被打成 409 —— 必须在映射表前面显式加分支。
- **风险**:新增血缘校验若放在 `local_project_id` 复用分支之后,会放过「既有作品改判成衍生作品」;必须放在复用分支内判定。
- **风险**:公开 payload 不得回传对象键;血缘只回传作品摘要与代际。
@@ -0,0 +1,53 @@
# 【里程碑】作品工程源包与一键改造
| 字段 | 值 |
| ----------- | ----------------------------------------------------- |
| Version | 1.0 |
| Status | proposed |
| Date | 2026-10-03 |
| Parent Spec | `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md` |
## 目标
作者在授权允许时,把工程源码作为该发行版本的可选伴随资产一起发布;其他用户拿到的是**源码级工程**,可以改核心逻辑、重跑构建并发布,改造质量与原作者体验一致。
## 范围
- 工程源包作为发行版本的可选伴随资产:上传、确认、只读回读与对象存储生命周期。
- 工程源包的内容门禁(与模板包同一套排除规则与体积上限),服务端独立复核。
- 改造内容下发入口的来源优先级:同一版本同时存在工程源包与成品包时优先下发工程源包,并如实标注来源类型。
- 客户端:源码工程打包 → 上传(含中断续传);下载 → 校验摘要 → 解压 → 以源码工程形态建项。
- 发布面板中「是否公开工程」的选择与后果说明(默认不公开)。
## 不在范围内
- 成品包路径的改造闭环(见「成品包改造闭环」里程碑;本里程碑复用其入口、血缘声明与建项基座)。
- 工程源包的版本回溯(历史版本没有工程包时不为它补做)。
- 网页端上传工程源码包(首期只支持客户端)。
- 相似度比对与低改动度判定、收益分成。
## 依赖与前置条件
- 「游戏共创授权与血缘」里程碑已通过验收。
- 「成品包改造闭环」里程碑已通过验收(内容下发入口、客户端建项基座、发布携带来源、授权面板均在那一里程碑落地)。
- 客户端已有的「从包安装并建项」基座与包内容门禁可直接复用;本里程碑不新建第二套解压或建项路径。
- 决策:本里程碑成立的前提是产品同意引入工程源包;若否决,本里程碑取消,改造能力止于产物级。
## 验收标准
- [ ] 授权为「禁止共创」时不产生任何工程包上传,也不出现可被他人下载的工程地址。
- [ ] 含被排除目录(版本控制、依赖目录、编辑器与构建产物)或含绝对路径、上级路径、盘符、反斜杠、符号链接、超出条目数或体积上限的工程包在上传确认阶段被拒绝,且不产生任何对象或残留。
- [ ] 同一版本重复确认同一工程包不产生第二份对象;换内容重传按冲突拒绝。
- [ ] 上传中断后可按权威偏移续传,不重放整包、不跳段。
- [ ] 同一版本同时存在两种来源时,下发入口优先返回工程源包并如实标注来源类型;未上传工程包时仍能拿到成品包。
- [ ] 客户端在真实环境中完成源码工程形态建项:新项目可打开、可编辑源码、可试玩、可重跑构建并发布。
- [ ] 通过源码路径发布的作品,其来源、代际与根与成品包路径完全一致,不产生第二套血缘语义。
- [ ] 工程包未上传或上传失败不阻断发布,但界面必须明确告知改造能力被降到产物级。
- [ ] 作品公开后提升授权,可对**当前公开版本**补传工程包一次;补齐后改造路径升级为源码级,无需作者发新版本。
- [ ] 再次补传、换内容重传被拒绝;目标版本不是当前公开版本、或作品授权仍为禁止时,补传同样被拒绝;历史版本不会被补齐。
## 证据要求
- 自动化:打包排除规则与体积上限的客户端定向测试、上传确认与冲突用例、服务端门禁与鉴权拒绝用例、来源优先级与标注用例、DTO 一致性与 schema 检查、编码与文档索引检查。
- 运行时:真实 api-server + 真实对象存储 + 真实客户端跑通「拿到源码 → 改核心逻辑 → 试玩 → 发布 → 溯源与代际正确」,附对比截图或录屏。
- 边界:越权下载、无授权下载、来源已下架、摘要不符、超限包、解压失败、上传中断续传、账号切换后的迟到响应、同版本双来源优先级。
@@ -0,0 +1,48 @@
# 【里程碑】创作族谱与衍生列表
| 字段 | 值 |
| ----------- | ----------------------------------------------------- |
| Version | 1.0 |
| Status | proposed |
| Date | 2026-10-03 |
| Parent Spec | `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md` |
## 目标
任意作品的读者都能看到以母版为顶的创作族谱树,并从任一节点进入对应作品;作者能在自己的作品页看到「被改编」的直接衍生作品列表。
## 范围
- 族谱读取:以某个作品的根为顶,返回各代节点(标题、作者、代际、父作品、公开状态、游玩数),按代际与创建时间稳定排序,超出上限截断并如实标注。
- 网页新增族谱页面与路由,含根节点、分支、当前作品高亮、节点跳转、空态与失败态。
- 作品详情页的族谱入口。
- 我的作品页的「被改编」入口与直接衍生作品列表弹层。
- 来源作品已下架或封禁时节点的降级展示。
## 不在范围内
- 共创主题(平台命名的归组实体)与广场共创分区。
- 族谱的排序算法、热度权重、推荐位。
- 树的可视化交互增强(缩放、拖拽、导出图片)。
- 收益或流量回馈的任何计算。
## 依赖与前置条件
- 「游戏共创授权与血缘」里程碑已通过验收。
- 「成品包改造闭环」里程碑产生的真实数据用于端到端验证(仅展示层不依赖它,但真实链路验证需要)。
## 验收标准
- [ ] 三层链路作品打开族谱页,根节点为母版,各节点代际与父作品关系正确,点击任意节点进入对应详情页。
- [ ] 未登录用户可以浏览族谱页,不触发登录门禁;已下架但仍有血缘的节点保留在树上并标注原作品不可用,不出现空白或断链。
- [ ] 超出节点上限时如实标注已截断,不静默丢弃;空族谱(无任何衍生)给出明确空态而不是报错。
- [ ] 我的作品页「被改编」列表只包含直接衍生作品,数量与族谱树中该作品的子节点一致。
- [ ] 族谱与衍生列表的公开数据不泄露未公开作品、被隐藏内容或对象键。
- [ ] 灰度未命中时族谱入口不渲染,直接访问路由给出与现役未知路径一致的降级行为。
- [ ] 桌面与移动端布局可用,长标题与较大数字不撑破容器。
## 证据要求
- 自动化:族谱与衍生列表的排序、截断、可见性过滤定向测试;路由与前端组件定向测试;DTO 一致性与编码、文档索引检查。
- 运行时:真实数据上打开族谱页与「被改编」列表,包含一条来源已下架的链路;桌面与窄屏浏览器验证跳转与布局。
- 边界:无衍生作品的空族谱、超上限截断、来源下架、未公开子作品不出现在树中、未登录访问。
@@ -0,0 +1,50 @@
# 【里程碑】成品包改造闭环
| 字段 | 值 |
| ----------- | ----------------------------------------------------- |
| Version | 1.0 |
| Status | proposed |
| Date | 2026-10-03 |
| Parent Spec | `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md` |
## 目标
用户能在作品详情页一键把别人的已公开作品拿到本地、改完再发布,且溯源自动正确。整条链路**复用平台已存在的成品包**,作者侧不需要任何新增上传动作。
## 范围
- 受鉴权的改造内容下发入口(先只服务成品包):只对满足授权与公开性条件的请求开放,不下发可直接匿名访问的对象地址。
- 客户端:下载 → 摘要校验 → 解压 → 以「静态可玩入口」形态在本机建成新项目 → 项目内记录来源并在界面展示。
- 从平台作品唤起客户端的入口。
- 发布链路自动携带来源声明,不要求用户手填。
- 客户端发布面板的共创授权选择与相应提示。
- 能力边界的如实告知:基于已构建成品时,界面必须说明可改范围,不能让用户误以为拿到源码。
## 不在范围内
- 工程源包的上传、下载与源码形态建项(见「作品工程源包与一键改造」里程碑)。
- 网页端手填来源声明。
- 创作族谱页面(见「创作族谱与衍生列表」里程碑)。
- 相似度比对、收益分成、游玩次数上报。
## 依赖与前置条件
- 「游戏共创授权与血缘」里程碑已通过验收(授权与血缘的数据合同、状态机、灰度入口)。
- 客户端现有的「从包安装并建项」基座、解压路径门禁与「已有可玩入口直接打包」能力可直接复用,不新建第二套解压或建项路径。
## 验收标准
- [ ] 授权为「禁止共创」的作品不出现改造入口;绕过界面直接请求内容入口同样被拒绝。
- [ ] 未登录、无授权、来源作品未公开或已下架时,内容入口全部拒绝,且不泄露摘要与地址。
- [ ] 客户端在真实环境中完成「详情页 → 唤起客户端 → 下载 → 建项」:摘要校验失败时不留半成品目录,成功时新项目可直接试玩。
- [ ] 由该路径建成并发布的作品,详情页显示正确的来源、代际与衍生关系;代际与根由服务端计算,客户端无法伪造或覆盖。
- [ ] 未携带来源声明的发布路径(旧客户端、网页端)不产生血缘,也不因此报错。
- [ ] 账号切换或退出后,迟到的下载与建项响应不得写入任何本地项目或项目来源信息。
- [ ] 移动端不出现需要桌面端才能完成的改造动作,或明确给出桌面端提示。
- [ ] 灰度未命中时改造入口不渲染,写接口返回服务不可用。
## 证据要求
- 自动化:内容入口鉴权与可用性拒绝用例、客户端下载/摘要校验/解压门禁/建项的定向测试、发布链路携带来源的用例、DTO 一致性与编码、文档索引检查。
- 运行时:真实 api-server + 真实对象存储 + 真实客户端跑通「改别人的已公开作品 → 试玩 → 发布 → 溯源与代际正确」,附对比截图或录屏。
- 边界:越权下载、无授权下载、来源已下架、摘要不符、解压失败、账号切换后的迟到响应、旧客户端发布不产生血缘。
@@ -0,0 +1,57 @@
# 【里程碑】游戏共创授权与血缘
| 字段 | 值 |
| ----------- | ----------------------------------------------------- |
| Version | 1.0 |
| Status | implemented-local(本地实现完成;运行时端到端与浏览器验证待补) |
| Date | 2026-10-03 |
| Parent Spec | `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md` |
## 目标
作者可以对自己的作品设置「共创授权」,之后只能单向提升;所有浏览者能在作品详情页看到授权状态、代际与溯源信息;公开页展示真实作者署名。
## 范围
- 作品级共创授权三态(禁止共创 / 允许非商用共创 / 允许全开放共创)的持久化、默认值与单向提升规则。
- 作品级血缘关系(父作品、来源版本快照、根作品、代际)的持久化与查询,创建作品时对来源的完整校验。
- 详情页:授权徽章、溯源卡(改编自《X》· 由 Y 制作)、代际与衍生数量。
- 我的作品页:授权三态设置(仅允许提升,终态只读)。
- 后台游戏管理:授权与代际的只读展示。
- 公开页作者署名取真实账号资料,不再落到兜底文案。
- 端到端灰度开关与前端入口联动。
## 不在范围内
- 改造内容的下发与客户端建项(成品包路径见「成品包改造闭环」里程碑,源码路径见「作品工程源包与一键改造」里程碑)。
- 创作族谱页面与衍生作品列表(见「创作族谱与衍生列表」里程碑)。
- 共创主题(平台命名的归组实体)。
- 收益分成、流量回馈、相似度反洗稿校验。
- 游玩次数上报。
## 依赖与前置条件
- 主规范 §3 的数据模型与状态机已评审通过。
- 决策:授权默认值取「禁止共创」还是「允许」需产品拍板;本里程碑的实现按拍板结果设定默认值,其余合同不变。
- 决策:是否引入共创主题实体需产品拍板;本里程碑不依赖该实体。
## 验收标准
- [ ] 新建作品默认授权为拍板结果;迁移前已存在的作品在升级后同样按该默认解释,无需人工回填。
- [ ] 同一次授权变更里,合法提升(含跳级)成功、任何降级被拒绝且不写库。
- [ ] 非作品作者不能变更授权;基于旧值的并发请求按期望值冲突拒绝。
- [ ] 重复提交同一授权变更请求不产生第二次副作用,如实回报为幂等重放。
- [ ] 声明血缘时:来源作品不存在、未公开、已被封禁、授权为禁止、来源版本不等于来源作品当前公开版本,五类情形全部失败关闭且给出可区分的原因。
- [ ] 代际与根作品由服务端计算:三层链路(A→B→C)得到 B 为第 1 代、C 为第 2 代,且 B、C 的根作品都是 A。
- [ ] 血缘不可变:同一作品第二次声明血缘被拒绝;既有作品复用身份的场景不接受血缘声明。
- [ ] 来源作品下架或封禁后,既有衍生作品保持公开,新的血缘声明被拒绝。
- [ ] 详情页展示的授权、代际、溯源与衍生数量与后端一致;来源作品不可读时该节点降级展示而非空白。
- [ ] 公开详情与广场展示真实作者名与头像(读时联账号表),兜底文案不再出现在可正常读取账号的场景;现役公开 DTO 未暴露陶泥号,如需展示须另加字段。
- [ ] 公开响应不泄露对象键、未公开作品或未公开来源信息。
- [ ] 发布开关收紧时,共创授权写入返回 `503 GAME_DISTRIBUTION_PUBLISH_DISABLED`;开关状态读取失败按关闭处理。(M1 复用现役 `game-distribution:publish` 开关,不新增独立灰度键。)
## 证据要求
- 自动化:领域规则单测(授权状态机、代际与根计算、血缘校验)、发行模块与 BFF 定向测试、共享 DTO 一致性检查、生成绑定与 schema 检查、编码与文档索引检查。
- 运行时:真实 api-server + 本地数据库上完成「设置授权 → 提升 → 声明血缘 → 详情页展示 → 父作品下架后新声明被拒」整链 smoke;浏览器在桌面与窄屏检查详情页与我的作品页。
- 边界:未登录、非作者、期望值不匹配、重复请求、来源作品五种不可用情形、父作品下架前后对比。