# M0:仓库边界决议 日期:`2026-04-20` 依据来源: - [../docs/technical/SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md](../docs/technical/SPACETIMEDB_AXUM_OSS_BACKEND_REWRITE_DESIGN_2026-04-20.md) - [00_MASTER_TASKLIST.md](./00_MASTER_TASKLIST.md) - [01_M0_M2_FOUNDATION_AND_AUTH.md](./01_M0_M2_FOUNDATION_AND_AUTH.md) ## 1. 文档目的 这份文档用于持续冻结 `M0` 中与仓库边界直接相关的决策,避免进入 `M1` 后再反复改目录、改职责口径。 当前已确认的事项只包含第一条;后续几条会继续在这份文档上追加。 ## 2. 边界决议状态 | 事项 | 当前状态 | 当前结论 | | --- | --- | --- | | Rust 后端新目录名与根目录落位方案 | 已确认 | 新 Rust 后端固定为仓库根目录下的 `server-rs/`,与 `server-node/` 同级。 | | 旧 `server-node/` 在迁移期继续保留,不提前删除 | 已确认 | `server-node/` 在 `M0 ~ M6` 期间持续保留,直到 `M7` 切流与回退验证完成后再评估清理。 | | 前端第一阶段仍然只访问 Axum,不直连 SpacetimeDB | 已确认 | `M0 ~ M6` 前端统一只访问 Axum 暴露的 `/api/*`、`/healthz`、SSE 与静态资源兼容层,不新增直连 SpacetimeDB 原生协议路径。 | | 外部副作用统一收口在 Axum,不放进 SpacetimeDB 模块 | 已确认 | OSS、LLM、短信、微信 OAuth、本地文件系统等外部副作用统一落在 Axum/application/infra,不进入 SpacetimeDB reducer/module。 | | `server-rs/` 内部采用多 package 组织,由主工程统一引用模块包 | 已确认 | `server-rs/` 采用 `apps/* + packages/*` 工作区结构,`apps/api-server` 与 `apps/spacetime-module` 作为主工程,独立模块以 `packages/module-*` 形式被主工程引用。 | ## 3. 已确认决议一:`server-rs/` 固定落在仓库根目录 ### 3.1 决议内容 本次重写固定采用以下仓库落位: 1. 新后端目录名固定为 `server-rs/` 2. 目录位置固定在仓库根目录 3. 与以下目录保持同级: - `server-node/` - `src/` - `docs/` - `packages/` 目标形态: ```text Genarrative/ ├─ server-node/ ├─ server-rs/ ├─ src/ ├─ packages/ ├─ docs/ └─ backend-rewrite-tasklist/ ``` ### 3.2 不采用的落位方案 以下方案当前明确不采用: 1. 不放进 `server-node/` 子目录中做“Node + Rust 混编后端”。 2. 不放进 `packages/`,避免被前端 package/workspace 语义误导。 3. 不使用过于泛化的根目录名如 `server/`、`backend/`,避免和当前 `server-node/` 职责混淆。 ### 3.3 这样落位的原因 1. 与当前重写设计文档、任务清单、后续 `M1` 多 package 规划保持一致。 2. 允许 `server-node/` 与 `server-rs/` 在迁移期并行存在,便于逐阶段切流。 3. 让 Rust 工作区边界清晰,不污染现有前端 `src/`、`packages/`、Vite 工具链。 4. 后续新增 `server-rs/scripts/*`、`Cargo.toml`、`apps/*`、`packages/*` 时路径最直接,不需要额外中间层。 ### 3.4 对后续任务的直接约束 从这一条决议开始,后续任务必须统一按以下路径落位: 1. `M1` 的工作区初始化在 `server-rs/` 2. Axum 主工程在 `server-rs/apps/api-server` 3. SpacetimeDB 主工程在 `server-rs/apps/spacetime-module` 4. 独立模块包在 `server-rs/packages/module-*` 5. 相关脚本在 `server-rs/scripts/` ## 4. 本条任务完成定义 当以下条件成立时,这一条边界任务视为完成: 1. 新 Rust 后端目录名已经书面固定为 `server-rs/` 2. 目录位置已经书面固定为仓库根目录 3. 后续 `M1` 的工作区初始化不会再出现 `server-rs/`、`backend-rs/`、`server/` 等多套候选名并存 ## 5. 已确认决议二:迁移期保留 `server-node/` ### 5.1 决议内容 在本次重写迁移期内,旧 `server-node/` 固定继续保留,不提前删除、不整体挪位、不提前做破坏性收缩。 保留周期固定为: 1. `M0` 到 `M6` 全阶段 2. 至少持续到 `M7` 的以下条件全部满足之后,才允许评估清理: - 新后端已切流 - 旧接口 contract 回归通过 - 关键主链 smoke 通过 - 已具备明确回退方案 ### 5.2 保留它的原因 1. 旧 `server-node/` 是当前 `96` 条路由、`6` 个挂载面、`12` 个模块的真实对照实现。 2. 前面已经冻结的路由矩阵、模块迁移清单、SSE 协议、静态资源前缀,都需要它作为回归对照源。 3. 如果在 `M1 ~ M6` 提前删除旧实现,就会失去最可靠的回退锚点与 diff 基准。 ### 5.3 迁移期允许做什么 迁移期内允许: 1. 在 `server-rs/` 中逐步补等价实现。 2. 在文档和 manifest 中继续引用 `server-node/` 作为当前系统基线。 3. 在必要时从 `server-node/` 补测试样例、补协议对照、补回归夹具。 迁移期内不允许: 1. 提前整体删除 `server-node/` 2. 把 `server-node/` 改成只剩空壳目录 3. 在还没切流前,把旧服务关键实现批量迁走导致无法对照 ### 5.4 对后续任务的直接约束 从这一条决议开始,后续任务必须遵守: 1. `M1` 搭建 `server-rs/` 时,不改动 `server-node/` 的存在性。 2. `M2 ~ M6` 迁移功能时,旧 `server-node/` 继续作为验收基线与回退锚点。 3. 真正评估清理旧 Node 后端的动作,只能放到 `M7` 切流完成之后。 ## 6. 已确认决议三:前端第一阶段只访问 Axum ### 6.1 决议内容 在 `M0 ~ M6` 迁移期内,前端访问新后端的唯一入口固定为 Axum。 第一阶段允许前端继续访问的面固定为: 1. `/api/*` 2. `/healthz` 3. 当前已冻结的 SSE 路由 4. 当前已冻结的 `/generated-*` 静态资源兼容前缀 第一阶段明确不做的事: 1. 不让 Web 前端直接接 SpacetimeDB 原生 HTTP 接口。 2. 不让 Web 前端直接接 SpacetimeDB 订阅协议。 3. 不要求前端新增一套“Axum + SpacetimeDB 双后端并行直连”调用模式。 ### 6.2 这样决议的原因 1. 当前前端已经直接依赖现有 `/api/*` 路由、response envelope、SSE、`/generated-*` 路径习惯。 2. 如果在第一阶段就让前端同时认识 Axum 与 SpacetimeDB,会把迁移面从“后端平移”扩大成“前后端协议双重重写”。 3. Axum 需要承担统一鉴权、cookie、JWT、OSS 签名、错误格式与 contract 兼容职责,这些都不应分散到前端直连多个后端协议。 ### 6.3 对后续任务的直接约束 从这一条决议开始,后续任务必须遵守: 1. `M1 ~ M2` 的 Axum 中间件与鉴权必须先跑通,再谈前端联调。 2. `M3 ~ M6` 新增的 SpacetimeDB reducer/view 先通过 Axum facade 暴露,不直接要求前端改成原生 SpacetimeDB 客户端。 3. 若后续要让前端直连 SpacetimeDB,只能作为第二阶段优化事项,不能混入当前重写主链。 ## 7. 已确认决议四:外部副作用统一收口在 Axum ### 7.1 决议内容 本次重写固定采用以下边界: 1. `SpacetimeDB` 只负责状态、规则、reducer、view、订阅读模型。 2. `Axum/application/infra` 统一负责所有外部副作用。 固定收口到 Axum 的外部副作用包括: 1. 阿里云 OSS 上传、下载、签名、直传凭证 2. DashScope / Ark / 其他 LLM 请求 3. 微信 OAuth 4. 手机验证码短信发送与校验编排 5. 本地文件系统读写 ### 7.2 明确不允许放进 SpacetimeDB 的内容 以下能力当前明确禁止进入 `spacetime-module/`: 1. 直接发 HTTP 请求给第三方供应商 2. 直接访问 OSS SDK 3. 直接读写本地磁盘 4. 直接处理 Cookie、回调跳转、multipart 上传 5. 直接承担供应商重试、熔断、超时与日志策略 ### 7.3 这样决议的原因 1. 这些能力都强依赖 HTTP 头、Cookie、SDK、签名、超时与日志,不适合绑进 SpacetimeDB 模块发布周期。 2. 当前前端 contract、鉴权、SSE、静态资源兼容都要求一个稳定的 HTTP 边界层,Axum 更适合承担这个角色。 3. 把副作用统一收口到 Axum,才能让 SpacetimeDB 保持“状态机真相源”的纯度。 ### 7.4 对后续任务的直接约束 从这一条决议开始,后续任务必须遵守: 1. `M1` package 设计时,`platform-oss`、`platform-llm`、`platform-auth` 固定属于 Axum / 模块应用层一侧。 2. `M2 ~ M6` 设计 reducer 时,只写状态变更,不直接发外部请求。 3. 若确实需要异步副作用,也必须由 Axum worker 或应用层作业执行,再把结果回写 SpacetimeDB。 ## 8. 已确认决议五:`server-rs/` 内部采用多 package 组织 ### 8.1 决议内容 从当前版本开始,`server-rs/` 内部结构固定采用: 1. `apps/*`:主工程 package 2. `packages/*`:独立模块 package 3. `scripts/*`:开发、发布、回归脚本 主工程固定包含: 1. `apps/api-server` 2. `apps/spacetime-module` 独立模块 package 固定按“每个独立模块一个 package”推进,至少覆盖: 1. `packages/module-auth` 2. `packages/module-runtime` 3. `packages/module-story` 4. `packages/module-combat` 5. `packages/module-inventory` 6. `packages/module-npc` 7. `packages/module-progression` 8. `packages/module-quest` 9. `packages/module-runtime-item` 10. `packages/module-custom-world` 11. `packages/module-assets` 12. `packages/module-editor` 13. `packages/module-ai` 跨模块共享 package 固定包含: 1. `packages/shared-contracts` 2. `packages/shared-kernel` 3. `packages/platform-auth` 4. `packages/platform-oss` 5. `packages/platform-llm` 6. `packages/spacetime-client` 7. `packages/tests-support` ### 8.2 这样决议的原因 1. 用户已经明确要求后端采用多 package 模式,独立模块不能继续堆回单个技术层大包。 2. 当前后端已有 `12` 个内部模块边界,多 package 方案更容易保持一一映射与独立演进。 3. `apps/api-server` 与 `apps/spacetime-module` 只做组合与发布,更符合“主工程引用模块包”的组织方式。 ### 8.3 对后续任务的直接约束 从这一条决议开始,后续任务必须遵守: 1. `M1` 后续目录创建任务统一按 `apps/* + packages/*` 执行,不再新增 `crates/*` 目录规划。 2. 每个业务模块默认先有自己的 workspace package,再由主工程引用。 3. 只有共享 contract、共享领域内核、平台适配、SpacetimeDB client 这类跨模块能力,才允许使用共享 package,而不是业务模块混装。