# 前端逻辑后移实施方案(2026-04-21) 更新时间:`2026-04-21` ## 1. 目标 本方案只回答一件事: **怎样把当前仍残留在前端的正式运行时逻辑、正式会话真相与正式生成编排,继续收回到 Express 后端。** 这份文档不是泛泛而谈的方向说明,而是直接面向本轮与后续几轮编码落地的实施基线。 --- ## 2. 本轮确定的硬边界 根据仓库约束与当前审计结果,本轮继续冻结以下边界: 1. 前端只负责表现、输入采集、临时 UI 状态与服务端结果渲染。 2. 后端负责正式鉴权、正式会话、正式运行时快照、正式任务生成、正式运行时物品意图生成、正式自定义世界生成。 3. 浏览器内不再保存 access token,不再把浏览历史作为本地正式真相,不再保留正式 quest / runtime item / custom world 生成编排。 4. 运行时主链必须继续向“前端提交意图,后端解释快照并返回展示模型”收敛。 --- ## 3. 现状拆分 当前残留问题已经收敛为三批: ### 3.1 第一批:正式真相仍在前端 1. `src/services/apiClient.ts` - 浏览器仍保存 access token,并拼接 `Authorization: Bearer ...` 2. `src/services/authService.ts` - 登录、微信绑定等流程仍把 access token 当作前端真相 3. `src/components/game-shell/PreGameSelectionFlow.tsx` - 浏览历史仍是本地写入 + 后端回填的双真相 4. `src/services/platformBrowseHistory.ts` - 维护浏览历史本地存储、迁移标记与同步状态 ### 3.2 第二批:运行时主链仍依赖前端预写快照 1. `src/hooks/story/runtimeStoryCoordinator.ts` - 在请求 runtime state / runtime action 前,仍先 `PUT /runtime/save/snapshot` 2. `src/hooks/story/npcEncounterActions.ts` - 待接委托的“更换任务”“放弃任务”仍由前端正式结算 ### 3.3 第三批:正式生成编排仍残留在浏览器 1. `src/services/questDirector.ts` 2. `src/services/runtimeItemAiDirector.ts` 3. `src/services/aiService.ts` 的 custom world profile 生成入口 4. `src/services/ai.ts` 中仍保留的浏览器侧 legacy AI orchestration --- ## 4. 分批实施策略 ## 4.1 第一批:先收正式真相 ### 鉴权 目标状态: 1. 后端通过 HttpOnly Cookie 持有 refresh session 与 access session。 2. 前端请求层不再读写 access token。 3. 前端只监听鉴权状态事件,不解释 token 生命周期。 本批涉及: 1. `server-node/src/auth/accessSessionCookie.ts` 2. `server-node/src/routes/authRoutes.ts` 3. `server-node/src/middleware/auth.ts` 4. `src/services/apiClient.ts` 5. `src/services/authService.ts` 6. `src/components/auth/AuthGate.tsx` ### 浏览历史 目标状态: 1. 浏览历史唯一真相在 `runtimeRepository`。 2. 前端不再保留本地浏览历史、迁移标记、同步标记。 3. 浏览历史只通过 `storageService` 读取和写入。 本批涉及: 1. `src/components/game-shell/PreGameSelectionFlow.tsx` 2. `src/components/game-shell/PlatformHomeView.tsx` 3. `src/services/storageService.ts` 4. `src/services/platformBrowseHistory.ts` ## 4.2 第二批:把 runtime story 快照解释权收回后端 目标状态: 1. 前端不再通过单独的 `PUT /runtime/save/snapshot` 预写快照再触发动作。 2. runtime state / runtime action 允许前端提交当前快照上下文,由后端内部决定是否写入、如何解释、何时持久化。 3. NPC 待接委托的 replace / abandon / accept 全部走后端 runtime action。 建议实施方式: 1. 扩展 `packages/shared/src/contracts/story.ts` - `RuntimeStoryActionRequest` 增加可选 `snapshot` - 新增 `RuntimeStoryStateRequest` 2. 新增 `POST /api/runtime/story/state/resolve` 3. `storyActionService` 内部统一处理“请求携带快照上下文时的服务端同步” 4. 把 `npc_chat_quest_offer_replace` / `npc_chat_quest_offer_abandon` 接到后端 runtime action ## 4.3 第三批:把正式生成编排收成后端唯一出口 目标状态: 1. `questDirector` 只保留轻量 SDK。 2. `runtimeItemAiDirector` 只保留轻量 SDK。 3. custom world profile 正式生成走后端 route。 4. 浏览器侧 `src/services/ai.ts` 不再承担正式浏览器主链。 建议实施方式: 1. `server-node/src/routes/runtimeRoutes.ts` - 补 `custom-world/profile` 正式 route 2. `src/services/aiService.ts` - custom world 入口改走后端 3. `src/services/questDirector.ts` - 只请求 `/api/runtime/quests/generate` 4. `src/services/runtimeItemAiDirector.ts` - 只请求 `/api/runtime/items/runtime-intent` --- ## 5. 本轮落地范围 本轮优先完成以下内容: 1. 鉴权 access token 从前端 localStorage 后移到后端 Cookie。 2. 浏览历史从前端本地真相后移到后端唯一真相。 3. custom world profile 正式生成入口补齐后端 route,并把前端收成 SDK。 4. `questDirector` / `runtimeItemAiDirector` 收缩为前端 SDK。 5. runtime story contract 开始补“随请求提交快照上下文”的后端承接能力,并把 NPC 待接委托 replace / abandon 接到后端。 --- ## 6. 验收标准 ### 第一批验收 1. 浏览器中不再保存 access token。 2. `fetchWithApiAuth` 不再拼接 Bearer token。 3. 浏览历史仅通过远端接口读写。 4. `src/services/platformBrowseHistory.ts` 不再是正式链路依赖。 ### 第二批验收 1. `runtimeStoryCoordinator.ts` 不再在动作前独立 `PUT /runtime/save/snapshot`。 2. `NPC` 待接委托 replace / abandon / accept 都以后端返回结果为准。 ### 第三批验收 1. `questDirector.ts` 与 `runtimeItemAiDirector.ts` 不再保留正式 fallback orchestration。 2. custom world profile 的浏览器正式入口不再直接 import legacy `./ai`。 --- ## 7. 一句话结论 这轮迁移的重点不是“把几个 helper 挪到 server-node 目录”,而是: **把前端里仍然承担正式真相、正式运行时解释和正式生成编排的那一层职责,继续收回到 Express 后端。**