# Express 后端并行任务完成度审计(2026-04-09) ## 1. 审计范围 本次审计以 `docs/planning/EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md` 为基准,只检查仓库内可直接验证的代码、测试、脚本和文档产物。 不能仅靠仓库静态内容确认的团队协作物,例如看板、口头冻结流程、每日集成节奏,只按“仓库内可见状态”记录,不把它们误判成完全验收。 --- ## 2. 任务完成度总览 | 任务 | 状态 | 结论 | | --- | --- | --- | | 任务 0:集成岗与接口冻结 | 基本完成 | 已补齐接口冻结与集成清单文档,contract 版本表、热点文件编辑规则、集成窗口检查项都已落库;但团队执行节奏本身仍无法仅凭仓库静态确认。 | | 任务 1:共享 Contract 与目录抽离 | 部分完成 | `packages/shared` 已建立并承接 auth/runtime/story contract,且 NPC Task6 bridge 与 chat prompt builder 已进一步下沉到后端本地模块;但 AI 编排主链仍残留少量 `src/**` 反向依赖,分层尚未完全闭合。 | | 任务 2:PostgreSQL 持久化基线收口 | 已完成 | `server-node/src/config.ts`、`db.ts`、`repositories/**`、迁移脚本、`pg-mem` 测试与部署文档均已到位。 | | 任务 3:HTTP 基础设施与统一响应壳层 | 已完成 | 统一错误格式、`requestId`、route meta、响应壳层、观测测试已落地。 | | 任务 4:服务端 AI 编排收口 | 基本完成 | orchestration 模块、SSE 转发和主链调用已回到后端,但仍有少量 prompt/规则模块通过 `src/**` 复用,属于后续继续收敛项。 | | 任务 5:Story / Combat / NPC | 已完成 | 后端 story action route、session 组装、combat/npc 领域服务和对应回归测试已落地。 | | 任务 6:Inventory / Quest / Build / Runtime Item | 已完成 | 对应模块、服务与回归测试已经覆盖主要正式运行时结算。 | | 任务 7:前端 SDK、鉴权、持久化瘦身 | 部分完成 | `apiClient`、`authService`、`storageService` 已统一,但前端仍保留一部分存档归一化和主流程协调职责。 | | 任务 8:编辑器 API 归口与工具链隔离 | 基本完成 | editor/assets 模块、前端 editor client、迁移文档均已出现,职责边界基本清晰。 | | 任务 9:测试、观测与部署基线 | 已完成 | baseline test、smoke、proxy smoke、部署与回滚清单、日志链路均已具备。 | | 任务 10:前端主流程壳层与大 Hook 瘦身 | 部分完成 | `GameShellRuntime` / `useGameShellRuntimeViewModel` 以及新的 `storyRequestCoordinator` 已拆出,但 `useStoryGeneration.ts` 仍然过重,主流程尚未彻底退回“表现层协调器”。 | --- ## 3. 本轮补齐项 本轮先补齐了任务 0 缺失的仓库内协作产物: - 新增 `docs/technical/EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md` - 落库当前 contract 版本表 - 明确热点文件编辑规则 - 补齐 shared/runtime/editor/frontend 壳层各自的集成窗口清单 这让任务 0 不再只停留在规划文档里,而是有了一份可随版本一起更新的冻结口径。 随后补上了一段此前仍偏向前端快照解释的恢复链路: - `src/hooks/story/runtimeStoryCoordinator.ts` - 新增 `resumeServerRuntimeStory` - 继续游戏时,若当前是正式运行时故事快照,会先请求 `/api/runtime/story/state/:sessionId` - 让当前 `storyText` 与可用 `options` 优先以后端 runtime state 为准 - `src/hooks/useGamePersistence.ts` - `continueSavedGame()` 现在会优先走后端 runtime story 恢复 - 如果服务端恢复失败,再回退到本地快照归一化结果 - 额外补了 `bottomTab` 归一化,避免恢复时吃到宽泛字符串 - `src/hooks/story/runtimeStoryCoordinator.test.ts` - 新增“继续游戏时优先从后端恢复 runtime story”的测试 - 新增“非正式运行时快照不额外请求后端”的测试 这次补丁对应的是任务 7 与任务 10 之间的一段未完全闭合边界:前端在恢复流程里不应该只把远端存档当作“原始 JSON 缓存”,而应优先相信后端当前 runtime state。 此外,本轮还继续补了任务 1 的一段后端分层收口: - 新增 `server-node/src/modules/runtime/runtimeStatePrimitives.ts` - 后端本地承接 `addInventoryItems` - 后端本地承接 `removeInventoryItem` - 后端本地承接 `incrementGameRuntimeStats` - 后端本地承接 `buildRelationState` - 新增 `server-node/src/modules/runtime/runtimeStatePrimitives.test.ts` - 校验背包合并、移除、运行时统计累加、关系阶段映射 - 调整桥接层: - `server-node/src/bridges/legacyInventoryRuntimeBridge.ts` - `server-node/src/bridges/legacyNpcTask6Bridge.ts` - `server-node/src/modules/quest/questTask6Bridge.ts` 这意味着任务 5/6 主链里最基础的一批状态原语,已经不再依赖前端 `src/data/runtimeStats.ts`、`src/data/attributeResolver.ts`、`src/data/npcInteractions.ts` 的对应实现。 本轮又继续把 NPC Task6 bridge 里最后一批直接挂到前端 `npcInteractions.ts` 的函数下沉到了后端本地: - 新增 `server-node/src/modules/npc/npcTask6Primitives.ts` - 后端本地承接 `applyStoryChoiceToStanceProfile` - 后端本地承接 `buildInitialNpcState` - 后端本地承接 `syncNpcTradeInventory` - 后端本地承接 `getGiftCandidates` - 后端本地承接 `buildNpcGiftCommitActionText` - 后端本地承接 `buildNpcGiftResultText` - 后端本地承接 `buildNpcTradeTransactionActionText` - 后端本地承接 `buildNpcTradeTransactionResultText` - 新增 `server-node/src/modules/npc/npcTask6Primitives.test.ts` - 覆盖 NPC 初始库存生成 - 覆盖交易库存刷新时保留非交易物品 - 覆盖赠礼偏好排序 - 调整桥接层: - `server-node/src/bridges/legacyNpcTask6Bridge.ts` 这意味着 Task6 的 NPC 交易/赠礼/初始库存这条支链,已经不再直接依赖前端 `src/data/npcInteractions.ts`。 同时还把叙事语言检测工具下沉到了共享层: - 新增 `packages/shared/src/llm/narrativeLanguage.ts` - `src/services/narrativeLanguage.ts` 改为复用共享实现 - `server-node/src/modules/ai/storyOrchestrator.ts` 改为直接依赖共享层 这部分虽然不是大块业务迁移,但它属于任务 1 最稳定的一类收口:把纯函数共识从前端目录中抽离出来。 再补充一批已经完成的后端纯原语迁移: - 新增 `server-node/src/modules/runtime/runtimeEconomyPrimitives.ts` - 后端本地承接 `formatCurrency` - 后端本地承接 `getInventoryItemValue` - 后端本地承接 `getNpcPurchasePrice` - 后端本地承接 `getNpcBuybackPrice` - 新增 `server-node/src/modules/runtime/runtimeTreasureTexts.ts` - 后端本地承接 `buildTreasureResultText` - 新增 `server-node/src/modules/runtime/runtimeEconomyPrimitives.test.ts` - 覆盖交易定价、货币文本、宝藏奖励文本 对应桥接层: - `server-node/src/bridges/legacyNpcTask6Bridge.ts` - 不再依赖前端 `src/data/economy.ts` - `server-node/src/bridges/legacyTreasureRuntimeBridge.ts` - 不再从前端导出 `buildTreasureResultText` 这说明任务 5/6 主链中一部分交易、礼物、宝藏结算反馈文本,也已经从前端数据层抽离。 本轮又进一步补了 NPC 状态与叙事记忆的后端本地原语: - 新增 `server-node/src/modules/runtime/runtimeNpcStatePrimitives.ts` - 后端本地承接 `normalizeNpcPersistentState` - 后端本地承接 `markNpcFirstMeaningfulContactResolved` - 新增 `server-node/src/modules/runtime/runtimeNarrativeMemory.ts` - 后端本地承接 `appendStoryEngineCarrierMemory` - 新增 `server-node/src/modules/runtime/runtimeNpcStatePrimitives.test.ts` - 覆盖 NPC 状态归一化、首次有效接触标记、叙事载体记忆写入 对应桥接层: - `server-node/src/bridges/legacyNpcTask6Bridge.ts` - 不再依赖前端 `src/services/storyEngine/echoMemory.ts` - 不再依赖前端 `src/data/npcInteractions.ts` 中的 NPC 状态归一化与首次接触标记逻辑 这进一步缩小了后端在任务 5/6 主链上对前端 story-engine 服务目录的借用范围。 本轮还整块收口了 Quest 与 Runtime Item 两条桥接链: - 新增 `server-node/src/modules/quest/runtimeQuestModule.ts` - 后端本地承接 `buildQuestForEncounter` - 后端本地承接 `evaluateQuestOpportunity` - 后端本地承接 `buildFallbackQuestIntent` - 后端本地承接 `compileQuestIntentToQuest` - 后端本地承接 `buildQuestGenerationContextFromState` - 后端本地承接 `buildQuestIntentPrompt` - 后端本地承接 Quest 进度归一化与 signal 推进 - 更新桥接层: - `server-node/src/bridges/legacyQuestProgressBridge.ts` - `server-node/src/bridges/legacyQuestRuntimeBridge.ts` 这意味着 Quest 的“确定性委托构建 + AI 意图上下文 + 任务推进”已经不再依赖前端 `src/data/questFlow.ts`、`src/services/questDirector.ts`、`src/services/questPrompt.ts`。 同时,Runtime Item 也已经收回到后端本地: - 新增 `server-node/src/modules/runtime-item/runtimeItemModule.ts` - 后端本地承接 `buildRuntimeItemAiIntent` - 后端本地承接 `buildRuntimeItemIntentPrompt` - 后端本地承接 `buildLooseRuntimeItemGenerationContext` - 后端本地承接 `buildQuestRuntimeItemGenerationContext` - 后端本地承接 `buildDirectedRuntimeReward` - 后端本地承接 `buildRuntimeInventoryStock` - 后端本地承接 `flattenDirectedRuntimeRewardItems` - 新增 `server-node/src/modules/runtime-item/runtimeTreasureModule.ts` - 后端本地承接 `resolveTreasureReward` - 更新桥接层: - `server-node/src/bridges/legacyRuntimeItemBridge.ts` - `server-node/src/bridges/legacyRuntimeItemResolutionBridge.ts` - `server-node/src/bridges/legacyTreasureRuntimeBridge.ts` 这说明 Runtime Item / Treasure 相关的 AI 意图、奖励生成和库存生成,也已经从前端目录中抽离。 本轮还继续整块收口了 Build / Inventory / Forge / Equipment 规则桥接: - 新增 `server-node/src/modules/runtime/runtimeEquipmentModule.ts` - 后端本地承接 `getEquipmentSlotFromItem` - 后端本地承接 `getEquipmentSlotLabel` - 后端本地承接 `getEquipmentBonuses` - 后端本地承接 `applyEquipmentLoadoutToState` - 新增 `server-node/src/modules/runtime/runtimeInventoryEffectsModule.ts` - 后端本地承接 `isInventoryItemUsable` - 后端本地承接 `resolveInventoryItemUseEffect` - 后端本地承接 `buildInventoryUseResultText` - 新增 `server-node/src/modules/runtime/runtimeForgeModule.ts` - 后端本地承接 `getForgeRecipeViews` - 后端本地承接 `executeForgeRecipe` - 后端本地承接 `executeDismantleItem` - 后端本地承接 `executeReforgeItem` - 后端本地承接 `getReforgeCostView` - 后端本地承接 `buildForgeSuccessText` - 新增 `server-node/src/modules/runtime/runtimeBuildModule.ts` - 后端本地承接 `appendBuildBuffs` - 后端本地承接 `getPlayerBuildDamageBreakdown` - 后端本地承接 `resolvePlayerOutgoingDamageResult` 对应桥接层: - `server-node/src/bridges/legacyBuildRuntimeBridge.ts` - `server-node/src/bridges/legacyInventoryRuntimeBridge.ts` 这意味着 Build / Inventory / Forge / Equipment 相关的后端主链结算,已经不再依赖前端 `src/data/buildDamage.ts`、`src/data/equipmentEffects.ts`、`src/data/forgeSystem.ts`、`src/data/inventoryEffects.ts`。 本轮又补了一段任务 1 的 AI 编排收口: - 新增 `server-node/src/modules/ai/chatPromptBuilders.ts` - 后端本地承接 character chat reply / suggestions / summary prompt 组装 - 后端本地承接 npc chat / recruit prompt 组装 - 调整: - `server-node/src/modules/ai/chatOrchestrator.ts` - `server-node/src/modules/ai/orchestrator.test.ts` 这意味着 chat orchestration 已不再依赖前端 `src/services/characterChatPrompt.ts` 与 `src/services/prompt.ts`。 本轮继续把 story orchestration 主链也收回到了后端本地: - 新增 `server-node/src/modules/ai/storyPromptBuilders.ts` - 后端本地承接 `SYSTEM_PROMPT` - 后端本地承接 `buildUserPrompt` - 重写 `server-node/src/modules/ai/storyOrchestrator.ts` - 正式生产链不再依赖前端 `src/services/prompt.ts` - 正式生产链不再依赖前端 `src/data/stateFunctions.ts` - 正式生产链不再依赖前端 `src/data/scenePresets.ts` - 正式生产链不再依赖前端 `src/data/hostileNpcs.ts` - 调整: - `server-node/src/modules/ai/orchestrator.test.ts` 到这里,`server-node` 正式生产代码路径里,Story / Chat / Quest / Runtime Item / Treasure / Build / Inventory / Forge / NPC Task6 主链都已经从前端 `src/**` 目录脱钩。 本轮也继续推进了任务 10 的主流程瘦身: - 新增 `src/hooks/story/storyRequestCoordinator.ts` - 抽离运行时 option source 解析 - 抽离服务端 option catalog 回退策略 - 抽离 initial / next story 请求参数协调 - 新增 `src/hooks/story/storyRequestCoordinator.test.ts` - 覆盖服务端 option catalog 切换 - 覆盖显式 option catalog 短路 - 覆盖服务端目录加载失败时回退本地可用项 - 调整: - `src/hooks/useStoryGeneration.ts` 这说明 `useStoryGeneration.ts` 虽然仍重,但“故事请求协调”已经不再和主流程 UI 状态、NPC/战斗/宝藏后续处理混在同一个大段里。 本轮又补了一段任务 10 的纯展示逻辑拆分: - 新增 `src/hooks/story/storyPresentation.ts` - 抽离 story options 去重与补齐 - 抽离对白 turn 解析 - 抽离 dialogue story moment 组装 - 抽离 typewriter delay - 新增 `src/hooks/story/storyPresentation.test.ts` - 覆盖对白解析与 dialogue story moment - 覆盖选项池去重与补齐 - 调整: - `src/hooks/useStoryGeneration.ts` 这意味着 `useStoryGeneration.ts` 又减少了一批与 React 状态本身无关的纯函数逻辑,任务 10 的主流程壳层拆分继续向前推进。 本轮还补上了任务 1 的最后一条后端反向依赖: - 删除 `server-node/src/bridges/legacyCustomWorldAiBridge.ts` - 重写 `server-node/src/modules/ai/customWorldOrchestrator.ts` - 后端本地承接 custom world generation 的 deterministic 生成流程 - 后端本地承接 generation progress 汇报 这意味着 `server-node/src/**` 的正式生产代码路径已经不再反向依赖前端 `src/**` 目录。 --- ## 4. 仍需继续收口的重点 ### 4.1 任务 1 的剩余问题 当前从仓库内直接扫描看,`server-node/src/**` 的正式生产代码路径已经不再存在对前端 `src/**` 的反向依赖。 其中 Story / Chat / Quest / Runtime Item / Treasure / Build / Inventory / Forge / Equipment / NPC Task6 / Custom World generation 相关正式生产链都已经从这个列表中退出。 同时,`server-node/src/modules/ai/orchestrator.test.ts` 已不再直接依赖前端 `src/services/prompt.ts` 与 `src/data/stateFunctions.ts`。 这说明任务 1 在“后端正式生产运行时不反向依赖前端目录”这一层面已经完成。 #### 4.1.1 当前残留依赖的真实形态 从当前状态看,任务 1 后续不再是“补洞”,而是“优化”: - 继续提高 custom world generation 的质量与保真度 - 继续把真正通用的 prompt / JSON repair / batch helper 整理进 `packages/shared` 或 `server-node/src/modules/ai/**` - 维持后端不再回流引用前端目录的约束 #### 4.1.2 更适合的继续收口顺序 结合当前状态,任务 1 后续更适合做的是能力优化: 1. 继续增强 custom world generation 的语义保真度与校验强度。 2. 继续把 prompt builder、JSON repair、批处理工具整理到 `packages/shared` 或 `server-node/src/modules/ai/**`。 3. 持续维持“后端正式生产代码不反向依赖前端目录”的约束,避免后续重新开洞。 ### 4.2 任务 7 的剩余问题 前端虽然已经大量改成 SDK 消费层,但 `src/persistence/runtimeSnapshot.ts` 里仍保留较重的存档归一化与迁移修复逻辑。 这部分后续仍建议继续向后端迁移,避免前后端双边解释快照。 #### 4.2.1 `runtimeSnapshot.ts` 当前仍承担的职责 从文件本身看,`src/persistence/runtimeSnapshot.ts` 仍不是一个单纯的“读取后端结果并转成 UI 状态”的轻薄消费层。 它当前仍直接负责: - 存档迁移 manifest 应用 - roster 归一化 - player currency 默认值补齐 - equipment loadout 回填与属性重算 - NPC persistent state 归一化 - quest log 归一化 - runtime stats 归一化 - scene encounter preview 修复 - story engine memory 缺省补齐 这说明任务 7 的剩余问题,不只是“前端还有一点 normalize 代码”,而是: - 前端仍在解释正式存档的结构语义 - 前端仍在决定若干正式运行时字段的缺省和修复策略 - 后端与前端之间仍存在“双边都能定义快照有效形态”的空间 #### 4.2.2 下一步更合适的迁移方向 结合本轮已经补上的“继续游戏优先以后端 runtime story state 为准”这段恢复链路,任务 7 后续更适合继续向这个方向推进: 1. 把 `runtimeSnapshot.ts` 中的迁移、归一化、缺省补齐继续下沉到后端持久化层或专门的 runtime snapshot service。 2. 让前端拿到的远端快照尽量已经是“可直接消费的正式形态”,而不是“仍需前端补算的半成品”。 3. 把前端保留的本地 hydrate 逻辑收缩到纯 UI 恢复字段,例如当前页签、面板开合、局部显示态。 只有这样,任务 7 才算真正回到“前端只做消费层,后端才是正式状态解释者”的目标。 ### 4.3 任务 10 的剩余问题 当前最大的未完成项仍然是: - `src/hooks/useStoryGeneration.ts` 它仍承担了大量: - 正式运行时故事编排 - 本地 fallback 组织 - NPC / 宝藏 / 战斗后续协调 - 主流程状态推进 现阶段虽然已经有: - `src/hooks/useGameShellRuntime.ts` - `src/components/game-shell/useGameShellRuntimeViewModel.ts` - `src/hooks/story/runtimeStoryCoordinator.ts` - `src/hooks/story/storyRequestCoordinator.ts` 但主流程还没有彻底完成 action/view model 化,任务 10 仍应视为“进行中”。 #### 4.3.1 `useStoryGeneration.ts` 当前仍然为什么过重 从仓库现状看,`src/hooks/useStoryGeneration.ts` 目前仍有约 1700 行,且其过重问题已经不是单纯“文件太长”,而是它还保留着大量正式业务协调职责。 当前这个 hook 里仍集中着: - `buildStoryContextFromState` 这一整块故事上下文拼装 - AI 请求前的 option catalog / fallback 组织 - NPC / 宝藏 / 战斗 / inventory / goal / session 多条子链的集中协调 - 本地 fallback story 生成 - 一部分运行时规则与 narrative context 的最终拼装入口 这意味着即使已经拆出了: - `runtimeStoryCoordinator` - `storyRequestCoordinator` - `choiceActions` - `npcEncounterActions` - `sessionActions` `useStoryGeneration.ts` 仍然不是“单纯的 UI 壳层 hook”,而更像前端侧的运行时总协调器。 #### 4.3.2 任务 10 后续更值得优先拆的部分 按当前文件结构看,后续最值得优先继续抽离的不是零散按钮逻辑,而是下面三类真正还握在主 hook 里的核心块: 1. `buildStoryContextFromState` 这一整块 story-engine 叙事上下文装配。 2. `buildFallbackStoryForState` / `getAvailableOptionsForState` 这类“正式规则兜底与选项来源判断”。 3. NPC / Treasure / Character Chat / Session 这些子流之间的最终总装协调。 如果只是继续把零散函数拆到 `src/hooks/story/**`,但上述三块还留在主 hook 里,那么任务 10 仍然不会真正完成。 ### 4.4 建议的下一轮补齐顺序 结合任务 1、任务 7、任务 10 当前的剩余形态,后续更合适的补齐顺序建议是: 1. 先继续收任务 7 的 runtime snapshot 解释权,把正式快照的迁移、修复、归一化口径继续回收到后端。 2. 再继续收任务 10,把 `useStoryGeneration.ts` 压回主流程协调壳层,而不是继续让它承担正式运行时总装职责。 这样排的原因是: - 任务 1 已经完成后,新的主阻塞就变成了任务 7 和任务 10。 - 如果任务 7 不继续收,前端仍会在恢复链路里保留正式状态解释权,任务 10 也很难真正变薄。 - 等到 runtime state 与 snapshot 口径都更稳定后,再继续瘦 `useStoryGeneration.ts`,返工会更少。 --- ## 5. 本轮验证 已通过: - `npm run server-node:test` - `npx vitest run src/hooks/story/storyRequestCoordinator.test.ts src/hooks/story/runtimeStoryCoordinator.test.ts` - `npm run typecheck` - `npm run check:encoding` --- ## 6. 结论 从仓库可验证结果看,任务 2、3、5、6、9 已经达到“可认为完成”的状态;任务 0、4、8 基本完成;任务 1、7、10 仍有明显后续收口空间。 当前最主要的未完成中心已经不再是后端基建,而是: **把前端主流程和存档恢复彻底收成“以后端 runtime state 和 view model 为唯一真相源”。**