From 35958d5942c74f26d35883819489797adbd01018 Mon Sep 17 00:00:00 2001 From: kdletters Date: Wed, 22 Apr 2026 18:51:29 +0800 Subject: [PATCH] docs: add backend rewrite governance and route index --- .../07_CROSS_CUTTING_AND_ACCEPTANCE.md | 44 ++--- ...ITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md | 138 +++++++++++++++ docs/technical/README.md | 2 + .../RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md | 159 ++++++++++++++++++ 4 files changed, 324 insertions(+), 19 deletions(-) create mode 100644 docs/technical/BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md create mode 100644 docs/technical/RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md diff --git a/backend-rewrite-tasklist/07_CROSS_CUTTING_AND_ACCEPTANCE.md b/backend-rewrite-tasklist/07_CROSS_CUTTING_AND_ACCEPTANCE.md index cf9191c4..c0e479dc 100644 --- a/backend-rewrite-tasklist/07_CROSS_CUTTING_AND_ACCEPTANCE.md +++ b/backend-rewrite-tasklist/07_CROSS_CUTTING_AND_ACCEPTANCE.md @@ -4,33 +4,39 @@ ### Contract 与前端兼容 -- [ ] 梳理当前 `packages/shared/src/contracts/*` 到 Rust DTO 的映射 -- [ ] 设计 Rust 侧 contract 生成或手写策略 -- [ ] 保持当前字段名、枚举值、响应结构稳定 -- [ ] 为 breaking change 建立显式变更流程 +- [x] 梳理当前 `packages/shared/src/contracts/*` 到 Rust DTO 的映射 +- [x] 设计 Rust 侧 contract 生成或手写策略 +- [x] 保持当前字段名、枚举值、响应结构稳定 +- [x] 为 breaking change 建立显式变更流程 ### SpacetimeDB schema 演进治理 -- [ ] 约定 stable reducer 命名规则 -- [ ] 约定 stable table 命名规则 -- [ ] 约定列追加式演进规则 -- [ ] 约定软删除而不是直接删表删列的场景 -- [ ] 约定事件表与投影表拆分规则 +- [x] 约定 stable reducer 命名规则 +- [x] 约定 stable table 命名规则 +- [x] 约定列追加式演进规则 +- [x] 约定软删除而不是直接删表删列的场景 +- [x] 约定事件表与投影表拆分规则 ### 大对象与缓存治理 -- [ ] 明确哪些内容入 OSS -- [ ] 明确哪些内容只存 SpacetimeDB 元数据 -- [ ] 明确哪些内容允许短期本地缓存 -- [ ] 明确 workflow cache 生命周期 +- [x] 明确哪些内容入 OSS +- [x] 明确哪些内容只存 SpacetimeDB 元数据 +- [x] 明确哪些内容允许短期本地缓存 +- [x] 明确 workflow cache 生命周期 ### 文档维护 -- [ ] 每个阶段完成后同步更新设计文档 -- [ ] 每个阶段完成后补一份落地记录 -- [ ] 完成接口迁移后更新新的模块与 API 索引文档 +- [x] 每个阶段完成后同步更新设计文档 +- [x] 每个阶段完成后补一份落地记录 +- [x] 完成接口迁移后更新新的模块与 API 索引文档 - [ ] `M4` 结构变更同步对齐 `docs/technical/RPG_ENTRY_RUNTIME_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md` -- [ ] `M5` 结构变更同步对齐 `docs/technical/CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md` +- [x] `M5` 结构变更同步对齐 `docs/technical/CREATION_FLOW_CHAIN_REFACTOR_EXECUTION_PLAN_2026-04-21.md` + +补充说明: + +1. 横向治理规则已冻结在 [../docs/technical/BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md](../docs/technical/BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md)。 +2. Rust 侧 96 条 Axum 路由索引已冻结在 [../docs/technical/RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md](../docs/technical/RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md)。 +3. `M4` 当前仍存在 `runtime_story` 独立 crate 拆分工作区,结构文档对齐需等该拆分收口后再勾选。 ## 2. 第一优先级建议执行顺序 @@ -44,13 +50,13 @@ ## 3. 最终验收清单 -- [ ] 当前 `96` 条后端接口已全部迁移或有兼容替代 +- [x] 当前 `96` 条后端接口已全部迁移或有兼容替代 - [ ] 当前 `6` 个挂载面已全部迁移 - [ ] 当前 `12` 个内部模块已完成新架构落位 - [ ] Axum 已成为唯一 HTTP / SSE / 副作用边界 - [ ] SpacetimeDB 已成为唯一运行时状态真相源 - [ ] 阿里云 OSS 已成为唯一资产对象仓 - [ ] `M4` 已与 `rpgEntry / rpgSession / rpgRuntime / rpgRuntimeStory / rpgProfile` 主链口径一致 -- [ ] `M5` 已与 `agent session -> result preview -> published profile` 主链口径一致 +- [x] `M5` 已与 `agent session -> result preview -> published profile` 主链口径一致 - [ ] 前端主流程在不大改 UI 的前提下可跑通 - [ ] 能完成灰度切流,并保留可回退能力 diff --git a/docs/technical/BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md b/docs/technical/BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md new file mode 100644 index 00000000..f1999976 --- /dev/null +++ b/docs/technical/BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md @@ -0,0 +1,138 @@ +# 后端重写横向治理规则(2026-04-22) + +更新时间:`2026-04-22` + +## 1. 文档目标 + +本文件冻结 `SpacetimeDB + Axum + OSS` 后端重写收口阶段的横向规则,覆盖: + +1. 前端 TypeScript contract 与 Rust DTO 的映射策略。 +2. SpacetimeDB table / reducer / procedure 的演进规则。 +3. 大对象、manifest、workflow cache 的存储边界。 +4. 阶段文档与 API 索引的维护规则。 + +这些规则用于减少 M4/M5/M6/M7 后续并行推进时的 contract 漂移。 + +## 2. Contract 与前端兼容 + +### 2.1 映射原则 + +1. `packages/shared/src/contracts/*` 是前端消费 contract 的现有事实来源。 +2. `server-rs/crates/shared-contracts/src/*.rs` 是 Rust `api-server` 返回 DTO 的事实来源。 +3. 两侧字段名必须继续使用当前前端已消费的 JSON 命名,不因 Rust 字段命名风格改变外部 shape。 +4. Rust DTO 必须通过 `serde(rename_all = "camelCase")`、显式 `rename` 或兼容枚举值保持旧 contract。 +5. 临时兼容字段只能标记为 optional,不能在没有迁移说明和测试前直接删除。 + +### 2.2 当前映射面 + +| 前端 contract | Rust DTO 模块 | 当前用途 | +| --- | --- | --- | +| `packages/shared/src/contracts/auth.ts` | `shared-contracts::auth` | 登录方式、用户信息、会话、审计、验证码与微信登录 | +| `packages/shared/src/contracts/runtime.ts` | `shared-contracts::runtime` | profile dashboard、play stats、wallet ledger、browse history、settings、inventory | +| `packages/shared/src/contracts/rpgRuntimeStoryAction.ts` | `shared-contracts::runtime_story` | runtime story action request / response、state resolve、view model | +| `packages/shared/src/contracts/rpgRuntimeStoryState.ts` | `shared-contracts::runtime_story` | runtime story state / presentation 兼容 | +| `packages/shared/src/contracts/rpgAgent*.ts` | `shared-contracts::runtime` 与 `custom_world` 相关 DTO | custom world agent session、message、operation、action | +| `packages/shared/src/contracts/rpgCreation*.ts` | `shared-contracts::runtime` 与 `custom_world` 相关 DTO | result preview、works、library、published profile | +| `packages/shared/src/contracts/common.ts` | `shared-contracts::api` | 统一 success / error envelope | + +### 2.3 变更流程 + +1. 扩字段:先加 Rust optional 字段和 contract test,再接前端消费。 +2. 改字段语义:必须新增技术方案说明旧语义、新语义、迁移期兼容逻辑和回退方式。 +3. 删字段或删枚举:必须先证明前端调用、Node 兼容层、历史 fixture 和测试都不再消费。 +4. breaking change 必须在任务清单和设计文档中显式标注,不允许只靠 PR diff 表达。 +5. 所有 shared contract 变更至少运行 `cargo test -p shared-contracts --manifest-path server-rs/Cargo.toml`。 + +## 3. SpacetimeDB Schema 演进治理 + +本节按 SpacetimeDB 约束执行: + +1. reducer 是事务性写入口,不依赖 reducer 返回值读取数据。 +2. reducer 必须确定性执行,不做网络、文件系统、外部随机数或时间副作用。 +3. 客户端读取依赖 table / subscription / procedure 返回的显式 DTO,不把 Axum 进程内缓存当真相。 +4. 用户身份以后续接入 SpacetimeDB 直连时的 `ctx.sender()` 为准,不信任客户端传入 owner 字段。 + +### 3.1 命名规则 + +1. table 使用稳定单数 snake_case 名称,例如 `story_session`、`asset_object`、`custom_world_agent_session`。 +2. reducer 使用动作动词 + 领域对象,例如 `upsert_runtime_snapshot`、`confirm_asset_object`、`turn_in_quest`。 +3. 需要同步返回 DTO 的 procedure 统一使用 `_and_return` 或 `get_ / list_ / compile_` 语义。 +4. public table 只暴露客户端确实需要订阅或查询的状态;内部审计、token、风控等默认不 public。 +5. event table 只用于事件广播,不替代持久状态表。 + +### 3.2 列演进规则 + +1. 优先追加 optional 字段,不直接改名、改类型或删除列。 +2. 必须删除语义时,先软废弃字段并让读模型停止依赖,再在独立迁移窗口清理。 +3. 状态类枚举新增值时,前端必须有 unknown / fallback 处理。 +4. 需要唯一约束或索引时,先补设计文档说明查询路径,再改 schema。 +5. 大规模重排表结构必须拆成新表 + 双写 / 读模型迁移,不在原表上做破坏性变更。 + +### 3.3 软删除规则 + +1. 用户可见业务实体优先使用 `status`、`deleted_at`、`archived_at` 表达生命周期。 +2. 会话、作品、资产绑定、审计和任务记录默认不物理删除。 +3. 物理删除只用于临时草稿、过期验证码、过期 OAuth state 等明确可丢弃数据。 +4. 删除 reducer 必须写清是否幂等,重复调用不能造成不可恢复错误。 + +## 4. 大对象与缓存治理 + +### 4.1 OSS 存储边界 + +必须进入 OSS: + +1. 图片、视频、动作帧、封面图、场景图。 +2. 大型 JSON manifest。 +3. 角色工作流缓存 JSON。 +4. 导入视频和生成过程草稿资源。 + +只进入 SpacetimeDB 元数据: + +1. `bucket`、`object_key`、`asset_kind`、`content_type`、`content_length`、`content_hash`、`version`。 +2. `asset_entity_binding` 的业务实体、槽位、owner 和 profile 绑定关系。 +3. AI task、asset task、publish gate 等状态字段。 +4. 可用于列表和权限判断的轻量 summary。 + +### 4.2 本地缓存边界 + +1. 生产主链不得把仓库 `public/generated-*` 作为资产真相。 +2. 旧 `/generated-*` 仅作为同源代理兼容路径,读取私有 OSS 对象。 +3. 测试环境允许使用 `#[cfg(test)]` 内存兜底,但必须在文档中注明不进入生产链。 +4. workflow cache 当前真相是 OSS JSON 草稿对象,不落本地文件。 +5. 临时生成文件如需存在,必须限制在进程临时目录,并在任务完成后清理。 + +### 4.3 Manifest 与版本 + +1. 多文件资产集合使用 OSS manifest 表达,不重复新增结构化表,除非已证明查询需求需要。 +2. `asset_object.version` 当前默认 `1`,版本升级必须说明兼容读取规则。 +3. `content_hash` 可为空,但一旦用于去重,必须先补冲突处理和重算策略。 +4. 强业务资产表只有在需要领域查询、审核、回滚或权限策略时再新增。 + +## 5. 文档维护规则 + +1. 工程修改必须同步对应阶段任务清单。 +2. 新增或改变接口时,同步更新 [RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md](./RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md)。 +3. 仍存在 Node 旧能力差异时,同步更新 [NODE_BACKEND_MODULE_AND_API_INDEX.md](./NODE_BACKEND_MODULE_AND_API_INDEX.md) 的过期说明或新增 Rust 侧补充索引。 +4. M4 结构变更同步维护 RPG runtime 链路文档。 +5. M5 结构变更同步维护 creation flow 链路文档。 +6. M6 资产链路变更同步维护 OSS / asset_object / generated path 文档。 +7. M7 切流相关变更同步维护部署、预检、smoke 与回滚文档。 + +## 6. 验收门禁 + +横向治理完成不等价于真实切流完成。当前可本地验收的门禁是: + +1. `cargo check -p api-server --manifest-path server-rs/Cargo.toml` +2. `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` +3. `cargo test -p shared-contracts --manifest-path server-rs/Cargo.toml` +4. `cargo test -p api-server --manifest-path server-rs/Cargo.toml --no-run` +5. `node scripts/check-encoding.mjs ...` + +真实切流前仍必须单独完成: + +1. OSS 真实读写 smoke。 +2. LLM / DashScope 真实生成 smoke。 +3. 关键 SSE 接口联调。 +4. SpacetimeDB publish / rollback 演练。 +5. 灰度环境双跑对比。 + diff --git a/docs/technical/README.md b/docs/technical/README.md index 6f5d17f5..dcb32d06 100644 --- a/docs/technical/README.md +++ b/docs/technical/README.md @@ -4,6 +4,8 @@ ## 文档列表 +- [RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md](./RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md):记录当前 Rust `api-server` 已挂载的 96 条 Axum 路由,按 auth、assets、runtime、custom world、story、generated path 等挂载面归类,用于对照 Node 能力基线与切流 smoke 清单。 +- [BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md](./BACKEND_REWRITE_CROSS_CUTTING_GOVERNANCE_2026-04-22.md):冻结后端重写收口阶段的横向治理规则,覆盖 TypeScript contract 到 Rust DTO 映射、SpacetimeDB schema 演进、大对象 / workflow cache 存储边界和文档维护门禁。 - [PLATFORM_LLM_TEXT_GATEWAY_DESIGN_2026-04-21.md](./PLATFORM_LLM_TEXT_GATEWAY_DESIGN_2026-04-21.md):`platform-llm` 文本模型网关首版设计,冻结 OpenAI 兼容 `/chat/completions`、SSE 增量解析、错误模型与重试边界。 - [API_SERVER_PLATFORM_LLM_PROXY_DESIGN_2026-04-21.md](./API_SERVER_PLATFORM_LLM_PROXY_DESIGN_2026-04-21.md):`api-server` 接入 `platform-llm` 的最小代理设计,冻结 `/api/llm/chat/completions` 的配置、状态注入与首版非流式兼容边界。 - [PHONE_SMS_LOGIN_STAGE_A_IMPLEMENTATION_2026-04-21.md](./PHONE_SMS_LOGIN_STAGE_A_IMPLEMENTATION_2026-04-21.md):冻结手机号验证码登录第一阶段的真实落地边界,明确游客兜底默认关闭、公开请求不污染登录态,以及 smoke 必须覆盖短信登录主链。 diff --git a/docs/technical/RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md b/docs/technical/RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md new file mode 100644 index 00000000..8d7195c1 --- /dev/null +++ b/docs/technical/RUST_API_SERVER_ROUTE_INDEX_2026-04-22.md @@ -0,0 +1,159 @@ +# Rust API Server 路由索引(2026-04-22) + +更新时间:`2026-04-22` + +## 1. 文档目标 + +本文件记录当前 `server-rs/crates/api-server/src/app.rs` 中已挂载的 Rust Axum 路由面,用于对照 Node 后端 `96` 条路由能力基线。 + +本文件只做路由索引,不替代单个阶段的设计文档;接口字段、权限、错误模型仍以各阶段技术方案和 `shared-contracts` 为准。 + +## 2. 当前统计 + +当前 Rust `api-server` 从 `app.rs` 可抽取到 `96` 条路由: + +1. 内部鉴权调试接口:`2` 条。 +2. AI task 接口:`9` 条。 +3. assets / OSS 接口:`15` 条。 +4. auth 接口:`12` 条。 +5. custom world / agent 接口:`23` 条。 +6. llm proxy 接口:`1` 条。 +7. profile / runtime profile 接口:`12` 条。 +8. runtime story / story gameplay 接口:`15` 条。 +9. legacy generated 静态路径兼容:`6` 条。 +10. health check:`1` 条。 + +## 3. 路由清单 + +### 3.1 内部鉴权调试 + +1. `GET /_internal/auth/claims` +2. `GET /_internal/auth/refresh-cookie` + +### 3.2 AI Task + +1. `POST /api/ai/tasks` +2. `POST /api/ai/tasks/{task_id}/start` +3. `POST /api/ai/tasks/{task_id}/cancel` +4. `POST /api/ai/tasks/{task_id}/complete` +5. `POST /api/ai/tasks/{task_id}/fail` +6. `POST /api/ai/tasks/{task_id}/chunks` +7. `POST /api/ai/tasks/{task_id}/references` +8. `POST /api/ai/tasks/{task_id}/stages/{stage_kind}/start` +9. `POST /api/ai/tasks/{task_id}/stages/{stage_kind}/complete` + +### 3.3 Assets / OSS + +1. `POST /api/assets/direct-upload-tickets` +2. `POST /api/assets/sts-upload-credentials` +3. `POST /api/assets/objects/confirm` +4. `POST /api/assets/objects/bind` +5. `GET /api/assets/read-url` +6. `POST /api/assets/character-visual/generate` +7. `GET /api/assets/character-visual/jobs/{task_id}` +8. `POST /api/assets/character-visual/publish` +9. `POST /api/assets/character-animation/generate` +10. `GET /api/assets/character-animation/jobs/{task_id}` +11. `POST /api/assets/character-animation/publish` +12. `POST /api/assets/character-animation/import-video` +13. `GET /api/assets/character-animation/templates` +14. `GET /api/assets/character-workflow-cache/{character_id}` +15. `GET / POST /api/assets/character-workflow-cache` + +### 3.4 Auth + +1. `GET /api/auth/login-options` +2. `GET /api/auth/me` +3. `POST /api/auth/logout` +4. `POST /api/auth/logout-all` +5. `GET /api/auth/sessions` +6. `POST /api/auth/refresh` +7. `POST /api/auth/phone/send-code` +8. `POST /api/auth/phone/login` +9. `GET /api/auth/wechat/start` +10. `GET /api/auth/wechat/callback` +11. `POST /api/auth/wechat/bind-phone` +12. `POST /api/auth/entry` + +### 3.5 Custom World / Agent + +1. `GET /api/runtime/custom-world-library` +2. `GET /api/runtime/custom-world-library/{profile_id}` +3. `POST /api/runtime/custom-world-library/{profile_id}/publish` +4. `POST /api/runtime/custom-world-library/{profile_id}/unpublish` +5. `GET /api/runtime/custom-world-gallery` +6. `GET /api/runtime/custom-world-gallery/{owner_user_id}/{profile_id}` +7. `GET /api/runtime/custom-world/works` +8. `POST /api/runtime/custom-world/agent/sessions` +9. `GET /api/runtime/custom-world/agent/sessions/{session_id}` +10. `POST /api/runtime/custom-world/agent/sessions/{session_id}/messages` +11. `GET /api/runtime/custom-world/agent/sessions/{session_id}/messages/stream` +12. `GET /api/runtime/custom-world/agent/sessions/{session_id}/operations/{operation_id}` +13. `GET /api/runtime/custom-world/agent/sessions/{session_id}/cards/{card_id}` +14. `POST /api/runtime/custom-world/agent/sessions/{session_id}/actions` +15. `POST /api/custom-world/entity` +16. `POST /api/runtime/custom-world/entity` +17. `POST /api/custom-world/scene-npc` +18. `POST /api/runtime/custom-world/scene-npc` +19. `POST /api/custom-world/scene-image` +20. `POST /api/custom-world/cover-image` +21. `POST /api/custom-world/cover-upload` +22. `POST /api/runtime/custom-world/cover-image` +23. `POST /api/runtime/custom-world/cover-upload` + +### 3.6 LLM Proxy + +1. `POST /api/llm/chat/completions` + +### 3.7 Profile / Runtime Profile + +1. `GET /api/profile/dashboard` +2. `GET /api/runtime/profile/dashboard` +3. `GET /api/profile/play-stats` +4. `GET /api/runtime/profile/play-stats` +5. `GET /api/profile/wallet-ledger` +6. `GET /api/runtime/profile/wallet-ledger` +7. `GET /api/profile/browse-history` +8. `GET /api/runtime/profile/browse-history` +9. `GET /api/profile/save-archives` +10. `GET /api/runtime/profile/save-archives` +11. `POST /api/profile/save-archives/{world_key}` +12. `POST /api/runtime/profile/save-archives/{world_key}` + +### 3.8 Runtime Story / Gameplay + +1. `POST /api/runtime/save/snapshot` +2. `GET /api/runtime/settings` +3. `GET /api/runtime/story/state/{session_id}` +4. `POST /api/runtime/story/state/resolve` +5. `POST /api/runtime/story/actions/resolve` +6. `POST /api/runtime/story/initial` +7. `POST /api/runtime/story/continue` +8. `POST /api/story/sessions` +9. `POST /api/story/sessions/continue` +10. `GET /api/story/sessions/{story_session_id}/state` +11. `POST /api/story/battles` +12. `POST /api/story/battles/resolve` +13. `GET /api/story/battles/{battle_state_id}` +14. `POST /api/story/npc/battle` +15. `GET /api/runtime/sessions/{runtime_session_id}/inventory` + +### 3.9 Legacy Generated 路径 + +1. `GET /generated-character-drafts/{*path}` +2. `GET /generated-characters/{*path}` +3. `GET /generated-animations/{*path}` +4. `GET /generated-custom-world-scenes/{*path}` +5. `GET /generated-custom-world-covers/{*path}` +6. `GET /generated-qwen-sprites/{*path}` + +### 3.10 Health + +1. `GET /healthz` + +## 4. 维护规则 + +1. 新增、删除或改名 Rust 路由时,必须同步更新本索引。 +2. 如果 Node 后端 `NODE_BACKEND_MODULE_AND_API_INDEX.md` 的现役能力面发生变化,必须同时更新本索引与对应阶段任务清单。 +3. 任何 breaking route change 都必须先更新阶段设计文档,再改代码。 +4. 真实切流前,必须用本索引对照代理层、前端调用面和 smoke 清单,避免只完成编译而遗漏外部可访问路径。