Commit Graph

429 Commits

Author SHA1 Message Date
suzmii 6aa2f97410 feat(游戏共创): 贡献归集与归因(接口 + 契约 + 文档;反洗稿改判搁置)
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
产品口径:「子代所有的都算父代的」,并要能溯源「多少是子代给的、多少是自己的」。本期**只做计算**,
不含资金/分成结算。

- 递归定义:`inherited(W) = Σ_{c∈直接子代} total(c)`,`total(W) = own(W) + inherited(W)`;每个后代在它的每个
  祖先里只计一次。
- 接口:`GET /api/game-distribution/games/{game_id}/contribution`(Bearer + `no-store`)——**仅该作品作者**:
  未登录/失效 401(中间件)、非作者 403(复用既有 owner-mismatch → FORBIDDEN,不新增第二套鉴权)、
  作品不存在或根自身已软删 404。响应:`{ gameId, own, inherited, total, byGeneration[], directChildren[],
  nodeCount, truncated, truncatedReason }`;指标结构 `ContributionTotals{playCount}` 可扩展(将来加点赞/收藏/收入)。
- 不变量(测试钉住):`inherited == Σ byGeneration.total == Σ directChildren.total`、`total == own + inherited`、
  `nodeCount == Σ byGeneration.gameCount`;`byGeneration` 只含后代(绝对代际,升序)。
- 上限与截断:节点 500 / 深度 32;超限如实标 `truncated: true` + `truncatedReason ∈ {node_limit, depth_limit}`,
  已计入部分仍自洽(与族谱 `truncated` 同约定,不静默给半个数);遍历只用血缘表既有索引,**不新增表/索引**。
- 契约:shared-contracts 4 个 DTO + TS 镜像 + parity(+4 组 → 66 组);7 个生成绑定(含 procedure)。
- 文档:技术方案新增 `§3.11 贡献归集与权益归因`(定义/归因分解/接口/上限与截断/鉴权口径与理由)+ §3.4 路由行 +
  §5.4 实施证据;**任务 B**:反洗稿(相似度校验)从「待拍板」改为「**产品已决定搁置(2026-10-06)**」并从待拍板
  清单移除,结算口径统一为「本期只做贡献归集与归因计算」。
- 测试:module-game-distribution **131 passed**(contribution 12 条,含 A→B→C 三层链路不变量);spacetime-module
  **304 passed / 1 ignored**(+3 结构断言);spacetime-client 43 passed;api-server game_distribution **107 passed**(+3)。

门禁:wasm build 0;`cargo check --all-targets` 0;`SPACETIME_SCHEMA_BASE_REF=9f4c7d76 npm run check:spacetime-schema`
0(98 表);DTO parity 0(66 组 / 17 构建器 / 15 手拼类型);`check:project-bundle-policy-parity` OK;
`check:encoding` 0(5543 files);`cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check` 0;`git diff --check` 0。

注:本块未提交 `scripts/*.mjs`(`check-game-distribution-lineage-e2e.mjs` / `-theme-e2e.mjs` /
`capture-game-lineage-visual.mjs`)——属其它 owner,工作区保留未提交。
2026-10-06 18:05:49 +08:00
suzmii 512bbb7a62 feat(游戏共创): 衍生作品创建时自动继承父作品授权档位(客户端不可另选)
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m9s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m3s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m46s
Project CI / Frontend tests (pull_request) Successful in 3m11s
Project CI / Native shell tests (pull_request) Failing after 3m18s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m20s
Project CI / Repository checks (pull_request) Successful in 6m4s
Project CI / Backend tests (pull_request) Successful in 8m2s
对齐需求文档 revision 1554「授权设置区:自动继承父作品授权」(被划掉的那句「可收窄、不可放宽」不做)。

- **口径**:衍生作品创建时 `fork_authorization` **直接取父作品当时的档位**(创建时快照),客户端传值一律
  **忽略且不报错**(旧客户端会惯常带默认值);母版不变(按请求值,缺省 `forbidden`,未知档位仍失败关闭);
  收窄入口不做;**PUT 提升接口语义未改**(见下)。
- **落点**:`resolve_game_distribution_fork_declaration_tx` 原本就在父行上判「存在/未软删/已公开/非禁止/来源版本
  等于父当前公开版本」,现在把父档位一并回传(`(root, generation, ForkAuthorization)`);新增纯函数
  `resolve_game_distribution_creation_fork_authorization(parent, requested)`:有父 → 父档位,无父 → 解析请求值
  (未知 → `FORK_AUTHORIZATION_UNKNOWN`);创建事务里把血缘解析挪到授权裁决之前,新行写裁决结果。
- **无 schema / 无契约形状变化**:`GameDistributionCreateGameRequest.forkAuthorization` 保留(非 Option +
  `serde(default)` 未动 ⇒ 幂等摘要不变);表列、client record、快照均无字段增删。
- **文档**:技术方案 §2.3(授权模式 + 时序图两条继承边)/§2.4/§3.2.1/§3.4 `POST /games` 行/§3.9 补充/新增 §5.3
  实施证据/§7 第 2 条(待拍板 → 已定口径并注明收窄不做);数据契约 `game_distribution_game` 授权条;共创授权与
  血缘里程碑(依赖决策/验收第 1 条/实施记录);decision-log 新增 2026-10-06 决策条。
- **测试**:spacetime-module +7(继承矩阵:父 full/nonCommercial × 请求 forbid/nonCommercial/full/空串 一律落
  父档位;母版按请求值;未知档位失败关闭;以及「血缘解析返回父档位 + 裁决排在解析之后且写库之前」的结构断言)。
  Rust 侧原本**没有**断言「衍生默认 forbidden」的用例(已 grep 核对),因此没有为了让测试过而弱化任何断言。

门禁:`SPACETIME_SCHEMA_BASE_REF=9f4c7d76 npm run check:spacetime-schema` 0(98 表);`cargo check --all-targets` 0;
`cargo test -p module-game-distribution` 119 passed;`cargo test -p spacetime-module` **301 passed / 1 ignored**;
`cargo test -p api-server game_distribution` 104 passed;DTO parity 0(62 组 / 17 构建器 / 15 手拼类型);
`check:encoding` 0(5535 files);`cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check` 0;`git diff --check` 0。

**待你拍板(只报不改)**:继承是「创建时快照 + 等值」,而 PUT 只限制方向不限制对象 ⇒ 衍生作品作者仍可把继承来的
档位再往上提,得到比祖先更宽的子作品,「不可放宽」会被绕过。选项:① 保持现状(PUT 对衍生作品也生效);
② 禁止对衍生作品 PUT 提升(档位只由继承决定;需新增「该 game 无血缘行」判定 + 稳定错误码,并同步文档与前端入口)。

**需其它 owner 同步**(我未改,属其文件):`scripts/check-game-distribution-lineage-e2e.mjs`(richB1/richC1/richD
从 `forbidden` 提升的前置假设已不成立)、`scripts/capture-game-lineage-visual.mjs`(固定
`expectedForkAuthorization: 'forbidden'` 的造树与断言)。
2026-10-06 17:39:35 +08:00
suzmii d0176f48b7 feat(游戏共创): 衍生作品发布必填「本次核心改动说明」(版本级存储 + 可达错误码)
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
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
按需求文档 revision 1554「发布设置页 → 二创信息区(必填项)」:衍生作品(有血缘行)发布新版本时**必须**
提供「本次核心改动说明」;母版(0 代)不需要——提供了也忽略、不校验、不落库。

- **存储**:`game_distribution_version` **表尾追加** `change_summary: Option<String>`(`#[default(None)]`);
  列序属 wire format,`game_distribution_version_type` / `_version_snapshot_type` / `_create_version_input_type`
  三个绑定同步重生成(仓外临时 out-dir,只回写受影响文件)。
- **请求**:`GameDistributionCreateVersionRequest.change_summary`(`#[serde(default, skip_serializing_if)]`:
  缺省不序列化 `null`,保住旧客户端的幂等摘要)。
- **校验**:纯函数 `game_distribution_change_summary_violation(value, is_derivative)`,trim 后按**字符**计
  **20..=500** —— 20 是「能写清改了什么」的下限,500 约 1 KiB 上限,兼顾详情页/族谱展示与存储;
  超限或缺失**失败关闭**,错误码 `FORK_CHANGE_SUMMARY_REQUIRED` / `FORK_CHANGE_SUMMARY_INVALID`(均 **400**),
  已登记进 api-server 的 `FORK_` 映射表并纳入「FORK 码由模块真实文案可达」的枚举测试(防上次那种不可达码)。
- **公开投影**:`currentVersion.changeSummary`(衍生为字符串、母版 `null`,发键不发值),版本负载键集合
  逐字钉死为 id/version/entryUrl/sha256/publishedAt/controls/changeSummary,不带对象键/素材 id/审核字段。
- **契约与登记**:Rust DTO + TS 镜像 + parity(`version_summary_payload` 加 `mustEmit: ['changeSummary']`)。
- **文档**:技术方案 `§3.4`(请求增量 + 长度口径与理由 + 两个错误码 + 幂等摘要口径 + 公开投影)、数据契约
  文档的版本表小节(表尾追加列)。
- **测试**:纯函数 5 条(衍生缺失/超短(ASCII 与汉字)/超长(ASCII 与汉字)/区间内 trim 边界/母版忽略)+
  事务 4 条 + 接口 3 条(含公开负载键集合与母版 null)。

门禁:`SPACETIME_SCHEMA_BASE_REF=9f4c7d76 npm run check:spacetime-schema` 0(98 表);`cargo check --all-targets` 0;
`cargo test -p module-game-distribution` **119 passed**;`cargo test -p api-server game_distribution` **104 passed**;
DTO parity 0(62 组 / 17 构建器 / 15 手拼类型);`check:encoding` 0(5535 files);
`cargo fmt --all --manifest-path server-rs/Cargo.toml -- --check` 0;`git diff --check` 0。

注:本块**未提交** `scripts/check-game-distribution-lineage-e2e.mjs` / `check-game-distribution-theme-e2e.mjs` /
`capture-game-lineage-visual.mjs` 的配套改动(属别的 session 的文件,工作区里保留未提交,需其 owner 决定:
衍生作品发布若不传 `changeSummary` 现在会 400,那三个脚本需要同步补字段)。
2026-10-06 17:24:42 +08:00
suzmii eeb101458a Merge remote-tracking branch 'origin/master' into feat/game-fork
Project CI / Backend tests (pull_request) Failing after 34s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m27s
Project CI / Native shell tests (pull_request) Failing after 2m46s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m58s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m23s
Project CI / AI game creator shell web tests (pull_request) Failing after 45s
Project CI / Frontend tests (pull_request) Successful in 2m24s
Project CI / Repository checks (pull_request) Failing after 1m1s
# Conflicts:
#	apps/ai-game-creator-shell/src-tauri/src/game_distribution_publish.rs
#	apps/ai-game-creator-shell/src/components/game-distribution/GameDistributionPublishPanel.tsx
#	apps/ai-game-creator-shell/tests/gameDistributionPublishPanel.test.tsx
#	docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md
#	package.json
#	packages/shared/src/contracts/gameDistribution.ts
#	scripts/check-game-distribution-dto-parity.mjs
#	server-rs/crates/api-server/src/modules/game_distribution.rs
#	server-rs/crates/module-game-distribution/src/errors.rs
#	server-rs/crates/module-game-distribution/src/lib.rs
#	server-rs/crates/shared-contracts/src/game_distribution.rs
#	server-rs/crates/spacetime-client/src/active.rs
#	server-rs/crates/spacetime-client/src/active/mapper.rs
#	server-rs/crates/spacetime-client/src/active/mapper/game_distribution.rs
#	server-rs/crates/spacetime-client/src/game_distribution.rs
#	server-rs/crates/spacetime-client/src/module_bindings.rs
#	server-rs/crates/spacetime-client/src/module_bindings/game_distribution_game_snapshot_type.rs
#	server-rs/crates/spacetime-client/src/module_bindings/game_distribution_game_type.rs
#	server-rs/crates/spacetime-module/src/game_distribution.rs
#	server-rs/crates/spacetime-module/src/migration.rs
#	src/components/game-distribution/GameDetailPage.tsx
#	src/components/game-distribution/GameDistributionPages.test.tsx
#	src/components/game-distribution/GamePlayPage.tsx
#	src/components/platform-entry/PlatformEntryActiveFlowShell.tsx
#	src/services/gameDistributionClient.test.ts
#	src/services/gameDistributionClient.ts
2026-10-06 16:10:52 +08:00
suzmii 54e05d5e84 lineage viz polish 2: dual-axis fit, readable floor, fixed axis layer, edge contrast
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
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
2026-10-06 14:47:51 +08:00
suzmii f0cad9dddc 合并 origin/master(52c83cc2a,248 个提交)到 feat/game-purchase
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m28s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m26s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m41s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m56s
Project CI / Backend tests (pull_request) Successful in 9m4s
Project CI / Repository checks (pull_request) Successful in 7m13s
Project CI / Native shell tests (pull_request) Successful in 10m16s
Project CI / Frontend tests (pull_request) Successful in 2m26s
- 同步 master 侧 248 个提交:会员与泥点计费(PR #588 / #603)、创作者主页与关注粉丝(PR #638)、运行页刷新真重载(PR #640)、AGC 模板 templateVersion 递增(PR #643)等;确认 master 未触碰发行网关与 `api-server/src/modules/game_distribution.rs`。
- 冲突 1(server-rs/crates/module-runtime/src/domain.rs:1157-1162)`RuntimeProfileWalletLedgerSourceType` 两侧各自在末尾追加变体:保留 master 的 `MembershipUpgradeGrant` 为索引 16(线上已落库口径),本分支 `GamePurchase` 顺延为索引 17,并保留其「每账号每游戏一次扣费」注释。
- 冲突 2(server-rs/crates/module-runtime/src/domain.rs:1184-1188)`as_str()` 同时保留 `membership_upgrade_grant` 与 `game_purchase` 两个分支。
- 冲突 3(server-rs/crates/spacetime-client/src/active/mapper/runtime_profile.rs:95-101)bindings→领域枚举映射同时保留 `MembershipUpgradeGrant` 与 `GamePurchase` 两支,按新索引顺序排列。
- 冲突 4(server-rs/crates/spacetime-client/src/module_bindings/runtime_profile_wallet_ledger_source_type_type.rs:43-47)生成枚举按模块源码顺序合并为 …`MembershipUpgradeGrant`、`GamePurchase`;随后 `npm run spacetime:generate` 复核该文件与生成结果逐字节一致。
- 冲突 5(server-rs/crates/api-server/src/admin.rs:4849-4853)sats 索引映射改为 `16 => membership_upgrade_grant` 与 `17 => game_purchase` 两条并存。
- 冲突 6(server-rs/crates/api-server/src/admin.rs:6368-6461)索引断言并入 master 的 `[16] => membership_upgrade_grant`,并把 master 的「17 尚未映射」占位断言替换为 `[17] => game_purchase`;本分支的后台消耗统计两个用例原样保留。
- 冲突 7(server-rs/crates/api-server/src/runtime_profile.rs:219-226)来源文案格式化同时保留 `MembershipUpgradeGrant` 与 `GamePurchase` 两支,注释随 `GamePurchase` 保留。
- 冲突 8(docs/project-memory/shared-memory/decision-log.md:3-24)两条决策记录并列保留:本分支 2026-10-05「播放会话前缀在三处入口清空 Cookie」在前,master 2026-10-03「每日免费发放额为 0 时前端隐藏该池」在后。
- 保住 master 侧:发行响应 ETag/304/gzip(`release_asset_response_with_cache` 五参形态与 `release_asset_etag` / `if_none_match_matches` / `accepts_gzip_encoding` / `gzip_release_asset` / `release_asset_not_modified_response`)、共享加载面 `PlatformGameLoadingSurface` 及其使用方、三池钱包与会员档位目录改造。
- 保住本分支侧:付费作品 404 守卫(`price_mud_points > 0` 且位于 `load_package` 之前)、购买与播放会话网关路由、nginx×3 / Pingora / Vite 的播放会话 Cookie 清空与 `nginx-route-parity.matrix.json` 登记、viewer 感知公开详情、后台审核价格、`PlatformGamePricingField` 共享定价组件与两端接入、AGC 项目版本只读 + 平台派发下一版本号、schema 与迁移白名单、钱包来源 `game_purchase`。
- 验证:`git merge-base --is-ancestor origin/master HEAD` 返回 0;`check:encoding`、`check:doc-index`、`check:spacetime-schema`、`check:server-rs-ddd`、`check:rustfmt`、`check:npm-workspaces`、`check:game-distribution-dto-parity`、`check:game-distribution-price-limit-parity`、`check:pingora-route-parity`、`check:nginx-spa-routes`、根/admin-web/AGC typecheck、`git diff --check` 全绿。
- 测试:`cargo test -p module-game-distribution` 30 passed,`cargo test -p api-server game_distribution` 61 passed,`cargo test -p spacetime-module game_distribution` 7 passed;定向 vitest 28 个文件 252 个用例全通过。
- `npm run spacetime:generate` 除 11 个 procedure 文件的纯空白格式差异外无任何语义改动(`git diff -w` 为空),已保留 master 的生成产物形态,提交内无 schema/绑定语义变化。
2026-10-06 13:12:32 +08:00
suzmii 2a04f293b1 Merge remote-tracking branch 'origin/master' into feat/game-fork
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m25s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m18s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m31s
Project CI / Frontend tests (pull_request) Successful in 2m38s
Project CI / Native shell tests (pull_request) Failing after 2m52s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m29s
Project CI / Backend tests (pull_request) Successful in 7m44s
Project CI / Repository checks (pull_request) Successful in 5m37s
2026-10-06 12:24:10 +08:00
k88936 796cf9843c Merge remote-tracking branch 'origin/master' into feat/pricing-plan
Project CI / AI game creator shell Rust crates (pull_request) Successful in 6m0s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m43s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m42s
Project CI / Frontend tests (pull_request) Failing after 1m16s
Project CI / Backend tests (pull_request) Successful in 8m51s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m34s
Project CI / Repository checks (pull_request) Successful in 5m34s
Project CI / Native shell tests (pull_request) Successful in 7m18s
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
2026-10-06 10:14:15 +08:00
suzmii ce614d59c1 feat(游戏共创): 主题详情 rootsTruncated 信号(memberCount 报真实可见成员数)
Project CI / AI game creator shell Rust crates (pull_request) Successful in 6m1s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 7m10s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m58s
Project CI / Backend tests (pull_request) Successful in 9m10s
Project CI / Frontend tests (pull_request) Successful in 2m58s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m32s
Project CI / Native shell tests (pull_request) Successful in 6m37s
Project CI / Repository checks (pull_request) Successful in 4m55s
裁定(与族谱 `truncated` 同约定):`memberCount` = **真实可见成员数**(不受展示上限污染),新增布尔
`rootsTruncated`,**仅当 `roots` 被 50 上限截断时为 true**。此前两个数被同一个 50 上限截断 ⇒ 可见成员
> 50 时静默截断,客户端既看不到全部树、也拿不到任何信号。

- 纯函数:`game_distribution_theme_roots_truncated(visible_member_count, returned_root_count)`
  (相等 / 回传更多 ⇒ false;后者是防御性口径:两组数字不同源时不得凭空报「还有更多」)。
- 契约:`GameDistributionThemeDetail` 加 `roots_truncated`(serde camelCase ⇒ `rootsTruncated`),
  TS 镜像同步;parity `public_theme_detail_payload.mustEmit` 6 键 → **7 键**。
- 事务:`member_count` 走可见成员清单的 `len()`(**不再**经 `page_theme_members` 与上限),`roots` 仍是
  同一清单排序后取前 50,`rootsTruncated` 由纯函数算出(不写死「>50 就 true」——阈值与上限是两个
  独立事实);列表入口共用同一计数函数 ⇒ 同一主题在列表与详情里不会报出两个 `memberCount`。
- api-server:`public_theme_detail_payload` 增加 `rootsTruncated`;形状单测 6 → 7 键,并加
  `memberCount=120 / roots=1 / rootsTruncated=true` 用例,证明两个键口径独立。
- 结构断言同步修正:列表侧原「成员数与 roots 共用同一上限」改为「成员数数的是全部可见成员(断言
  源码里不含切页函数与上限常量)」;详情侧改为「必须调用共享纯函数 + 不得再恒等 `roots.len()` +
  该字段必须进入返回值」。
- 生成绑定:`module_bindings/game_distribution_theme_detail_result_type.rs` 手改后用临时 out-dir 重跑
  `spacetime generate --lang rust` 逐字节校对一致。**wire format 变更 ⇒ 部署需重新 publish 模块**
  (客户端绑定已同步)。
- 文档:技术方案 §3.4 / §3.10.6 / §3.10.9(原「已知限制·三个备选待拍板」→ 已定口径)、里程碑
  (依赖、接口表、验收标准、纯函数表、测试清单、待确认项)、以及数据契约文档里那句「主题详情的
  roots 与列表的 memberCount 永远一致」(本改动已使其为假)。

门禁:wasm build 0;`cargo check --all-targets` 0;`cargo test -p api-server game_distribution` 86 passed;
`cargo test -p module-game-distribution` **101 passed**;`cargo test -p spacetime-module` 286 passed /
1 ignored;DTO parity 0(58 组 / **15** 构建器 / 12 手拼类型);`check:spacetime-schema` 0(96 tables);
`check:encoding` 0(5420 files);`cargo fmt --all -- --check` 0;`git diff --check` 0。

遗留(不在本仓可改范围,需前端 session 跟进):`src/services/gameDistributionClient.ts` 有自己一份主题
详情本地类型与 normalize,会丢弃 `rootsTruncated`(约 3 行小改),因此网页主题页暂时拿不到截断信号;
admin-web 走共享契约类型,后台侧即时生效。
2026-10-06 04:09:45 +08:00
suzmii 742723a58c feat(游戏共创): 共创主题(二)公开读路径(事务 + client + 两个公开路由 + 详情 themes 增量)
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m44s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m35s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m37s
Project CI / Backend tests (pull_request) Successful in 9m29s
Project CI / Frontend tests (pull_request) Successful in 3m7s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m7s
Project CI / Repository checks (pull_request) Successful in 6m48s
Project CI / Native shell tests (pull_request) Successful in 8m39s
- **事务**(`spacetime-module`):公共列表 `list_game_distribution_themes_tx`(匿名可读;先按 `published` 过滤、再排序切页——`created_at` 倒序 + `theme_id` 兜底;只对当页现算 `member_count`;不写库);主题详情 `get_game_distribution_theme_detail_tx`(不存在 / 未发布**同一句**「主题不存在」→ 404;`roots` 逐条复用公开目录同一份 `public_game_distribution_snapshot`;成员可见性委托 `game_distribution_theme_member_visible`,被滤掉的行**不删除**;已发布但可见成员为空 = Ok + 空 roots = 200);作品→主题 `list_game_distribution_theme_refs_for_root_tx`(入参任意代作品,先取**根**再按根反查成员、只保留 `published` 主题;排序复用 `sort_public_themes`)。**根解析只有一份实现**:抽成 `game_distribution_theme_root_of` 并让既有 `game_distribution_lineage_tx` 复用(测试钉住)。
- **client**:3 个新方法 + mapper 记录类型(`spacetime-client`)。
- **公开路由**(`api-server`):`GET /api/game-distribution/themes?limit=&cursor=`(匿名可读 + `no-store`;`limit` 缺省 20 / 上限 50 / 超界截断;非法游标 **400** 透传;末页 `nextCursor: null`)、`GET /api/game-distribution/themes/{theme_id}`(顶层扁平 `{themeId,name,summary,badge,memberCount,roots}`;不存在 / draft / archived → **404**,不回空壳、不带 `THEME_` 码)、既有公开作品详情追加 `themes`(匿名与登录**都**发、空数组恒发;`collected` 仅登录发的老口径不变;因按根反查,**第 N 代作品也能跳到主题页**)。
- **错误码**:新增 6 个 `THEME_*` 稳定码集中在 `map_spacetime_error` 映射(不落 axum 默认 422 纯文本);未登记码兜底 **400 `THEME_ERROR`**。
- **契约/parity**:5 条手拼响应构建器登记(`public_themes_payload` / `public_theme_detail_payload` / `public_theme_summary_payload` / `theme_reference_payload`,并给 `public_game_detail_payload` 加 `mustEmit: [themes]`)→ 58 组类型 + 10 个构建器一致。
- **测试 +13**:spacetime-module 4 条源码结构断言(根解析单一实现、先过滤再切页、投影不删行、详情只有两种失败且同一 404 文案、refs 走具名根索引 + 只保留 published)、api-server 7 条(路由挂载与 `no-store`、列表/详情响应形状与末页 null、`roots` 逐字节等于 `public_game_payload`、limit 缺省与截断、非法游标 400、404 与 6 个 THEME_ 码映射、作品详情 `themes` 恒发而 `collected` 仅登录)、client mapper 2 条。
- **门禁**:wasm build 0;`cargo check --all-targets` 0;`cargo test -p api-server game_distribution` **79 passed**;`cargo test -p module-game-distribution` **97 passed**;`cargo test -p spacetime-module` **278 passed** / 1 ignored;`cargo test -p spacetime-client` 34 passed;DTO parity **58 组 / 10 构建器**;`check:spacetime-schema` 0(96 tables);`check:encoding` 0(5399 files);`cargo fmt --all -- --check` 0;`git diff --check` 0。

已知限制(**已上报,待拍板**):主题详情的 `roots` 沿用页上限 50,`memberCount == roots.len()`,因此可见成员 > 50 时**静默截断且无「还有更多」标志**——设计文档未定义该行为,三个备选(去上限 / 加成员游标 / memberCount 报真实数)待定;本轮不改契约。
2026-10-06 02:15:03 +08:00
suzmii 2fa201e0dc feat(游戏共创): 共创主题(一)数据模型与领域纯函数
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m30s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m12s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m44s
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
按 `docs/【技术方案】游戏共创与作品Fork-2026-10-03.md §3.10` 与里程碑《共创主题与作品树-2026-10-06》的清单 A/B/F 落地(本块**不含** procedure / 路由)。

- **表**:`game_distribution_theme`(`theme_id` 主键、`name`/`summary`/`badge`/`sort_order`/`status ∈ draft|published|archived`/`created_by_user_id`/`created_at`/`updated_at`)+ `game_distribution_theme_member`(确定性主键 `member_id = "{theme_id}:{root_game_id}"`,`theme_id`、`root_game_id` 各具名 btree 索引,`sort_order`、`created_at`);归档 / 下架只改公开投影,不删成员行。`migration.rs` 白名单登记两张表(随迁移导出/导入)。
- **生成绑定**:4 个 `game_distribution_theme*` 生成文件 + `module_bindings.rs` 入口(纯追加)。生成时**不覆盖工作树**(本仓共享工作树禁止 git 写命令):先 `spacetime generate --lang rust --out-dir <仓外临时目录>`,rustfmt 后只拷回本次相关文件,避免上一轮踩过的「rustfmt 漂移把别人文件一起改」。
- **领域纯函数**(`module-game-distribution/src/theme.rs`,风格照同目录 `collection.rs`):状态合法/公开可见判定、`game_distribution_theme_member_id`、成员可见性(**委托** `collection.rs` 的判定,不复制第二套)、`game_distribution_theme_root_acceptable(has_lineage_row)`、页大小(缺省 20 / 上限 50 / 0 取默认 / 超界截断)、游标编解码(`"{createdAtMicros}:{themeId}"`,Err 文案「主题列表游标格式无效」,已核对不含 404/409 关键词)、`sort_public_themes`(`created_at` 倒序 + `theme_id` 兜底)、`page_public_themes`(排序 → retain 游标之后 → 多取一条判 has_more;**先过滤再切页**的顺序语义写进文档注释)、`sort_theme_members`(`sort_order` 升序 + `member_id` 兜底)与 `page_theme_members`。
- **契约**:`shared-contracts` 新增 `GameDistributionThemeStatus` / `GameDistributionThemeReference` / `GameDistributionThemeSummary` / `GameDistributionThemeListResponse` / `GameDistributionThemeDetail` / `GameDistributionCreateThemeRequest` / `GameDistributionUpdateThemeRequest` / `GameDistributionUpsertThemeMemberRequest`,`GameDistributionGameSummary` 追加可选 `themes`(按 `collected` 先例只在详情路径下发);TS 镜像同步;parity 登记 **58 组**(响应构建器待路由落地后再登记,parity 要求函数真实存在)。
- **数据契约表目录**:补两张表小节,94 → **96**。
- **测试**:`theme.rs` 16 个单测(成员 id 确定性、状态三态与公开可见、成员可见性逐格与收藏判定等价、根判定、页大小边界、游标往返与非法输入、排序稳定性与同 `sort_order` 兜底、分页不重不漏)。
- **门禁**:wasm build 0;`cargo check --all-targets` 0;`cargo test -p module-game-distribution` **97 passed**;`cargo test -p spacetime-module` 274 passed / 1 ignored;DTO parity **58 组**;`check:spacetime-schema` 0(**96** tables);`check:server-rs-ddd` 0;`check:encoding` 0(5388 files);`cargo fmt --all -- --check` 0;`git diff --check` 0(8 个改动文件 0 删除行)。
2026-10-06 01:46:23 +08:00
suzmii f09607d903 feat(游戏共创): 收录(收藏)列表补真分页(cursor + limit)
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
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
- 纯函数(`module-game-distribution/src/collection.rs`,与收藏另两条规则同文件):`encode/parse_game_distribution_collection_cursor`(`"{created_at_micros}:{collection_id}"`,复用仓库既有 `"{micros}:{id}"` 惯例;非法 → Err「收藏列表游标格式无效」→ 400)、`game_distribution_collection_page_limit`(0/缺省 → 20,超界 → 50)、`game_distribution_collection_page`(稳定全序排序 → 跳过游标之前 → 取 limit → 多取一条判 has_more,只对页内最后一条编码下一游标)
- 排序与顺序语义:`created_at` 倒序 + `collection_id` 升序兜底(主键、同用户内唯一 ⇒ 全序,翻页不重不漏);**先按可见性过滤、再排序切页**——游标位置必须落在已过滤序列上,否则被过滤的行会让下一页漏项(推理写进 tx 与纯函数注释);snapshot 只对最终页成员计算
- 模块:list 的 input 增 `limit` / `cursor`,result 增 `next_cursor`;api-server `my-collections` 加 `Query<MyCollectionsQuery>`,默认 20 / 上限 50(网格一屏 vs 单响应体积;与后台列表的 200 口径不必相等,理由写进注释),超界**截断**不报错,非法游标 400 透传不吞,日志带 `has_more`
- 契约:Rust DTO 增 `next_cursor`、TS 镜像同步、parity 登记(50 组一致)
- 文档:§3.4 的 `my-collections` 行补分页语义(默认/上限/游标格式/非法 400/末页 null/排序口径)
- 测试 13 条:纯函数 8(不足一页 → None;恰好整页不产生空游标;5 条 limit=2 连翻 3 页不重不漏;同 `created_at` 用 `collection_id` 兜底;limit=0 与超界;游标往返 + 7 种非法输入)、模块事务结构 2、api-server 3(默认与截断、`nextCursor` 透传、非法游标 → 400)
- 门禁:wasm build 0;`cargo check --all-targets` 0;`cargo test -p module-game-distribution` **81 passed**;`cargo test -p api-server game_distribution` **73 passed**;`cargo test -p spacetime-module` 274 passed / 1 ignored;DTO parity **50 组**;`check:spacetime-schema` 0(94 tables);`check:encoding` 0(5382 files);`cargo fmt --all -- --check` 0;`git diff --check` 0
2026-10-06 01:31:09 +08:00
suzmii 4b1f24a8fc feat(游戏共创): 收录(收藏)契约与文档同步(块 3/3)
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
- `shared-contracts`:新增 `GameDistributionCollectionState { collected, replayed: Option<bool> }` 承载 PUT/DELETE 共用形状(PUT 才发 `replayed`);既有 `GameDistributionGameSummary` 增 `collected: Option<bool>`(公开详情登录时才带)——该类型只被 api-server 测试与 `GameDistributionListResponse` 引用,加字段不影响任何现有发送方
- `packages/shared` TS 镜像同步(`{ collected: boolean; replayed?: boolean }` 与 `GameDistributionGame.collected?: boolean`),并按既有约定登记进 `scripts/check-game-distribution-dto-parity.mjs`(PAIRS + 手拼响应构建器);注意 `json!` 字面量里不插注释行(parity 脚本抓顶层键时不剥注释,这个坑今天踩过一次)
- 技术方案:`§2.4` 入口矩阵补「收藏按钮 / 我的收藏(登录)与我的作品页同行风格」;`§3.4` 接口表补三条路由(含 404/409 语义、PUT 要求幂等键而 DELETE 不要求及理由、`my-collections` 只含公开作品且不删行)与公开详情 `collected` 的可见性口径;`§7` 把「收录/收藏」从范围外移除并标注已纳入落地
- 数据契约表目录:新增 `game_distribution_collection` 小节(主键确定性、两个索引、为什么不删行、为什么不建唯一索引),供 `check:spacetime-schema` 守卫通过(94 tables)
- 门禁:DTO parity 0(**49 组** Rust/TS 一致,较本轮前 +7);`check:spacetime-schema` 0(94 tables,对照新 merge-base `51cb05f4`);`check:encoding` 0;`git diff --check` 0
2026-10-06 01:14:05 +08:00
suzmii 959ed4fd53 合并 origin/master(51cb05f41,22 个提交)到 feat/game-purchase
- 逐块合并 server-rs/crates/api-server/src/modules/game_distribution.rs:以 master 的 ReleaseAssetResponseInput / 5 参 release_asset_response_with_cache / ETag / 304 / gzip 结构为准,并在其上保留本分支的付费 404 守卫(price_mud_points > 0 仍在 release_package_bytes 读包之前返回);播放会话资源响应改用同一结构(etag None、cache_control no-store、沿用 accept-encoding 协商)。
- 合并 src/components/game-distribution/GamePlayPage.tsx:接入 master 的共享 PlatformGameLoadingSurface 与 PLATFORM_GAME_LOADING_TIMEOUT_MS,删除本地重复常量 GAME_PLAY_STARTUP_TIMEOUT_MS 与裸 div,买断制播放会话准备态改由共享加载面承载。
- 合并 src/components/game-distribution/GameDetailPage.tsx:同时保留 master 的 onOpenCreator 作者插槽与本分支的买断制购买弹窗、onOpenRecharge 充值入口。
- 合并 vite.config.ts:保留 master 的 /api/creators 代理,并保留 play-sessions 前缀清 Cookie 规则(顺序仍在通用 /api/game-distribution 之前)。
- 合并 deploy/nginx/README.md:保留 master 的 SPA allowlist 门禁口径(含 /creators、/creators/connections)与本分支的播放会话前缀章节;三份 nginx 模板的 ^~ play-sessions location 与清 Cookie 原样保留。
- 合并 apps/admin-web/src/pages/AdminGameDistributionReviewPage.test.tsx:保留 master 的加载面/超时用例与本分支的审核价格(冻结价优先、历史按 0)用例。
- 合并 src/components/game-distribution/GameDistributionPages.test.tsx:保留双方 mock,并新增「付费作品在会话签发期间显示共享加载面」用例。
- 合并 docs/【玩法创作】平台入口与玩法链路-2026-05-15.md(保留买断制合同并回填 master 的创作者主页与关注粉丝合同)、decision-log.md、pitfalls.md:追加双方条目,不改写任一侧正文。
- 保留 master 侧新增能力:release_asset_etag / if_none_match_matches / accepts_gzip_encoding / gzip_release_asset / release_asset_not_modified_response、SPA 加载面、创作者主页与关注粉丝(user_follow 表、creator 查询与 author_id 过滤)。
2026-10-06 00:28:36 +08:00
suzmii bdcefe91d1 Merge remote-tracking branch 'origin/master' into feat/game-fork
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m31s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m20s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 4m3s
Project CI / Frontend tests (pull_request) Successful in 2m54s
Project CI / Backend tests (pull_request) Successful in 7m36s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m26s
Project CI / Repository checks (pull_request) Successful in 6m25s
Project CI / Native shell tests (pull_request) Successful in 9m34s
# Conflicts:
#	deploy/container/nginx.conf
#	deploy/nginx/genarrative-dev-http.conf
#	deploy/nginx/genarrative.conf
#	server-rs/crates/api-server/src/modules/game_distribution.rs
#	src/components/game-distribution/GameDetailPage.tsx
#	src/components/game-distribution/GameDistributionPages.test.tsx
#	src/components/platform-entry/PlatformEntryActiveFlowShell.tsx
2026-10-06 00:19:40 +08:00
lhk229 51cb05f418 补充创作者主页与关注粉丝工程文档 (#638)
Project CI / AI game creator shell Rust crates (push) Successful in 5m56s
Project CI / AI game creator shell Rust lane 2/2 (push) Successful in 6m36s
Project CI / AI game creator shell Rust lane 1/2 (push) Successful in 7m37s
Project CI / Backend tests (push) Successful in 9m22s
Project CI / Frontend tests (push) Successful in 4m40s
Project CI / AI game creator shell web tests (push) Successful in 3m50s
Project CI / Repository checks (push) Successful in 6m30s
Project CI / Native shell tests (push) Successful in 8m32s
本 PR 补齐创作者主页与关注粉丝功能的产品合同和工程设计,供后续按里程碑实施;本次只修改文档。

桌面导航第四项进入自己的创作者主页,“我的”移到第五项。游戏详情可进入作者主页并关注/取消关注;自己或他人的关注、粉丝列表均公开可查看,点击用户头像或昵称可进入其主页。本人支持取消/重新关注、回关和移除粉丝,并明确两个关注方向独立。

工程设计包含关系表与 DTO、认证和事务边界、跨页状态同步、共享组件、深链及验收要求,拆分关系查询和页面交互两个里程碑。按用户要求,游戏列表沿用最多 48 项的现有限制,不增加游戏目录分页改造。

验证:
- 已合入最新 origin/master(21c79f54a);共享决策记录冲突保留双方新增内容。
- npm run check:encoding 通过。
- npm run check:doc-index 通过。
- git diff --check 与暂存差异检查通过。
- 相对 master 仅六份文档发生变化;没有业务代码或 schema 修改,未执行业务测试或部署。

Reviewed-on: #638
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-10-05 22:05:11 +08:00
k88936 a938a4ef9e 兼容(契约): 响应 DTO 新增字段一律可选默认
- ProfileMudPointBalanceResponse.monthly_points 缺省为 0
- ProfileMembershipResponse 的 cycleIndex / cycleCount / cycleKind 缺省 1 / 1 / yearly
- ProfileMembershipPlanResponse 的 recommended / unlimitedConcurrency 缺省 false
- ProfileRechargeCenterResponse.membershipPlans 缺省空数组
- 补「旧服务端缺字段仍可整包解析」契约测试,身份与状态字段仍保持必填
- 后端架构文档新增 shared-contracts DTO 变更规则,并同步团队约定
2026-10-05 19:37:48 +08:00
suzmii d1bfe4c08b 修复游戏买断制付费的作者豁免、价格口径与契约可空性
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
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
- H1:购买事务在扣费前判定 `game.owner_user_id == user_id` 并失败关闭,领域 `resolve_game_purchase_decision` 新增 `is_owner` 标记返回 `OwnerCannotPurchase`(文案「作者本人无需购买」);api-server `map_purchase_error` 映射为 400 `GAME_PURCHASE_OWNER_EXEMPT`;购买路由按角色显式拒绝管理员令牌(403 `GAME_PURCHASE_ADMIN_NOT_ALLOWED`),管理员免购买不扣费。

- M1:`version_detail_payload` 的历史版本价格改为 `frozen_version_price_mud_points(version).unwrap_or(0)`,与待审列表及审核通过后生效的游戏行价格统一;同步把既有断言改为「历史版本缺 `priceMudPoints` 按免费(0)」。

- M2:`shared-contracts::GameDistributionVersionSummary.entry_url` 改为 `#[serde(default)] Option<String>`,与公开投影对未购买者下发的 `entryUrl: null` 一致。

- M3/L5:SpacetimeDB 购买事务改为复用 `module_game_distribution::resolve_game_purchase_decision`(新增 `game_distribution_visibility` 与 `resolve_game_distribution_purchase_decision` 包装),可购买性口径统一为「活动版本存在且 `status = published`」(复用 `public_game_distribution_version`),删除事务内联判定。

- 测试:内存领域作者自购拒绝;SpacetimeDB 购买判定五分支(免费 / 未公开 / 版本未公开 / 已拥有 / 作者自购)、事务源扫描(先判定后扣费、公开投影口径)、审核通过时历史版本价格生效为 0;api-server 管理员令牌 403、公开投影 `entryUrl: null` 可被 Rust DTO 解析、错误映射补作者豁免。

- `scripts/check-game-distribution-dto-parity.mjs` 增加可空性一致性比对(TS `| null` ⟺ Rust `Option`,允许 `?` 表示可省略),已用负例验证能拦住同类漂移。

- 同步更新 docs/【后端架构】server-rs与SpacetimeDB数据契约:登记作者豁免 / 管理员 403 / 可玩性口径 / 历史价格按 0;顺带修复 `module-game-distribution` 与 `spacetime-module` 既有未格式化行。
2026-10-05 18:00:03 +08:00
k88936 87a3794423 文档(会员契约): 后台改档请求并发上限不再硬编码 128
- AdminUpsertProfileMembershipPlanRequest.concurrentJobLimit 改为引用后端下发的 unlimitedConcurrencyThreshold
- 同步重新生成 ts-rs 绑定
2026-10-05 17:56:02 +08:00
k88936 8e9d2389e0 文档(会员契约): 并发上限不再硬编码 128 哨兵
- ProfileMembershipPlanResponse.concurrentJobLimit 改为引用后端下发的 unlimitedConcurrencyThreshold
- 同步重新生成 ts-rs 绑定,避免哨兵值变更时注释误导消费方
2026-10-05 17:54:38 +08:00
k88936 759bcf98a8 文档(会员契约): 澄清 status 兜底只作用于 Rust 客户端
- ProfileMembershipResponse.status 注释改为“Rust 反序列化未知取值按 active 兜底,TS 侧不归一化”
- 同步重新生成 ts-rs 绑定,避免 Web 消费方误以为前端也会 fail-open
2026-10-05 17:53:23 +08:00
suzmii 604ce7f3ec feat(游戏共创): M2b 数据模型——版本行三列工程源包 + 契约与绑定(块 A)
- `server-rs/crates/spacetime-module/src/game_distribution.rs`:`game_distribution_version` 表尾追加三列(明确默认值,遵循既有追加规则)——`project_bundle_object_key: Option<String>`(`#[default(None)]`)、`project_bundle_bytes: u64`(`#[default(0)]` = 未上传)、`project_bundle_sha256: Option<String>`(`#[default(None)]`);三列同步进 `GameDistributionVersionSnapshot`、版本快照构造与建版本时的初始化
- 同文件:`GameDistributionForkSourceSnapshot` 与扁平结果类型追加 `project_bundle_sha256` / `project_bundle_bytes`,下行据此判断走 `project` 还是回落 `package`(字节数与摘要成对,缺一视为没有工程包)
- 同文件:新增 `GAME_DISTRIBUTION_ACTION_UPLOAD_PROJECT_BUNDLE` 动作常量、输入 `GameDistributionConfirmProjectBundleInput`、事务 `confirm_game_distribution_project_bundle_tx` 与 procedure `confirm_game_distribution_project_bundle_and_return`。语义:可选资产、**不驱动版本状态机**;owner 校验 → 阶段门(`awaiting_upload` / `upload_failed`,与发行包确认同口径,已公开/已取消/已撤回一律拒绝)→ 同内容幂等重放 / 换内容冲突 → 写三列 + 幂等收据
- `spacetime-client`:`GameDistributionVersionRecord` 与 `map_version` 同步三列(生成绑定把 `project_bundle_sha256` 折成 `project_bundle_sha_256`,与 `package_sha_256` 同约定);新增 `GameDistributionConfirmProjectBundleRecordInput` 与 `confirm_game_distribution_project_bundle`(沿用 `map_game_distribution_game_result` 再取 version 的既有写法)
- 契约:`shared-contracts` 的 `GameDistributionPrivateVersion` 追加 `project_bundle_bytes`(必需,`0` = 未上传)与 `project_bundle_sha256`(可选);`packages/shared` TS 镜像同步;api-server `private_version_payload` 追加同名键——**对象键不下发**,只回摘要与字节数
- 生成物:重跑 `npm run spacetime:generate -- --rust-only`,只保留 `module_bindings/game_distribution*`(含 2 个新文件)与 `module_bindings.rs`,其余 `module_bindings/**` 的 rustfmt 漂移已 `git checkout --` 还原
- 文档:数据契约表目录 `game_distribution_version` 小节补三列语义与对象键不出服务端的口径
- 顺手记下一条门禁陷阱:`scripts/check-game-distribution-dto-parity.mjs` 抓 `json!` 顶层键时要求「键前一个非空字符是 `{` 或 `,`」且**不剥注释**,在字面量里插注释行会让紧随其后的键被判成缺失(已写进 `private_version_payload` 的文档注释)
- 门禁:wasm build 0;`cargo check --all-targets` 0;`cargo test -p module-game-distribution` 69 passed;`cargo test -p api-server game_distribution` 54 passed;DTO parity 42 组 OK;`check:spacetime-schema` 92 tables OK;`check:encoding` 5301 files OK;`git diff --check` 0;`cargo fmt --all -- --check` 0
2026-10-05 17:30:48 +08:00
suzmii 4626aeefd4 fix(埋点合同): 服务端同步 AGC 新增的 creation_source=platform_game
- 依据客户端提交 `5d01e43b6`:AGC 的 `CreationSource` 新增 `PlatformGame`,按 serde snake_case 落到线上取值 **`platform_game`**(同提交的 `creation_source_gains_platform_game_without_breaking_existing_values` 用例显式给出该字面量),上报字段仍是 `project_create_success` 的属性 `creation_source`。服务端枚举此前没有它,整条事件会被判 `invalid_properties` 直接丢弃
- `shared-contracts/src/agc_analytics.rs`:`values!(CreationSource { .. })` 追加 `PlatformGame`(注释与客户端一致);解析走 serde 派生,无需新增匹配分支
- `module-runtime/src/agc_analytics.rs`:新增 `agc_accepts_every_creation_source_and_rejects_unknown`——五个受支持取值(home_game / home_design / template / selected_directory / **platform_game**)逐个通过整批校验(事件形如 `project_create_success` 且带 `project_id`),未知取值(`remix` / `platform` / `PLATFORM_GAME` / 空串)仍然失败关闭为 `invalid_properties`
- 文档:`docs/technical/【技术方案】客户端本地埋点与主站入库契约-2026-09-21.md` §6.6 的 `creation_source` 取值列表补 `platform_game`(保持 `/` 分隔与 snake_case 风格)
- 全仓核对:该枚举只有两处定义(AGC `analytics/contract.rs` 与 `shared-contracts`),**无第二处服务端镜像**、无 TS 联合类型、无 schema/OpenAPI 取值表;生成绑定不含该类型(埋点批量跨模块边界走 `payload_json: String`),因此无需重跑 spacetime generate
2026-10-05 17:30:46 +08:00
suzmii 775dea02ea 修正 M3 族谱口径注释并抽出图装配纯函数(第二批)
- 修正 spacetime-module 里 get_game_distribution_lineage_and_return 的文档注释:锚点不存在/已软删除/未公开一律 found=false(api-server 映射 404),并写明理由——用空标题占位或空树代替 404 等于确认该 gameId 的存在、代际与血缘位置
- 修正 shared-contracts 里节点 status 的注释:当前只有已公开作品会成为节点(未公开节点被过滤、未公开锚点直接 404),线上取值实际恒为 published;保留该字段是为将来允许非公开节点进入树时不必再改契约
- 新增纯函数 assemble_lineage_tree_entries:家族归属校验(只保留 root_game_id 命中的血缘行)、根行以 0 代入集合、游戏行缺失的行安全跳过、重复行去重(根行优先);module 侧只负责取行与按根查索引
- 新增纯函数 resolve_lineage_author_name:账号昵称优先(trim 后非空)→ 退回发布时冻结的作者名 → 两者都空白则 None(不占位)
- 新增纯函数 lineage_entry_from_game_facts:族谱装配与衍生列表共用同一份字段映射
- module 删除 game_distribution_lineage_entry,衍生列表 tx 改用共用构造函数并复用同一份行事实折叠
- 新增 6 条单测:整族装配、旁支排除、缺行跳过、无根行回退、重复行去重、作者名归一三态
- 本批未改前端;package.json 与 lineage e2e 脚本属第三个 session,未触碰
2026-10-05 17:30:46 +08:00
suzmii 8f87c826cf feat(游戏共创): M2a 受鉴权内容下发通道(fork-source 元数据 + 整包取件)
- 契约:新增 `GameDistributionForkSourceKind` / `GameDistributionForkSource` / `GameDistributionForkSourceResponse`(shared-contracts + TS 镜像 + parity 登记),字段 `gameId / versionId / source / sha256 / bytes / downloadPath`,**不含对象键**
- 读取:spacetime-module 新增 `GameDistributionForkSourceInput`、扁平结果类型与 procedure `get_game_distribution_fork_source_and_return`;tx 把「行是否存在 / 能否作为来源(未删+已公开+有当前公开版本)/ 授权档位原值」分开回传——既有 owner-or-public 读会把「已软删除」与「未公开」都折成 None,HTTP 层就没法区分 404 与 409;`sha256` / `bytes` 取自版本行,不重算
- 客户端:spacetime-client 新增 record + mapper + `get_game_distribution_fork_source`(生成绑定把 `package_sha256` 折成 `package_sha_256`,与版本快照同约定)
- 路由:新增 `fork_sources` 子路由(`require_bearer_auth` + `add_no_store_response_headers`,**不叠加发布灰度**),两条:`GET …/fork-source`(元数据)与 `GET …/fork-source/package`(ZIP 字节)
- 校验:抽出纯函数 `fork_source_target` 供两个 handler 共用——404 `FORK_SOURCE_NOT_FOUND` / 409 `FORK_SOURCE_NOT_AVAILABLE` / 403 `FORK_NOT_AUTHORIZED`(未知档位按禁止解释);`available` 为真却缺版本元数据时失败关闭为 409
- 取件本体:复用发行网关的 `release_package_bytes`(整包进内存 + 进程内缓存,4 条 / 256 MiB),不新造 OSS 客户端;缓存值由 `Arc<Vec<u8>>` 改为 `Bytes`,整包交给响应体只加引用计数、不复制;响应**不做**引用归一化与 `RELEASE_STORAGE_BOOTSTRAP` 注入(下发原始构建产物,客户端按摘要校验后离线解压);`RELEASE_PACKAGE_CACHE` 顺手改用 `LazyLock`(初始值编译期已知)
- 路径:`downloadPath` 为同源相对路径,复用新抽出的 `is_path_safe_game_id`(与发行入口同一判据),绝不下发对象键
- 测试:新增 4 条——两条路由未带 Bearer → 401;`fork_source_target` 的 404 / 409 / 403 / 未知档位 / 缺元数据失败关闭逐项断言(409 先于 403);元数据 payload 的 sha256/bytes 取自行、downloadPath 形状、序列化后不含对象键;取件包头与长度(`application/zip`、`Content-Length` = 行 `package_bytes`、`Content-Disposition`、`no-store`)
- 文档:技术方案 §3.4 把两个接口从「规划」改成与实现一致的形状,并单独拆出「登录用户(Bearer,不叠加发布灰度)」小节;§3.5.1 的「下载通道(当前不存在)」改为 M2a 已实现,写明它只服务当前公开版本、不做归一化、大包续传仍待做
2026-10-05 17:30:45 +08:00
suzmii 39669763fe 实现游戏共创 M3:创作族谱树与衍生列表
- 新增 module-game-distribution/src/lineage.rs:锚点可读性、可见性过滤、稳定排序、上限截断的纯函数,附 15 个单测(复用 M1 的软删除判定,不重写第二套规则)
- 新增公开只读 procedure get_game_distribution_lineage / list_game_distribution_derived_games;锚点必须公开可读(未公开/已软删除/不存在一律按不存在处理),树内只出现未软删除且已公开的节点,不补 null 占位节点
- api-server 新增 GET /games/{id}/lineage 与 /games/{id}/derived(匿名可读、no-store),响应走结构化 DTO,节点键集合由测试钉死,杜绝下发对象键/素材键
- 作者自有游戏聚合追加 forkCount(与公开详情 forkCount 同口径),供「被改编 N」入口使用
- shared-contracts 与 TS 契约新增 LineageNode / LineageResponse / DerivedResponse 三型并登记 DTO 一致性检查
- 前端新增 /games/lineage 族谱页,登记 stage 类型、路由表、页面标题与壳层渲染分支;详情页共创卡新增「查看创作族谱」入口(仅已公开作品)
- 我的作品页新增「被改编 N」行内展开,列出直接子代的标题/作者/代际/状态,含空态与失败重试(仅已公开作品)
- 补前端组件/路由/标题/客户端用例与 api-server 路由、负载映射用例;同步里程碑验收标准与技术方案 §3.4 的锚点可读性口径
2026-10-05 17:30:45 +08:00
suzmii 1e7ec6dbe7 实现游戏共创 M1:作品级共创授权与改编血缘
- game_distribution_game 表尾追加 fork_authorization(默认 forbidden,只升不降,旧行自动取默认)
- 新增 game_distribution_lineage 表,记录父作品、来源版本、根作品与代际,并按 parent/root/owner 建索引
- migration.rs 登记新表并注明血缘随迁移导出
- 新增 set_game_distribution_fork_authorization_and_return procedure 与幂等收据、期望值 CAS
- 创建作品时校验改编声明:来源存在、已公开、授权开放、来源版本等于当前公开版本;复用既有身份时拒绝携带血缘
- 公开与后台响应增量:forkAuthorization、forkCount、lineage、generation、forkedFromGameId、derivedCount
- 公开快照的作者名与头像改为读时联 user_account,不再落到「创作者」兜底文案
- api-server 新增 PUT /api/game-distribution/games/{game_id}/fork-authorization(Bearer、幂等键、期望值校验)
- 错误映射新增 FORK_ 前缀分支并置于通用子串分支之前,避免被误判成 409 或 404
- module-game-distribution 增加授权阶梯、代际计算与错误码,并补单测覆盖阶梯与错误码前缀
- 网页端详情页新增共创信息卡,我的作品页新增授权提升入口,补服务层调用与定向测试
- 重新生成 SpacetimeDB 绑定,登记 DTO 一致性脚本的共创类型
2026-10-05 17:30:44 +08:00
suzmii 80fd5a9fea 新增游戏买断制泥点付费领域规则、SpacetimeDB schema、钱包来源与 Rust DTO
Project CI / Backend tests (pull_request) Failing after 19s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 4m10s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 4m18s
Project CI / Repository checks (pull_request) Failing after 26s
Project CI / AI game creator shell Rust crates (pull_request) Failing after 5m5s
Project CI / Frontend tests (pull_request) Successful in 3m48s
Project CI / AI game creator shell web tests (pull_request) Successful in 4m4s
Project CI / Native shell tests (pull_request) Failing after 8m31s
- server-rs/crates/module-game-distribution:新增价格校验 normalize_game_price_mud_points(0..=1000000,0 为免费)、购买资格 resolve_game_purchase_decision、GamePurchaseSnapshot 与 game_purchase_id(前缀 gdpurchase_);GameSnapshot/GameVersionSnapshot 增加 price_mud_points,审核通过时随版本价格生效;新增购买服务方法与纯内存测试。
- server-rs/crates/spacetime-module/src/game_distribution.rs:GameDistributionGame 末尾追加 #[default(0u64)] price_mud_points;新增私有表 game_distribution_purchase(purchase_id 主键 + user_id/game_id btree 索引);新增 purchase_game_distribution_game_and_return(同事务校验可见性/价格 CAS/未购买并原子扣费、幂等收据 action=purchase)与只读 get_game_distribution_purchase_and_return;approve 在同一事务内把冻结资料 priceMudPoints 生效到游戏行;公开游戏投影带出 priceMudPoints。
- server-rs/crates/spacetime-module/src/runtime/active/profile.rs:新增 consume_profile_wallet_points_for_game_purchase 复用通用钱包写入路径(来源类型 game_purchase、流水 ID game_purchase:{userId}:{gameId}、metadata_json 记 kind/gameId);profile_wallet_balance 提升为 pub(crate)。
- server-rs/crates/spacetime-module/src/migration.rs:迁移表白名单登记 game_distribution_purchase。
- server-rs/crates/module-runtime/src/domain.rs:RuntimeProfileWalletLedgerSourceType 追加 GamePurchase 变体与 game_purchase 文案,未改 profile_wallet_ledger 表结构。
- server-rs/crates/shared-contracts:新增 PROFILE_WALLET_LEDGER_SOURCE_TYPE_GAME_PURCHASE;公开游戏摘要/详情增加 priceMudPoints 与 purchased;GameDistributionPrivateVersion 与 GameDistributionCreateVersionRequest 增加 priceMudPoints;新增 GameDistributionPurchaseRequest/GameDistributionPurchase/GameDistributionPurchaseResponse/GameDistributionPlaySessionResponse。
- server-rs/crates/spacetime-client:新增购买与回读 typed facade、GameDistributionPurchaseRecord 与 row mapper,GameDistributionGameRecord 带出 price_mud_points,钱包来源 mapper 支持 GamePurchase。
- docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md:登记 price_mud_points、game_distribution_purchase 与 game_purchase 流水来源。
- 重新生成 SpacetimeDB Rust 绑定(购买表/过程与价格字段)。
2026-10-05 17:02:56 +08:00
k88936 bc3e36ff33 重构(会员契约): 会员结构体改用 ts-rs 生成类型
- shared-contracts 为 10 个会员结构体补 ts_rs::TS / ts(export),64 位整数字段补 ts(type = "number") 对齐前端 number
- 新增 10 个生成绑定;packages/shared 与 admin-web 改为 re-export 生成类型,仅 kind / status 等前端收窄联合用 Omit 组合保留
- 同步设计文档 §2.5 与决策日志
2026-10-05 15:51:07 +08:00
k88936 42c4cacf72 修复(会员契约): 响应 token 反序列化前向兼容
- shared-contracts 为会员响应 DTO 的 plan / status / cycle_kind / model_access 字段加 deserialize_with,未知取值 fail-open 兜底到已知最高档,避免 AGC Tauri shell 等旧 Rust 客户端因后端新增 token 整包解析失败
- 入参 DTO 保持严格拒绝,不改枚举自身 Deserialize,避免 Unknown 变体污染入参
- 补响应兼容与入参严格测试;同步设计文档 §2.5 与决策日志
2026-10-05 15:11:47 +08:00
k88936 cc0c07223c 重构(会员契约): 充值中心会员状态改用强类型 token
- ProfileMembershipResponse.status 由裸 String 改为 ProfileMembershipStatusToken,与前端 ProfileMembershipStatus 对齐
- BFF 直接用 From<RuntimeProfileMembershipStatus> 转换,测试改用具名枚举
2026-10-05 12:22:28 +08:00
k88936 4bd080eff5 修复(LLM目录契约): 响应枚举未知取值前向兼容
- LlmModelsResponse 内 agentMode / protocol 遇到未知 token 回退 Codex / 由 agentMode 推导默认协议,不再让旧客户端整份反序列化失败
- 输入校验仍走严格 parse;补未知 token 用例
2026-10-05 12:19:15 +08:00
k88936 c7150b590c 修复(LLM目录契约): protocol 缺省改为按 agent_mode 推导
- LlmModelSummary/LlmUnavailableModel 反序列化缺失 protocol 时取 agent_mode 的默认协议,不再一律 openai_responses
- 补 cc / anthropic 别名 / 显式 protocol 用例;同步生成绑定注释
2026-10-05 12:18:05 +08:00
k88936 6d9125586a 文档(AGC模型): access 字段注释改为访问级别
- AdminAgcModel.access 与 AgcModel.access 的注释不再写成「会员档位」,避免与会员 plan 档位混淆
2026-10-05 12:01:43 +08:00
k88936 a48b7f8de8 Merge remote-tracking branch 'origin/master' into feat/pricing-plan
Project CI / Backend tests (pull_request) Failing after 48s
Project CI / Native shell tests (pull_request) Failing after 3m50s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m21s
Project CI / Frontend tests (pull_request) Failing after 47s
Project CI / AI game creator shell web tests (pull_request) Failing after 39s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m6s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m23s
Project CI / Repository checks (pull_request) Successful in 6m31s
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
2026-10-05 10:50:30 +08:00
k88936 284b656b59 fix(充值商品): 移除已退役的 bonus_points / duration_days 入参
- 后台 upsert 请求 DTO 与 SpacetimeDB procedure 入参移除 bonus_points、duration_days(评审第 19 条)
- 充点商品固定「¥1 = 10 泥点、无首充赠送」,module 落库统一写 0,保留退役列兼容存量 schema
- 删除 InvalidRechargeProductFields 校验与错误文案;api-server / spacetime-client 同步收敛
- admin-web 表单移除「首充赠送」输入与状态,列表改为只展示基础泥点
- scripts/admin-web-fake-api.mjs 假数据同步 bonusPoints: 0
2026-10-04 21:33:39 +08:00
k88936 dcaab089cc refactor(后台契约): AdminAgcModel.access 改 ProfileMembershipModelAccessToken
- shared-contracts 的 AdminAgcModel.access 由裸 String 改为 ProfileMembershipModelAccessToken,未知值在反序列化阶段被拒(评审第 18 条)
- module-runtime 补 AgcModelAccess <-> ProfileMembershipModelAccessToken 双向 From
- api-server 的 agc_models 去掉 AgcModelAccess::parse 兜底,改直接 From
- admin-web 的 AdminAgcModelAccess 改为复用 @genarrative/shared 生成类型
- 扩展 catalog_dto 测试断言缺省 Basic 与未知 access 反序列化失败
2026-10-04 20:58:21 +08:00
k88936 54d1df9d21 refactor(契约): 会员 token 枚举走 ts-rs 生成,前端不再手写联合类型
- shared-contracts 给 ProfileMembershipPlanToken/CycleKindToken/StatusToken/ModelAccessToken/ChangeKindToken 补 ts_rs::TS + ts(export),生成 5 个 .ts 到 packages/shared/src/contracts/generated/(评审第 14 条)
- packages/shared/src/contracts/runtime.ts 的 ProfileMembershipPlan/Status/CycleKind/ModelAccess 改为生成类型的别名并 re-export
- apps/admin-web/src/api/adminApiTypes.ts 删除本地手写联合类型,改为从 @genarrative/shared 导入 / re-export
- npm run check:generated-bindings、admin-web:typecheck、npm run typecheck 通过
2026-10-04 19:35:28 +08:00
k88936 3a955889f0 refactor(后台契约): 会员详情 plan/status/cycle_kind 收口为 token 枚举
- shared-contracts 新增 ProfileMembershipStatusToken(normal/active)
- AdminProfileMembershipPayload 的 plan/status/cycle_kind 由 String 改为 ProfileMembershipPlanToken/ProfileMembershipStatusToken/ProfileMembershipCycleKindToken,未知值在反序列化即被拒(评审第 13 条)
- module-runtime 补 RuntimeProfileMembershipStatus -> ProfileMembershipStatusToken 的 From 映射
- api-server 的 map_membership 改为直接 .into(),去掉 as_str().to_string()
2026-10-04 19:14:31 +08:00
k88936 e89420053a feat(会员): 模型列表返回可用与不可用分桶
- shared-contracts 新增 llm_catalog.rs:LlmModelsResponse/LlmModelSummary/LlmUnavailableModel/LlmModelUnavailableReason(plan_required/disabled/unknown),未停用优先于档位的 disabled 语义留给域层
- AgcAgentMode/AgcModelProtocol 从 module-runtime 迁入 shared-contracts(前后端 + ts-rs 单一真源),module-runtime re-export 保持路径可用
- 整个目录 DTO 与枚举走 ts-rs,生成到 packages/shared/src/contracts/generated,revision 标 number
- module-runtime 新增 AgcModelCatalog::unavailable_models_for(access):保持目录顺序,停用优先于档位不足,补单测
- api-server public_model_catalog 产出 models + unavailableModels 两桶,重写 model_catalog_tests
2026-10-04 13:29:29 +08:00
k88936 2630b0f690 feat(会员): 后台 AGC 模型支持标注权限档
- AdminAgcModel 新增 access 字段(缺省 basic,失败开放),GET 回读 PUT 写入
- api-server 保存时校验权限档只允许 basic/full
- 后台 AGC 模型页新增「权限档」列,可按模型选择基础/高性能模型
- fake API 与页面用例覆盖权限档选择与保存
2026-10-04 13:28:13 +08:00
k88936 d7dec9b475 枚举化(会员后台):档位与模型权限请求字段改用 typed enum
- AdminUpsertProfileMembershipPlanRequest.plan/model_access 由 String 改为 token 枚举
- 未登记的档位 / 权限 token 在反序列化阶段直接拒绝,后台不能再持久化任意字符串
- admin handler 去掉字符串解析分支,改为 From 转换
- 删除仅用于手写解析的 parse_runtime_profile_membership_* 辅助函数
2026-10-04 11:46:08 +08:00
k88936 c660ca41fe 枚举化(会员):快照与报价/档位响应改用 typed enum
- shared-contracts 新增 ProfileMembershipPlan/CycleKind/ModelAccess/ChangeKind Token 枚举
- RuntimeProfileMembershipOrderChangeSnapshot 与 UpgradeQuoteRecord 档位/周期改用模块枚举
- AdminMembershipOrderChangePayload、ProfileMembership/Plan/UpgradeQuote Response 改用 token 枚举
- module-runtime 提供模块枚举与 wire token 的双向 From 映射
- api-server / spacetime-client / spacetime-module 同步去掉 as_str().to_string() 拼装
- 重生成 SpacetimeDB 绑定:订单变更快照字段改为枚举
2026-10-04 11:43:57 +08:00
k88936 1744262b0b 对齐(会员订单):granted_points_delta 全链路 i64 改 u64
- profile_recharge_order.membership_granted_points_delta 列由 i64 改为 u64
- RuntimeProfileMembershipOrderChangeSnapshot 与 AdminMembershipOrderChangePayload 同步改 u64
- 删除 snapshot/order 之间的 as i64 与 try_from 兜底转换
- 重生成 SpacetimeDB 绑定:profile_recharge_order、订单变更快照
2026-10-04 11:23:21 +08:00
suzmii daae35a1a1 AGC 发布版本标签改由工程内部版本派生,拆除 projectVersion 写链路
- shared contracts:resolveGameCreationAppProjectVersion 改为按 manifest.versions 条数派生,删除 isGameCreationAppProjectVersion,projectVersion 注释降级为遗留兼容位
- Rust shared-contracts:删除 resolve_game_creation_app_project_version / is_game_creation_app_project_version / GAME_CREATION_APP_FIRST_PROJECT_VERSION,project_version 注释改遗留位并重写往返测试
- AGC 发布面板:项目版本改为 useMemo 派生只读输入框,删除本地 state、失焦落盘与 onManifestUpdated 回调
- AGC 发布服务:删除 saveGameDistributionProjectVersion,提交版本号缺省改为按 versions 派生
- AGC 原生:发布成功回写与绑定回填不再写 project_version(置空),删除 update_game_distribution_project_version 命令
- AGC 命令注册与白名单:desktop.rs 注销命令、check-config.mjs 移除白名单条目
- AGC 前端装配:App.tsx 移除两处 onManifestUpdated 传递
- AGC 测试:publish/panel 两条测试改为覆盖派生口径,删除四条写回用例
- 注释对齐:game_publish_attempt.rs / project/manifest.rs / styles.css / shared-contracts 的 game_distribution.rs 把版本标签口径改为「由 versions[] 派生」,清掉 projectVersion 遗留位表述
- 文档:decision-log 追加本决策条目,两份 2026-10-02 计划加取代标注,新增 2026-10-03 里程碑与实施计划
2026-10-04 00:16:14 +08:00
k88936 dfa92607b4 Merge remote-tracking branch 'origin/master' into feat/pricing-plan
Project CI / Backend tests (pull_request) Failing after 1m51s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m10s
Project CI / Frontend tests (pull_request) Failing after 1m31s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m59s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m50s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m38s
Project CI / Repository checks (pull_request) Failing after 4m27s
Project CI / Native shell tests (pull_request) Successful in 7m43s
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
#	server-rs/crates/module-runtime/src/lib.rs
2026-10-03 20:32:40 +08:00
k88936 44bbc846ae fix(后台会员): 并发上限展示与提示改用后端下发值
- ProfileMembershipPlanAdminListResponse 增加 unlimitedConcurrencyThreshold,会员档位列表接口下发 MEMBERSHIP_UNLIMITED_CONCURRENCY。
- admin-web 的档位响应补上 unlimitedConcurrency,列表“不设上限”展示改用该标志,表单提示与校验改用后端阈值,删除页面硬编码的 128。
- 本地假后台同步补 unlimitedConcurrency 与 unlimitedConcurrencyThreshold。
2026-10-03 17:45:30 +08:00
k88936 c9ad084f78 fix(后台权限): 补上 membership-plans Tab 授权
- ADMIN_TAB_PERMISSIONS 增加 membership-plans 并把数组长度改为 22,使非 owner 管理员可被授予会员档位页权限,修复该页接口对普通管理员恒 403。
- every_assignable_admin_tab_has_a_backend_route 增加断言:路由使用的每个 Tab 必须登记在 ADMIN_TAB_PERMISSIONS。
2026-10-03 17:36:43 +08:00
suzmii f4ca1aeecc 合并最新 master 到作品管理分支
Project CI / Backend tests (pull_request) Failing after 39s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m44s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 3m43s
Project CI / Repository checks (pull_request) Failing after 40s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m52s
Project CI / Frontend tests (pull_request) Successful in 3m17s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m12s
Project CI / Native shell tests (pull_request) Successful in 6m41s
2026-10-03 17:34:23 +08:00
kdletters 4b529a8952 新增支付服务接入与订单收银台
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m59s
Project CI / Backend tests (pull_request) Failing after 4m8s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m9s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m20s
Project CI / Frontend tests (pull_request) Successful in 3m17s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m48s
Project CI / Repository checks (pull_request) Failing after 4m15s
Project CI / Native shell tests (pull_request) Successful in 6m52s
新增支付应用、API Key 与外部产品订单接口

接入微信 Native 下单、二维码收银台与支付结果回调

新增后台支付订单与回调投递页面

补齐 SpacetimeDB 支付表、生成绑定、OpenAPI 与使用说明
2026-10-03 17:18:13 +08:00