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