Files
Genarrative/docs/technical/SERVER_RS_DDD_FULL_REFACTOR_2026-04-28.md
高物 5831703156
Some checks failed
CI / verify (push) Has been cancelled
1
2026-05-02 20:43:41 +08:00

15 KiB
Raw Blame History

server-rs DDD 一次性重构落地方案

日期:2026-04-28

1. 背景与当前结论

当前仓库已经进入 server-rs + Axum + SpacetimeDB 单一后端路线,旧 server-node 已不存在,后续不再围绕 Express / PostgreSQL 做兼容设计。本轮重构目标不是新增玩法,而是把已有 Rust 后端统一成可长期演进的 DDD 边界:

  1. 领域规则沉到 module-*
  2. SpacetimeDB 事务、表、reducer、procedure 留在 spacetime-module
  3. HTTP / SSE / BFF 留在 api-server
  4. 外部副作用留在 platform-*api-server 应用编排层。
  5. 前后端 DTO 留在 shared-contracts,跨领域纯值处理留在 shared-kernel

本文件是后续编码前的总纲。若局部历史文档与本文冲突,以本文和对应 SpacetimeDB skill 为准;若本文仍无法精准指导某一处编码,必须先补本文或新增更细技术文档,再继续改工程。

2. 依赖方向

允许方向:

api-server
  -> shared-contracts
  -> module-*
  -> spacetime-client
  -> platform-*

spacetime-module
  -> module-*
  -> shared-kernel

module-*
  -> shared-kernel
  -> 其他 module-* 的纯领域类型(仅在确有跨域规则复用时)

platform-*
  -> shared-kernel

shared-contracts
  -> shared-kernel

禁止方向:

  1. module-* 直接依赖 Axum、HTTP client、OSS、LLM、文件系统、SpacetimeDB table/reducer/procedure API。
  2. module-* 新增 mapper.rs,映射只能落在 adapter crate。
  3. spacetime-module 反向依赖 api-serverspacetime-clientplatform-*
  4. shared-kernel / shared-contracts 依赖业务 crate。
  5. 前端绕过 Axum 直接承接后端业务规则或数据真相。

阶段性例外必须满足三个条件:

  1. 在本文“阶段性债务表”登记。
  2. 有明确迁出目标 crate。
  3. 不允许继续扩大例外范围。

3. crate 职责矩阵

crate 职责 禁止内容
module-ai AI 任务、阶段、流式片段、结果引用的纯领域模型和状态机 真实 LLM 调用、HTTP、SSE
module-assets 资产对象、资产绑定、历史查询输入输出和纯校验规则 OSS head、reqwest、进程内 fallback store 扩散到领域核心
module-auth 用户、会话、验证码、微信绑定、密码规则、领域错误 文件持久化、真实短信副作用、HTTP cookie 写入
module-big-fish 大鱼创作会话、素材槽、运行态规则 图片生成、OSS 上传、HTTP handler
module-combat 战斗聚合、行动结算、奖励结果 直接写背包表、直接发放成长账本
module-custom-world 世界 profile、Agent 会话、草稿卡、发布门禁规则 LLM 推理、OSS、Axum response shape
module-inventory 背包、装备槽、堆叠与消耗规则 SpacetimeDB table 操作
module-npc NPC 关系、好感、互动、招募规则 战斗表初始化事务
module-progression 玩家等级、章节预算、经验记账规则 查询前端视图拼装
module-puzzle 拼图创作与运行态纯规则 图片生成、排行榜 HTTP shape
module-quest 任务领取、推进、完成、交付规则 奖励跨域副作用直接写表
module-runtime 运行时设置、快照、个人页状态、存档领域模型 直接读写 SpacetimeDB
module-runtime-item 宝箱、奖励物品、运行时物品快照 背包持久化事务
module-runtime-story RPG runtime story 新接口下的纯应用编排、剧情投影、场景旅行、战后收束、prompt context 投影 Axum、LLM、SpacetimeDB
module-story story session、story event 与推进输入输出 直接调用 LLM 或 HTTP
spacetime-module 表、reducer、procedure、事务内查询写回、row/snapshot mapper、event table 领域规则大段堆叠
spacetime-client api-server 调用 SpacetimeDB 的客户端 facade 与绑定 mapper 领域规则
api-server 路由、鉴权上下文、请求响应映射、SSE、平台服务编排 表结构定义、领域规则主逻辑
platform-* JWT/SMS/微信/OSS/LLM/HTTP client 等外部能力 玩法领域规则
shared-kernel 字符串、时间、ID、纯值归一化 业务流程
shared-contracts HTTP/前端 DTO、兼容 response shape 领域状态机

4. 统一目录结构

所有 module-* 必须具备以下文件。第一阶段允许旧实现仍在 lib.rs 或历史子模块中,但新增和迁移代码必须进入对应落点。

src/
├─ lib.rs
├─ domain.rs 或 domain/
├─ commands.rs
├─ application.rs
├─ events.rs
└─ errors.rs

落位规则:

  1. domain.rs / domain/*:聚合、值对象、领域方法、纯校验、状态迁移。
  2. commands.rs:写入用例输入,只表达意图和必要参数,不含 adapter 类型。
  3. application.rs:纯应用编排函数,输出领域事件或应用结果,不执行外部副作用。
  4. events.rs:领域事件和跨上下文事件,例如奖励待入账、画廊投影待刷新。
  5. errors.rs:领域错误,优先可测试、可映射,不直接绑定 HTTP status。
  6. mapper.rs:只允许在 api-serverspacetime-modulespacetime-client 等 adapter crate 中出现。

5. 上下文设计清单

5.1 认证 module-auth

聚合:

  1. AuthUser账号、公开百梦号、登录方式、绑定状态、token version。
  2. RefreshSessionrefresh token hash、客户端信息、过期、吊销、last seen。
  3. SmsVerification:手机号、场景、验证码状态、冷却、失败次数。
  4. WechatBinding:微信 provider 身份、union id、绑定状态。

命令:

  1. PasswordEntryInput
  2. SendPhoneCodeInput
  3. PhoneLoginInput
  4. CreateRefreshSessionInput
  5. RevokeRefreshSessionInput
  6. ResolveWechatLoginInput

事件:

  1. AuthUserCreated
  2. RefreshSessionIssued
  3. RefreshSessionRevoked
  4. PhoneCodeAccepted
  5. WechatIdentityLinked

读模型:

  1. AuthMeResult
  2. PublicUserSearchResult
  3. AuthSessionListResult

迁移要求:文件持久化和内存 store 从领域核心剥离到 adapter 或临时测试支撑;短信真实发送继续在 platform-auth

5.2 资产 module-assets

聚合:

  1. AssetObjectbucket、object key、访问策略、hash、版本、业务归属。
  2. AssetEntityBinding:实体类型、实体 id、slot、资产对象 id。

命令:

  1. ConfirmAssetObjectInput
  2. AssetObjectUpsertInput
  3. AssetEntityBindingInput
  4. AssetHistoryListInput

事件:

  1. AssetObjectConfirmed
  2. AssetEntityBindingChanged

读模型:

  1. AssetObjectUpsertSnapshot
  2. AssetEntityBindingSnapshot
  3. AssetHistoryEntrySnapshot

迁移要求OSS head_object、reqwest client 和 fallback store 不再放入领域核心SpacetimeDB 持久化由 spacetime-module 完成。

5.3 RPG 运行时

覆盖 module-storymodule-combatmodule-inventorymodule-npcmodule-progressionmodule-questmodule-runtime-item

聚合:

  1. StorySessionStoryEvent
  2. BattleState
  3. InventorySlot
  4. NpcState
  5. PlayerProgressionChapterProgression
  6. QuestRecordQuestLog
  7. TreasureRecord

跨上下文事件:

  1. CombatVictoryResolved
  2. QuestTurnedIn
  3. InventoryItemsGranted
  4. ProgressionXpGranted
  5. NpcRelationChanged
  6. RuntimeStoryProjectionChanged

事务边界:

  1. 单聚合变更在对应 module-* 纯函数中完成。
  2. 战斗奖励、任务奖励、背包写入、成长记账由 spacetime-module 或应用服务显式编排。
  3. reducer/procedure 不允许复制领域规则,只负责取 row、调用领域函数、写回 row 和事件表。

5.4 世界创作 module-custom-world

聚合:

  1. CustomWorldProfile
  2. CustomWorldSession
  3. CustomWorldAgentSession
  4. CustomWorldAgentMessage
  5. CustomWorldAgentOperation
  6. CustomWorldDraftCard
  7. CustomWorldGalleryEntry

命令:

  1. 创建/恢复 Agent 会话。
  2. 写入用户消息。
  3. 写入 LLM 最终回复。
  4. 更新草稿卡。
  5. 发布/下架 profile。

事件:

  1. CustomWorldDraftChanged
  2. CustomWorldProfilePublished
  3. CustomWorldGalleryProjectionChanged
  4. CustomWorldAgentOperationProgressed

迁移要求LLM 提示词和推理在 api-server + platform-llmSpacetimeDB 只落真相表和投影。

5.5 拼图 module-puzzle

聚合:

  1. PuzzleAgentSession
  2. PuzzleAgentMessage
  3. PuzzleWorkProfile
  4. PuzzleRuntimeRun

事件:

  1. PuzzleDraftChanged
  2. PuzzleWorkPublished
  3. PuzzleRunAdvanced

读模型:

  1. 作品卡片。
  2. 运行态快照。
  3. 排行榜结果。

5.6 大鱼吃小鱼 module-big-fish

聚合:

  1. BigFishCreationSession
  2. BigFishAgentMessage
  3. BigFishAssetSlot
  4. BigFishRuntimeRun

事件:

  1. BigFishDraftChanged
  2. BigFishAssetSlotChanged
  3. BigFishRunTicked

5.7 AI module-ai

聚合:

  1. AiTask
  2. AiTaskStage
  3. AiTextChunk
  4. AiResultReference

事件:

  1. AiTaskStarted
  2. AiTaskStageCompleted
  3. AiTaskFailed
  4. AiResultAttached

边界:真实模型调用只在 platform-llmmodule-ai 只表达状态机。

6. SpacetimeDB adapter 映射

spacetime-module 中每个上下文遵循:

src/<context>/
├─ mod.rs
├─ tables.rs        # table 和 public/event 标记
├─ reducers.rs      # 客户端可调用写入口
├─ procedures.rs    # 需要同步返回或外部 procedure 语义的入口
├─ mapper.rs        # row <-> module-* snapshot/input
└─ queries.rs       # 事务内查询辅助,只返回 adapter DTO

当前已有历史拆分与本文不同名时,先按现有文档继续维护;新增或迁移时逐步对齐上面结构。

Reducer / procedure 规则:

  1. reducer 使用 &ReducerContext,返回 Result<(), String> 处理预期错误。
  2. reducer 内授权必须基于 ctx.sender(),禁止信任参数中的身份。
  3. reducer 禁止网络、文件系统、外部随机数和全局状态。
  4. procedure 使用 SpacetimeDB 2.0 正确 API涉及事务必须显式 with_tx / try_with_tx
  5. 表访问必须使用 ctx.db.table(),更新只通过主键。
  6. 复杂查询不复用写模型;需要前端订阅时新增明确读模型或 public 投影表。

7. 表结构约束

默认不改现有 SpacetimeDB 主表。确需改表时按以下优先级:

  1. 新增 optional 字段。
  2. 新增投影表或 event table。
  3. 新增索引。
  4. 最后才考虑 rename/delete/type change且必须单独写迁移方案。

任何 table 变更必须同步:

  1. server-rs/crates/spacetime-module/src/migration.rs
  2. docs/technical/SPACETIMEDB_TABLE_CATALOG.md
  3. 对应 reducer/procedure 测试或最小 smoke
  4. 绑定生成和前端/spacetime-client 映射

本阶段只做目录、文档和边界检查,不变更表结构,因此不需要改 migration.rs

8. 查询策略

  1. 写模型不直接服务复杂前端页面。
  2. 每个前端场景必须有独立 query/result DTO。
  3. private table 默认不暴露给前端。
  4. public table 只服务明确订阅场景。
  5. event table 用于 reducer 后广播一次性事件,客户端必须显式订阅。

9. 第一阶段落地范围

第一阶段只做低风险基础设施:

  1. 新增本文作为 DDD 总纲。
  2. 所有 module-* 补齐 domain / commands / application / events / errors 过渡落位文件。
  3. 新增 scripts/check-server-rs-ddd-boundaries.mjs,检查 DDD 骨架、禁用 mapper 落位和 SpacetimeDB/Axum 绝对边界。
  4. 更新文档索引和后端 README。
  5. 不改表、不改 reducer/procedure 名、不改 HTTP contract。

9.1 首个样板切片

module-assets 先作为 DDD 分层导出样板:

  1. domain.rs 对外导出资产对象、实体绑定、访问策略、快照和纯校验函数。
  2. commands.rs 对外导出确认资产、绑定实体、资产历史查询等输入。
  3. application.rs 对外导出应用结果和纯构建函数。
  4. errors.rs 对外导出资产领域错误。
  5. asset_object_core.rs 暂作为内部历史实现文件保留,不再由 lib.rs 直接对外导出;后续触碰资产规则时继续把实现逐段迁到 DDD 文件。

10. 阶段性债务表

债务 当前位置 迁出目标 约束
资产 OSS head 与 reqwest 服务仍在 module-assets server-service feature module-assets/src/asset_object_service.rs api-server 应用服务或独立 adapter crate 不得被 domain.rs 引用,不得新增更多 OSS 领域规则
认证内存 store / 文件持久化仍在 module-auth module-auth/src/lib.rs adapter / repository 目录或 api-server 启动恢复层 新业务规则不得继续依赖文件路径
spacetime-module/src/lib.rs 仍有大量 gameplay 入口 spacetime-module/src/lib.rs src/gameplay/*src/custom_world/*src/puzzle/* 新增实现禁止继续堆回根入口
部分 module-* 仍是单文件领域实现 多个 module-*src/lib.rs 对应 DDD 文件 每次触碰模块时顺手迁移相关片段
runtime story 兼容层仍存在 module-runtime-story-compatapi-server/src/runtime_story/compat*、前端旧 runtime story client module-runtime-story、session scoped 新接口、前端新 client 本轮允许 breaking change不再为旧 HTTP shape 保留双接口

11. 全局并行执行清单

2026-04-29 起,server-rs DDD 全局重构按 SERVER_RS_DDD_PARALLEL_TASKLIST_2026-04-29.md 执行。该清单覆盖:

  1. 文档、契约、DDD 骨架和边界检查。
  2. module-authmodule-assetsmodule-aimodule-custom-worldmodule-big-fishmodule-puzzlemodule-runtime、RPG gameplay 域和 runtime story 域。
  3. spacetime-modulespacetime-clientapi-serverplatform-* 和前端接入。
  4. 旧层删除、命名收口、全链验证和 Maincloud smoke。

12. 去兼容层任务

2026-04-29runtime story / chat 改造按 SERVER_RS_DDD_PARALLEL_TASKLIST_2026-04-29.md 中的 WP-RS Runtime Story 去兼容层 工作包执行。该工作包明确:

  1. 当前 compat 层可以物理删除。
  2. 新接口采用 POST /api/runtime/story/sessions/:sessionId/... 的 session scoped 口径。
  3. 前端允许同步修改以匹配新 contract。
  4. api-server 不再为旧 worldType / character / monsters / history / context 请求体保留正式主链分支。

13. 验收命令

阶段验收至少执行:

node scripts/check-server-rs-ddd-boundaries.mjs
cargo fmt --all --check --manifest-path server-rs/Cargo.toml
cargo test --workspace --manifest-path server-rs/Cargo.toml
cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml
npm run api-server:maincloud
npm run check:encoding

npm run api-server:maincloud 因本机未配置 Maincloud 数据库或令牌失败,必须记录具体错误;不能改用旧后端重启命令。