Merge remote-tracking branch 'origin/master'

# Conflicts:
#	docs/technical/README.md
#	server-rs/crates/spacetime-client/src/module_bindings/mod.rs
This commit is contained in:
2026-05-01 01:14:04 +08:00
601 changed files with 19836 additions and 4468 deletions

View File

@@ -0,0 +1,835 @@
# 抓大鹅 Match3D 创作与运行态最小落地技术方案 2026-04-30
## 1. 文档目的
本文件承接 PRD《AI 原生抓大鹅 Match3D 玩法创作工具与玩法系统 PRD》冻结首版 demo 的最小可开发方案。
本轮目标不是先做一个纯前端临时小游戏,而是在当前平台内新增独立 `match3d` 玩法域,跑通下面这条最小主链:
1. 平台创作入口选择“抓大鹅”。
2. Agent 对话确认题材、需要消除次数和难度。
3. 编译 Match3D 草稿。
4. 进入结果页编辑游戏名称、标签和封面图。
5. 发布前试玩,可随时停止并返回修改。
6. 发布作品。
7. 玩家进入单局运行态。
8. 前端即时呈现点击、飞入、入槽、三消、腾格、胜负过渡。
9. 后端权威确认点击、入槽、消除、失败、胜利和成绩。
本文是后续并行开发的工程合同。若实现过程中发现字段、路由、表结构或前后端职责需要变化,必须先更新本文,再进入对应编码分支。
---
## 2. 本轮明确不做
1. 不做多关卡链。
2. 不做排行榜展示。
3. 不做道具逻辑,只预留字段和扩展点。
4. 不做真实 3D 模型和真实 3D 物理遮挡。
5. 不做洗牌、重置、旋转、放大等局内操作。
6. 不做必须试玩通关才能发布。
7. 不做前端本地最终规则真相。
8. 不接入 `server-node` 或 PostgreSQL。
9. 不把 Match3D 挂到 RPG、拼图或大鱼吃小鱼旧命名下。
---
## 3. 分层边界
## 3.1 前端
前端继续使用当前 `React + TypeScript + Vite` 平台壳层,负责所有即时呈现的局内反馈:
1. 创作入口、Agent 工作区、结果页、试玩和运行态 UI。
2. 参考图片上传入口。
3. 运行态圆形空间、2D 物品、倒计时和 `7` 格备选栏展示。
4. 基于后端快照做 2D 命中检测、悬停、按压、选中反馈。
5. 在等待后端确认期间,先行播放飞入、入槽、三消、腾格、胜利和失败过渡。
6. 收到后端确认后,以权威快照校正本地表现。
7. 后端拒绝或版本冲突时,回滚本次即时反馈。
前端禁止:
1. 把本地即时反馈作为最终规则真相。
2. 本地生成可提交成绩。
3. 本地伪造胜利、失败、消除计数或运行态持久化结果。
4. 在 UI 中默认展示长篇玩法规则说明。
## 3.2 api-server
`server-rs/crates/api-server` 负责 Match3D 对外 HTTP facade
1. 鉴权、请求上下文、错误 envelope。
2. 创作 Agent 的 LLM turn 编排。
3. 参考图片上传复用现有资产/OSS 能力。
4. 调用 `spacetime-client` 读写 Match3D 会话、作品和运行态。
5. 对前端返回稳定 HTTP DTO不泄露 SpacetimeDB 内部表结构。
## 3.3 SpacetimeDB
`server-rs/crates/spacetime-module` 负责 Match3D 真相态:
1. 存储 Agent session / message。
2. 存储作品 profile。
3. 存储运行态 run snapshot。
4. 通过 procedure 同步返回会话、作品和运行态快照。
5. 在 reducer/procedure 内保持确定性,不做网络、文件系统或外部模型调用。
## 3.4 纯领域 crate
新增:
```text
server-rs/crates/module-match3d
```
职责:
1. 创作配置校验。
2. 物品类型规划。
3. 初始布局生成输入/输出模型。
4. 2D 遮挡与可点击快照计算。
5. 点击确认。
6. 入槽与三消确认。
7. 胜负确认。
8. 成绩基础数据计算。
`module-match3d` 不直接依赖 Axum、不访问 OSS、不调用 LLM、不读写 SpacetimeDB 表。
---
## 4. 共享契约
## 4.1 TypeScript shared contracts
新增:
```text
packages/shared/src/contracts/match3dAgent.ts
packages/shared/src/contracts/match3dWorks.ts
packages/shared/src/contracts/match3dRuntime.ts
```
### `match3dAgent.ts`
承载:
1. `Match3DAgentSession`
2. `Match3DAgentMessage`
3. `Match3DCreatorConfig`
4. `Match3DCompileDraftRequest`
5. `Match3DCompileDraftResult`
### `match3dWorks.ts`
承载:
1. `Match3DWorkProfile`
2. `Match3DWorkSummary`
3. `Match3DWorkUpdateRequest`
4. `Match3DPublishRequest`
5. `Match3DPublishResult`
### `match3dRuntime.ts`
承载:
1. `Match3DRunSnapshot`
2. `Match3DItemSnapshot`
3. `Match3DTraySlot`
4. `Match3DStartRunRequest`
5. `Match3DClickItemRequest`
6. `Match3DClickItemResult`
7. `Match3DStopRunRequest`
8. `Match3DRestartRunRequest`
## 4.2 Rust shared contracts
新增:
```text
server-rs/crates/shared-contracts/src/match3d_agent.rs
server-rs/crates/shared-contracts/src/match3d_works.rs
server-rs/crates/shared-contracts/src/match3d_runtime.rs
```
并在 `server-rs/crates/shared-contracts/src/lib.rs` 导出。
Rust DTO 只承载 HTTP contract 和跨 crate 稳定模型,不直接暴露 `module-match3d` 内部结构。
## 4.3 命名约束
1. 对外展示:抓大鹅。
2. 工程域:`match3d`
3. TypeScript 类型前缀:`Match3D`
4. Rust 类型前缀:`Match3D`
5. HTTP path`/api/creation/match3d/*``/api/runtime/match3d/*`
6. SpacetimeDB 表与 procedure 前缀:`match3d_`
---
## 5. SpacetimeDB 表
首版保持最小闭环,复杂结构统一使用结构化字段 + `snapshot_json` / `draft_json`,避免过早拆出多张高耦合子表。
新增表属于安全 schema 演进;后续如果改字段,必须遵守 `SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md`,不能直接删除、重排或改名已有列。表结构变更后必须同步对齐 `migration.rs`
## 5.1 `match3d_agent_session`
作用:保存 Match3D 创作 Agent 会话、配置草稿和发布指针。
字段:
1. `session_id: String`,主键。
2. `owner_user_id: String`,索引。
3. `seed_text: String`,用户初始输入或自动配置摘要。
4. `current_turn: u32`
5. `progress_percent: u32`
6. `stage: String`,建议值:`Collecting``ReadyToCompile``DraftCompiled``Published`
7. `config_json: String`,序列化 `Match3DCreatorConfig`
8. `draft_json: String`,序列化草稿结果。
9. `last_assistant_reply: String`
10. `published_profile_id: String`,未发布为空字符串。
11. `created_at: Timestamp`
12. `updated_at: Timestamp`
## 5.2 `match3d_agent_message`
作用:保存 Match3D 创作 Agent 消息流水。
字段:
1. `message_id: String`,主键。
2. `session_id: String`,索引。
3. `role: String`,建议值:`user``assistant``system`
4. `kind: String`,建议值:`text``action``error`
5. `text: String`
6. `created_at: Timestamp`
## 5.3 `match3d_work_profile`
作用:保存 Match3D 作品主表和发布状态。
字段:
1. `profile_id: String`,主键。
2. `owner_user_id: String`,索引。
3. `source_session_id: String`
4. `author_display_name: String`
5. `game_name: String`
6. `theme_text: String`
7. `summary_text: String`
8. `tags_json: String`
9. `cover_image_src: String`
10. `cover_asset_id: String`
11. `clear_count: u32`
12. `difficulty: u32`
13. `config_json: String`
14. `publication_status: String`,建议值:`Draft``Published`
15. `play_count: u32`
16. `updated_at: Timestamp`
17. `published_at: Option<Timestamp>`,未发布为 `None`
## 5.4 `match3d_runtime_run`
作用:保存 Match3D 单局运行态快照和成绩基础数据。
字段:
1. `run_id: String`,主键。
2. `owner_user_id: String`,索引。
3. `profile_id: String`,索引。
4. `status: String`,建议值:`Running``Won``Failed``Stopped`
5. `snapshot_version: u32`
6. `started_at_ms: i64`
7. `duration_limit_ms: i64`,首版固定 `600000`
8. `finished_at_ms: i64`,未结束为 `0`
9. `elapsed_ms: i64`
10. `clear_count: u32`
11. `total_item_count: u32`
12. `cleared_item_count: u32`
13. `failure_reason: String`,建议值为空、`TimeUp``TrayFull`
14. `snapshot_json: String`,序列化 `Match3DRunSnapshot`
15. `created_at: Timestamp`
16. `updated_at: Timestamp`
## 5.5 `match3d_play_record`
首版可选,若本轮不做排行榜,可先不建表,只在 `match3d_runtime_run` 保留成绩字段。
若实现成绩历史,字段建议:
1. `record_id: String`,主键。
2. `profile_id: String`,索引。
3. `owner_user_id: String`,索引。
4. `run_id: String`
5. `status: String`
6. `elapsed_ms: i64`
7. `cleared_item_count: u32`
8. `total_item_count: u32`
9. `created_at: i64`
---
## 6. SpacetimeDB procedure
本轮全部使用 procedure 同步返回快照,避免 `api-server` 在写入后再读 private table。
## 6.1 创作链
1. `create_match3d_agent_session(input)`
创建会话,写入初始配置或空配置,返回 session snapshot。
2. `get_match3d_agent_session(input)`
获取会话、消息和当前 draft。
3. `submit_match3d_agent_message(input)`
只写 user message不调用 LLM不生成 assistant 回复。
4. `finalize_match3d_agent_message_turn(input)`
`api-server` LLM turn 完成后写入 assistant message、配置状态、进度和 `last_assistant_reply`
5. `compile_match3d_draft(input)`
校验题材、需要消除次数、难度,生成草稿和作品 draft profile。
## 6.2 作品链
1. `update_match3d_work(input)`
更新游戏名称、标签、封面、题材、需要消除次数和难度。
2. `publish_match3d_work(input)`
校验基础信息完整后发布作品,不要求试玩通关。
3. `list_match3d_works(input)`
查询当前用户作品。
4. `get_match3d_work_detail(input)`
查询作品详情,支持结果页恢复和作品详情页。
5. `delete_match3d_work(input)`
可后置;若接入创作中心删除,需要与其他玩法卡片删除语义一致。
## 6.3 运行态链
1. `start_match3d_run(input)`
基于作品配置生成单局快照,返回 `Match3DRunSnapshot`
2. `get_match3d_run(input)`
返回当前权威运行态快照。
3. `click_match3d_item(input)`
根据 `run_id / item_instance_id / client_snapshot_version` 权威确认点击、入槽、三消、失败或胜利,返回新快照和确认结果。
4. `stop_match3d_run(input)`
把运行态标记为 `Stopped`,供试玩中止和返回结果页使用。
5. `restart_match3d_run(input)`
复用同一作品配置创建新 run返回新快照。
6. `finish_match3d_time_up(input)`
可选。若倒计时由前端触发,前端在倒计时归零时调用该 procedure后端确认 `TimeUp`。也可以由 `click_match3d_item``get_match3d_run` 懒确认超时。
## 6.4 procedure 输入输出约束
1. 所有 mutation 输入必须带 `owner_user_id` 或由 `api-server` 注入用户上下文SpacetimeDB 内部仍需以可信身份或 owner 字段校验归属。
2. 运行态 mutation 必须携带 `client_snapshot_version`
3. 若版本不匹配,返回 `VersionConflict`,并携带最新快照。
4. procedure 返回字符串化 JSON 时,`spacetime-client` 必须负责反序列化和错误归一化。
---
## 7. 运行态确认协议
Match3D 首版采用“前端即时反馈 + 后端权威确认”。
## 7.1 点击流程
```text
玩家点击物品
-> 前端基于最新快照做 2D 命中检测
-> 前端立即播放按压/选中/飞入表现
-> 前端调用 click_match3d_item
-> 后端确认点击是否合法
-> 后端返回新快照与确认结果
-> 前端按确认结果固化或回滚表现
```
## 7.2 点击请求
```ts
interface Match3DClickItemRequest {
runId: string;
itemInstanceId: string;
clientSnapshotVersion: number;
clientEventId: string;
clickedAtMs: number;
}
```
字段说明:
1. `clientSnapshotVersion` 用于发现前端基于旧快照操作。
2. `clientEventId` 用于前端去重和日志定位。
3. `clickedAtMs` 只用于观测,不作为成绩可信时间源。
## 7.3 点击结果
```ts
type Match3DClickConfirmStatus =
| 'Accepted'
| 'RejectedNotClickable'
| 'RejectedAlreadyMoved'
| 'RejectedTrayFull'
| 'VersionConflict'
| 'RunFinished';
interface Match3DClickItemResult {
status: Match3DClickConfirmStatus;
run: Match3DRunSnapshot;
acceptedItemInstanceId?: string;
clearedItemInstanceIds: string[];
failureReason?: 'TimeUp' | 'TrayFull';
}
```
## 7.4 前端回滚规则
1. `Accepted`:固化飞入、入槽、消除或胜负表现。
2. `RejectedNotClickable`:被点物品回到原位,备选栏恢复。
3. `RejectedAlreadyMoved`:直接应用后端最新快照。
4. `RejectedTrayFull`:应用后端失败快照。
5. `VersionConflict`:取消当前局部动画,应用最新快照,允许用户继续操作。
6. `RunFinished`:应用后端胜负快照,进入结算。
## 7.5 快照版本
1. 每次后端接受会改变运行态的操作,`snapshot_version` 必须递增。
2. 前端所有即时反馈都基于某个明确版本。
3. 前端同时只能有一个未确认的点击操作;首版不做多点击并发队列。
4. 如果动画期间用户再次点击,前端应忽略或排队到当前确认完成后再处理;首版建议忽略。
---
## 8. 运行态快照
## 8.1 `Match3DRunSnapshot`
```ts
interface Match3DRunSnapshot {
runId: string;
profileId: string;
status: 'Running' | 'Won' | 'Failed' | 'Stopped';
snapshotVersion: number;
startedAtMs: number;
durationLimitMs: number;
serverNowMs: number;
remainingMs: number;
clearCount: number;
totalItemCount: number;
clearedItemCount: number;
traySlots: Match3DTraySlot[];
items: Match3DItemSnapshot[];
failureReason?: 'TimeUp' | 'TrayFull';
}
```
说明:
1. `serverNowMs` 用于前端校准倒计时。
2. `remainingMs` 由后端按 `durationLimitMs` 和服务端时间计算。
3. 前端可以本地递减倒计时,但归零失败必须调用后端确认或等待下一次后端确认。
## 8.2 `Match3DItemSnapshot`
```ts
interface Match3DItemSnapshot {
itemInstanceId: string;
itemTypeId: string;
visualKey: string;
x: number;
y: number;
radius: number;
layer: number;
state: 'InBoard' | 'Flying' | 'InTray' | 'Cleared';
clickable: boolean;
}
```
说明:
1. `Flying` 可以作为前端表现态使用,不要求后端逐帧落库。
2. 后端主要确认 `InBoard -> InTray -> Cleared` 的权威状态变化。
3. `clickable` 是后端计算给前端的可点击快照,前端命中检测必须尊重它。
## 8.3 `Match3DTraySlot`
```ts
interface Match3DTraySlot {
slotIndex: number;
itemInstanceId?: string;
itemTypeId?: string;
visualKey?: string;
}
```
## 8.4 2D 遮挡口径
首版不做真实物理遮挡。
建议后端按以下输入计算 `clickable`
1. 物品圆形或近似圆形碰撞范围。
2. `layer` 越大越靠上。
3. 被更高层物品覆盖到低于可点击阈值时,标记为不可点击。
4. 阈值首版作为领域常量,后续体验后再参数化。
前端基于 `clickable` 和自身命中检测呈现即时反馈;后端仍在点击确认时再次校验。
---
## 9. 领域规则冻结
## 9.1 创作配置
```ts
interface Match3DCreatorConfig {
themeText: string;
referenceImageSrc?: string;
clearCount: number;
difficulty: number;
}
```
规则:
1. `themeText` 必填。
2. `clearCount` 必须为正整数。
3. `difficulty` 范围 `1~10`
4. `referenceImageSrc` 首版只支持图片,不支持视频。
## 9.2 物品数量
```text
totalItemCount = clearCount * 3
```
每种 `itemTypeId` 的数量必须是 `3` 的倍数。
## 9.3 demo 视觉素材
首版使用 `10` 种颜色形状组合素材。
1. `visualKey` 固定为内置素材 key。
2. 题材主题先进入作品配置和 Agent 文案,不强制生成题材素材。
3. 后续接入真实题材素材前,必须另补资产生成方案。
## 9.4 难度
首版 `difficulty` 只作为布局和生成算法参数。
后端需要保留参数入口,但难度公式先保持简洁:
1. 难度越高,物品尺寸可整体略小。
2. 难度越高,堆叠层级可略深。
3. 难度越高,首屏可直接三消的可见组合可略少。
具体数值不在 A0 冻死,由 B1 领域 crate 分支给出首版常量并通过测试覆盖。
---
## 10. api-server HTTP facade
## 10.1 创作链
```text
POST /api/creation/match3d/sessions
GET /api/creation/match3d/sessions/:sessionId
POST /api/creation/match3d/sessions/:sessionId/messages
POST /api/creation/match3d/sessions/:sessionId/messages/stream
POST /api/creation/match3d/sessions/:sessionId/compile
```
说明:
1. 同步消息接口用于普通提交。
2. 流式接口复用现有 Agent SSE 基建。
3. `messages` 只写 user messageLLM 推理由 `api-server` 完成后 finalize 到 SpacetimeDB。
4. `compile` 不生成额外素材,只生成 Match3D 草稿和作品 draft。
## 10.2 作品链
```text
PATCH /api/creation/match3d/works/:profileId
POST /api/creation/match3d/works/:profileId/publish
GET /api/creation/match3d/works
GET /api/creation/match3d/works/:profileId
```
首版发布不要求试玩通关。
## 10.3 运行态链
```text
POST /api/runtime/match3d/works/:profileId/runs
GET /api/runtime/match3d/runs/:runId
POST /api/runtime/match3d/runs/:runId/click
POST /api/runtime/match3d/runs/:runId/stop
POST /api/runtime/match3d/runs/:runId/restart
POST /api/runtime/match3d/runs/:runId/time-up
```
`time-up` 可后置;若不单独实现,`get` 或下一次 `click` 必须能懒确认超时失败。
## 10.4 错误语义
HTTP 层使用现有 API envelope。
建议错误码:
1. `MATCH3D_SESSION_NOT_FOUND`
2. `MATCH3D_WORK_NOT_FOUND`
3. `MATCH3D_RUN_NOT_FOUND`
4. `MATCH3D_INVALID_CONFIG`
5. `MATCH3D_PUBLISH_BLOCKED`
6. `MATCH3D_RUN_VERSION_CONFLICT`
7. `MATCH3D_RUN_ALREADY_FINISHED`
---
## 11. 前端落点
## 11.1 contracts 与 service
新增:
```text
src/services/match3d-creation/
src/services/match3d-works/
src/services/match3d-runtime/
```
分别负责 Agent/草稿、作品/发布、运行态请求。
## 11.2 组件
新增:
```text
src/components/match3d-creation/
src/components/match3d-result/
src/components/match3d-runtime/
```
## 11.3 平台入口
需要接入:
1. `src/components/platform-entry/platformEntryCreationTypes.ts`
2. `src/components/platform-entry/PlatformEntryCreationTypeModal.tsx`
3. `src/components/platform-entry/usePlatformCreationAgentFlowController.ts`
入口展示:
1. 名称:`抓大鹅`
2. 子标题:`经典消除玩法`
## 11.4 运行态 UI
首版运行态必须移动端优先:
1. 圆形空间占据主要区域。
2. 备选栏固定 `7` 格。
3. 倒计时清晰但不遮挡物品。
4. 物品点击区域稳定,不因动画造成布局跳动。
5. 胜利/失败结算使用独立面板,不在当前面板下方展开。
## 11.5 本地 mock 口径
F3 运行态即时反馈分支可以先用本地 mock snapshot 开发,但必须满足:
1. mock 类型来自 `packages/shared/src/contracts/match3dRuntime.ts`
2. mock 字段不得脱离 A0 文档。
3. 接入真实 API 时删除或降级为测试 fixture。
---
## 12. 并行开发包
## 12.1 第二波并行
### B1 + B2领域 crate 与 shared contracts
写入范围:
1. `server-rs/crates/module-match3d/`
2. `server-rs/Cargo.toml`
3. `server-rs/crates/shared-contracts/src/match3d_*.rs`
4. `packages/shared/src/contracts/match3d*.ts`
交付:
1. 领域规则单测。
2. DTO 编译通过。
3. 不接 SpacetimeDB。
### B3SpacetimeDB 表与 procedure
写入范围:
1. `server-rs/crates/spacetime-module/src/match3d/`
2. `server-rs/crates/spacetime-module/src/lib.rs`
3. `server-rs/crates/spacetime-module/src/migration.rs`
4. 生成后的 bindings 由后续 B4 处理。
交付:
1. 表和 procedure 定义。
2.`module-match3d` 规则接线。
3. `spacetime build` 或仓库现有等价脚本通过。
B3 当前落地状态:
1. `server-rs/crates/spacetime-module/src/match3d/` 已承载 Match3D 的表、procedure 输入输出类型和 procedure 实现,并由 `server-rs/crates/spacetime-module/src/lib.rs` 挂载导出。
2. `migration.rs` 已纳入 `match3d_agent_session``match3d_agent_message``match3d_work_profile``match3d_runtime_run` 四张表,后续字段变更继续按 `SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md` 追加兼容字段。
3. 运行态 `start_match3d_run``click_match3d_item``stop_match3d_run``finish_match3d_time_up` 通过适配层调用 `module-match3d` 的领域规则SpacetimeDB 层只负责归属校验、事务写入、权威快照持久化和 procedure JSON 返回。
4. B3 对外仍返回当前首版快照字段 `snapshotVersion / clientSnapshotVersion` 对应语义;`module-match3d` 内部的 `board_version` 只在适配层中转换,避免影响并行中的 B4/F3 接入。
5. SpacetimeDB module 的有效验收命令是 `spacetime build --module-path crates/spacetime-module`;不要用普通 native `cargo test -p spacetime-module` 作为验收口径,因为该 crate 会链接 SpacetimeDB 宿主符号。
### F1创作入口与 Agent UI
写入范围:
1. `src/components/platform-entry/`
2. `src/components/match3d-creation/`
3. `src/services/match3d-creation/`
交付:
1. 平台入口可见。
2. Agent 工作区能收集题材、需要消除次数和难度。
3. 可用 mock client等待 B5 接口。
### F3运行态即时反馈 UI
写入范围:
1. `src/components/match3d-runtime/`
2. `src/services/match3d-runtime/`
交付:
1. 圆形空间、2D 物品、`7` 格备选栏。
2. 点击命中、飞入、入槽、三消、腾格、胜负过渡。
3. 后端确认失败时的回滚和快照校正逻辑。
4. 先用 mock snapshot。
## 12.2 第三波并行
### B4 + B5spacetime-client 与 api-server facade
写入范围:
1. `server-rs/crates/spacetime-client/src/match3d.rs`
2. `server-rs/crates/spacetime-client/src/lib.rs`
3. `server-rs/crates/api-server/src/match3d.rs`
4. `server-rs/crates/api-server/src/app.rs`
5. `server-rs/crates/api-server/src/main.rs` 如需注册模块
交付:
1. HTTP facade 可调用 SpacetimeDB procedure。
2. 创作、作品、运行态接口返回 shared-contract DTO。
3. 后端定向测试通过。
### F2结果页与发布
写入范围:
1. `src/components/match3d-result/`
2. `src/services/match3d-works/`
3. 创作中心作品恢复相关最小接线。
交付:
1. 编辑游戏名称、标签、封面图。
2. 试玩入口。
3. 发布入口。
### F4平台分发最小接入
写入范围:
1. 创作中心作品货架。
2. 首页/分类/广场卡片映射。
3. 作品详情启动运行态入口。
交付:
1. 已发布 Match3D 作品可进入平台列表。
2. 卡片可进入详情或运行态。
## 12.3 最后集成
### Q1集成验收
交付:
1. 创作到发布到试玩主链通过。
2. 运行态点击、入槽、三消、失败、胜利通过。
3. 移动端视口检查通过。
4. `npm run api-server:maincloud` 通过。
5. 对应测试与 `npm run check:encoding` 通过。
---
## 13. 合并顺序
建议合并顺序:
1. A0本文档。
2. B1 + B2领域 crate 与 shared contracts。
3. B3SpacetimeDB 表和 procedure。
4. B4 + B5spacetime-client 与 api-server facade。
5. F1 / F2 / F3前端创作、结果页、运行态。
6. F4平台分发。
7. Q1集成收口。
如果 F1/F3 先完成,应只以 mock client 保持可编译,不直接修改后端合同。
---
## 14. 验收命令
后续编码分支按改动范围执行。
文档分支:
```powershell
npm run check:encoding -- docs/technical/MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md docs/technical/README.md
```
后端分支:
```powershell
cargo test -p module-match3d
cargo test -p shared-contracts
npm run api-server:maincloud
npm run check:encoding
```
SpacetimeDB 分支按仓库现有发布脚本执行,并在需要生成绑定时使用 `spacetime generate` 或仓库封装脚本。不得手写生成文件。
前端分支:
```powershell
npm run check:encoding
npm run typecheck
```
若新增定向测试,应补跑对应 `vitest`
---
## 15. 一句话结论
Match3D 首版按独立玩法域落地:前端负责所有局内即时反馈以保证手感,后端通过 SpacetimeDB procedure 权威确认规则和成绩api-server 只暴露稳定 HTTP facade后续并行分支必须围绕本文冻结的 DTO、表、procedure 和路由推进。

View File

@@ -0,0 +1,111 @@
# 抓大鹅 Match3D 领域规则与共享契约 Stage1 方案
日期:`2026-04-30`
## 1. 文档目的
本文件承接 [MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md](./MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md),只冻结 B1 + B2 开发范围:
1. 新增 `module-match3d` 纯领域 crate。
2. 新增 Rust shared contracts。
3. 新增 TypeScript shared contracts。
本阶段不实现 SpacetimeDB 表、procedure、`spacetime-client` 调用封装、`api-server` facade 和前端页面。
## 2. Stage1 边界
## 2.1 本阶段做
1. 领域层定义创作配置、作品草稿、作品 profile、运行态快照、物品、托盘、点击确认结果。
2. 领域层提供纯函数:
- 校验创作配置
- 编译默认草稿
- 校验发布字段
- 按确定性 seed 生成初始运行态
- 刷新 2D 可点击快照
- 确认点击、入槽、三消、胜利、托盘满失败
- 确认倒计时失败
3. Rust / TypeScript shared contracts 提供前后端对齐的请求与响应 DTO。
4. 运行态采用“前端即时反馈 + 后端权威确认”契约:
- 前端可先播放点击、飞入、入槽、三消、腾格和胜负过渡。
- 后端确认后返回权威快照。
- 后端拒绝或快照版本不一致时,前端按权威快照回滚或校正。
## 2.2 本阶段不做
1. 不新增 SpacetimeDB 表。
2. 不新增 SpacetimeDB procedure。
3. 不生成新的 SpacetimeDB bindings。
4. 不新增 `api-server` 路由。
5. 不接入平台入口、结果页或运行态 UI。
6. 不接入真实图片生成。
7. 不做排行榜与后续关卡推荐。
## 3. 领域 crate 设计
新增:
```text
server-rs/crates/module-match3d
```
该 crate 是纯领域层,不读写数据库,不访问网络,不依赖浏览器或文件系统。
本阶段虽然不落 SpacetimeDB 表和 procedure但领域模型已经为后续 SpacetimeDB 接入预留 `spacetime-types` feature。后续在 `spacetime-module` 内使用这些类型时,仍必须遵守 reducer 确定性、`ctx.sender()` 鉴权和表结构迁移约束。
核心类型:
1. `Match3DCreatorConfig`
2. `Match3DResultDraft`
3. `Match3DWorkProfile`
4. `Match3DRunSnapshot`
5. `Match3DItemSnapshot`
6. `Match3DTraySlot`
7. `Match3DClickConfirmation`
核心函数:
1. `build_creator_config`
2. `compile_result_draft`
3. `validate_publish_requirements`
4. `create_work_profile`
5. `publish_work_profile`
6. `start_run_with_seed_at`
7. `confirm_click_at`
8. `resolve_run_timer_at`
## 4. 即时反馈与权威确认
本阶段将点击处理明确拆成两层:
1. 前端即时反馈层
- 读取后端快照中的 `boardVersion`、物品位置、层级、半径和 `clickable`
- 本地做命中检测和动画。
- 立即表现飞入、入槽、三消和胜负过渡。
2. 后端权威确认层
- 校验 `runId``itemInstanceId`、运行态状态和物品是否仍可点击。
- 重新计算入槽、三消、托盘满失败和胜利。
- 返回最新 `Match3DRunSnapshot`
-`boardVersion` 帮前端识别是否需要校正。
`Flying` 只作为前端表现态,不要求后端逐帧落库。后端只确认物品是否已从 `InBoard` 进入 `InTray``Cleared`
运行态领域内部使用 `board_version` 表示权威快照版本HTTP 与 TypeScript shared contracts 对外使用 `snapshotVersion` / `clientSnapshotVersion`,由后续 `api-server` facade 做字段映射。
## 5. 生成规则 Stage1 口径
1. `clearCount` 必须是正整数。
2. `totalItemCount = clearCount * 3`
3. 难度范围为 `1~10`
4. 首版内置 `10` 种 demo 视觉 key。
5.`clearCount > 10` 时,复用视觉 key并保证每种物品数量仍为 `3` 的倍数。
6. 初始布局使用确定性 seed 生成圆形空间内的 2D 坐标。
7. 可点击判定只做 2D 近似:若物品被更高层物品完全覆盖,则不可点击;否则可点击。
## 6. 验收
1. `cargo test -p module-match3d` 通过。
2. `cargo test -p shared-contracts match3d` 通过。
3. `npm run check:encoding` 覆盖新增中文文档和新增源码。
4. 本阶段不要求运行 `npm run api-server:maincloud`因为未修改后端运行服务入口、SpacetimeDB 表或 `api-server` facade。

View File

@@ -0,0 +1,91 @@
# 抓大鹅 Match3D F1 创作入口与 Agent UI 落地记录 2026-04-30
## 1. 阶段边界
本文件承接《MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md》的 F1 包。
F1 只处理前端创作入口、Agent 工作区和等待后端 B5 facade 前的 mock client。它不实现运行态规则不修改 SpacetimeDB 表,不接 `api-server` 路由。
## 2. 本阶段写入范围
1. `src/components/platform-entry/`
2. `src/components/match3d-creation/`
3. `src/services/match3d-creation/`
4. `packages/shared/src/contracts/match3dAgent.ts`
其中 `packages/shared/src/contracts/match3dAgent.ts` 作为 F1 与后续 B5 的 DTO 对齐点F1 mock client 不自建脱离共享契约的临时类型。
## 3. 入口接入
平台入口新增可见创作类型:
```text
id: match3d
title: 抓大鹅
subtitle: 经典消除玩法
badge: 可创建
```
入口来源统一走 `getVisiblePlatformCreationTypes()`,因此创作首页首屏卡带与“选择创作类型”弹层会同时出现抓大鹅。
## 4. Agent 工作区
新增 `Match3DAgentWorkspace`,复用通用 `CreationAgentWorkspace`
Agent 只收集三类锚点:
1. 题材主题。
2. 需要消除次数。
3. 难度。
工作区支持参考图片上传入口。图片在 F1 中先以 Data URL 形式随消息 payload 带给 mock clientB5 接入后由后端 facade 替换为正式资产上传与引用。
UI 中不默认展示玩法规则长文,只展示进度、锚点、聊天内容和必要按钮。
## 5. mock client
新增 `src/services/match3d-creation/match3dCreationClient.ts`
mock client 提供:
1. `createMatch3DCreationSession`
2. `getMatch3DCreationSession`
3. `streamMatch3DCreationMessage`
4. `executeMatch3DCreationAction`
mock 行为:
1. 创建本地会话。
2. 从中文输入中提取题材、消除次数和难度。
3. 支持“自动配置”。
4. 当三项配置完整时允许执行 `match3d_compile_draft`
5. 编译后返回 `draft_ready` 会话和草稿。
## 6. 结果承接
F1 新增 `Match3DDraftReadyView` 作为草稿生成后的临时承接页,只展示草稿基础信息并允许返回 Agent 修改。
正式结果页的基础信息编辑、封面图、试玩、发布由 F2 接入F1 不在这里模拟发布。
## 7. 后续替换点
B5 完成后,只需要把 `match3dCreationClient` 的本地 Map mock 替换为 HTTP/SSE facade
```text
POST /api/creation/match3d/sessions
GET /api/creation/match3d/sessions/:sessionId
POST /api/creation/match3d/sessions/:sessionId/messages/stream
POST /api/creation/match3d/sessions/:sessionId/compile
```
`PlatformEntryFlowShellImpl``Match3DAgentWorkspace` 不应再改一轮业务字段。
## 8. 验收口径
1. 创作首页能看到“抓大鹅 / 经典消除玩法”。
2. 弹层选择“抓大鹅”能进入 Agent 工作区。
3. 输入题材、消除次数、难度后进度到 `100%`
4. 点击“生成结果页”进入草稿承接页。
5. 可从草稿承接页返回 Agent 修改。
6. `npm run check:encoding` 通过。
7. `npm run typecheck` 通过。

View File

@@ -0,0 +1,394 @@
# 抓大鹅 Match3D F2 结果页与发布技术方案
日期:`2026-04-30`
## 1. 文档目的
本文件承接 [MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md](./MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md),只冻结 F2 开发范围:
1. Match3D 待发布结果页。
2. 作品基础信息编辑。
3. 发布前试玩入口。
4. 发布入口。
5. 已发布作品二次编辑恢复口径。
本阶段不实现运行态即时反馈 UI不实现 SpacetimeDB 表与 procedure不实现 `api-server` facade。F2 可以先基于 shared contracts 与 mock client 开发,等待 B4+B5 接入真实 HTTP。
---
## 2. 前置依赖
F2 依赖以下已冻结文档:
1. PRD[AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md](../prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md)
2. A0[MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md](./MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md)
3. B1+B2[MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md](./MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md)
F2 可在 B4+B5 之前并行开发,但必须遵守 B2 的 TypeScript contract不得在前端私自扩字段。
---
## 3. 本阶段做
1. 新增 Match3D 结果页组件目录。
2. 新增 Match3D works service 目录。
3. 展示草稿配置摘要:
- 题材主题
- 需要消除次数
- 难度
- 参考图片预览
4. 支持编辑发布基础信息:
- 游戏名称
- 标签
- 封面图
5. 支持发布前试玩入口。
6. 支持试玩中止后回到结果页继续编辑。
7. 支持发布入口。
8. 支持已发布作品二次编辑的前端恢复路径。
---
## 4. 本阶段不做
1. 不生成题材物品素材。
2. 不生成额外封面图;封面图只接收已有图片、上传图片或后端已有占位结果。
3. 不要求试玩通关后才能发布。
4. 不实现运行态点击、飞入、三消等即时反馈。
5. 不实现首页、分类页和广场投影。
6. 不实现排行榜。
7. 不在 UI 中默认展示玩法规则说明长文。
8. 不把发布校验只写在前端;前端只做即时提示,后端 publish gate 是最终门槛。
---
## 5. 文件落点
## 5.1 前端组件
新增:
```text
src/components/match3d-result/
```
建议文件:
```text
src/components/match3d-result/Match3DResultView.tsx
src/components/match3d-result/Match3DResultView.test.tsx
src/components/match3d-result/index.ts
```
如组件变大,可后续拆分:
```text
Match3DResultHeader.tsx
Match3DResultBasicsForm.tsx
Match3DResultConfigPreview.tsx
Match3DResultPublishPanel.tsx
```
首版不要过早拆太多文件,优先保持可读和低冲突。
## 5.2 前端 service
新增:
```text
src/services/match3d-works/
```
建议文件:
```text
src/services/match3d-works/match3dWorksClient.ts
src/services/match3d-works/index.ts
```
F2 只负责 works 维度:
1. 读取作品详情。
2. 更新作品基础信息。
3. 发布作品。
4. 删除作品可后置,若 F4 需要再补。
运行态启动接口归 `src/services/match3d-runtime/`F2 只调用上层传入的 `onStartTestRun`
---
## 6. shared contracts 使用
F2 只消费 B2 已冻结的 TypeScript contract
```text
packages/shared/src/contracts/match3dWorks.ts
packages/shared/src/contracts/match3dAgent.ts
packages/shared/src/contracts/match3dRuntime.ts
```
必要类型:
1. `Match3DWorkProfile`
2. `Match3DWorkSummary`
3. `Match3DWorkUpdateRequest`
4. `Match3DPublishRequest`
5. `Match3DPublishResult`
6. `Match3DCompileDraftResult`
7. `Match3DCreatorConfig`
F2 不新增独立的前端私有数据结构来表达作品真相;只允许使用局部表单状态承载未保存输入。
---
## 7. 结果页 props contract
建议 `Match3DResultView` props
```ts
type Match3DResultViewProps = {
profile: Match3DWorkProfile;
draft?: Match3DCompileDraftResult | null;
isBusy?: boolean;
error?: string | null;
onBack: () => void;
onStartTestRun: (profile: Match3DWorkProfile) => void;
onPublish: (payload: Match3DPublishRequest) => void;
onSaved?: (profile: Match3DWorkProfile) => void;
};
```
说明:
1. `profile` 是结果页当前作品真相源。
2. `draft` 只用于展示草稿生成附加信息;不能覆盖 `profile` 的发布字段。
3. `onStartTestRun` 进入 F3/B5 运行态链路。
4. `onPublish` 可以先由 mock client 实现B5 完成后替换为真实 HTTP。
5. `onSaved` 用于把自动保存后的 profile 回写给上层流程控制器。
---
## 8. 页面内容顺序
结果页保持单列表,不做多 Tab。
固定顺序:
1. 顶部返回与保存状态。
2. 封面图。
3. 游戏名称。
4. 标签。
5. 题材主题。
6. 需要消除次数。
7. 难度。
8. 参考图片预览。
9. 试玩按钮。
10. 发布按钮。
UI 只呈现必要信息,不在页面中展示玩法规则说明长文。
---
## 9. 字段编辑规则
## 9.1 游戏名称
1. 必填。
2. 首版建议前端限制 `1~30` 个中文字符等价长度。
3. 默认值来自 Agent 确认题材或系统生成草稿。
## 9.2 标签
1. 必填。
2. 首版建议 `3~6` 个标签,与拼图发布门槛保持一致。
3. 输入支持中文逗号、英文逗号、顿号、换行拆分。
4. 前端需要去重和去空格。
## 9.3 封面图
1. 必填。
2. F2 可先复用参考图片、占位封面或用户上传图。
3. 图片真实存储由现有资产链或后续 B5 facade 处理。
4. 前端不得把本地临时 blob URL 当作已发布封面真相。
## 9.4 题材主题、需要消除次数、难度
首版结果页允许展示并可编辑这些配置。
修改后必须同步保存到作品 profile
1. `themeText`
2. `clearCount`
3. `difficulty`
注意:
1. `clearCount` 必须为正整数。
2. `difficulty` 必须在 `1~10`
3. 修改配置后,下一次试玩必须基于最新保存配置启动。
---
## 10. 自动保存
F2 建议实现自动保存,口径参考拼图结果页:
1. 输入变更后 `600ms` debounce。
2. 只保存结果页可编辑字段。
3. 保存中展示轻量状态。
4. 保存失败展示轻量错误,不弹长说明。
5. 发布前必须等待最后一次保存完成,或发布 payload 直接携带当前表单字段。
建议状态:
```ts
type Match3DAutoSaveState = 'idle' | 'saving' | 'saved' | 'error';
```
---
## 11. 发布门槛
前端即时 blocker
1. 游戏名称为空。
2. 标签数量不在 `3~6`
3. 封面图为空。
4. `clearCount` 不是正整数。
5. `difficulty` 不在 `1~10`
后端 publish gate 是最终门槛,前端不得绕过。
发布不要求试玩通关。
---
## 12. 试玩入口
结果页提供“试玩”入口。
行为:
1. 点击试玩前先保存当前表单。
2. 保存成功后调用 `onStartTestRun(profile)`
3. 上层进入 Match3D 运行态。
4. 运行态停止或返回后,回到同一个结果页继续编辑。
F2 不实现运行态本身;只冻结结果页如何发起试玩。
---
## 13. 发布接口
F2 service 建议接口:
```ts
const MATCH3D_WORKS_API_BASE = '/api/creation/match3d/works';
export async function getMatch3DWorkDetail(profileId: string): Promise<Match3DWorkDetailResponse>;
export async function updateMatch3DWork(
profileId: string,
payload: Match3DWorkUpdateRequest,
): Promise<Match3DWorkMutationResponse>;
export async function publishMatch3DWork(
profileId: string,
payload: Match3DPublishRequest,
): Promise<Match3DPublishResult>;
```
后续 B5 必须提供同名 HTTP facade 或在 service 层做最小适配。
---
## 14. Mock client 口径
F2 可以在真实 B5 接口完成前使用 mock client。
要求:
1. mock 数据必须来自 shared contracts。
2. mock profile 字段必须覆盖发布必填项。
3. mock publish 只能返回“可发布成功”的本地结果,不得伪造平台广场投影。
4. B5 接入后mock 只能保留为测试 fixture。
---
## 15. 已发布作品二次编辑
进入自己已发布 Match3D 作品时,结果页应支持二次编辑。
规则:
1. 优先通过 `sourceSessionId` 恢复原创作 session。
2. 如果没有 session则通过 `profileId` 读取作品详情进入结果页。
3. 二次发布不得创建新作品,必须覆盖同一 `profileId`
4. 不清零 `playCount`
5. 不改变作品归属。
---
## 16. 与其它分支的接口边界
## 16.1 依赖 F1
F1 负责创建会话和 Agent UI。F2 接收 F1 编译出的 `profile / draft`,不重复实现 Agent 对话。
## 16.2 依赖 F3
F3 负责运行态 UI。F2 只提供 `onStartTestRun` 入口。
## 16.3 依赖 B5
B5 负责真实 HTTP facade。F2 的 service path 和 DTO 必须按本文冻结,避免后续替换 mock 时改组件结构。
## 16.4 依赖 F4
F4 负责首页、分类页和广场分发。F2 发布成功后只需要把返回 profile 交给上层;不直接刷新广场列表。
---
## 17. 测试要求
建议新增:
```text
src/components/match3d-result/Match3DResultView.test.tsx
```
覆盖:
1. 展示游戏名称、标签、封面图、题材、需要消除次数和难度。
2. 游戏名称为空时发布按钮阻断。
3. 标签数量不足时发布按钮阻断。
4. `clearCount` 非正整数时发布按钮阻断。
5. `difficulty` 超出 `1~10` 时发布按钮阻断。
6. 点击试玩前触发保存。
7. 发布不要求试玩通关。
service 测试可在 B5 接入后补齐。
---
## 18. 验收命令
F2 文档分支:
```powershell
npm run check:encoding -- docs/technical/MATCH3D_F2_RESULT_AND_PUBLISH_2026-04-30.md docs/technical/README.md
```
F2 前端实现分支:
```powershell
npm run check:encoding
npm run typecheck
```
如新增组件测试,补跑对应 `vitest`
---
## 19. 一句话结论
F2 只负责把 Match3D 草稿变成可编辑、可试玩、可发布的作品工作台;它必须复用平台结果页和发布体验,发布不要求试玩通关,并为 B5 真实后端接口与 F3 运行态试玩入口保留清晰边界。

View File

@@ -0,0 +1,126 @@
# 抓大鹅 Match3D B4+B5 spacetime-client 与 api-server facade 落地记录
日期:`2026-04-30`
## 1. 本阶段目标
本文件记录 B4+B5 的技术落地范围:把 B3 已生成的 Match3D SpacetimeDB procedure 接到 `spacetime-client`,再通过 `api-server` 暴露给前端使用的 HTTP facade。
本阶段不改 SpacetimeDB 表结构,不新增 migration不接入真实题材素材生成也不改前端即时反馈实现。
## 2. 已落地范围
### 2.1 SpacetimeDB bindings
使用仓库封装脚本重新生成 bindings
```powershell
npm run spacetime:generate
```
Windows 下 SpacetimeDB CLI 可能在 Rust bindings 已生成后输出 `Could not format generated files: 文件名或扩展名太长。 (os error 206)`。脚本已调整为:当 CLI 退出码为 `0` 且只是格式化警告时继续同步生成文件。
生成文件仍视为机器产物,禁止手写修改。
### 2.2 spacetime-client facade
新增:
```text
server-rs/crates/spacetime-client/src/match3d.rs
```
并在 `spacetime-client/src/lib.rs` 导出 `match3d` 模块与 Match3D Record 类型。
已覆盖:
1. 创作会话create / get / submit message / finalize / compile draft。
2. 作品list / get detail / update / publish / delete / public gallery list。
3. 运行态start / get / click / stop / restart / time-up。
`mapper.rs` 负责把 procedure 返回的 JSON 字符串解析为稳定 Record不把 generated bindings 泄露到 `api-server`
### 2.3 api-server HTTP facade
新增:
```text
server-rs/crates/api-server/src/match3d.rs
```
并在 `main.rs` 注册模块,在 `app.rs` 挂载路由。
已挂载路由:
```text
POST /api/creation/match3d/sessions
GET /api/creation/match3d/sessions/{session_id}
POST /api/creation/match3d/sessions/{session_id}/messages
POST /api/creation/match3d/sessions/{session_id}/messages/stream
POST /api/creation/match3d/sessions/{session_id}/actions
POST /api/creation/match3d/sessions/{session_id}/compile
GET /api/creation/match3d/works
GET /api/creation/match3d/works/{profile_id}
PATCH /api/creation/match3d/works/{profile_id}
PUT /api/creation/match3d/works/{profile_id}
DELETE /api/creation/match3d/works/{profile_id}
POST /api/creation/match3d/works/{profile_id}/publish
GET /api/runtime/match3d/gallery
POST /api/runtime/match3d/works/{profile_id}/runs
GET /api/runtime/match3d/runs/{run_id}
POST /api/runtime/match3d/runs/{run_id}/click
POST /api/runtime/match3d/runs/{run_id}/stop
POST /api/runtime/match3d/runs/{run_id}/restart
POST /api/runtime/match3d/runs/{run_id}/time-up
```
`api-server` 返回 `shared-contracts` 中的 Match3D DTO前端不需要感知 SpacetimeDB 内部 JSON 快照结构。
## 3. 创作 Agent 当前口径
B5 首版先采用确定性配置抽取,不在本阶段新增真实 LLM prompt
1. 创建会话时可从 `themeText / seedText / clearCount / difficulty / referenceImageSrc` 形成配置。
2. 发送消息时根据用户文本或 `quickFillRequested` 更新题材、需要消除次数和难度。
3. `match3d_compile_draft` 动作调用 SpacetimeDB `compile_match3d_draft`,生成 draft work profile。
后续若要接真实 LLM turn应复用现有创作 Agent 公共编排,并保持 submit/finalize 两阶段职责不变。
## 4. 运行态确认协议
B5 保持 PRD 调整后的边界:
1. 前端负责点击、飞入、入槽、三消、腾格、胜负等即时表现。
2. 后端通过 `click_match3d_item``finish_match3d_time_up` 等 procedure 做权威确认。
3. HTTP response 会把 SpacetimeDB `Accepted / VersionConflict / RunFinished` 等状态归一到前端 shared contract 可消费的 `accepted / rejectReason / run` 结构。
4. `snapshotVersion` 继续作为前端即时反馈和后端确认之间的版本校验字段。
## 5. shared contract 对齐
本阶段补齐 Rust shared contract 与 TypeScript contract 的已知差异:
1. `Match3DAgentSessionSnapshotResponse` 增加 `anchorPack`
2. `Match3DResultDraftResponse` 增加 `profileId / summaryText / totalItemCount`,同时保留 `summary` 兼容结果页读取。
3. `PutMatch3DWorkRequest` 增加可选 `themeText`,结果页可编辑题材;旧请求缺省时 API 会沿用已有作品题材。
## 6. 验收命令
本阶段至少执行:
```powershell
cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
cargo check -p api-server --manifest-path server-rs\Cargo.toml
cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml
npm run check:encoding
npm run api-server:maincloud
```
`api-server:maincloud` 是修改后端后的必跑项;如果本地缺少 Maincloud 环境或 SpacetimeDB 发布态不一致,需要在最终结果里明确说明。
## 7. 后续接入点
1. F1/F2/F3 可把 mock client 替换到上述 HTTP facade。
2. F4 平台分发可先读取 `/api/runtime/match3d/gallery` 的已发布作品列表。
3. 若后续要记录排行榜或作品播放统计,需要补 Match3D 成绩表或 play record procedure并同步更新 migration。

View File

@@ -6,6 +6,10 @@
- [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md):冻结 SpacetimeDB 表结构变更约束、自动迁移可接受范围、冲突后的系统行为,以及保留旧数据的增量迁移流程;凡涉及 `spacetime publish`、表字段调整或 `migration.rs` 对齐时优先参考。
- [PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md](./PROFILE_INVITE_CODE_REGISTRATION_AND_ADMIN_2026-04-30.md):冻结邀请码从“我的 Tab 填写”迁到注册环节的前后端边界、`profile_invite_code.metadata_json` 表结构扩展、管理员邀请码虚拟主体和奖励规则。
- [MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md](./MATCH3D_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-30.md):冻结抓大鹅 Match3D 首版 demo 的独立玩法域、表与 procedure、HTTP facade、前端即时反馈/后端权威确认协议,以及可并行开发包。
- [MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md](./MATCH3D_DOMAIN_AND_CONTRACTS_STAGE1_2026-04-30.md):冻结抓大鹅 Match3D B1+B2 的纯领域规则 crate、Rust/TypeScript shared contracts以及 Stage1 不触碰 SpacetimeDB 表和 api-server 的边界。
- [MATCH3D_F1_CREATION_ENTRY_AND_AGENT_UI_2026-04-30.md](./MATCH3D_F1_CREATION_ENTRY_AND_AGENT_UI_2026-04-30.md):记录抓大鹅 F1 创作入口、Agent 工作区、参考图入口、本地 mock client 与后续 B5 HTTP facade 替换点。
- [MATCH3D_F2_RESULT_AND_PUBLISH_2026-04-30.md](./MATCH3D_F2_RESULT_AND_PUBLISH_2026-04-30.md):冻结抓大鹅 F2 结果页、基础信息编辑、发布前试玩入口、发布门槛、自动保存和已发布作品二次编辑恢复口径。
- [PLATFORM_MOBILE_BOTTOM_DOCK_VIEWPORT_FIX_2026-04-30.md](./PLATFORM_MOBILE_BOTTOM_DOCK_VIEWPORT_FIX_2026-04-30.md):记录平台首页底部 dock 在手机浏览器地址栏展开时脱离可见区域的根因,以及 `100dvh`、固定底部锚点和安全区占位的修复口径。
- [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md):记录 SpacetimeDB private 表迁移 JSON 导出/导入 procedure、迁移操作员授权、HTTP 413 分片导入、Jenkins 自动迁移回灌和导入脚本参数。
- [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md):记录 `Genarrative-Database-Export` / `Genarrative-Database-Import` 两条 SCM-backed 数据库迁移流水线参数、默认 dry-run、token 边界和 `CHUNK_SIZE` 413 规避参数。

View File

@@ -27,6 +27,7 @@ spacetime sql <db> "SELECT * FROM custom_world_gallery_entry"
| RPG 运行时 | `story_session`, `story_event`, `npc_state`, `inventory_slot`, `battle_state`, `treasure_record`, `quest_record`, `quest_log`, `player_progression`, `chapter_progression` |
| 世界创作 | `custom_world_profile`, `custom_world_session`, `custom_world_agent_session`, `custom_world_agent_message`, `custom_world_agent_operation`, `custom_world_draft_card`, `custom_world_gallery_entry` |
| 拼图 | `puzzle_agent_session`, `puzzle_agent_message`, `puzzle_work_profile`, `puzzle_runtime_run` |
| 抓大鹅 Match3D | `match3d_agent_session`, `match3d_agent_message`, `match3d_work_profile`, `match3d_runtime_run` |
| 大鱼吃小鱼 | `big_fish_creation_session`, `big_fish_agent_message`, `big_fish_asset_slot`, `big_fish_runtime_run` |
| 资产 | `asset_object`, `asset_entity_binding` |
| AI 任务 | `ai_task`, `ai_task_stage`, `ai_text_chunk`, `ai_result_reference` |
@@ -446,6 +447,53 @@ SELECT * FROM puzzle_runtime_run WHERE run_id = '<run_id>';
SELECT * FROM puzzle_runtime_run WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
```
## 抓大鹅 Match3D 表
### `match3d_agent_session`
- 作用:抓大鹅 Match3D 创作 Agent 会话表,保存种子、配置 JSON、草稿 JSON 和发布 profile 指针。
- 结构:`session_id PK: String`, `owner_user_id: String`, `seed_text: String`, `current_turn: u32`, `progress_percent: u32`, `stage: String`, `config_json: String`, `draft_json: String`, `last_assistant_reply: String`, `published_profile_id: String`, `created_at: Timestamp`, `updated_at: Timestamp`
- 索引:`owner_user_id`
```sql
SELECT * FROM match3d_agent_session WHERE session_id = '<session_id>';
SELECT * FROM match3d_agent_session WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
```
### `match3d_agent_message`
- 作用:抓大鹅 Match3D 创作 Agent 消息流水。
- 结构:`message_id PK: String`, `session_id: String`, `role: String`, `kind: String`, `text: String`, `created_at: Timestamp`
- 索引:`session_id`
```sql
SELECT * FROM match3d_agent_message WHERE session_id = '<session_id>' ORDER BY created_at ASC;
```
### `match3d_work_profile`
- 作用:抓大鹅 Match3D 作品主表,保存作品基础信息、配置、发布状态和游玩次数。
- 结构:`profile_id PK: String`, `owner_user_id: String`, `source_session_id: String`, `author_display_name: String`, `game_name: String`, `theme_text: String`, `summary_text: String`, `tags_json: String`, `cover_image_src: String`, `cover_asset_id: String`, `clear_count: u32`, `difficulty: u32`, `config_json: String`, `publication_status: String`, `play_count: u32`, `updated_at: Timestamp`, `published_at: Option<Timestamp>`
- 索引:`owner_user_id`, `publication_status`
```sql
SELECT * FROM match3d_work_profile WHERE profile_id = '<profile_id>';
SELECT * FROM match3d_work_profile WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
SELECT * FROM match3d_work_profile WHERE publication_status = 'Published';
```
### `match3d_runtime_run`
- 作用:抓大鹅 Match3D 单局运行态表,保存权威快照、快照版本、胜负状态和成绩基础字段。
- 结构:`run_id PK: String`, `owner_user_id: String`, `profile_id: String`, `status: String`, `snapshot_version: u32`, `started_at_ms: i64`, `duration_limit_ms: i64`, `finished_at_ms: i64`, `elapsed_ms: i64`, `clear_count: u32`, `total_item_count: u32`, `cleared_item_count: u32`, `failure_reason: String`, `snapshot_json: String`, `created_at: Timestamp`, `updated_at: Timestamp`
- 索引:`owner_user_id`, `profile_id`
```sql
SELECT * FROM match3d_runtime_run WHERE run_id = '<run_id>';
SELECT * FROM match3d_runtime_run WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
SELECT * FROM match3d_runtime_run WHERE profile_id = '<profile_id>';
```
## 大鱼吃小鱼表
### `big_fish_creation_session`