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:
2026-05-15 06:24:07 +08:00
parent 2eded08bc7
commit 3cb3efb4d0
708 changed files with 4033 additions and 142328 deletions

View File

@@ -1,276 +0,0 @@
# M3runtime settings Axum + SpacetimeDB 落地设计
日期:`2026-04-21`
关联任务:
- [../../backend-rewrite-tasklist/02_M3_RUNTIME_PROFILE.md](../../backend-rewrite-tasklist/02_M3_RUNTIME_PROFILE.md)
- [../../backend-rewrite-tasklist/M0_PHASE_ACCEPTANCE_MATRIX_2026-04-20.md](../../backend-rewrite-tasklist/M0_PHASE_ACCEPTANCE_MATRIX_2026-04-20.md)
关联现状:
- [SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md](./SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md)
- [CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md](./CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md)
- `server-node/src/routes/rpg-profile/rpgProfileRoutes.ts`
- `server-node/src/repositories/runtimeRepository.ts`
## 1. 文档目的
`02_M3_RUNTIME_PROFILE.md` 已经冻结了 M3 的任务范围但还没有把首批可编码切片细化到表字段、procedure、Axum facade、兼容错误格式和测试策略。
本文件只解决 M3 第一批最小纵向切片:
1. `GET /api/runtime/settings`
2. `PUT /api/runtime/settings`
以及其在 Rust 重写中的完整落位:
1. `module-runtime` 的字段约束与 DTO
2. `crates/spacetime-module``runtime_setting` 表与 procedure
3. `crates/spacetime-client` 的 procedure 调用封装
4. `crates/api-server` 的兼容 facade 与响应 contract
本文件不新增 checklist不替代 [../../backend-rewrite-tasklist/02_M3_RUNTIME_PROFILE.md](../../backend-rewrite-tasklist/02_M3_RUNTIME_PROFILE.md),只补足可以直接编码的技术口径。
## 2. 为什么先做 runtime settings
在 M3 范围内,`runtime settings` 是当前最适合先迁移的纵向切片:
1. 读写模型最小,只依赖 `user_id + music_volume + platform_theme`
2. 旧 Node 逻辑没有跨表聚合、副作用和复杂 projection。
3. 前端 contract 清晰,兼容路径只有一条,不涉及 `/api/profile/*` 双路径。
4. 可以先把 `Axum -> JWT -> SpacetimeDB procedure -> 标准 envelope` 主链跑通,为后续 `browse history / snapshot / save archive / dashboard` 复用。
## 3. 旧实现冻结口径
当前 Node 侧 `runtime settings` 行为来自:
- `server-node/src/routes/rpg-profile/rpgProfileRoutes.ts`
- `server-node/src/repositories/runtimeRepository.ts`
冻结行为如下:
### 3.1 路由
- `GET /api/runtime/settings`
- `PUT /api/runtime/settings`
两条接口都要求 JWT。
### 3.2 请求体
`PUT /api/runtime/settings` 请求体:
```json
{
"musicVolume": 0.42,
"platformTheme": "light"
}
```
校验规则:
1. `musicVolume` 必须在 `0 ~ 1`
2. `platformTheme` 只接受 `light | dark`
### 3.3 默认值
默认值来自 `packages/shared/src/contracts/runtime.ts`
1. `DEFAULT_MUSIC_VOLUME = 0.42`
2. `DEFAULT_PLATFORM_THEME = "light"`
当用户从未写入过设置时,读取接口必须返回默认值,而不是 `404``null`
### 3.4 归一化规则
旧 Node 写入时会做以下归一化:
1. `musicVolume` 强制 clamp 到 `0 ~ 1`
2. `platformTheme` 如果不是 `dark`,统一回退到 `light`
Rust 重写阶段仍保持同样语义,避免前端产生行为漂移。
## 4. Rust 落位决议
### 4.1 crate 分工
本切片固定按以下边界落位:
1. `crates/module-runtime`
- 定义 `RuntimeSettings` 领域 DTO、默认值、字段校验与归一化规则。
2. `crates/spacetime-module`
- 定义 `runtime_setting` 表。
- 提供 `upsert_runtime_setting_and_return` procedure。
3. `crates/spacetime-client`
- 提供 `get_runtime_settings``put_runtime_settings` 调用封装。
4. `crates/api-server`
- 提供 `GET/PUT /api/runtime/settings`
- 保持当前 envelope / 错误格式 / 请求头兼容。
### 4.2 身份边界
当前阶段前端仍只访问 Axum不直连 SpacetimeDB。
因此:
1. 用户身份仍由 Axum 侧 JWT middleware 校验。
2. Axum 从已校验的 access token claims 中取 `user_id`
3. `user_id` 作为 procedure 入参写入 `runtime_setting`
注意:
1. 这不是最终的 SpacetimeDB 原生身份透传形态。
2. 在 M3 首批切片里,先以 Axum 作为唯一鉴权边界,保证与当前前端 contract 一致。
## 5. SpacetimeDB 表设计
### 5.1 表名
`runtime_setting`
### 5.2 字段
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `user_id` | `String` | 主键,绑定平台用户 |
| `music_volume` | `f32` | 音量,持久化归一化后的值 |
| `platform_theme` | `RuntimePlatformTheme` | 平台主题枚举 |
| `created_at` | `Timestamp` | 首次创建时间 |
| `updated_at` | `Timestamp` | 最近更新时间 |
### 5.3 设计决议
1. 每个用户只保留一行设置,不做历史版本表。
2. `user_id` 直接作为主键,避免再引入无业务价值的自增 ID。
3. `platform_theme` 固定为枚举,不把 `light/dark` 继续散落成字符串字面量。
4. 首批阶段不把设置拆成多行 KV 表,避免简单需求被过度抽象。
## 6. Procedure 设计
### 6.1 不单独暴露 reducer 给 Axum
本切片优先提供 procedure而不是让 Axum 直接调 reducer + 再查询表。
原因:
1. 当前 `spacetime-client` 已经以 procedure 返回结果的模式承接资产链。
2. 设置接口需要同步返回最终写入结果procedure 可减少一次额外查询。
3. 当前 `runtime_setting` 不需要客户端订阅private table + procedure 更直接。
### 6.2 Procedure 列表
1. `get_runtime_setting_or_default`
2. `upsert_runtime_setting_and_return`
返回 DTO 固定为:
```text
RuntimeSettingSnapshot {
user_id
music_volume
platform_theme
created_at_micros
updated_at_micros
}
```
如果用户还没有设置记录:
1. `get_runtime_setting_or_default` 返回默认值快照。
2. 但不强制立即插入表,避免纯读取请求制造无意义写入。
## 7. Axum facade 设计
### 7.1 GET /api/runtime/settings
行为:
1.`require_bearer_auth`
2.`claims.user_id` 取用户 ID。
3.`spacetime_client.get_runtime_settings(user_id)`
4. 返回:
```json
{
"musicVolume": 0.42,
"platformTheme": "light"
}
```
### 7.2 PUT /api/runtime/settings
行为:
1.`require_bearer_auth`
2. 使用 Axum `Json` + `serde` 解析请求。
3.`module-runtime` 内做归一化。
4.`spacetime_client.put_runtime_settings(user_id, payload)`
5. 返回归一化后的最终值。
### 7.3 错误映射
1. 请求体解析失败:`400 BAD_REQUEST`
2. 字段校验失败:`400 BAD_REQUEST`
3. SpacetimeDB 调用失败:`502 BAD_GATEWAY`
4. JWT 缺失或失效:沿用现有 `401 UNAUTHORIZED`
错误 `details.provider` 固定为:
1. `runtime-settings`:本地字段归一化或 DTO 构建失败
2. `spacetimedb`procedure 调用失败
## 8. 首批测试策略
本切片测试分两层:
### 8.1 必跑测试
1. `module-runtime`
- 默认值
- clamp 规则
- theme 归一化
2. `api-server`
- 未登录返回 `401`
- 请求 envelope 打开时返回标准 `ok/data/error/meta`
- JSON 结构与字段名兼容
### 8.2 可选联调测试
补一条 `#[ignore]` 的集成测试:
1. 需要本地 SpacetimeDB 已启动
2. 需要当前 `spacetime-module` 已发布
3. 验证 `PUT -> GET` 能往返一致
原因:
1. 当前仓库已有资产链的 `#[ignore]` 集成测试模式。
2. 在未稳定建立测试 harness 前,不强制把 SpacetimeDB 作为默认单测前置条件。
## 9. 后续扩展顺序
`runtime settings` 完成后M3 后续能力按以下顺序推进:
1. `user_browse_history`
2. `runtime_snapshot`
3. `profile_save_archive`
4. `profile_dashboard_state + profile_wallet_ledger + profile_played_world`
顺序原因:
1. `browse_history` 仍是单表为主,只带去重与排序规则。
2. `snapshot``save_archive` 依赖兼容聚合策略,复杂度更高。
3. `dashboard / play-stats / wallet-ledger` 依赖 projection更适合放在 snapshot 规则固定后收口。
## 10. 本文完成定义
当以下条件成立时,本设计文档视为完成:
1. `runtime settings` 的字段、默认值、归一化规则、procedure 与 Axum facade 已书面冻结。
2. 后续编码无需再猜测:
- 表字段名
- 主键策略
- 默认值来源
- Axum 与 SpacetimeDB 的职责边界
3. 可以直接据此开始 `module-runtime``spacetime-module``spacetime-client``api-server` 编码。