Prune stale docs and update .hermes content
Delete a large set of outdated documentation (many files under docs/ and .hermes/plans/, including audits, design, prd, technical, planning, assets, and todos). Update and consolidate .hermes content: refresh shared-memory pages (decision-log, development-workflow, document-map, pitfalls, project-overview, team-conventions) and several skills/references under .hermes/skills. Also modify AGENTS.md, README.md, UI_CODING_STANDARD.md, docs/README.md and .encoding-check-ignore. Purpose: clean up stale planning/audit material and keep current hermes documentation and related top-level docs in sync.
This commit is contained in:
@@ -1,232 +0,0 @@
|
||||
# M4 Runtime Inventory State Query 设计(2026-04-22)
|
||||
|
||||
更新时间:`2026-04-22`
|
||||
|
||||
## 0. 文档目标
|
||||
|
||||
本文件只冻结当前 `M4` 的一个最小新增切片:
|
||||
|
||||
**新增 `GET /api/runtime/sessions/:runtimeSessionId/inventory`,让 Axum 能从 `SpacetimeDB` 同步读取当前玩家在指定 `runtime_session` 下的 `inventory_slot` 真相态,不提前承诺旧 `GameState.playerInventory / playerEquipment` 全量兼容。**
|
||||
|
||||
本轮目标不是把旧前端背包 view model 一次性全迁到 Rust,也不是把 `inventory_use / craft / dismantle / reforge` 一次性补齐。
|
||||
|
||||
---
|
||||
|
||||
## 1. 为什么先做这个切片
|
||||
|
||||
当前 inventory 主链已经具备:
|
||||
|
||||
1. `module-inventory` 已冻结 `inventory_slot`、`apply_inventory_mutation` 的首版领域 contract。
|
||||
2. `spacetime-module` 已有 `inventory_slot` 真相表与 `apply_inventory_mutation` reducer。
|
||||
3. `treasure / quest / battle` 奖励物品已经能同步写入 `inventory_slot`。
|
||||
|
||||
真正缺的部分是:
|
||||
|
||||
1. 背包真相态还没有稳定查询入口。
|
||||
2. `api-server` 还不能按 `runtime_session_id + 当前用户` 同步返回当前背包与装备状态。
|
||||
3. 后续如果要把背包面板、装备面板或 runtime story projection 收口到 `SpacetimeDB`,需要先有一个最小 inventory query 切片可复用。
|
||||
|
||||
因此本轮先补“只读查询”能力,不提前跳到更重的旧前端状态兼容。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前冻结范围
|
||||
|
||||
本轮只包含以下能力:
|
||||
|
||||
1. 新增公开接口:`GET /api/runtime/sessions/:runtimeSessionId/inventory`
|
||||
2. 认证方式:Bearer JWT
|
||||
3. 查询 scope:`runtime_session_id + 当前登录用户`
|
||||
4. 数据来源:`SpacetimeDB procedure get_runtime_inventory_state`
|
||||
5. 返回体只包含:
|
||||
- `runtimeSessionId`
|
||||
- `actorUserId`
|
||||
- `backpackItems`
|
||||
- `equipmentItems`
|
||||
|
||||
本轮明确不做:
|
||||
|
||||
1. 不兼容旧 `GameState.playerInventory`
|
||||
2. 不兼容旧 `GameState.playerEquipment`
|
||||
3. 不补按 `story_session_id` 或全局用户维度的 inventory 查询
|
||||
4. 不做 inventory public subscription / view
|
||||
5. 不在查询链路里拼装 quest / npc / battle / story_event
|
||||
6. 不提前做 `inventory_use / craft / dismantle / reforge`
|
||||
|
||||
---
|
||||
|
||||
## 3. 为什么按 `runtime_session_id + 当前用户` 查询
|
||||
|
||||
当前 `inventory_slot` 的主作用域字段是:
|
||||
|
||||
1. `runtime_session_id`
|
||||
2. `actor_user_id`
|
||||
3. `story_session_id`
|
||||
|
||||
本轮选择 `runtime_session_id + actor_user_id` 作为最小 query scope,原因如下:
|
||||
|
||||
1. `inventory_slot` 当前是运行态背包真相,不是单个 story session 的临时投影。
|
||||
2. 同一 `runtime_session` 下的宝箱、任务、战斗奖励都已经按这个 scope 汇入同一张表。
|
||||
3. 旧前端背包面板语义本质上也是“当前运行态玩家的背包”,不是“某个 story session 的局部背包”。
|
||||
4. 若后续确实需要更细的 `story_session` 投影,应通过上层 façade 或专门 view 提供,而不是先把真相查询 scope 做窄。
|
||||
|
||||
---
|
||||
|
||||
## 4. 接口 contract
|
||||
|
||||
### 4.1 请求
|
||||
|
||||
- 方法:`GET`
|
||||
- 路径:`/api/runtime/sessions/:runtimeSessionId/inventory`
|
||||
- 认证:必须携带 Bearer JWT
|
||||
- 路径参数:
|
||||
- `runtimeSessionId`:目标运行时会话 ID
|
||||
|
||||
### 4.2 成功响应
|
||||
|
||||
成功响应延续当前 `api-server` 统一 envelope,`data` 字段结构为:
|
||||
|
||||
```json
|
||||
{
|
||||
"runtimeSessionId": "runtime_xxx",
|
||||
"actorUserId": "user_xxx",
|
||||
"backpackItems": [
|
||||
{
|
||||
"slotId": "invslot_xxx",
|
||||
"containerKind": "backpack",
|
||||
"slotKey": "invslot_xxx",
|
||||
"itemId": "consumable_heal_potion",
|
||||
"category": "消耗品",
|
||||
"name": "疗伤药",
|
||||
"description": "用于恢复少量气血。",
|
||||
"quantity": 3,
|
||||
"rarity": "common",
|
||||
"tags": ["healing"],
|
||||
"stackable": true,
|
||||
"stackKey": "heal_potion",
|
||||
"equipmentSlotId": null,
|
||||
"sourceKind": "treasure_reward",
|
||||
"sourceReferenceId": "treasure_xxx",
|
||||
"createdAt": "2026-04-22T00:00:00.000000Z",
|
||||
"updatedAt": "2026-04-22T00:01:00.000000Z"
|
||||
}
|
||||
],
|
||||
"equipmentItems": [
|
||||
{
|
||||
"slotId": "invslot_weapon_xxx",
|
||||
"containerKind": "equipment",
|
||||
"slotKey": "weapon",
|
||||
"itemId": "weapon_trial_blade",
|
||||
"category": "武器",
|
||||
"name": "试作短剑",
|
||||
"description": "一柄适合入门者的短剑。",
|
||||
"quantity": 1,
|
||||
"rarity": "rare",
|
||||
"tags": ["weapon"],
|
||||
"stackable": false,
|
||||
"stackKey": "weapon_trial_blade",
|
||||
"equipmentSlotId": "weapon",
|
||||
"sourceKind": "quest_reward",
|
||||
"sourceReferenceId": "quest_xxx",
|
||||
"createdAt": "2026-04-22T00:00:00.000000Z",
|
||||
"updatedAt": "2026-04-22T00:05:00.000000Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 错误响应
|
||||
|
||||
当前延续 runtime/profile/story 查询已有策略:
|
||||
|
||||
1. `SpacetimeClientError::Runtime(_)` 映射为 `400`
|
||||
2. 其他 `SpacetimeClientError` 映射为 `502`
|
||||
3. 错误 `details.provider`:
|
||||
- 参数构建或本地语义错误:`runtime-inventory`
|
||||
- 下游 `SpacetimeDB` 失败:`spacetimedb`
|
||||
|
||||
---
|
||||
|
||||
## 5. 分层职责
|
||||
|
||||
### 5.1 `module-inventory`
|
||||
|
||||
职责:
|
||||
|
||||
1. 冻结 `RuntimeInventoryStateQueryInput`
|
||||
2. 冻结 `RuntimeInventoryStateSnapshot`
|
||||
3. 冻结 `RuntimeInventorySlotRecord`
|
||||
4. 负责 builder、validator 与 record 映射
|
||||
|
||||
不负责:
|
||||
|
||||
1. HTTP 路径解析
|
||||
2. JWT 鉴权
|
||||
3. 旧前端背包 view model 编译
|
||||
|
||||
### 5.2 `spacetime-module`
|
||||
|
||||
职责:
|
||||
|
||||
1. 读取指定 `runtime_session_id + actor_user_id` 下的 `inventory_slot`
|
||||
2. 按 `container_kind` 拆成 `backpackItems / equipmentItems`
|
||||
3. 复用 `module-inventory` 的 query input / snapshot 结构
|
||||
4. 通过 `get_runtime_inventory_state` procedure 返回当前真相态
|
||||
|
||||
### 5.3 `spacetime-client`
|
||||
|
||||
职责:
|
||||
|
||||
1. 构造 `RuntimeInventoryStateQueryInput`
|
||||
2. 调用 `get_runtime_inventory_state`
|
||||
3. 把返回结果映射为稳定 Rust record
|
||||
|
||||
### 5.4 `api-server`
|
||||
|
||||
职责:
|
||||
|
||||
1. 暴露 `GET /api/runtime/sessions/:runtimeSessionId/inventory`
|
||||
2. 做 Bearer JWT 鉴权
|
||||
3. 从 token 中注入 `actorUserId`
|
||||
4. 把 inventory record 映射到 JSON payload
|
||||
|
||||
---
|
||||
|
||||
## 6. 排序规则
|
||||
|
||||
为了保证前端和后续 façade 读到稳定顺序,本轮冻结以下排序口径:
|
||||
|
||||
1. `backpackItems`
|
||||
- 先按 `slot_key`
|
||||
- 再按 `slot_id`
|
||||
2. `equipmentItems`
|
||||
- 先按装备位固定顺序:`weapon -> armor -> relic`
|
||||
- 再按 `slot_id`
|
||||
|
||||
当前不在 query 层额外做“按稀有度”“按分类”“按来源”的排序投影。
|
||||
|
||||
---
|
||||
|
||||
## 7. 验收口径
|
||||
|
||||
本轮验收只要求以下几点:
|
||||
|
||||
1. `module-inventory` 已补 inventory query contract 与最小测试
|
||||
2. `spacetime-module` 已新增 `get_runtime_inventory_state` procedure
|
||||
3. `spacetime-client` 已能同步读取 inventory 真相态
|
||||
4. `api-server` 已真实挂出 `GET /api/runtime/sessions/:runtimeSessionId/inventory`
|
||||
5. `cargo check -p module-inventory -p spacetime-module -p spacetime-client -p api-server` 可通过
|
||||
6. `npm run check:encoding` 已执行,确保新增中文文档与接口文件没有编码损坏
|
||||
|
||||
---
|
||||
|
||||
## 8. 后续边界
|
||||
|
||||
这条最小 inventory query 落地后,后续再继续拆下一层:
|
||||
|
||||
1. 评估是否需要补 `story session` 局部 inventory projection
|
||||
2. 评估是否需要把 inventory query 接成旧背包面板 view model
|
||||
3. 再继续补 `inventory_use / craft / dismantle / reforge`
|
||||
4. 最后再考虑 inventory subscription / public view
|
||||
|
||||
在这些 contract 未冻结前,不应把当前接口误称为“旧背包系统已完整迁移完成”。
|
||||
Reference in New Issue
Block a user