Merge branch 'master' of https://git.genarrative.world/GenarrativeAI/Genarrative
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
- 不提交个人配置、API Key、会话转录、模型密钥、本地路径密钥等敏感内容。
|
||||
- 个人 Hermes 的 `~/.hermes/config.yaml`、`~/.hermes/.env`、`~/.hermes/sessions/` 不应复制到本仓库。
|
||||
- 开发前先阅读本目录下与任务相关的记忆文件;开发后如产生稳定知识,更新对应文档。
|
||||
- 后续新增的 Markdown 文档文件名必须以分类标签开头,格式为 `【标签名】中文标题-日期.md`,便于团队跨目录检索。
|
||||
- 若本目录内容与 `docs/` 或代码事实冲突,以当前代码和最新 `docs/` 为准,并同步修正过期记忆。
|
||||
|
||||
## 目录结构
|
||||
@@ -24,6 +25,7 @@
|
||||
│ ├─ pitfalls.md # 踩坑与排障记录
|
||||
│ └─ handoff-template.md # 任务交接模板
|
||||
├─ plans/ # 阶段性计划与实施方案
|
||||
├─ todos/ # 已定稿但尚未执行的共享 TODO 计划
|
||||
├─ skills/ # 仓库级 Hermes skills
|
||||
└─ plugins/ # 仓库级 Hermes plugins(需显式启用项目 plugin)
|
||||
```
|
||||
@@ -89,4 +91,3 @@ HERMES_ENABLE_PROJECT_PLUGINS=1 HERMES_PLUGINS_DEBUG=1 hermes chat -q "请读取
|
||||
- 大段临时聊天记录
|
||||
- 尚未确认的一次性猜测
|
||||
- 构建产物、日志、缓存、数据库 dump
|
||||
|
||||
|
||||
549
.hermes/plans/BARK_BATTLE_PHASE2_PLATFORM_WORK_LOOP_PLAN.md
Normal file
549
.hermes/plans/BARK_BATTLE_PHASE2_PLATFORM_WORK_LOOP_PLAN.md
Normal file
@@ -0,0 +1,549 @@
|
||||
# Bark Battle Phase 2 Platform Work Loop Implementation Plan
|
||||
|
||||
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
|
||||
|
||||
**Goal:** 将 `bark-battle` 从内部试玩 demo 升级为 Genarrative 正式 play type,打通轻创作配置、发布态作品、正式 runtime、run start / finish、后端裁决、个人历史、作品统计和最小排行榜闭环。
|
||||
|
||||
**Architecture:** 先冻结 shared contracts 与 `module-bark-battle` 纯领域规则,再落 SpacetimeDB 表/reducer、`spacetime-client` facade 和 `api-server` BFF,随后接前端最小纵切,最后补排行榜/个人历史/作品统计投影体验。前端只承接表现、交互和临时 UI 状态,正式业务真相由后端裁决。
|
||||
|
||||
**Tech Stack:** React + TypeScript + Vite, server-rs + Axum, SpacetimeDB Rust module, shared-contracts, Vitest, Cargo tests, npm scripts.
|
||||
|
||||
---
|
||||
|
||||
## 0. 已确认决策
|
||||
|
||||
1. “有效叫声”统一为 **有效声浪触发**:当前采样响度达到有效阈值且满足 `minBarkGapMs` 冷却即触发;不再要求 `minBarkDurationMs` / `maxBarkDurationMs`,也不等待响度回落。
|
||||
2. Phase 2 范围是 **Bark Battle 平台作品闭环**,不是单纯玩法表现深化。
|
||||
3. 作品形态是 **轻创作配置作品**:标题、描述、主题/背景预设、狗狗皮肤预设、难度预设、排行榜开关。
|
||||
4. 难度预设只影响 AI 对手行为;不影响有效阈值、冷却、时长、分数公式或反作弊阈值。
|
||||
5. 排行榜按 `workId + difficultyPreset + rulesetVersion` 分榜。
|
||||
6. 后端裁决正式单局结果;前端只提交派生指标,`clientResult` 只用于 debug/对账。
|
||||
7. 排行榜只收录 `serverResult = player_win` 且未被反作弊拒绝的单局结果,排序以 `finalEnergy` 优先。
|
||||
8. 作品统计使用最小后端投影:start、finish、win/draw/loss、flagged、leaderboard、best/avg energy。
|
||||
9. 个人历史成绩 = 最近记录列表 + 个人最佳摘要;仅本人可见。
|
||||
10. 正式入口闭环覆盖创作入口、作品详情 CTA、广场/作品卡片、我的作品、稳定作品 ID runtime 路由和 `work_play_start`。
|
||||
11. 创作编辑形态是单页轻配置表单 + 预览卡片。
|
||||
12. 实施顺序固定为:契约与领域规则 → SpacetimeDB 表/reducer 与 api-server BFF → 最小前端纵切 → 投影与列表体验 → 收口验证。
|
||||
|
||||
---
|
||||
|
||||
## 1. 必读文档与约束
|
||||
|
||||
实施前先读:
|
||||
|
||||
- `AGENTS.md`
|
||||
- `CONTEXT.md`
|
||||
- `docs/prd/BARK_BATTLE_BDD_2026-05-11.md`
|
||||
- `docs/technical/BARK_BATTLE_BACKEND_DDD_TECHNICAL_PLAN_2026-05-11.md`
|
||||
- `docs/technical/BARK_BATTLE_2D_RUNTIME_TECHNICAL_PLAN_2026-05-11.md`
|
||||
- `docs/technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md`
|
||||
- `docs/technical/SERVER_RS_DDD_FULL_REFACTOR_2026-04-28.md`
|
||||
- `.codex/skills/spacetimedb-cli/SKILL.md`
|
||||
- `.codex/skills/spacetimedb-rust/SKILL.md`
|
||||
- `.codex/skills/spacetimedb-concepts/SKILL.md`
|
||||
- `.codex/skills/spacetimedb-typescript/SKILL.md`
|
||||
|
||||
关键约束:
|
||||
|
||||
- 后端路线固定 `server-rs + Axum + SpacetimeDB`。
|
||||
- 领域规则进 `module-bark-battle`,SpacetimeDB 表和事务编排进 `spacetime-module`。
|
||||
- HTTP/SSE/BFF 留在 `api-server`。
|
||||
- 前后端 DTO 留在 `shared-contracts`。
|
||||
- 数据库表结构更改必须同步 `migration.rs` 和生成绑定。
|
||||
- 人工命令/文档示例禁止继续使用 `spacetime --root-dir`。
|
||||
- 修改中文文件后必须跑 `npm run check:encoding`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 阶段一:契约与领域规则
|
||||
|
||||
### Task 1.1: 新增 Rust shared-contracts 模块
|
||||
|
||||
**Objective:** 定义 Bark Battle Phase 2 的 Rust DTO 边界。
|
||||
|
||||
**Files:**
|
||||
- Create: `server-rs/crates/shared-contracts/src/bark_battle.rs`
|
||||
- Modify: `server-rs/crates/shared-contracts/src/lib.rs`
|
||||
- Test: `server-rs/crates/shared-contracts/src/bark_battle.rs`
|
||||
|
||||
**Steps:**
|
||||
1. 新增枚举:`BarkBattleDifficultyPreset { Easy, Normal, Hard }`、`BarkBattleServerResult { PlayerWin, OpponentWin, Draw }`、`BarkBattleFinishStatus { Accepted, AcceptedWithFlags, Rejected }`。
|
||||
2. 新增配置 DTO:`BarkBattleDraftConfig`、`BarkBattlePublishedConfig`、`BarkBattleRuntimeConfig`。
|
||||
3. 新增 run DTO:`BarkBattleRunStartRequest/Response`、`BarkBattleRunFinishRequest/Response`。
|
||||
4. 新增派生指标 DTO:`BarkBattleDerivedMetrics`,字段包含 `trigger_count`、`max_volume`、`average_volume`、`final_energy`、`combo_max`。
|
||||
5. 新增排行榜/历史/统计 DTO:`BarkBattleLeaderboardEntry`、`BarkBattlePersonalHistoryItem`、`BarkBattlePersonalBestSummary`、`BarkBattleWorkStats`。
|
||||
6. 在 `lib.rs` 导出 `pub mod bark_battle;`。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p shared-contracts bark_battle
|
||||
```
|
||||
|
||||
Expected: contracts tests pass.
|
||||
|
||||
### Task 1.2: 新增 TypeScript shared contracts mirror
|
||||
|
||||
**Objective:** 让前端获得与 Rust DTO 对齐的类型。
|
||||
|
||||
**Files:**
|
||||
- Create: `packages/shared/src/contracts/barkBattle.ts`
|
||||
- Modify: `packages/shared/src/contracts/index.ts`
|
||||
- Test: `packages/shared/src/contracts/barkBattle.test.ts`
|
||||
|
||||
**Steps:**
|
||||
1. 定义 `BarkBattleDifficultyPreset = 'easy' | 'normal' | 'hard'`。
|
||||
2. 定义 `BarkBattleServerResult = 'player_win' | 'opponent_win' | 'draw'`。
|
||||
3. 定义 draft / published / runtime config 类型。
|
||||
4. 定义 start / finish request response 类型。
|
||||
5. 定义 leaderboard / personal history / work stats 类型。
|
||||
6. 写最小序列化/fixture 测试,确保字段命名采用前端约定 camelCase,并在 API client 层做必要映射。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
npm test -- --run packages/shared/src/contracts/barkBattle.test.ts
|
||||
npx tsc -p tsconfig.typecheck-guardrails.json --noEmit --pretty false
|
||||
```
|
||||
|
||||
### Task 1.3: 新建 module-bark-battle crate
|
||||
|
||||
**Objective:** 将正式裁决规则放入纯领域 crate。
|
||||
|
||||
**Files:**
|
||||
- Create: `server-rs/crates/module-bark-battle/Cargo.toml`
|
||||
- Create: `server-rs/crates/module-bark-battle/src/lib.rs`
|
||||
- Create: `server-rs/crates/module-bark-battle/src/domain.rs`
|
||||
- Create: `server-rs/crates/module-bark-battle/src/scoring.rs`
|
||||
- Modify: `server-rs/Cargo.toml`
|
||||
|
||||
**Steps:**
|
||||
1. 在 workspace 中注册 `module-bark-battle`。
|
||||
2. 定义 `RulesetVersion`,首版固定如 `bark-battle-ruleset-v1`。
|
||||
3. 定义 `BarkBattleRuleset`,包含标准局时长 30s、`min_bark_gap_ms`、合法音量/能量/连击范围、duration tolerance。
|
||||
4. 实现 `validate_finish_metrics()`。
|
||||
5. 实现 `adjudicate_result()`:以后端 `final_energy` 和 draw threshold 生成 `serverResult`。
|
||||
6. 实现 `compute_leaderboard_score()`:只允许胜利局入榜,排序因子为 `finalEnergy`、`triggerCount`、`maxVolume`、duration 接近度、`finishedAt`。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p module-bark-battle
|
||||
```
|
||||
|
||||
### Task 1.4: 领域规则单测覆盖作弊边界
|
||||
|
||||
**Objective:** 防止前端伪造 finish 直接刷榜。
|
||||
|
||||
**Files:**
|
||||
- Modify: `server-rs/crates/module-bark-battle/src/scoring.rs`
|
||||
|
||||
**Test cases:**
|
||||
- 28s-35s 合法窗口内可接受。
|
||||
- 1s / 300s 应 rejected 或 flagged。
|
||||
- `triggerCount > durationMs / minBarkGapMs + tolerance` 应 flagged。
|
||||
- `finalEnergy` 越界应 rejected。
|
||||
- 平/负不生成 leaderboard entry。
|
||||
- easy/normal/hard 不改变阈值、冷却、分数公式,只改变 AI preset key。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p module-bark-battle -- --nocapture
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 阶段二:SpacetimeDB 表/reducer 与 api-server BFF
|
||||
|
||||
### Task 2.1: 设计 SpacetimeDB 表目录
|
||||
|
||||
**Objective:** 新增 Bark Battle 表并与 migration 对齐。
|
||||
|
||||
**Files:**
|
||||
- Create: `server-rs/crates/spacetime-module/src/bark_battle/mod.rs`
|
||||
- Create: `server-rs/crates/spacetime-module/src/bark_battle/types.rs`
|
||||
- Create: `server-rs/crates/spacetime-module/src/bark_battle/tables.rs`
|
||||
- Modify: `server-rs/crates/spacetime-module/src/lib.rs`
|
||||
- Modify: `server-rs/crates/spacetime-module/src/migration.rs`
|
||||
|
||||
**Tables:**
|
||||
- `bark_battle_draft_config`
|
||||
- `bark_battle_published_config`
|
||||
- `bark_battle_runtime_run`
|
||||
- `bark_battle_score_record`
|
||||
- `bark_battle_leaderboard_entry`
|
||||
- `bark_battle_work_stats_projection`
|
||||
- `bark_battle_personal_best_projection`
|
||||
|
||||
**Pitfalls:**
|
||||
- 表结构不要 derive `SpacetimeType`。
|
||||
- reducer 使用 `&ReducerContext`。
|
||||
- 授权身份来自 `ctx.sender()`。
|
||||
- 需要公开订阅的表才加 `public`。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p spacetime-module
|
||||
```
|
||||
|
||||
### Task 2.2: 实现草稿/发布 reducer
|
||||
|
||||
**Objective:** 支持轻配置草稿保存和发布态 config 固化。
|
||||
|
||||
**Reducers:**
|
||||
- `create_bark_battle_draft`
|
||||
- `update_bark_battle_draft_config`
|
||||
- `publish_bark_battle_work`
|
||||
- `get_bark_battle_runtime_config` 如仓库约定使用 reducer/procedure 查询则按现有 pattern 实现。
|
||||
|
||||
**Rules:**
|
||||
- 草稿配置只允许标题、描述、主题/背景预设、狗狗皮肤预设、难度预设、排行榜开关。
|
||||
- 发布生成稳定作品 ID / config version。
|
||||
- 发布态 config 包含 `rulesetVersion`。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p spacetime-module bark_battle
|
||||
```
|
||||
|
||||
### Task 2.3: 实现 run start / finish reducer
|
||||
|
||||
**Objective:** 打通正式运行态后端事务。
|
||||
|
||||
**Reducers:**
|
||||
- `start_bark_battle_run`
|
||||
- `finish_bark_battle_run`
|
||||
- `get_bark_battle_run`
|
||||
|
||||
**Rules:**
|
||||
- start 创建 `run_id` 和一次性 `run_token`。
|
||||
- start 记录 work/config/ruleset/difficulty 快照。
|
||||
- finish 必须校验 run token、未 finish、work/config/ruleset/difficulty 一致。
|
||||
- finish 调用 `module-bark-battle` 裁决结果。
|
||||
- accepted 写 score record。
|
||||
- `serverResult = player_win` 且排行榜开启且未 rejected 时写 leaderboard entry。
|
||||
- accepted / accepted_with_flags 更新 work stats 和 personal best projection。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p spacetime-module bark_battle_run
|
||||
```
|
||||
|
||||
### Task 2.4: 更新 migration 与生成绑定
|
||||
|
||||
**Objective:** 让 SpacetimeDB 表结构变更可发布。
|
||||
|
||||
**Files:**
|
||||
- Modify: `server-rs/crates/spacetime-module/src/migration.rs`
|
||||
- Generated: `server-rs/crates/spacetime-client/src/module_bindings/*bark*`
|
||||
|
||||
**Commands:**
|
||||
按仓库现有脚本优先;不要手改 generated bindings。
|
||||
|
||||
```bash
|
||||
npm run spacetime:build
|
||||
npm run spacetime:generate
|
||||
```
|
||||
|
||||
若脚本名不同,先查 `package.json` 和 `server-rs` README。
|
||||
|
||||
### Task 2.5: 实现 spacetime-client facade
|
||||
|
||||
**Objective:** api-server 不直接操作 generated bindings。
|
||||
|
||||
**Files:**
|
||||
- Create: `server-rs/crates/spacetime-client/src/bark_battle.rs`
|
||||
- Modify: `server-rs/crates/spacetime-client/src/lib.rs`
|
||||
|
||||
**Methods:**
|
||||
- `create_bark_battle_draft`
|
||||
- `save_bark_battle_draft_config`
|
||||
- `publish_bark_battle_work`
|
||||
- `get_bark_battle_runtime_config`
|
||||
- `start_bark_battle_run`
|
||||
- `finish_bark_battle_run`
|
||||
- `list_bark_battle_leaderboard`
|
||||
- `list_my_bark_battle_history`
|
||||
- `get_my_bark_battle_best_summary`
|
||||
- `get_bark_battle_work_stats`
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p spacetime-client bark_battle
|
||||
```
|
||||
|
||||
### Task 2.6: 实现 api-server BFF 路由
|
||||
|
||||
**Objective:** 暴露前端需要的 HTTP API。
|
||||
|
||||
**Files:**
|
||||
- Create: `server-rs/crates/api-server/src/bark_battle.rs`
|
||||
- Modify: `server-rs/crates/api-server/src/app.rs`
|
||||
|
||||
**Routes:**
|
||||
- `POST /api/bark-battle/drafts`
|
||||
- `PATCH /api/bark-battle/drafts/:draftId`
|
||||
- `POST /api/bark-battle/drafts/:draftId/publish`
|
||||
- `GET /api/bark-battle/works/:workId/runtime-config`
|
||||
- `POST /api/bark-battle/runs/start`
|
||||
- `POST /api/bark-battle/runs/:runId/finish`
|
||||
- `GET /api/bark-battle/works/:workId/leaderboard`
|
||||
- `GET /api/bark-battle/me/history`
|
||||
- `GET /api/bark-battle/me/best-summary`
|
||||
- `GET /api/bark-battle/works/:workId/stats`
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
cargo test -p api-server bark_battle
|
||||
npm run api-server
|
||||
curl -f http://127.0.0.1:<api-port>/healthz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 阶段三:最小前端纵切
|
||||
|
||||
### Task 3.1: 新增前端 service client
|
||||
|
||||
**Files:**
|
||||
- Create: `src/services/bark-battle/barkBattleClient.ts`
|
||||
- Test: `src/services/bark-battle/barkBattleClient.test.ts`
|
||||
|
||||
**Methods:** 与 BFF routes 一一对应。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
npm test -- --run src/services/bark-battle/barkBattleClient.test.ts
|
||||
```
|
||||
|
||||
### Task 3.2: 接入创作入口与 SelectionStage
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/config/newWorkEntryConfig.ts`
|
||||
- Modify: `src/components/platform-entry/platformEntryCreationTypes.ts`
|
||||
- Modify: `src/components/platform-entry/platformEntryTypes.ts`
|
||||
- Modify: `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
|
||||
|
||||
**Rules:**
|
||||
- 新增 `bark-battle` play type。
|
||||
- 入口打开单页轻配置表单,不走复杂 agent workspace。
|
||||
- 移动端入口布局不能溢出。
|
||||
|
||||
### Task 3.3: 实现单页轻配置表单 + 预览卡片
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/bark-battle-creation/BarkBattleConfigEditor.tsx`
|
||||
- Create: `src/components/bark-battle-creation/BarkBattlePreviewCard.tsx`
|
||||
- Test: `src/components/bark-battle-creation/BarkBattleConfigEditor.test.tsx`
|
||||
|
||||
**UI fields:**
|
||||
- 标题必填
|
||||
- 简介选填
|
||||
- 主题/背景预设
|
||||
- 狗狗皮肤预设
|
||||
- 难度预设,默认 `normal`
|
||||
- 排行榜开关,默认开启
|
||||
|
||||
**UI constraints:**
|
||||
- 不堆大段玩法说明。
|
||||
- 按现有游戏 UI 风格设计。
|
||||
- 移动端优先。
|
||||
|
||||
### Task 3.4: 发布后进入作品详情
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
|
||||
- Modify: `src/components/platform-entry/PlatformWorkDetailView.tsx`
|
||||
- Modify: `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- Modify: `src/components/custom-world-home/creationWorkShelf.ts`
|
||||
|
||||
**Rules:**
|
||||
- 发布成功刷新 works/gallery/shelf。
|
||||
- 跳作品详情。
|
||||
- 详情 CTA 可以进入正式 runtime。
|
||||
|
||||
### Task 3.5: runtime 拉发布态 config 并 start / finish
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/games/bark-battle/*`
|
||||
- Modify: `src/games/bark-battle/ui/BarkBattleRuntimeShell.tsx`
|
||||
- Create/Modify: `src/components/bark-battle-runtime/BarkBattleRuntimeRoute.tsx` 如需要
|
||||
|
||||
**Rules:**
|
||||
- runtime 通过稳定 `workId` 拉 `BarkBattleRuntimeConfig`。
|
||||
- 开始正式局时调用 start run。
|
||||
- 结束时提交 finish 派生指标。
|
||||
- 结算展示 `serverResult`、`scoreSummary`、`antiCheatFlags`、leaderboard entry。
|
||||
- 麦克风原始音频不上传。
|
||||
|
||||
**Verification:**
|
||||
|
||||
```bash
|
||||
npm test -- --run src/games/bark-battle/domain/__tests__/BarkDetector.test.ts src/games/bark-battle/application/__tests__/BarkBattleController.test.ts src/games/bark-battle/ui/__tests__/BarkBattleRuntimeShell.test.tsx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 阶段四:投影与列表体验
|
||||
|
||||
### Task 4.1: 排行榜 UI
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/bark-battle-leaderboard/BarkBattleLeaderboardPanel.tsx`
|
||||
- Test: `src/components/bark-battle-leaderboard/BarkBattleLeaderboardPanel.test.tsx`
|
||||
- Modify: `src/components/platform-entry/PlatformWorkDetailView.tsx`
|
||||
|
||||
**Rules:**
|
||||
- 查询维度 `workId + difficultyPreset + rulesetVersion`。
|
||||
- 只展示胜利入榜成绩。
|
||||
- 不展示平/负/flagged 历史。
|
||||
|
||||
### Task 4.2: 个人历史最近记录 + 最佳摘要 UI
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/bark-battle-history/BarkBattlePersonalHistoryPanel.tsx`
|
||||
- Test: `src/components/bark-battle-history/BarkBattlePersonalHistoryPanel.test.tsx`
|
||||
|
||||
**Rules:**
|
||||
- 默认最近 20 条。
|
||||
- 仅本人可见。
|
||||
- 可按 workId / difficultyPreset 过滤。
|
||||
- flagged 只做轻提示,不展示详细反作弊原因。
|
||||
|
||||
### Task 4.3: 作品统计展示
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/bark-battle-stats/BarkBattleWorkStatsPanel.tsx`
|
||||
- Test: `src/components/bark-battle-stats/BarkBattleWorkStatsPanel.test.tsx`
|
||||
|
||||
**Fields:**
|
||||
- `playStartCount`
|
||||
- `finishCount`
|
||||
- `winCount`
|
||||
- `drawCount`
|
||||
- `lossCount`
|
||||
- `flaggedCount`
|
||||
- `leaderboardEntryCount`
|
||||
- `bestLeaderboardScore`
|
||||
- `bestFinalEnergy`
|
||||
- `averageFinalEnergy`
|
||||
- `updatedAt`
|
||||
|
||||
### Task 4.4: 广场卡片/我的作品适配
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/components/custom-world-home/creationWorkShelf.ts`
|
||||
- Modify: `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- Modify: `src/components/rpg-entry/rpgEntryWorldPresentation.ts`
|
||||
- Modify: `src/services/publicWorkCode.ts` 如分享码需要支持
|
||||
|
||||
**Rules:**
|
||||
- Bark Battle 作品能展示、打开详情、开始游玩。
|
||||
- 不新增独立 Bark Battle 专区。
|
||||
|
||||
---
|
||||
|
||||
## 6. 阶段五:收口验证
|
||||
|
||||
### Task 5.1: 自动测试清单
|
||||
|
||||
```bash
|
||||
cargo test -p shared-contracts bark_battle
|
||||
cargo test -p module-bark-battle
|
||||
cargo test -p spacetime-module bark_battle
|
||||
cargo test -p spacetime-client bark_battle
|
||||
cargo test -p api-server bark_battle
|
||||
npm test -- --run packages/shared/src/contracts/barkBattle.test.ts
|
||||
npm test -- --run src/services/bark-battle/barkBattleClient.test.ts
|
||||
npm test -- --run src/components/bark-battle-creation/BarkBattleConfigEditor.test.tsx
|
||||
npm test -- --run src/games/bark-battle/domain/__tests__/BarkDetector.test.ts src/games/bark-battle/application/__tests__/BarkBattleController.test.ts src/games/bark-battle/ui/__tests__/BarkBattleRuntimeShell.test.tsx
|
||||
npx tsc -p tsconfig.typecheck-guardrails.json --noEmit --pretty false
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
```
|
||||
|
||||
### Task 5.2: 后端 smoke
|
||||
|
||||
1. 按项目脚本启动 SpacetimeDB + api-server,优先使用 `npm run api-server`,不要使用旧命令。
|
||||
2. 确认 `/healthz`。
|
||||
3. smoke 流程:创建草稿 → 保存配置 → 发布 → 拉 runtime config → start run → finish run → 查询 leaderboard/history/stats。
|
||||
|
||||
### Task 5.3: 人工验收路径
|
||||
|
||||
1. 进入创作入口/玩法选择,选择 Bark Battle。
|
||||
2. 在单页轻配置表单中填写标题,选择主题、狗狗皮肤、难度,保持排行榜开启。
|
||||
3. 保存草稿。
|
||||
4. 发布作品。
|
||||
5. 发布后自动进入作品详情。
|
||||
6. 点击开始游玩进入正式 runtime。
|
||||
7. 授权麦克风,完成 30 秒单局。
|
||||
8. 结算页显示后端 `serverResult` 和 score summary。
|
||||
9. 若胜利,排行榜出现本局成绩。
|
||||
10. 我的记录显示最近记录和个人最佳摘要。
|
||||
11. 作品详情/作者视角能看到作品统计。
|
||||
12. 广场/作品卡片和我的作品入口都能再次进入详情和 runtime。
|
||||
|
||||
---
|
||||
|
||||
## 7. 不做范围
|
||||
|
||||
- 不做实时多人。
|
||||
- 不做 ghost replay。
|
||||
- 不做 AI 狗叫识别。
|
||||
- 不保存原始音频、PCM、waveform 或可还原语音内容。
|
||||
- 不做独立 Bark Battle 专区/活动页。
|
||||
- 不做挑战分享、好友邀请、多人数房间。
|
||||
- 不做复杂编辑器、多步骤向导、规则参数编辑、AI 生成配置。
|
||||
- 不做 DAU/留存、按小时统计曲线、好友对比。
|
||||
|
||||
---
|
||||
|
||||
## 8. 三人并行建议
|
||||
|
||||
### 开发者 A:后端契约与领域规则
|
||||
|
||||
负责 Task 1.1、1.3、1.4。先提交 contracts 与 `module-bark-battle`,为后续后端/前端提供稳定类型和裁决规则。
|
||||
|
||||
### 开发者 B:SpacetimeDB + api-server
|
||||
|
||||
负责 Task 2.1 到 2.6。必须等开发者 A 的 DTO/领域规则基本稳定后开始,或先基于计划字段开分支实现表结构。
|
||||
|
||||
### 开发者 C:前端纵切与 UI
|
||||
|
||||
负责 Task 3.x 与 4.x。开始时可先做组件空态和 service client 类型,真正联调等 B 的 BFF ready。
|
||||
|
||||
---
|
||||
|
||||
## 9. 推荐提交节奏
|
||||
|
||||
1. `feat: add bark battle contracts and domain rules`
|
||||
2. `feat: add bark battle spacetime tables and reducers`
|
||||
3. `feat: add bark battle api server routes`
|
||||
4. `feat: add bark battle creation editor`
|
||||
5. `feat: connect bark battle runtime to server results`
|
||||
6. `feat: add bark battle leaderboard history stats`
|
||||
7. `docs: finalize bark battle phase2 verification guide`
|
||||
|
||||
---
|
||||
|
||||
## 10. 完成定义
|
||||
|
||||
Phase 2 完成必须同时满足:
|
||||
|
||||
- Bark Battle 可以从正式创作入口创建轻配置作品。
|
||||
- 作品可以发布为稳定 workId。
|
||||
- 作品详情/广场/我的作品可以发现并进入正式 runtime。
|
||||
- runtime 从后端发布态 config 拉配置。
|
||||
- start run 写 `work_play_start`。
|
||||
- finish 只上传派生指标。
|
||||
- 后端裁决 `serverResult` / `scoreSummary` / `leaderboardScore` / `antiCheatFlags`。
|
||||
- 胜利局进入按 `workId + difficultyPreset + rulesetVersion` 分榜的排行榜。
|
||||
- 个人历史和作品统计可查询。
|
||||
- 自动测试、encoding、typecheck、diff check 和人工验收路径通过。
|
||||
@@ -127,6 +127,22 @@
|
||||
- 验证方式:执行 `npm run check:encoding`、`node scripts/check-wechat-miniprogram-auth-smoke.mjs`、`cargo test -p shared-contracts wechat_bind_phone_request_accepts_mini_program_phone_code --manifest-path server-rs/Cargo.toml`、`cargo test -p api-server wechat_miniprogram_bind_phone_code_activates_pending_user --manifest-path server-rs/Cargo.toml -- --nocapture`。
|
||||
- 关联文档:`docs/technical/WECHAT_MINIPROGRAM_WEB_VIEW_SHELL_2026-05-03.md`。
|
||||
|
||||
## 2026-05-13 宝贝爱画先作为寓教于乐独立本地 Demo 落地
|
||||
|
||||
- 背景:第三关 `宝贝爱画` 需要默认出现在“发现 / 寓教于乐”板块下方,但本阶段只验证画板、手部绘制、绘画魔法和本地保存闭环,不进入创作模板、公开作品或正式持久化。
|
||||
- 决策:`baby-love-drawing / 宝贝爱画` 先作为独立运行态接入,入口由发现页寓教于乐默认卡片打开,并支持 `/runtime/baby-love-drawing` 直达;关闭 `VITE_ENABLE_EDUTAINMENT_ENTRY` 时前端不展示频道/卡片且直达路由回落主应用。绘画魔法统一走 `POST /api/creation/edutainment/baby-love-drawing/magic` 后端安全代理,使用 VectorEngine `gpt-image-2-all` 与原始画布 Data URL 参考图生成绘本风图片;保存只写 localStorage,正式持久化后续再设计。
|
||||
- 影响范围:`packages/shared/src/contracts/edutainmentBabyDrawing.ts`、`src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx`、`src/services/edutainment-baby-drawing/`、`src/routing/appRoutes.tsx`、`src/components/rpg-entry/RpgEntryHomeView.tsx`、`server-rs/crates/api-server/src/edutainment_baby_drawing.rs`、`src/index.css`、宝贝爱画 PRD 与技术方案。
|
||||
- 验证方式:执行宝贝爱画 model/runtime/service/route 定向测试、`npm run typecheck`、定向 ESLint、`cargo test -p api-server edutainment_baby_drawing --manifest-path server-rs/Cargo.toml`、`cargo test -p api-server resolves_runtime_paths_to_creation_type_ids --manifest-path server-rs/Cargo.toml` 和编码检查;真实魔法生成需配置 `VECTOR_ENGINE_BASE_URL` 与 `VECTOR_ENGINE_API_KEY`。
|
||||
- 关联文档:`docs/prd/BABY_LOVE_DRAWING_EDUTAINMENT_LEVEL_PRD_2026-05-13.md`、`docs/technical/BABY_LOVE_DRAWING_RUNTIME_DEMO_IMPLEMENTATION_2026-05-13.md`。
|
||||
|
||||
## 2026-05-12 宝贝识物创作同时生成玩法视觉主题包
|
||||
|
||||
- 背景:`宝贝识物` 创作原本只根据两个关键词生成物品透明图,运行态背景、UI、礼物盒和篮子仍使用固定 CSS 绘本风,无法根据“小猪佩琪 / 奥特曼”或“苹果 / 橘子”等创作者提示词做主题化包装。
|
||||
- 决策:`POST /api/creation/edutainment/baby-object-match/assets` 同一次 image-2 / VectorEngine 调用链返回两个物品图和 `visualPackage`。视觉包包含 `background`、`ui-frame`、`gift-box`、`basket`、`smoke-puff` 五类资源;总风格保持寓教于乐明亮卡通绘本插画风,主题按两个物品关键词匹配,水果偏果园自然,动漫角色 / 玩具偏动漫玩具。物品图和礼物盒 / 篮子 / UI / 烟雾特效资源走透明 PNG 后处理,背景为清爽不遮挡玩法区的环境图;运行态中礼物盒按约 2 倍视觉尺寸展示、篮子按约 1.5 倍展示,礼物盒打开时使用 `smoke-puff` 弹出中央物品并移除礼盒。前端草稿保存该包,运行态消费该包;旧草稿以 `visualPackage = null` 继续使用 CSS 兜底。
|
||||
- 影响范围:`packages/shared/src/contracts/edutainmentBabyObject.ts`、`server-rs/crates/api-server/src/edutainment_baby_object.rs`、`src/services/edutainment-baby-object/babyObjectMatchClient.ts`、`src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.tsx`、`src/index.css`、宝贝识物 PRD 与技术方案。
|
||||
- 验证方式:执行宝贝识物 service / runtime 定向测试、`cargo test -p api-server edutainment_baby_object --manifest-path server-rs/Cargo.toml`、相关 ESLint 与编码检查;真实生图需配置 `VECTOR_ENGINE_BASE_URL` 与 `VECTOR_ENGINE_API_KEY`。
|
||||
- 关联文档:`docs/prd/BABY_OBJECT_MATCH_EDUTAINMENT_TEMPLATE_PRD_2026-05-11.md`、`docs/technical/BABY_OBJECT_MATCH_CREATION_PUBLISH_IMPLEMENTATION_2026-05-11.md`。
|
||||
|
||||
## 2026-05-11 拼图与抓大鹅结果页音频资产复用通用创作音频链路
|
||||
|
||||
- 背景:拼图和抓大鹅结果页需要接入 Suno 背景音乐,抓大鹅还需要物体点击音效,但当前两类作品没有独立的作品级音频表或 metadata 字段。
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
- `operations/`:后台运营核查、对账和排障查询。
|
||||
- `prd/`:产品需求与阶段计划。
|
||||
|
||||
新增 Markdown 文档文件名必须以分类标签开头,格式为 `【标签名】中文标题-日期.md`。标签用于跨目录检索,不替代 `docs/` 的目录分类;历史文档不要求批量重命名。
|
||||
|
||||
## 推荐阅读顺序
|
||||
|
||||
通用复杂任务:
|
||||
@@ -96,5 +98,6 @@ RPG 创作与运行时链路:
|
||||
|
||||
- 新增工程实现时,如果已有对应文档,必须同步更新。
|
||||
- 如果没有对应文档,新文档放入 `docs/` 下合适分类。
|
||||
- 新文档文件名必须使用 `【标签名】` 前缀,标题尽量保留中文语义,日期使用 `YYYY-MM-DD`。
|
||||
- `.hermes/shared-memory/` 只保留跨任务、跨成员、高频使用的摘要和索引。
|
||||
- 如果文档与代码冲突,先确认代码事实,再更新过期文档和共享记忆。
|
||||
|
||||
@@ -93,15 +93,55 @@
|
||||
- 验证:运行 `npx vitest run src\services\useMocapInput.test.ts src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx`,并在本地硬件服务启动后进入 `/child-motion-demo` 实测站位、招手、左右手挥动和跳跃阶段。
|
||||
- 关联:`src/services/useMocapInput.ts`、`src/components/child-motion-demo/ChildMotionWarmupDemo.tsx`、`docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`。
|
||||
|
||||
## 儿童动作 Demo 左右手阶段误通过先查身体侧映射和手臂展开阈值
|
||||
|
||||
- 现象:热身关“挥动左手 / 挥动右手”阶段,用户只是手自然下垂、横向小幅抖动,或挥了相反侧手,也可能被判定通过。
|
||||
- 原因:本地 mocap 的 handedness 当前按摄像头视角输出,不能直接当作用户身体左/右;同时左右手阶段的目标是确认现实空间安全,需要验证手臂向外打开和上下摆动角度,不能只看手部 `x` 轨迹范围。
|
||||
- 处理:热身关中用户左手应消费 camera-right,用户右手应消费 camera-left;左右手阶段只在同侧肩肘腕外展、手腕非自然下垂、连续有效帧、横向范围、上下摆动范围、肩腕角度范围和上下方向变化全部达标时完成,并记录轨迹空间包络、角度范围和最大外展距离。
|
||||
- 验证:运行 `npx vitest run src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx src\components\child-motion-demo\childMotionWarmupModel.test.ts`,确认相反侧手、自然下垂、单纯横向轨迹不会完成,真实展开上下摆动可以完成。
|
||||
- 关联:`src/components/child-motion-demo/ChildMotionWarmupDemo.tsx`、`src/components/child-motion-demo/childMotionWarmupModel.ts`、`docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`。
|
||||
|
||||
## 儿童动作 Demo 角色轮廓抽搐先查 mocap 坐标防抖和渲染分层
|
||||
|
||||
- 现象:`/child-motion-demo` 中间半透明小人在真实硬件驱动下左右轻微来回摆,移动过程中看起来忽大忽小,用户很难稳定停在目标圆环内。
|
||||
- 原因:`general.body.center_norm.x` 原始值逐包直接写入 `avatarX` 时,硬件坐标小噪声会直接驱动位置保持判定和 CSS 动画;如果角色外层同时承担横向定位和跳跃 `transform`,半透明 PNG 在移动时也更容易出现重采样抖动观感。
|
||||
- 处理:mocap 身体中心进入角色位置前必须先 clamp,再经过小幅死区、低通阻尼和单包最大步长限制;键盘 A/D 调试输入仍保持即时。角色 DOM 外层只负责横向定位,内层 sprite 负责轮廓图和跳跃位移,避免同一层 `transform` 同时表达多种运动。
|
||||
- 验证:运行 `npx vitest run src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx src\components\child-motion-demo\childMotionWarmupModel.test.ts src\services\useMocapInput.test.ts src\services\child-motion-demo\childMotionDebugInput.test.ts`,并用真实硬件进入站位阶段观察小幅身体晃动不会导致角色频繁左右跳动。
|
||||
- 关联:`src/components/child-motion-demo/ChildMotionWarmupDemo.tsx`、`src/index.css`、`docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`。
|
||||
|
||||
## 宝贝识物选篮误触发先查多套判定和残余轨迹
|
||||
|
||||
- 现象:`宝贝识物` 运行态打开礼物盒或反馈结束后,当前物品被连续送入左侧或右侧篮子,或硬件动作名偶发命中导致未做明确横移动作也触发选篮。
|
||||
- 原因:选篮如果同时消费 `wave_left_hand` / `wave_right_hand` / `wave` 动作名和手部轨迹,或在 `correct` / `wrong` 反馈阶段继续累计手部路径,会把抓握、反馈期间残留移动或未知侧别手部误算成下一次选篮。
|
||||
- 处理:宝贝识物选篮只使用明确 `leftHand` / `rightHand` 的连续横向轨迹阈值;侧别为 `unknown` 的手部轨迹不参与选篮;礼物盒打开和反馈阶段清空轨迹,不在非 `active` 阶段累计路径。礼物盒激活仍使用 `open_palm -> grab` 抓握序列。
|
||||
- 处理:宝贝识物选篮只使用明确 `leftHand` / `rightHand` 的连续横向轨迹阈值;侧别为 `unknown` 的手部轨迹不参与选篮;反馈阶段清空轨迹,不在非 `active` 阶段累计路径。进入关卡和每次正确反馈结束后自动弹出物品,不再用 `open_palm -> grab` 抓握序列激活礼物盒。
|
||||
- 补充:当前本地 mocap 的 handedness 是摄像头视角,宝贝识物选篮前需要换算为用户身体视角;`rightHand` 轨迹代表玩家左手并进入左篮,`leftHand` 轨迹代表玩家右手并进入右篮。键鼠调试不走该换算,仍保持鼠标左键=左篮、右键=右篮。
|
||||
- 验证:运行 `npm run test -- src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.test.tsx src/services/useMocapInput.test.ts`,确认动作名负向测试、未知侧别负向测试和左右手横向轨迹测试通过。
|
||||
- 关联:`src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.tsx`、`docs/technical/BABY_OBJECT_MATCH_CREATION_PUBLISH_IMPLEMENTATION_2026-05-11.md`。
|
||||
|
||||
## 宝贝爱画左右手反了先查 mocap 摄像头视角换算
|
||||
|
||||
- 现象:`宝贝爱画` 中真实硬件下左手指示器和右手画笔表现反向,用户抬右手却出现左手选色指示器,或抬左手却驱动画笔 / 橡皮。
|
||||
- 原因:本地 mocap 的 handedness 当前按摄像头视角输出,不能直接当成用户身体左 / 右;宝贝爱画初版直接消费 `latestCommand.leftHand/rightHand`,漏做摄像头视角到用户身体视角的换算。
|
||||
- 处理:宝贝爱画运行态消费 mocap 前先换算:`rightHand` 作为用户左手,用于颜色悬停和左手指示器;`leftHand` 作为用户右手,用于画笔 / 橡皮光标、绘制、擦除和工具切换。键鼠调试输入不做该换算,继续保持鼠标左键为左手、右键为右手。
|
||||
- 验证:运行 `npm run test -- src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.test.tsx src/components/edutainment-runtime/babyLoveDrawingModel.test.ts`,确认 camera-left 驱动用户右手画笔、camera-right 渲染用户左手选色指示器。
|
||||
- 关联:`src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx`、`docs/technical/BABY_LOVE_DRAWING_RUNTIME_DEMO_IMPLEMENTATION_2026-05-13.md`。
|
||||
|
||||
## 宝贝识物创作卡在准备结果页先查长耗时 image-2 请求
|
||||
|
||||
- 现象:`/creation/baby-object-match` 创作生成停在“准备结果页”,约 3 分钟后显示“生成失败 / 请求超时”;后端日志可能出现同一路由 `status=502 latency_ms=231291`,或前端已失败但后端稍后返回 200。
|
||||
- 原因:宝贝识物一次创作会生成 2 张物品图和 `background`、`ui-frame`、`gift-box`、`basket`、`smoke-puff` 5 张视觉包装图。旧前端只等待 180 秒并对长耗时 POST 自动重试,容易在 VectorEngine 仍在生成时先 abort,再重复发起第二次生成;上游某张图超过后端 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS` 或返回 5xx 时会表现为 502。
|
||||
- 处理:`babyObjectMatchClient` 对 `/api/creation/edutainment/baby-object-match/assets` 使用 10 分钟超时并取消自动重试;后端并发启动物品图和视觉主题包生成,并把该路由的 VectorEngine 单图请求等待预算提升到至少 8 分钟,按资源类别输出开始、完成和耗时日志。
|
||||
- 验证:运行 `npm run test -- src/services/edutainment-baby-object/babyObjectMatchClient.test.ts src/services/miniGameDraftGenerationProgress.test.ts`、`cargo test -p api-server edutainment_baby_object --manifest-path server-rs/Cargo.toml` 和编码检查;真实联调时查看 `宝贝识物 image-2 资源生成完成` 耗时是否小于前端超时,若仍 502 再看 `VectorEngine 图片生成上游错误` 的 `upstreamStatus/raw_excerpt`。
|
||||
- 关联:`src/services/edutainment-baby-object/babyObjectMatchClient.ts`、`src/services/miniGameDraftGenerationProgress.ts`、`server-rs/crates/api-server/src/edutainment_baby_object.rs`、`docs/technical/BABY_OBJECT_MATCH_CREATION_PUBLISH_IMPLEMENTATION_2026-05-11.md`。
|
||||
|
||||
## 寓教于乐作品和宝贝识物模板同时消失先查入口种子
|
||||
|
||||
- 现象:发现页“寓教于乐”分类下已发布的宝贝识物作品突然消失,同时创作界面模板选项中也看不到或无法正常展示 `宝贝识物`。
|
||||
- 原因:创作入口配置事实源已迁到 SpacetimeDB `creation_entry_type_config`;前端用 `baby-object-match` 入口可见性同时控制创作模板展示和发现页宝贝识物公开作品合入。若默认种子或后台配置缺少 `baby-object-match` 行,两条链路会一起被判定为不可见。
|
||||
- 处理:确认 `server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs` 默认种子包含 `id=baby-object-match`、`title=宝贝识物`、`visible=true`、`open=true`、`sort_order=90`;api-server 测试降级配置也要同步包含该类型。入口图片路径需指向真实存在资源,避免卡片图片 404。
|
||||
- 验证:运行 `cargo test -p module-runtime default_creation_entry_types_include_baby_object_match --manifest-path server-rs/Cargo.toml`、`cargo test -p api-server test_creation_entry_config_response_keeps_baby_object_match_visible --manifest-path server-rs/Cargo.toml`、`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 和 `npm run test -- src/components/platform-entry/platformEntryCreationTypes.test.ts`。
|
||||
- 关联:`server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs`、`server-rs/crates/api-server/src/creation_entry_config.rs`、`docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md`。
|
||||
|
||||
## 儿童动作 Demo 绘本风资源未生成先查 VectorEngine 配置
|
||||
|
||||
- 现象:`/child-motion-demo` 已经呈现绘本草地风格,但 `public/child-motion-demo/picture-book-grass-stage.png`、`picture-book-grass-floor.png`、`picture-book-ground-ring.png`、`picture-book-character-outline.png`、`picture-book-ui-panel.png` 或 `picture-book-ui-button.png` 不存在,Network 里对应图片返回 404,或运行 `npm run assets:child-motion-demo -- --live` 返回缺少 VectorEngine 配置。
|
||||
@@ -250,8 +290,8 @@
|
||||
|
||||
- 现象:本地 `npm run dev` 因 `3101` 已占用、重复发布 SpacetimeDB wasm 编译太慢,或只想检查 `spacetime-module` 语法而被完整联调链路拖慢。
|
||||
- 原因:`npm run dev` 默认同时启动 SpacetimeDB standalone、发布 `server-rs/crates/spacetime-module`、启动 Rust `api-server`、主站 Vite 与后台 Vite;并非每个阶段都需要完整重启和重新发布。
|
||||
- 处理:`npm run dev` 启动后会把实际 SpacetimeDB URL 记录到 `server-rs/.spacetimedb/local/data/dev-rust-spacetime-url`。下次启动即使没有传 `--skip-spacetime`,脚本也会先检查 `spacetime.pid` 对应进程和该 URL 是否在线;在线则直接复用现有宿主。确认需要新启动 SpacetimeDB 时,脚本先检测 `3101`,被占用则输出占用进程并选择最近可用端口,保证 publish 与 `api-server` 都连接同一个实际 SpacetimeDB URL。`api-server` 启动前也会检测 `8082` 并选择最近可用端口。Windows / Git Bash 下不要用 `tr/head/xargs` 管道读取 `spacetime.pid` 或 URL 记录,脚本应使用 Node 读取并短重试,避免 `tr: read error: Device or resource busy`;未修改 `spacetime-module` 时使用 `npm run dev -- --skip-publish`;只查模块语法时执行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。`npm run dev` 会在启动前检查 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,不可用时自动寻找后续可用端口,并把实际端口传给 publish、后端环境变量和前端代理目标。
|
||||
- 验证:`--skip-spacetime` 后脚本复用现有 `http://127.0.0.1:3101`;`3101` 或 `8082` 被其他进程占用时,脚本输出占用进程并使用最近可用端口;`--skip-publish` 后不再进入 publish 阶段;`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 能完成 Rust 语法和类型检查。端口漂移时控制台会打印 `[dev:ports] ... 不可用,改用 ...`,后续 `[dev:rust] web/admin web/rust api/spacetime` 地址应与实际端口一致。
|
||||
- 处理:`npm run dev` 启动后会把实际 SpacetimeDB URL 记录到 `server-rs/.spacetimedb/local/data/dev-rust-spacetime-url`。下次启动即使没有传 `--skip-spacetime`,脚本也会先检查 `spacetime.pid` 对应进程和该 URL 是否在线;在线则直接复用现有宿主。确认需要新启动 SpacetimeDB 时,脚本先检测 `3101`,被占用则输出占用进程并选择最近可用端口,保证 publish 与 `api-server` 都连接同一个实际 SpacetimeDB URL。显式传 `--skip-spacetime` 时表示复用既有宿主,脚本不再对 SpacetimeDB 端口做可用性漂移;`--spacetime-port 3101` 就是后端要连接的实际端口,避免被误改到空闲但未启动的 `3102`。`api-server` 启动前也会检测 `8082` 并选择最近可用端口。Windows / Git Bash 下不要用 `tr/head/xargs` 管道读取 `spacetime.pid` 或 URL 记录,脚本应使用 Node 读取并短重试,避免 `tr: read error: Device or resource busy`;未修改 `spacetime-module` 时使用 `npm run dev -- --skip-publish`;只查模块语法时执行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`。`npm run dev` 会在启动前检查 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,不可用时自动寻找后续可用端口,并把实际端口传给 publish、后端环境变量和前端代理目标。
|
||||
- 验证:`--skip-spacetime` 后脚本复用现有 `http://127.0.0.1:3101`;日志中的 `[dev:rust] spacetime:` 不应漂移到没有服务的 `3102`;`GET /api/creation-entry/config` 不应返回连接空端口导致的 `502`。`3101` 或 `8082` 被其他进程占用时,脚本输出占用进程并使用最近可用端口;`--skip-publish` 后不再进入 publish 阶段;`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 能完成 Rust 语法和类型检查。端口漂移时控制台会打印 `[dev:ports] ... 不可用,改用 ...`,后续 `[dev:rust] web/admin web/rust api/spacetime` 地址应与实际端口一致。
|
||||
- 关联:`docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`、`scripts/dev-rust-stack.sh`。
|
||||
|
||||
## 本地 SpacetimeDB publish 401 可清本地库重发
|
||||
@@ -654,6 +694,14 @@
|
||||
- 验证:mock 通知测试只能覆盖本地回调推进;真实环境还需用微信支付平台公钥、真实通知头和 API v3 密钥验证签名与解密链路。
|
||||
- 关联:`server-rs/crates/api-server/src/wechat_pay.rs`、`docs/technical/MY_TAB_ACCOUNT_RECHARGE_IMPLEMENTATION_2026-04-25.md`。
|
||||
|
||||
## 后台表查询展示 SpacetimeDB 枚举时不要套用 Option 解码
|
||||
|
||||
- 现象:后台“表查询”查看 `profile_recharge_order` 时,`kind` 和 `status` 显示为空数组 `[]`,例如充值订单原始行里 `points_60` 的类型和状态都不可读。
|
||||
- 原因:SpacetimeDB HTTP SQL 对无载荷枚举会返回 SATS 形态 `[variant_index, []]`;后台通用 normalizer 曾把任何 `[0, value]` 都当作 `Option::Some(value)` 展开,导致 `[0, []]` 最终只剩 `[]`。
|
||||
- 处理:通用表查询解析应先按表名和列名识别已知业务枚举,再落回 Option / Timestamp 通用展开;例如 `profile_recharge_order.kind` 映射为 `points` / `membership`,`profile_recharge_order.status` 映射为 `pending` / `paid` / `failed` / `closed` / `refunded`。
|
||||
- 验证:执行 `cargo test -p api-server admin_database -- --nocapture`,并确认后台详情弹层的 `raw` 与表格 `cells` 都显示业务字符串。
|
||||
- 关联:`server-rs/crates/api-server/src/admin.rs`、`docs/technical/ADMIN_DATABASE_TABLE_QUERY_2026-05-08.md`。
|
||||
|
||||
## 抓大鹅历史草稿外部 Rodin GLB 链接必须转存后再试玩或发布
|
||||
|
||||
- 现象:草稿页预览模型失败并报 `GL_INVALID_ENUM: Invalid cap.`,或结果页能看到历史生成记录但试玩、发布和正式运行态仍显示默认积木。
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
- `.hermes/shared-memory/` 团队级长期记忆
|
||||
- `.hermes/plans/` 阶段性实施计划
|
||||
- `.hermes/todos/` 已确定需要执行、但尚未进入实施的共享 TODO 计划
|
||||
- `.hermes/skills/` 未来可复用仓库级 skills
|
||||
- `docs/` 中 PRD、设计、技术、经验、审计、查询手册
|
||||
- `AGENTS.md` 项目级 Agent 约束
|
||||
@@ -41,6 +42,7 @@
|
||||
|
||||
- 保持修改范围聚焦,不做无关重构。
|
||||
- 复用、修改、扩展现有系统优先,避免新建重复系统或页面。
|
||||
- 新增 Markdown 文档时,文件名必须以分类标签开头,格式为 `【标签名】中文标题-日期.md`;只在任务需要时重命名历史文档,避免无关大 diff。
|
||||
- 涉及中文文本时注意 UTF-8 编码和乱码排查。
|
||||
- 涉及后端时遵循 DDD 分层,不把业务真相下沉到前端或临时兼容层。
|
||||
- `maincloud` / `Maincloud` / `MAINCLOUD` 相关代码、脚本、测试、环境变量、命令和文档要求均视为历史残留,禁止新增、运行或引用;API smoke 统一使用 `npm run api-server` 与 `/healthz`。
|
||||
@@ -51,9 +53,10 @@
|
||||
|
||||
1. 运行与修改范围匹配的测试或验证命令。
|
||||
2. 更新相关 `docs/` 文档。
|
||||
3. 若产生长期有效知识,更新 `.hermes/shared-memory/`。
|
||||
4. 若形成可复用流程,考虑沉淀到 `.hermes/skills/`。
|
||||
5. 在提交信息中区分代码变更与文档/记忆变更。
|
||||
3. 新增或沉淀 Markdown 文档时,确认文件名已使用 `【标签名】` 前缀。
|
||||
4. 若产生长期有效知识,更新 `.hermes/shared-memory/`。
|
||||
5. 若形成可复用流程,考虑沉淀到 `.hermes/skills/`。
|
||||
6. 在提交信息中区分代码变更与文档/记忆变更。
|
||||
|
||||
## 文档阅读顺序
|
||||
|
||||
|
||||
15
.hermes/todos/README.md
Normal file
15
.hermes/todos/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 项目共享 TODO 计划
|
||||
|
||||
本目录用于存放已经讨论定稿、需要后续执行,但当前尚未实施的项目级计划文档。
|
||||
|
||||
## 使用规则
|
||||
|
||||
- 每个 TODO 计划单独一个 Markdown 文件,文件名优先使用可检索的中文标题与日期。
|
||||
- 每个 TODO 计划文件名必须以分类标签开头,格式为 `【标签名】中文标题-日期.md`。
|
||||
- 计划内容必须足够明确,后续开发者可以直接据此开始实施。
|
||||
- 已执行完成的计划应迁移到对应 `docs/` 技术/规划文档,或在本文档中标记完成并移出 TODO 队列。
|
||||
- 不在这里保存个人私密路径、密钥、临时聊天记录或未确认猜测。
|
||||
|
||||
## 当前待执行
|
||||
|
||||
- [【后端架构】api-server 能力模块化与图片资产 Adapter 收口计划](./【后端架构】api-server能力模块化与图片资产Adapter收口计划-2026-05-14.md)
|
||||
@@ -0,0 +1,108 @@
|
||||
# api-server 能力模块化与生成资产 Adapter 完整收口计划
|
||||
|
||||
状态:待执行
|
||||
|
||||
## Summary
|
||||
|
||||
目标是把 `api-server` 从“超大 `app.rs` + 多个超大 handler 文件 + 多处生成资产重复链路”收成可长期维护的能力 Module 结构。
|
||||
|
||||
本计划完整覆盖:路由能力模块化、生成图片资产 Adapter、复杂媒体链路扩展、大 handler 瘦身、文档与验收。全程不改变 HTTP contract、DTO、SpacetimeDB schema、前端行为和计费语义,除非某阶段文档先明确提出并单独批准。
|
||||
|
||||
## 文档交付
|
||||
|
||||
先新增一个总纲,再按阶段新增单独执行文档:
|
||||
|
||||
- 总纲:`docs/technical/【后端架构】api-server能力模块化与生成资产Adapter总纲-2026-05-14.md`
|
||||
- 阶段 1:`docs/technical/【后端架构】api-server路由能力模块化执行计划-2026-05-14.md`
|
||||
- 阶段 2:`docs/technical/【后端架构】生成图片资产Adapter收口执行计划-2026-05-14.md`
|
||||
- 阶段 3:`docs/technical/【后端架构】复杂媒体资产链路Adapter扩展计划-2026-05-14.md`
|
||||
- 阶段 4:`docs/technical/【后端架构】api-server大Handler瘦身执行计划-2026-05-14.md`
|
||||
- 同步更新 `server-rs/crates/api-server/README.md`、`docs/technical/README.md`、本 TODO 文档。
|
||||
|
||||
## 阶段 0:基线盘点与总纲冻结
|
||||
|
||||
- 盘点 `app.rs` 当前全部 route,按 `admin/auth/assets/profile/creation/runtime/story/platform/internal` 分类形成 route inventory。
|
||||
- 盘点 Big Fish、Square Hole、Custom World、Puzzle、Match3D、Visual Novel、音频、视频、GLB 的生成资产链路,标出 provider、下载方式、OSS prefix、asset kind、entity binding、计费位置、降级行为。
|
||||
- 在总纲文档中冻结边界:`api-server` 只做 HTTP/SSE/BFF、鉴权、DTO 映射、平台服务编排;领域规则仍归 `module-*`,SpacetimeDB 真相仍归 `spacetime-module`。
|
||||
|
||||
退出条件:总纲和 inventory 能指导后续编码,不再只是一段方向描述。
|
||||
|
||||
## 阶段 1:路由能力模块化完整收口
|
||||
|
||||
- 新增 `server-rs/crates/api-server/src/modules/`,每个能力 Module 暴露 `router(state) -> Router<AppState>`。
|
||||
- 第一批迁移低风险路由:`admin`、`auth`、`assets`、`profile`、`internal`、`health`。
|
||||
- 第二批迁移平台编排路由:`ai_tasks`、`llm`、`speech`、`wechat`、`creative_agent`、`visual_novel`、通用 audio。
|
||||
- 第三批迁移玩法路由:`big_fish`、`square_hole`、`puzzle`、`match3d`、`custom_world`、`story`、runtime save/settings/chat/inventory。
|
||||
- `app.rs` 最终只保留全局 middleware、TraceLayer、request context、tracking middleware、`.merge(modules::*::router(...))` 和少量顶层 glue。
|
||||
- handler 实现第一阶段可以继续留在原文件;本阶段只改变路由装配位置,不混入业务重构。
|
||||
|
||||
验收:route inventory 中所有原 route 仍存在;旧明确下线 route 继续 404;`cargo test -p api-server app --manifest-path server-rs/Cargo.toml` 或等价 route 回归通过。
|
||||
|
||||
## 阶段 2:稳定单图生成资产 Adapter 收口
|
||||
|
||||
- 新增 `modules/assets/generated_image_assets` 内部 Module,Interface 覆盖“provider 生成 -> 下载/base64 解码 -> MIME/extension 归一 -> OSS private upload -> HEAD -> asset_object confirm -> entity binding”。
|
||||
- Adapter 输入包含 provider、prompt、negative prompt、size、reference images、OSS prefix/path/file name、asset kind、entity kind/id、slot、owner/profile/source_job_id、metadata、可选透明背景后处理。
|
||||
- Adapter 输出包含 `legacy_public_path`、`object_key`、`asset_object_id`、`mime_type`、`extension`、`task_id`、`actual_prompt`。
|
||||
- 首批迁移:
|
||||
- Big Fish 正式图片:主图、动作图、舞台背景。
|
||||
- Square Hole 图片:保留生成成功但入库失败时回退 Data URL。
|
||||
- Custom World 场景图、自动草稿场景图、生成封面图。
|
||||
- `asset_billing.rs` 仍由调用方显式包裹;Adapter 不扣费、不退款、不读钱包。
|
||||
|
||||
验收:三类调用方都经过同一 Adapter;删除旧重复 persist 函数后行为不变;Big Fish、Square Hole、Custom World 定向测试通过。
|
||||
|
||||
## 阶段 3:复杂媒体资产链路扩展
|
||||
|
||||
- 扩展 Adapter,但不把玩法图像处理规则塞进公共 Interface。
|
||||
- Puzzle:
|
||||
- 收口普通 generations、edits/multipart 生成结果的下载、OSS、asset object、binding。
|
||||
- 拼图关卡 JSON 更新、参考图策略、UI 背景落位仍留在 Puzzle 编排层。
|
||||
- Match3D:
|
||||
- APIMart material sheet、VectorEngine 背景/容器/封面生成接入统一入库能力。
|
||||
- 5x5 切图、绿幕透明化、格内校准、批量新增补齐规则仍留在 Match3D 专属处理器。
|
||||
- 音频:
|
||||
- 评估是否抽 `generated_media_assets`,但背景音乐、点击音效的计费和落位语义不与图片 Adapter 混用。
|
||||
- GLB/视频:
|
||||
- 仅历史转存链路复用“OSS + asset_object + binding”底层持久化能力,不恢复新草稿 GLB 生产。
|
||||
|
||||
验收:Puzzle 与 Match3D 的 generated 私有资产仍通过 `/api/assets/read-url` 换签读取;Match3D 不回退 Rodin/GLB;音频试听和运行态仍可播放。
|
||||
|
||||
## 阶段 4:超大 handler 能力内瘦身
|
||||
|
||||
- 在路由已模块化、资产 Adapter 已稳定后,再拆大文件,避免同时改 route 和业务实现。
|
||||
- 对 `match3d.rs`、`puzzle.rs`、`custom_world.rs`、`custom_world_ai.rs`、`big_fish.rs`、`square_hole.rs` 分别按能力拆:
|
||||
- `router.rs` 只挂路由。
|
||||
- `handlers.rs` 只做 Axum extract、鉴权、request/response。
|
||||
- `application.rs` 做 api-server 层编排。
|
||||
- `assets.rs` 只放玩法专属生成资产策略。
|
||||
- `mapper.rs` 只做 DTO/record 映射。
|
||||
- `errors.rs` 只做该能力错误映射。
|
||||
- 不把领域规则留在 handler;发现领域规则时只登记迁出候选,不在本阶段直接扩大到 `module-*` 重构。
|
||||
|
||||
验收:每个原超大文件显著缩小;新文件按能力可读;定向玩法测试和全量 `api-server` 测试通过。
|
||||
|
||||
## 阶段 5:清理、文档和最终验收
|
||||
|
||||
- 删除旧重复 helper、过时注释和已迁移的私有函数。
|
||||
- 更新 `api-server` README:目录规则、Router 暴露规则、Adapter 边界、禁止事项。
|
||||
- 更新 `.hermes/shared-memory` 中长期有效的架构约定和排障经验。
|
||||
- 最终验收命令:
|
||||
- `cargo check -p api-server --manifest-path server-rs/Cargo.toml`
|
||||
- `cargo test -p api-server --manifest-path server-rs/Cargo.toml`
|
||||
- `npm run check:server-rs-ddd`
|
||||
- `npm run check:encoding`
|
||||
- `git diff --check`
|
||||
- `npm run api-server` 后检查 `/healthz`
|
||||
- 禁止使用 `api-server:maincloud` 作为本轮 smoke。
|
||||
|
||||
## Public Interfaces
|
||||
|
||||
- HTTP route、DTO、error envelope、SpacetimeDB schema、前端调用方式默认不变。
|
||||
- 新增的都是 `api-server` 内部 Rust Interface,不进入 `shared-contracts`。
|
||||
- 若后续任何阶段发现必须改 contract,先更新对应阶段文档和 G1 route/contract 矩阵,再单独实施。
|
||||
|
||||
## Assumptions
|
||||
|
||||
- 本计划目标是完整收口,不是只完成第一阶段。
|
||||
- 可以分阶段提交,但每个阶段都必须有文档、测试和明确退出条件。
|
||||
- `generated_image_assets` 首版必须至少被三个真实调用方使用,否则不算形成有效 Module。
|
||||
Reference in New Issue
Block a user