1
This commit is contained in:
444
docs/audits/CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md
Normal file
444
docs/audits/CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 自定义世界创作工具问题审计与优化建议
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 结论先说
|
||||
|
||||
当前自定义世界创作工具已经有了比较强的生成骨架、锚点结构和结果编辑能力,但整体仍处在一个很明显的“半收口状态”:
|
||||
|
||||
**设计目标已经走到“创作者工作台”,数据结构已经支持“锚点化输入”,但实际体验仍然更像“大文本生成器 + 大型结果总表编辑器”。**
|
||||
|
||||
如果用一句话概括当前问题,就是:
|
||||
|
||||
**高杠杆创作入口还不够强,低杠杆编辑负担还偏重,局部重生成与后端收口也还没有真正闭环。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 审计范围
|
||||
|
||||
本次审计主要对照了三类信息:
|
||||
|
||||
1. 目标设计与 PRD
|
||||
- `docs/prd/AI_NATIVE_CUSTOM_WORLD_CREATION_FLOW_OPTIMIZATION_PRD_2026-04-06.md`
|
||||
- `docs/design/CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md`
|
||||
- `docs/design/CUSTOM_WORLD_SELF_OWNED_SETTING_LAYER_OPTIMIZATION_2026-04-08.md`
|
||||
- `docs/design/CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md`
|
||||
|
||||
2. 当前前端主流程与工作台
|
||||
- `src/components/SelectionCustomizationModals.tsx`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- `src/components/CustomWorldGenerationView.tsx`
|
||||
- `src/components/CustomWorldResultView.tsx`
|
||||
- `src/components/CustomWorldEntityCatalog.tsx`
|
||||
- `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
|
||||
3. 当前生成链与后端会话层
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `src/services/customWorldCreatorIntent.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `server-node/src/services/customWorldSessionStore.ts`
|
||||
- `server-node/src/services/customWorldGenerationService.ts`
|
||||
- `server-node/src/bridges/legacyAiRuntimeBridge.ts`
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前主要问题
|
||||
|
||||
## 2.1 输入层和意图结构已经脱节
|
||||
|
||||
当前数据结构已经支持:
|
||||
|
||||
- 世界一句话
|
||||
- 主题关键词
|
||||
- 气质约束
|
||||
- 玩家身份
|
||||
- 开局处境
|
||||
- 核心冲突
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性要素
|
||||
- 禁止事项
|
||||
|
||||
但实际入口 `src/components/SelectionCustomizationModals.tsx` 里,创作者弹窗仍然基本只有:
|
||||
|
||||
- 生成模式
|
||||
- 一块大 textarea
|
||||
|
||||
这导致两个直接后果:
|
||||
|
||||
1. 设计里已经想清楚的“高杠杆锚点输入”,还没有真正变成主入口。
|
||||
2. `CustomWorldCreatorIntent` 虽然已经能表达卡片化输入,但 UI 并没有把它转成真正可用的创作工作台。
|
||||
|
||||
目前 `card` 模式更多还停留在类型和测试层,没有成为真实用户路径。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把当前创建弹窗升级成“快速文本模式 / 创作卡片模式”双入口。
|
||||
- 快速文本模式保留,但提交后应自动拆出建议锚点,而不是直接把整段文本原封不动送进生成链。
|
||||
- 卡片模式先只做最关键的 `5~6` 张卡,不要一开始把所有高级字段都铺开。
|
||||
- 允许空卡提交,但明确区分“已锁定锚点”和“允许 AI 自由补全”的内容。
|
||||
|
||||
---
|
||||
|
||||
## 2.2 澄清机制已经存在,但没有真正服务创作者
|
||||
|
||||
`server-node/src/services/customWorldSessionStore.ts` 已经支持:
|
||||
|
||||
- 根据输入缺口生成澄清问题
|
||||
- 世界核心不足时追问
|
||||
- 玩家身份缺失时追问
|
||||
- 开局处境缺失时追问
|
||||
- 核心冲突缺失时追问
|
||||
|
||||
但 `src/services/aiService.ts` 当前做法是:
|
||||
|
||||
- 创建 session
|
||||
- 读取问题
|
||||
- 直接用 fallback 文案自动回答
|
||||
- 然后继续生成
|
||||
|
||||
这意味着:
|
||||
|
||||
**系统表面上已经有“先澄清再生成”的能力,但实际体验里,创作者并没有真正参与这一步。**
|
||||
|
||||
结果就是:
|
||||
|
||||
- 低信息量输入并没有被真正补强
|
||||
- 澄清问题变成了内部兜底,而不是创作协作
|
||||
- 很容易继续生成出“完整但不够像用户想要的世界”
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把 session question 真正接到前端,作为生成前的二次确认步骤。
|
||||
- 每次只问 `1~3` 个最关键问题,不要把它做成问卷。
|
||||
- 支持“一键使用系统建议”,但必须让创作者可见,而不是静默自动填充。
|
||||
- 把回答结果回写到 `creatorIntent`,而不是只作为一次性会话答案。
|
||||
|
||||
---
|
||||
|
||||
## 2.3 新建完成后的工作台闭环没有成立
|
||||
|
||||
设计文档里,自定义世界应该是:
|
||||
|
||||
`输入 -> 生成 -> 结果页确认/编辑 -> 保存并进入世界`
|
||||
|
||||
但当前 `src/components/game-shell/PreGameSelectionFlow.tsx` 里,新建世界生成成功后会:
|
||||
|
||||
- 直接保存到世界库
|
||||
- 清空 `generatedCustomWorldProfile`
|
||||
- 返回世界列表页
|
||||
|
||||
而不是进入 `custom-world-result` 结果工作台。
|
||||
|
||||
这会带来几个问题:
|
||||
|
||||
1. 新建后的第一时间确认感不够强。
|
||||
2. 快速模式生成出的“关键对象预览”没有自然承接页。
|
||||
3. 用户生成完后,如果想继续看结果、继续补全、继续编辑,还要再从世界列表里点一次“编辑”。
|
||||
|
||||
这条链路会让“创作中”与“已保存”之间的体验断开。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 新建完成后默认进入结果工作台,而不是直接跳回世界列表。
|
||||
- 保存动作留在结果页显式触发。
|
||||
- 可以增加“自动保存草稿,但仍停留在结果页”的策略,兼顾安全感和连贯性。
|
||||
- 世界列表更适合作为“已归档内容入口”,不适合作为新建完成页。
|
||||
|
||||
---
|
||||
|
||||
## 2.4 结果页仍然偏“数据总表”,低杠杆编辑负担偏重
|
||||
|
||||
当前结果页已经有 `世界 / 锚点 / 可扮演角色 / 场景角色 / 场景` 五个页签,这是正确方向。
|
||||
|
||||
但问题在于,进入编辑器后暴露出来的字段仍然太“底层”了,例如:
|
||||
|
||||
- `backstoryReveal`
|
||||
- 技能列表
|
||||
- 初始物品
|
||||
- 场景 NPC 分配
|
||||
- 场景连接关系
|
||||
|
||||
这些字段对少数深度编辑场景有用,但不应该成为默认主编辑内容。
|
||||
|
||||
当前 `src/components/CustomWorldEntityEditorModal.tsx` 已经变成一个非常重的综合编辑器,里面同时承担:
|
||||
|
||||
- 角色完整档案编辑
|
||||
- 形象编辑入口
|
||||
- AI 资产生成入口
|
||||
- 背景章节编辑
|
||||
- 技能与初始物品编辑
|
||||
- 场景内 NPC 分配
|
||||
- 场景连接维护
|
||||
|
||||
这会带来三层问题:
|
||||
|
||||
1. 创作者负担过重
|
||||
- 很多字段属于“系统编译层”,不属于“创作决策层”。
|
||||
|
||||
2. 移动端负担过重
|
||||
- 大量长表单、长弹窗和多级编辑,对手机创作并不友好。
|
||||
|
||||
3. 工程复杂度过高
|
||||
- 前端工作台承担了太多不同层级的编辑职责。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 默认只暴露高杠杆编辑:
|
||||
- 世界核心命题
|
||||
- 主题与气质
|
||||
- 玩家身份与开局
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性要素
|
||||
- 把技能、初始物品、章节 reveal、连接网络等移到“高级模式”或“系统层编辑”。
|
||||
- 结果页结构从“按对象字段堆表单”改成“按创作价值组织”。
|
||||
- 移动端优先改成分段式面板或底部工作台,不要把长表单都塞进同一个大 modal。
|
||||
|
||||
---
|
||||
|
||||
## 2.5 锁定与局部重生成机制还不完整
|
||||
|
||||
当前已经有两套看起来相关的能力:
|
||||
|
||||
1. `creatorIntent` 里的 `locked`
|
||||
2. `lockState` 里的角色 / 地点 / 势力锁定字段
|
||||
|
||||
但实际重生成时,`src/components/game-shell/PreGameSelectionFlow.tsx` 里的合并逻辑只真正处理了:
|
||||
|
||||
- 已锁定角色
|
||||
- 已锁定地点
|
||||
|
||||
而且还是按“名称匹配”保留,不是按稳定 id 或字段级锁定来处理。
|
||||
|
||||
这带来的问题很明显:
|
||||
|
||||
1. 角色或地点一旦重命名,锁定可能失效。
|
||||
2. 势力、冲突、世界概述等高价值内容没有真正进入局部重生成保护范围。
|
||||
3. 当前“锁定能力”更像一个早期过渡实现,还没有形成统一的重生成规则。
|
||||
|
||||
同时,结果页的“重新生成”提示文案仍然是“整世界覆盖式”的语义,这也会进一步削弱用户对重生成的信任感。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把锁定语义统一收口到后端,以 `lockState` 为唯一事实来源。
|
||||
- 锁定粒度改成:
|
||||
- 世界字段锁定
|
||||
- 势力锁定
|
||||
- 关键角色锁定
|
||||
- 关键地点锁定
|
||||
- 长尾内容可重生成
|
||||
- 局部重生成至少拆成几类:
|
||||
- 仅补长尾角色
|
||||
- 仅补长尾场景
|
||||
- 仅重做场景网络
|
||||
- 仅重做支持性 NPC
|
||||
- 合并逻辑不要再靠名称匹配,改成稳定 id 或锚点映射。
|
||||
|
||||
---
|
||||
|
||||
## 2.6 快速模式还不够“快”,生成页也还不够“创作者视角”
|
||||
|
||||
当前快速模式的主要区别,是把数量降成:
|
||||
|
||||
- 可扮演角色 `3`
|
||||
- 场景角色 `8`
|
||||
- 场景 `4`
|
||||
|
||||
但主生成链本身仍然会继续跑:
|
||||
|
||||
- framework
|
||||
- theme pack
|
||||
- story graph
|
||||
- role narrative
|
||||
- role dossier
|
||||
- narrative profile
|
||||
- finalization
|
||||
|
||||
也就是说:
|
||||
|
||||
**现在的 fast 更像“缩数量版 full”,还不是“先出关键锚点与关键对象的创作预览模式”。**
|
||||
|
||||
同时,`src/components/CustomWorldGenerationView.tsx` 当前展示的重点仍然是:
|
||||
|
||||
- 当前批次
|
||||
- 预计等待
|
||||
- 计时
|
||||
- 模型阶段
|
||||
|
||||
而不是创作者真正关心的:
|
||||
|
||||
- 关键角色有没有成型
|
||||
- 核心冲突有没有稳定
|
||||
- 哪些锚点已经锁定
|
||||
- 当前正在补的是关键对象还是长尾内容
|
||||
|
||||
可优化点:
|
||||
|
||||
- 快速模式改成真正的“关键锚点预览模式”:
|
||||
- 先只生成关键角色、关键地点、核心冲突摘要
|
||||
- 暂不补全所有长尾档案
|
||||
- 生成页改成“创作者视角进度”:
|
||||
- 世界灵魂已确定
|
||||
- 关键角色已成型
|
||||
- 关键地点已落地
|
||||
- 长尾扩展准备开始
|
||||
- 把技术批次隐藏到二级信息里,默认只展示创作状态。
|
||||
|
||||
---
|
||||
|
||||
## 2.7 自定义世界底层仍然没有完全脱离模板世界依赖
|
||||
|
||||
这部分设计文档和参考清单已经说得比较清楚,代码里也能看到对应痕迹:
|
||||
|
||||
- `templateWorldType`
|
||||
- `WUXIA / XIANXIA` 兼容字段
|
||||
- 规则层 fallback
|
||||
- 视觉参考池 fallback
|
||||
- 角色骨架与怪物池 fallback
|
||||
|
||||
当前问题不在于“还没完全去模板化”本身,而在于:
|
||||
|
||||
**这层依赖仍然深入到了生成、运行时规则、表现词汇和参考资源,不只是一个兼容字段。**
|
||||
|
||||
这会限制:
|
||||
|
||||
1. 跨题材表达稳定性
|
||||
2. 自定义世界的自有设定层独立性
|
||||
3. 后续真正做到“任何题材都能稳定跑”
|
||||
|
||||
可优化点:
|
||||
|
||||
- 继续按现有设计稿,把模板依赖逐步迁成:
|
||||
- 语义锚层
|
||||
- 规则层
|
||||
- 表现层
|
||||
- 原型参考层
|
||||
- 兼容迁移层
|
||||
- 在迁移完成前,保留兼容字段,但让新逻辑优先读取 `ownedSettingLayers`。
|
||||
- 明确哪些是“兼容桥”,哪些还是“真实主依赖”,避免继续混用。
|
||||
|
||||
---
|
||||
|
||||
## 2.8 前后端边界仍处于过渡态,和项目约束还有距离
|
||||
|
||||
当前自定义世界已经有了:
|
||||
|
||||
- Node 路由
|
||||
- session
|
||||
- 流式生成
|
||||
- 世界库存储接口
|
||||
|
||||
这是对的。
|
||||
|
||||
但问题是,`server-node/src/services/customWorldGenerationService.ts` 仍然通过 `server-node/src/bridges/legacyAiRuntimeBridge.ts` 去桥接 `src/services/ai.ts`。
|
||||
|
||||
这说明:
|
||||
|
||||
**核心生成逻辑虽然已经被路由包起来了,但真正的生成实现还没有完全成为 Express 侧自己的领域服务。**
|
||||
|
||||
同时,前端仍然承担了不少流程语义:
|
||||
|
||||
- 锁定内容合并
|
||||
- 重生成确认
|
||||
- 结果页覆盖提示
|
||||
- 工作台状态切换
|
||||
|
||||
这和当前仓库“前端只负责表现,逻辑与数据尽量收口到 Express 后端”的方向还有距离。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把自定义世界生成链正式下沉到 `server-node` 领域服务。
|
||||
- 把锁定、局部重生成、澄清会话、结果归档规则都放到后端。
|
||||
- 前端只负责:
|
||||
- 输入展示
|
||||
- 进度展示
|
||||
- 结果工作台展示
|
||||
- 明确的用户确认动作
|
||||
|
||||
---
|
||||
|
||||
## 2.9 移动端工作台仍有明显压迫感
|
||||
|
||||
项目文档已经明确要求移动端优先,但当前自定义世界工作台里仍有几个典型问题:
|
||||
|
||||
- 大量长 modal
|
||||
- 多段长表单
|
||||
- `window.confirm / window.alert` 原生弹框较多
|
||||
- 结果页与编辑器中同时承载太多操作密度
|
||||
|
||||
这些在桌面端还能勉强接受,但在手机上会很容易变成:
|
||||
|
||||
- 滚动层级混乱
|
||||
- 退出成本高
|
||||
- 修改焦点不明确
|
||||
- 确认感不稳定
|
||||
|
||||
可优化点:
|
||||
|
||||
- 移动端改成底部工作台 / 分步面板 / 可折叠分区。
|
||||
- 用项目内统一确认弹层替换 `window.confirm / window.alert`。
|
||||
- 让“保存”“继续补全”“局部重生成”这些关键动作固定在底部安全区附近。
|
||||
- 把搜索、批量删除、创建动作做成更轻的操作条,而不是持续挤压正文区。
|
||||
|
||||
---
|
||||
|
||||
## 3. 优先级建议
|
||||
|
||||
### P0:先修主链路闭环
|
||||
|
||||
- 补卡片化输入入口,至少把关键锚点输入真正开放出来。
|
||||
- 把澄清问题正式接入创作者流程,不再静默自动兜底。
|
||||
- 修正“新建完成后直接回世界列表”的流程,生成后默认进入结果工作台。
|
||||
- 统一锁定与局部重生成规则,先让“创作者不怕重生成”成立。
|
||||
|
||||
### P1:再降低工作台负担
|
||||
|
||||
- 结果页默认只展示高杠杆编辑。
|
||||
- 低杠杆字段进入高级模式。
|
||||
- 快速模式改成真正的关键对象预览模式。
|
||||
- 生成页改成创作者视角进度,而不是模型批次视角。
|
||||
|
||||
### P2:最后做架构收口与去模板化
|
||||
|
||||
- 把生成链、锁定规则、会话澄清彻底收回 Express 后端。
|
||||
- 持续推进 `ownedSettingLayers` 成为真实主设定层。
|
||||
- 逐步去掉自定义世界对模板世界的深依赖。
|
||||
- 针对移动端重做工作台的操作密度和确认路径。
|
||||
|
||||
---
|
||||
|
||||
## 4. 推荐落地顺序
|
||||
|
||||
如果只按“最小投入、最大体验收益”排序,建议按下面四步做:
|
||||
|
||||
1. 先改输入与结果闭环
|
||||
- 卡片化最小入口
|
||||
- 澄清问题接入
|
||||
- 新建后进入结果页
|
||||
|
||||
2. 再改锁定与局部重生成
|
||||
- 用稳定 id
|
||||
- 用统一 lockState
|
||||
- 增加局部重生成类型
|
||||
|
||||
3. 再改结果工作台结构
|
||||
- 默认高杠杆
|
||||
- 高级模式收纳低杠杆字段
|
||||
- 移动端拆分长表单
|
||||
|
||||
4. 最后做后端收口与去模板化
|
||||
- 服务端领域化
|
||||
- 设定层自有化
|
||||
- 跨题材泛化
|
||||
|
||||
---
|
||||
|
||||
## 5. 一句话判断
|
||||
|
||||
当前自定义世界创作工具最需要的,不是再继续补更多字段或更多生成步骤,而是:
|
||||
|
||||
**把“创作者先决定灵魂锚点,系统再稳定展开世界”这条主逻辑真正落到 UI、流程和后端边界上。**
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
- [FUNCTION_DESIGN_AUDIT_2026-04-03.md](./FUNCTION_DESIGN_AUDIT_2026-04-03.md):Function 体系分层、职责边界和当前结构问题。
|
||||
- [ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md](./ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md):物品生成与 Build 标签系统对 PRD 的落地情况。
|
||||
- [CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md](./CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md):自定义世界创作工具当前问题、体验断层和优化优先级审计。
|
||||
|
||||
## 推荐使用方式
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
- [EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md](./EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md):配装构筑与合成/锻造闭环设计。
|
||||
- [COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md](./COMPANION_FIRST_CONTACT_RELATIONSHIP_AND_PRIVATE_CHAT_DESIGN_2026-04-04.md):角色首遇感、关系分层解锁、私聊系统设计。
|
||||
- [SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md](./SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md):把每个场景收束成章节单元,并在首进场景时开启章节任务的设计稿。
|
||||
- [SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md](./SCENE_CHAPTER_BENCHMARK_GAP_AND_AI_NATIVE_EXPERIENCE_SUPPLEMENT_2026-04-08.md):对标仙剑、博德之门、黑神话,分析单场景章节的体验缺口,并给出 AI 原生补强方案。
|
||||
- [npc-conversation-situation-draft.md](./npc-conversation-situation-draft.md):NPC 对话阶段和情景注入草案。
|
||||
|
||||
## 推荐阅读
|
||||
@@ -21,4 +22,5 @@
|
||||
- 做“模板依赖如何真正变成自定义世界自有设定层”的具体迁移方案时,优先看新增的自有设定层优化方案。
|
||||
- 做角色关系、同伴互动、对话表现时,先看后两份。
|
||||
- 做剧情引擎章节化、场景闭环、章节任务接入时,优先看新增的场景章节设计稿。
|
||||
- 做“单章节体验还缺什么、该补哪种情感 / 抉择 / 试炼模块”时,优先看新增的章节对标补强设计稿。
|
||||
- 如果要判断是否符合目标,再和 `docs/prd/` 中对应 PRD 对照阅读。
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
# 单场景章节对标缺口与 AI 原生体验补强设计
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份文档补在:
|
||||
|
||||
- `docs/design/SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md`
|
||||
- `docs/prd/AI_NATIVE_CLASSIC_RPG_EXPERIENCE_BENCHMARK_PRD_2026-04-06.md`
|
||||
|
||||
之后,专门回答一个更具体的问题:
|
||||
|
||||
**如果把当前每个场景都视为一个章节,那么和《仙剑》《博德之门》《黑神话:悟空》里一个成立的章节相比,我们现在到底缺什么;以及结合当前项目的 AI 原生设计,应该补哪些体验层。**
|
||||
|
||||
这份文档不重复讨论“场景如何开章、任务如何挂接”的骨架问题,而是聚焦:
|
||||
|
||||
1. 单章节的体验密度还缺什么
|
||||
2. 每章最该补的体验模块是什么
|
||||
3. 哪些能力必须由服务端承接,前端只负责表现
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先说
|
||||
|
||||
当前项目把“场景 = 章节单元”的方向已经立住了一半骨架,但和这三类标杆作品相比,单章节体验还普遍缺 5 件事:
|
||||
|
||||
1. 缺一个让玩家记住“这章是关于谁”的情感锚点
|
||||
2. 缺一个让玩家中途改判的转折点
|
||||
3. 缺一个让玩家感到“这一段路在压着我走”的空间推进链
|
||||
4. 缺一个让玩家立场真正被表达出来的选择节点
|
||||
5. 缺一个能把结果写回人物、物件、后续章节的余波回响
|
||||
|
||||
一句话判断:
|
||||
|
||||
**现在的场景章节更像“带任务 lead 的剧情地点”,还不够像“有人物、有抉择、有试炼、有收束余味的一整章”。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 对标三个标杆后,当前单章节缺什么
|
||||
|
||||
## 2.1 相比《仙剑》式章节,缺的是“人和情”
|
||||
|
||||
《仙剑》式章节最强的不是题材,而是:
|
||||
|
||||
1. 一章里总有一个会被记住的人
|
||||
2. 这一章结束时,人物关系一定发生了变化
|
||||
3. 玩家记住的不是“我做了一个任务”,而是“我和谁经历了一段事”
|
||||
|
||||
当前场景章节的主要缺口如下:
|
||||
|
||||
| 维度 | 标杆章节会给玩家什么 | 当前缺口 | 应补什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 章节记忆点 | 明确的人物高光或情感切口 | 现在更多是场景 lead,不够像人物立题 | 每章必须有 `情感锚点 NPC / 关系对象` |
|
||||
| 关系推进 | 误会、试探、信任、失去、承诺会推进 | 现在 NPC 更像信息点或任务点 | 在 `opening / turning_point / aftermath` 至少安排一次关系变化 |
|
||||
| 章节余味 | 章节结束后仍有余波、牵挂、回看价值 | 现在更多是“交给下一场景” | 章节结束后补 `私聊 / 留言 / 赠礼反应 / 人物口风变化` |
|
||||
|
||||
结论:
|
||||
|
||||
**当前章节最缺的不是人物数量,而是“这一章让玩家和谁产生了关系变化”。**
|
||||
|
||||
## 2.2 相比《博德之门》式章节,缺的是“选择和反应”
|
||||
|
||||
《博德之门》式章节最强的不是分支数量,而是:
|
||||
|
||||
1. 玩家会在一章里表达立场
|
||||
2. 队友和 NPC 会明确回应这个立场
|
||||
3. 同一个问题通常不止一种处理方式
|
||||
|
||||
当前场景章节的主要缺口如下:
|
||||
|
||||
| 维度 | 标杆章节会给玩家什么 | 当前缺口 | 应补什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 处理路径 | 同一章通常有 `2~3` 种解法 | 现在大多仍是单主解推进 | 每章至少提供一次 `有限分歧结算` |
|
||||
| 队友反应 | 队友会认可、反对、沉默、插话 | 现在同伴存在感偏弱 | 每章至少有一次 `同伴反应批次` |
|
||||
| 后果落地 | 选择会改任务理解、人物态度、后续信息 | 现在选择更多是流程推进,不够像立场表达 | 把章节选择写回 `关系 / 线索可见性 / 后续 handoff` |
|
||||
|
||||
结论:
|
||||
|
||||
**当前章节最缺的不是做无限分支,而是做“有限分歧 + 强反馈”。**
|
||||
|
||||
## 2.3 相比《黑神话:悟空》式章节,缺的是“路和压迫”
|
||||
|
||||
《黑神话:悟空》式章节最强的不是题材,而是:
|
||||
|
||||
1. 一章的空间推进本身就在讲故事
|
||||
2. 玩家会记住路上的地标、残痕、敌人和压迫感
|
||||
3. 一章通常有一个明显的试炼点或高潮演出点
|
||||
|
||||
当前场景章节的主要缺口如下:
|
||||
|
||||
| 维度 | 标杆章节会给玩家什么 | 当前缺口 | 应补什么 |
|
||||
| --- | --- | --- | --- |
|
||||
| 空间推进 | 场景不是背景,而是一段穿行过程 | 现在场景更像承载节点,不够像旅程 | 每章补 `路线压力链` 和 `地标记忆点` |
|
||||
| 残痕叙事 | 地点、物件、敌人都在讲旧事 | 现在残痕有素材,但链不够强 | 每章至少串起 `2~3` 个残痕 / 证据 / 地标 |
|
||||
| 高潮试炼 | 一章通常有一个明显 setpiece / 强敌 / 对峙 | 现在收束常偏文本或任务状态 | 每章补一个 `高潮收束动作面` |
|
||||
|
||||
结论:
|
||||
|
||||
**当前章节最缺的不是更多场景描述,而是“空间本身要承担承压和收束”。**
|
||||
|
||||
## 2.4 三个标杆放在一起看,当前单章节的综合缺口
|
||||
|
||||
综合来看,当前每个场景章节最明显的缺口可以收束成下面 7 条:
|
||||
|
||||
1. 场景有主题,但缺“这一章是谁在发光”
|
||||
2. 任务有步骤,但缺“中途为什么会改判”
|
||||
3. 残痕有素材,但缺“沿路逐步加压的链条”
|
||||
4. 同伴会跟着走,但缺“针对你的立场说话”
|
||||
5. 战斗或冲突会发生,但缺“本章高潮”
|
||||
6. 章节会结束,但缺“结束后谁变了”
|
||||
7. 章节会交棒,但缺“这一章留下了什么可回响之物”
|
||||
|
||||
---
|
||||
|
||||
## 3. 每个场景章节都该补的标准体验包
|
||||
|
||||
建议以后把每个场景章节都按“九件套”来补,不要求每件都做得很重,但每章都不能缺位。
|
||||
|
||||
| 模块 | 每章最低要求 | 主要对标 |
|
||||
| --- | --- | --- |
|
||||
| 开章钩子 | 一进入场景就抛出一个异常、冲突或错位对白 | 三者共同 |
|
||||
| 情感锚点 | 至少一个本章承担关系变化的人物 | 仙剑 |
|
||||
| 路线压力链 | 至少 `2~3` 个地标、残痕或承压节点串起来 | 黑神话 |
|
||||
| 承压事件 | 一次调查、对峙、战斗或阻拦,证明这一章真有事在发生 | 三者共同 |
|
||||
| 改判节点 | 至少一条反证、误会破口或旧痕翻案 | 仙剑 + 博德之门 |
|
||||
| 立场选择 | 至少一次有代价的二选一 / 三选一 | 博德之门 |
|
||||
| 同伴反应 | 至少一次认可、反对、担忧、沉默中的一种反馈 | 博德之门 |
|
||||
| 高潮收束 | 一次明确的 confrontation、试炼、交付或揭示 | 黑神话 + 仙剑 |
|
||||
| 余波回响 | 至少留下一个后续会被提起的人、物、线索或态度变化 | 三者共同 |
|
||||
|
||||
这里的重点不是把每章都做成大体量内容,而是让每章都具备:
|
||||
|
||||
1. 可记住的人
|
||||
2. 可承压的路
|
||||
3. 可表达的立场
|
||||
4. 可回响的结果
|
||||
|
||||
---
|
||||
|
||||
## 4. 结合 AI 原生设计,单章节应该怎么补
|
||||
|
||||
## 4.1 不是做“无限分支”,而是做“有限模块 + 动态编排”
|
||||
|
||||
当前项目最适合的做法,不是给每个场景写爆炸式手工分支,而是:
|
||||
|
||||
1. 先给每章补稳定的体验模块
|
||||
2. 再让 AI 按当前线程、关系、残痕和场景状态去动态编排表达
|
||||
3. 本地规则负责章节状态、选择裁决、任务推进、关系变化和奖励回写
|
||||
|
||||
一句话说:
|
||||
|
||||
**AI 负责把这一章写活,本地规则负责保证这一章成立。**
|
||||
|
||||
## 4.2 建议新增一个章节体验画像
|
||||
|
||||
建议在现有 `ChapterState` 外,给每个场景章节补一个更偏体验编排的数据层,例如:
|
||||
|
||||
```ts
|
||||
interface ChapterExperienceProfile {
|
||||
sceneId: string;
|
||||
chapterArchetype: 'emotion' | 'choice' | 'trial' | 'hybrid';
|
||||
chapterPromise: string;
|
||||
emotionalAnchorNpcId?: string | null;
|
||||
guideNpcId?: string | null;
|
||||
opposingForceId?: string | null;
|
||||
routePressureBeats: string[];
|
||||
turningEvidenceIds: string[];
|
||||
stanceChoiceId?: string | null;
|
||||
climaxSetpieceId?: string | null;
|
||||
rewardCarrierSeed?: string | null;
|
||||
aftermathEchoTargets: string[];
|
||||
}
|
||||
```
|
||||
|
||||
它的作用不是替代现有 `ChapterState`,而是补“这一章体验上到底靠什么成立”。
|
||||
|
||||
## 4.3 每章都要有一个“人物轴”
|
||||
|
||||
这是补仙剑型体验最重要的一步。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每章必须指定一个 `emotionalAnchorNpcId`
|
||||
2. 这个角色不一定是最强、最重要的人,但一定是本章最会改变玩家理解的人
|
||||
3. 这个角色至少承担下面 2 件事:
|
||||
- `opening` 里立题或制造错位
|
||||
- `turning_point / aftermath` 里改口、揭示或留下余波
|
||||
|
||||
AI 原生补法:
|
||||
|
||||
1. AI 负责生成角色此章的表层说辞、压力表现和错位感
|
||||
2. 本地规则负责控制此章能披露哪些事实、关系如何变化
|
||||
|
||||
## 4.4 每章都要有一个“路线轴”
|
||||
|
||||
这是补黑神话型体验最重要的一步。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每章至少有 `2~3` 个 `routePressureBeats`
|
||||
2. 每个 beat 都不只是位置点,而是下面三类之一:
|
||||
- 地标记忆点
|
||||
- 场景残痕点
|
||||
- 敌对 / 阻拦 / 追索点
|
||||
3. `climax` 前必须至少有一次“越往前越不安”的空间升级
|
||||
|
||||
AI 原生补法:
|
||||
|
||||
1. AI 负责根据 `scene residue / thread / scar / motif` 生成现场感和残痕文本
|
||||
2. 本地规则负责决定 beat 顺序、是否已触发、何时进入高潮
|
||||
|
||||
## 4.5 每章都要有一个“立场轴”
|
||||
|
||||
这是补博德之门型体验最重要的一步。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每章至少抛一次立场问题
|
||||
2. 立场问题优先围绕:
|
||||
- 要不要信谁
|
||||
- 要不要公开某条线索
|
||||
- 要不要保一个人还是保规则
|
||||
- 要不要立刻动手还是继续查
|
||||
3. 不追求无限解,只要求:
|
||||
- `2~3` 个有限方案
|
||||
- 每个方案都能触发明确反应
|
||||
|
||||
AI 原生补法:
|
||||
|
||||
1. AI 负责把选择包装成角色化、情境化的动作与对白
|
||||
2. 本地规则负责裁决结果、写回 `CompanionStanceProfile / Quest / Knowledge / Echo`
|
||||
|
||||
## 4.6 每章都要有一个“高潮动作面”
|
||||
|
||||
目前很多场景的高潮更像“任务完成”,还不够像“一章真正收束了”。
|
||||
|
||||
建议每章在 `climax` 至少落成下面四类之一:
|
||||
|
||||
1. 正面对峙
|
||||
2. 小型试炼 / 强敌
|
||||
3. 真相交付
|
||||
4. 关系摊牌
|
||||
|
||||
要求:
|
||||
|
||||
1. 高潮不能只体现在任务状态变化
|
||||
2. 必须有明确前后差
|
||||
3. 必须能回写一条 `chapter aftermath`
|
||||
|
||||
## 4.7 每章都要留下一个可回响的载体
|
||||
|
||||
这是把三类标杆合在一起后最容易被低估的一层。
|
||||
|
||||
建议每章至少留下一个:
|
||||
|
||||
1. 章节证物
|
||||
2. 章节遗物
|
||||
3. 章节残痕
|
||||
4. 章节口风变化
|
||||
|
||||
它们至少要满足一条:
|
||||
|
||||
1. 下一章还能被提起
|
||||
2. 某个 NPC 会认出它
|
||||
3. 某个同伴会追加评论
|
||||
4. 某个任务会因为它改变说明或目标
|
||||
|
||||
---
|
||||
|
||||
## 5. 章节类型建议
|
||||
|
||||
不是每章都要平均模仿三款游戏,更稳的做法是:每章明确一个主类型,再配一个副类型。
|
||||
|
||||
| 章节类型 | 主对标 | 章节重点 | 必选模块 |
|
||||
| --- | --- | --- | --- |
|
||||
| 情感章 | 仙剑 | 人物关系、误会、牺牲、承诺、旧债 | 情感锚点、改判节点、余波回响 |
|
||||
| 抉择章 | 博德之门 | 立场表达、队友反应、有限分歧结算 | 立场选择、同伴反应、后果回写 |
|
||||
| 试炼章 | 黑神话 | 路线承压、地标残痕、高潮试炼 | 路线压力链、高潮收束、章节载体 |
|
||||
| 混合章 | 任选两者 | 既要有情感,也要有试炼或选择 | 视主副轴组合决定 |
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 每个场景章节都标一个 `主类型`
|
||||
2. 再选一个 `副类型`
|
||||
3. 不要让所有章节都只剩“调查 + 对话 + 交任务”
|
||||
|
||||
---
|
||||
|
||||
## 6. 服务端与前端的职责边界
|
||||
|
||||
结合当前项目约束,章节体验补强必须坚持:
|
||||
|
||||
**前端只负责表现,章节逻辑、状态、选择裁决、数据编排全部放在 Express 后端。**
|
||||
|
||||
## 6.1 服务端负责什么
|
||||
|
||||
建议把下面这些能力放在 `server-node/`:
|
||||
|
||||
1. 章节体验画像生成
|
||||
2. 章节选择裁决
|
||||
3. 同伴反应批次生成
|
||||
4. 章节残痕与路线 beat 编排
|
||||
5. 章节余波与回响写回
|
||||
6. 章节奖励载体编译
|
||||
|
||||
服务端输入应来自:
|
||||
|
||||
1. 当前 `sceneId`
|
||||
2. 当前 `ChapterState`
|
||||
3. 当前队伍与关系状态
|
||||
4. 当前激活线程与知识可见性
|
||||
5. 当前章节已触发的 beat、choice、residue、setpiece
|
||||
|
||||
服务端输出应编译成前端可直接消费的结果,例如:
|
||||
|
||||
1. 当前章节标题与阶段
|
||||
2. 当前章节 promise
|
||||
3. 当前 route beats
|
||||
4. 当前可选立场
|
||||
5. 同伴反应 feed
|
||||
6. 本章高潮结果
|
||||
7. 本章 aftermath 摘要
|
||||
|
||||
## 6.2 前端负责什么
|
||||
|
||||
前端只负责:
|
||||
|
||||
1. 表现章节标题、章节目标、路线节拍
|
||||
2. 表现情感锚点人物和同伴反应
|
||||
3. 表现本章高潮演出与余波反馈
|
||||
4. 表现章节奖励载体和 chronicle 回写结果
|
||||
|
||||
前端不要负责:
|
||||
|
||||
1. 计算选择结果
|
||||
2. 推导章节阶段
|
||||
3. 生成 route beat 顺序
|
||||
4. 决定同伴 stance 更新
|
||||
|
||||
---
|
||||
|
||||
## 7. 单章节设计卡模板
|
||||
|
||||
为了让后续每个场景都能按统一方式补体验,建议每章都补一张简版设计卡:
|
||||
|
||||
```md
|
||||
- 章节标题:
|
||||
- 主类型 / 副类型:
|
||||
- 本章 promise:
|
||||
- 情感锚点人物:
|
||||
- 开章钩子:
|
||||
- 路线压力链:
|
||||
- 承压事件:
|
||||
- 改判证据:
|
||||
- 立场选择:
|
||||
- 同伴反应:
|
||||
- 高潮收束:
|
||||
- 章节奖励载体:
|
||||
- 余波回响:
|
||||
- 下一章 handoff:
|
||||
```
|
||||
|
||||
只要这张卡填不满,说明这一章还没有真正成立。
|
||||
|
||||
---
|
||||
|
||||
## 8. 推荐补强顺序
|
||||
|
||||
如果按当前项目最稳的节奏推进,建议顺序如下:
|
||||
|
||||
## 阶段 A:先补“可被记住的人”
|
||||
|
||||
先做:
|
||||
|
||||
1. 情感锚点 NPC
|
||||
2. 改判节点
|
||||
3. 章节余波
|
||||
|
||||
原因:
|
||||
|
||||
这是最接近当前项目已有 NPC、关系和私聊链的部分,投入最小,感知提升最快。
|
||||
|
||||
## 阶段 B:再补“可被表达的立场”
|
||||
|
||||
先做:
|
||||
|
||||
1. 每章一次立场选择
|
||||
2. 同伴反应批次
|
||||
3. 后果写回任务 / 关系 / 线索可见性
|
||||
|
||||
原因:
|
||||
|
||||
这是对标《博德之门》最关键,同时也是最能让 AI 原生叙事摆脱“只会往前写”的一步。
|
||||
|
||||
## 阶段 C:最后补“可被承压的路”
|
||||
|
||||
先做:
|
||||
|
||||
1. route pressure beats
|
||||
2. 地标残痕链
|
||||
3. 高潮 setpiece
|
||||
|
||||
原因:
|
||||
|
||||
空间承压最依赖完整的场景节拍和演出支持,适合在前两层站稳后继续增强。
|
||||
|
||||
---
|
||||
|
||||
## 9. 章节体验验收标准
|
||||
|
||||
如果说一个场景章节已经明显更接近《仙剑》《博德之门》《黑神话:悟空》那类标杆,至少应满足下面这些结果:
|
||||
|
||||
1. 玩家玩完这一章后,能明确说出“这章主要在讲谁 / 讲什么”
|
||||
2. 玩家在中段经历过一次改判,而不是从头到尾只在确认原判断
|
||||
3. 玩家能记住至少一个地标、残痕或证物,而不只是任务标题
|
||||
4. 玩家至少做过一次立场表达,并收到过明确反应
|
||||
5. 玩家在章节结束时感到“这一章局部收住了”,而不只是“系统让我去下个场景”
|
||||
6. 本章至少有一条人物态度、物件、线索或 chronicle 被写进后续回响
|
||||
7. 首遇与低披露阶段不会把整章暗线和角色完整背景直接灌给模型
|
||||
|
||||
---
|
||||
|
||||
## 10. 一句话结论
|
||||
|
||||
如果把每个场景都视为一个章节,那么当前最该补的,不是继续堆更多场景文本,而是让每章都真正长出:
|
||||
|
||||
1. 一个会被记住的人
|
||||
2. 一段会逐步加压的路
|
||||
3. 一次会暴露立场的选择
|
||||
4. 一个能把本章收住的高潮
|
||||
5. 一条能延续到后面的余波
|
||||
|
||||
只有这样,当前项目的“场景章节化”才会从结构成立,进一步走到体验成立。
|
||||
@@ -0,0 +1,588 @@
|
||||
# Express 后端化并行任务拆分规划(2026-04-08)
|
||||
|
||||
## 1. 目的
|
||||
|
||||
这份文档用于把 [EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md](./EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md) 进一步拆成可并行推进、尽量互不冲突的任务流。
|
||||
|
||||
目标不是把大重构拆成很多零碎 TODO,而是把它拆成:
|
||||
|
||||
- 可以同时开工
|
||||
- 写入边界清晰
|
||||
- 交付物明确
|
||||
- 依赖关系稳定
|
||||
- 最后容易集成
|
||||
|
||||
---
|
||||
|
||||
## 2. 并行拆分原则
|
||||
|
||||
## 2.1 基本原则
|
||||
|
||||
- 每条任务尽量拥有独占目录或独占模块,不去抢同一批热点文件。
|
||||
- 热点集成文件只由“集成岗”或最后一轮集成处理,不作为多个任务的日常编辑目标。
|
||||
- 先搭协议边界,再迁规则执行,再收缩前端。
|
||||
- 前端与后端可以并行推进,但前提是先冻结 contract。
|
||||
- 编辑器链路和正式运行时链路分开拆,避免互相阻塞。
|
||||
|
||||
## 2.2 当前最容易冲突的文件
|
||||
|
||||
以下文件建议默认只由集成岗或最后一轮联调处理:
|
||||
|
||||
- `server-node/src/context.ts`
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
- `server-node/src/app.ts`
|
||||
- `src/services/apiClient.ts`
|
||||
- `src/hooks/useStoryGeneration.ts`
|
||||
- `src/hooks/useGameFlow.ts`
|
||||
- `src/components/GameShell.tsx`
|
||||
|
||||
其他任务如果必须影响这些文件,优先通过:
|
||||
|
||||
- 新增独立模块
|
||||
- 新增 adapter
|
||||
- 新增中间层入口
|
||||
|
||||
而不是直接在热点文件中大改。
|
||||
|
||||
---
|
||||
|
||||
## 3. 建议并行批次
|
||||
|
||||
## 批次 A:可立即并行开工
|
||||
|
||||
- 任务 0:集成岗与接口冻结
|
||||
- 任务 1:共享 contract 与目录抽离
|
||||
- 任务 2:PostgreSQL 持久化基线收口
|
||||
- 任务 3:服务端 HTTP 基础设施与统一响应壳层
|
||||
- 任务 8:编辑器 API 归口与工具链隔离
|
||||
- 任务 9:测试、观测与部署基线
|
||||
|
||||
## 批次 B:在 contract 初版落地后并行开工
|
||||
|
||||
- 任务 4:服务端 AI 编排收口
|
||||
- 任务 5:运行时领域模块 A,Story / Combat / NPC
|
||||
- 任务 6:运行时领域模块 B,Inventory / Quest / Build / Runtime Item
|
||||
- 任务 7:前端 SDK、鉴权、持久化瘦身
|
||||
|
||||
## 批次 C:在服务端 action 和 view model 稳定后开工
|
||||
|
||||
- 任务 10:前端主流程壳层与大 hook 瘦身
|
||||
|
||||
---
|
||||
|
||||
## 4. 任务拆分
|
||||
|
||||
## 任务 0:集成岗与接口冻结
|
||||
|
||||
### 目标
|
||||
|
||||
负责冻结边界、维护接口文档、控制热点文件的合并节奏,避免多人同时改核心入口。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `docs/planning/**`
|
||||
- `docs/technical/**`
|
||||
- 最终集成时的热点入口文件
|
||||
|
||||
### 主要输出
|
||||
|
||||
- 统一任务看板
|
||||
- contract 版本表
|
||||
- 热点文件编辑规则
|
||||
- 每日或每阶段集成清单
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 团队知道哪些文件不能多人同时改
|
||||
- 每条任务都有明确的上游 contract 与下游接入点
|
||||
|
||||
---
|
||||
|
||||
## 任务 1:共享 Contract 与目录抽离
|
||||
|
||||
### 目标
|
||||
|
||||
先把前后端共同识别的类型、schema、响应结构、错误结构抽出来,切断 `server-node -> src/**` 的长期反向依赖。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `packages/shared/**`
|
||||
- 新建的共享类型、schema、contract 目录
|
||||
|
||||
### 可改边界
|
||||
|
||||
- `server-node/src/**` 中的 import 替换入口
|
||||
- `src/**` 中的 import 替换入口
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 具体业务规则迁移
|
||||
- 前端页面行为调整
|
||||
- 数据库实现细节
|
||||
|
||||
### 主要输出
|
||||
|
||||
- 统一 API envelope
|
||||
- 统一错误对象
|
||||
- 统一 action / response contract
|
||||
- 统一领域类型和状态枚举
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 新增服务端模块不需要继续直接依赖前端目录里的实现细节
|
||||
- 前后端都以共享 contract 为边界协作
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 可与任务 2、任务 3、任务 8、任务 9 同时启动
|
||||
- 是任务 4、任务 5、任务 6、任务 7 的上游基础
|
||||
|
||||
---
|
||||
|
||||
## 任务 2:PostgreSQL 持久化基线收口
|
||||
|
||||
### 目标
|
||||
|
||||
把“已经切到 PostgreSQL”的状态收成真正稳定的后端基线,清掉 SQLite 残留口径与仓储层耦合问题。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `server-node/src/config.ts`
|
||||
- `server-node/src/db.ts`
|
||||
- `server-node/src/repositories/**`
|
||||
- `server-node/src/app.test.ts`
|
||||
- `.env.example`
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 剧情规则
|
||||
- 选项结算
|
||||
- 前端状态瘦身
|
||||
|
||||
### 主要输出
|
||||
|
||||
- PostgreSQL 连接配置
|
||||
- 仓储层接口统一
|
||||
- 数据表初始化/迁移方案
|
||||
- 运行时持久化测试基线
|
||||
- 文档中的数据库现状统一
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 后端运行时数据完全以后端数据库为准
|
||||
- 配置、日志、测试、文档里不再把 SQLite 写成当前正式现状
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 可与任务 1、任务 3、任务 8、任务 9 同时启动
|
||||
- 为任务 5、任务 6、任务 7 提供稳定持久化基础
|
||||
|
||||
---
|
||||
|
||||
## 任务 3:服务端 HTTP 基础设施与统一响应壳层
|
||||
|
||||
### 目标
|
||||
|
||||
建立统一的服务端响应结构、错误结构、请求链路日志、版本字段和中间件壳层。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `server-node/src/http.ts`
|
||||
- `server-node/src/errors.ts`
|
||||
- `server-node/src/middleware/**`
|
||||
- `server-node/src/app.ts`
|
||||
|
||||
### 可改边界
|
||||
|
||||
- 为 route 层提供新的响应 helper
|
||||
- 为后续 action 接口提供统一 envelope
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 具体 story / combat / quest 业务逻辑
|
||||
- 前端页面层接入
|
||||
|
||||
### 主要输出
|
||||
|
||||
- 统一 JSON 响应格式
|
||||
- 统一错误格式
|
||||
- `requestId`
|
||||
- `latency` 与关键日志字段
|
||||
- 路由级版本与元信息壳层
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 后端所有新接口都能套用同一层响应约定
|
||||
- 前端不需要为不同接口写多套错误解析逻辑
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 可与任务 1、任务 2、任务 8、任务 9 同时启动
|
||||
- 是任务 4、任务 5、任务 6、任务 7 的共同基础
|
||||
|
||||
---
|
||||
|
||||
## 任务 4:服务端 AI 编排收口
|
||||
|
||||
### 目标
|
||||
|
||||
把正式运行时的 prompt 组装、模型调用、容错、SSE 转发都收回后端,浏览器不再保留正式运行时 AI fallback。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `server-node/src/services/llmClient.ts`
|
||||
- `server-node/src/services/chatService.ts`
|
||||
- `server-node/src/services/storyService.ts`
|
||||
- `server-node/src/services/customWorldGenerationService.ts`
|
||||
- `server-node/src/services/questService.ts`
|
||||
- `server-node/src/services/runtimeItemService.ts`
|
||||
|
||||
### 可新增目录
|
||||
|
||||
- `server-node/src/modules/ai/**`
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 前端主流程组件
|
||||
- 数据库存储实现
|
||||
|
||||
### 主要输出
|
||||
|
||||
- 后端统一 AI orchestration 层
|
||||
- 流式接口统一适配
|
||||
- prompt 复用策略
|
||||
- 前端 fallback 清理清单
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 正式运行时不再依赖浏览器端大体量 AI 实现作为兜底
|
||||
- AI 失败、超时、流式中断都能在后端统一处理
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 建议在任务 1、任务 3 有初版后启动
|
||||
- 可与任务 5、任务 6、任务 7 并行
|
||||
|
||||
---
|
||||
|
||||
## 任务 5:运行时领域模块 A,Story / Combat / NPC
|
||||
|
||||
### 目标
|
||||
|
||||
把剧情推进、战斗结算、NPC 交互这些最核心的运行时状态迁移到后端领域模块。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `server-node/src/modules/story/**`
|
||||
- `server-node/src/modules/combat/**`
|
||||
- `server-node/src/modules/npc/**`
|
||||
|
||||
### 可改边界
|
||||
|
||||
- 为 route/action 层提供服务接口
|
||||
- 为前端提供 view model 所需聚合结果
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 背包、Build、任务奖励编排
|
||||
- 编辑器接口
|
||||
|
||||
### 主要输出
|
||||
|
||||
- story action resolver
|
||||
- combat resolution service
|
||||
- npc interaction service
|
||||
- 统一返回给 UI 的 presentation/view model 结构
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 前端不再本地决定 function 合法性、战斗结果、NPC 关键关系变化
|
||||
- 点击选项时,后端能返回完整下一步展示结果
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 依赖任务 1、任务 3
|
||||
- 可与任务 4、任务 6、任务 7 并行
|
||||
|
||||
---
|
||||
|
||||
## 任务 6:运行时领域模块 B,Inventory / Quest / Build / Runtime Item
|
||||
|
||||
### 目标
|
||||
|
||||
把任务推进、运行时物品、背包/装备、Build 收益等剩余核心规则迁到后端。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `server-node/src/modules/inventory/**`
|
||||
- `server-node/src/modules/quest/**`
|
||||
- `server-node/src/modules/build/**`
|
||||
- `server-node/src/modules/runtime-item/**`
|
||||
|
||||
### 可改边界
|
||||
|
||||
- 调用任务 2 的仓储层
|
||||
- 使用任务 1 的共享 contract
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 前端页面层改造
|
||||
- Story / Combat / NPC 主链路
|
||||
|
||||
### 主要输出
|
||||
|
||||
- inventory mutation service
|
||||
- quest signal progression service
|
||||
- build calculation service
|
||||
- runtime item resolution service
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 背包、任务、Build、运行时物品不再由前端保留正式结算逻辑
|
||||
- 这些领域能独立测试,不依赖 UI hook
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 依赖任务 1、任务 2、任务 3
|
||||
- 可与任务 4、任务 5、任务 7 并行
|
||||
|
||||
---
|
||||
|
||||
## 任务 7:前端 SDK、鉴权、持久化瘦身
|
||||
|
||||
### 目标
|
||||
|
||||
让前端从“业务执行层”退回“API 消费层 + 表现层状态协调层”。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `src/services/apiClient.ts`
|
||||
- `src/services/authService.ts`
|
||||
- `src/services/storageService.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `src/hooks/useGamePersistence.ts`
|
||||
- `src/hooks/useGameSettings.ts`
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 页面组件大范围重构
|
||||
- `useStoryGeneration.ts` 主流程瘦身
|
||||
|
||||
### 主要输出
|
||||
|
||||
- 轻量前端 SDK
|
||||
- 统一鉴权请求层
|
||||
- 统一错误态与重试策略
|
||||
- 远端快照/设置消费层
|
||||
- 正式运行时浏览器 fallback 下线方案
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 前端服务层不再保留完整正式规则或正式 AI 编排
|
||||
- 存档与设置以后端返回结果为准
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 依赖任务 1、任务 3
|
||||
- 可与任务 4、任务 5、任务 6 并行
|
||||
- 为任务 10 提供稳定的 API 消费层
|
||||
|
||||
---
|
||||
|
||||
## 任务 8:编辑器 API 归口与工具链隔离
|
||||
|
||||
### 目标
|
||||
|
||||
把编辑器的写盘、生成、任务查询能力从“散落接口”整理成清晰的编辑器后端模块,避免继续污染正式运行时。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `src/editor/shared/**`
|
||||
- `src/components/preset-editor/**`
|
||||
- `src/components/npcVisualEditorPersistence.ts`
|
||||
- `src/components/preset-editor/characterAssetStudioPersistence.ts`
|
||||
- `scripts/dev-server/**`
|
||||
- `server-node/src/modules/editor/**`
|
||||
- `server-node/src/modules/assets/**`
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 主游戏运行时 action 逻辑
|
||||
- 正式剧情流转
|
||||
|
||||
### 主要输出
|
||||
|
||||
- `/api/editor/*` 与 `/api/assets/*` 命名空间
|
||||
- 统一 editor client SDK
|
||||
- 写接口权限边界
|
||||
- 编辑器工具链迁移清单
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 编辑器组件不再散落直连多个写接口
|
||||
- 编辑器 API 与运行时 API 的职责边界清晰
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 可与任务 1、任务 2、任务 3、任务 9 同时启动
|
||||
- 与任务 5、任务 6、任务 10 基本不冲突
|
||||
|
||||
---
|
||||
|
||||
## 任务 9:测试、观测与部署基线
|
||||
|
||||
### 目标
|
||||
|
||||
为整个后端化改造提供自动回归、链路日志和部署基线,避免“功能迁过去了但不可验证”。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `server-node/src/**/*.test.ts`
|
||||
- `scripts/**`
|
||||
- 部署与运维相关文档
|
||||
- 反向代理与 smoke 测试脚本
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 具体业务模块实现
|
||||
|
||||
### 主要输出
|
||||
|
||||
- 后端接口测试
|
||||
- 关键主链路 smoke
|
||||
- request/response 日志校验
|
||||
- 同域部署基线
|
||||
- 回滚、备份、迁移检查清单
|
||||
|
||||
### 验收标准
|
||||
|
||||
- `web + server` 改造过程有最小自动回归保护
|
||||
- 关键接口失败时能追踪到请求链路
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 可与任务 1、任务 2、任务 3、任务 8 同时启动
|
||||
- 后续持续跟进任务 4、任务 5、任务 6、任务 7、任务 10 的交付
|
||||
|
||||
---
|
||||
|
||||
## 任务 10:前端主流程壳层与大 Hook 瘦身
|
||||
|
||||
### 目标
|
||||
|
||||
在服务端 action 和前端 SDK 稳定后,把 `GameShell`、`useStoryGeneration` 这一层改成真正的表现层协调器。
|
||||
|
||||
### 独占范围
|
||||
|
||||
- `src/hooks/useStoryGeneration.ts`
|
||||
- `src/hooks/story/**`
|
||||
- `src/hooks/useGameFlow.ts`
|
||||
- `src/components/GameShell.tsx`
|
||||
- `src/components/AdventurePanel.tsx`
|
||||
- `src/components/NpcModals.tsx`
|
||||
- `src/components/auth/**`
|
||||
|
||||
### 暂不负责
|
||||
|
||||
- 数据库、服务端仓储
|
||||
- 编辑器 API
|
||||
|
||||
### 主要输出
|
||||
|
||||
- 面向 action/view model 的前端流程层
|
||||
- 页面表现态与业务态分离
|
||||
- 大 hook 拆分后的协调层
|
||||
- 更容易测试和替换的主流程壳层
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 前端主流程不再直接吞下完整运行时规则
|
||||
- 页面层主要消费后端 view model,而不是本地自算结果
|
||||
|
||||
### 并行关系
|
||||
|
||||
- 依赖任务 5、任务 6、任务 7 至少有一轮稳定输出
|
||||
- 是最后一批大规模前端接入任务
|
||||
|
||||
---
|
||||
|
||||
## 5. 推荐协作顺序
|
||||
|
||||
## 第一步:先定边界
|
||||
|
||||
先启动:
|
||||
|
||||
- 任务 0
|
||||
- 任务 1
|
||||
- 任务 2
|
||||
- 任务 3
|
||||
|
||||
这一轮完成后,团队会得到:
|
||||
|
||||
- 统一 contract
|
||||
- 稳定数据库基线
|
||||
- 稳定后端响应壳层
|
||||
- 稳定任务分工边界
|
||||
|
||||
## 第二步:领域层和工具层分头推进
|
||||
|
||||
在第一步基础上并行启动:
|
||||
|
||||
- 任务 4
|
||||
- 任务 5
|
||||
- 任务 6
|
||||
- 任务 7
|
||||
- 任务 8
|
||||
- 任务 9
|
||||
|
||||
这一轮是整个改造的主生产阶段。
|
||||
|
||||
## 第三步:最后收前端主流程
|
||||
|
||||
最后启动:
|
||||
|
||||
- 任务 10
|
||||
|
||||
原因很简单:
|
||||
|
||||
- 如果太早改 `useStoryGeneration` 和 `GameShell`,前端还没有稳定的 action contract 和 view model,会反复返工。
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议的多人分工方式
|
||||
|
||||
如果是 4 人并行,建议:
|
||||
|
||||
- 1 人负责任务 1 + 任务 0 的 contract/集成
|
||||
- 1 人负责任务 2 + 任务 3 的后端基建
|
||||
- 1 人负责任务 4 + 任务 5 的运行时主链
|
||||
- 1 人负责任务 8 + 任务 9,之后转入任务 7 或任务 10
|
||||
|
||||
如果是 6 人并行,建议:
|
||||
|
||||
- 1 人负责任务 0 + 任务 1
|
||||
- 1 人负责任务 2
|
||||
- 1 人负责任务 3 + 任务 9
|
||||
- 1 人负责任务 4
|
||||
- 1 人负责任务 5
|
||||
- 1 人负责任务 6 + 任务 8
|
||||
|
||||
前端主流程任务 10 建议在第二轮由最熟悉当前 UI 壳层的人接手。
|
||||
|
||||
---
|
||||
|
||||
## 7. 合并规则建议
|
||||
|
||||
- 每条任务优先新增目录和新模块,少直接改热点文件。
|
||||
- 热点文件统一在集成窗口合并,不在多个任务里同步推进。
|
||||
- 任何任务如果需要改 `useStoryGeneration.ts`,默认先暂停并和任务 10 对齐。
|
||||
- 任何任务如果需要改 `server-node/src/routes/runtimeRoutes.ts`,默认先走任务 0 的接口冻结表。
|
||||
- 编辑器链路和正式运行时链路不要混在同一个 PR 里。
|
||||
|
||||
---
|
||||
|
||||
## 8. 一句话结论
|
||||
|
||||
这次重构最稳的并行方式不是“大家一起改前后端”,而是:
|
||||
|
||||
**先用 contract、数据库基线和 HTTP 壳层把边界钉死,再让服务端领域迁移、编辑器归口、前端瘦身分轨并行,最后由主流程壳层统一接入。**
|
||||
447
docs/planning/EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md
Normal file
447
docs/planning/EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md
Normal file
@@ -0,0 +1,447 @@
|
||||
# Express 后端化工程重构规划(2026-04-08)
|
||||
|
||||
## 1. 背景
|
||||
|
||||
当前项目已经引入 `Express` 后端,且 `server-node/` 已经承接了运行时鉴权、存档、设置、自定义世界、剧情生成、角色聊天、NPC 对话、运行时物品意图、任务生成等能力。
|
||||
|
||||
但从当前工程状态看,项目仍处于“后端已存在,但运行时领域层尚未完全脱前端”的过渡态,主要表现为:
|
||||
|
||||
- 前端 `src/hooks/useStoryGeneration.ts` 仍然承担了大量运行时编排、规则拼接与状态推进职责。
|
||||
- 前端 `src/services/ai.ts` 仍然保留了完整的 AI 调用、提示词拼装和本地兜底实现。
|
||||
- 前端 `src/hooks/useGamePersistence.ts` 仍在承担较重的存档恢复、schema 纠偏与归一化职责。
|
||||
- `server-node/src/**` 当前仍在直接引用 `src/types`、`src/data`、`src/services` 中的内容,分层尚未真正闭合。
|
||||
- 编辑器相关写接口仍然散落在前端组件与 `jsonClient` 中,运行时 API 与编辑器 API 还没有完全归口。
|
||||
|
||||
现在既然已经明确“前端只负责做表现,所有逻辑、数据都放到后端进行运算和存储”,就需要把这个原则升级成整个工程的硬边界,而不是只停留在一部分接口迁移完成的状态。
|
||||
|
||||
---
|
||||
|
||||
## 2. 重构总原则
|
||||
|
||||
本轮重构只坚持一个核心原则:
|
||||
|
||||
**前端不是业务执行层,而是表现层;后端才是唯一的运行时真相来源。**
|
||||
|
||||
进一步展开为:
|
||||
|
||||
- 前端只负责页面结构、动画演出、输入采集、局部交互态、加载态和错误态展示。
|
||||
- 后端负责鉴权、会话、规则计算、剧情推进、AI 编排、任务推进、道具结算、Build 结算、存档读写与持久化。
|
||||
- 浏览器内不再保留“正式运行时业务规则”的第二套实现。
|
||||
- 浏览器内允许存在少量纯表现计算,但不允许成为游戏状态真相来源。
|
||||
- 编辑器能力与正式运行时能力分离,避免 dev 工具链继续污染正式运行时边界。
|
||||
|
||||
---
|
||||
|
||||
## 3. 重构目标
|
||||
|
||||
## 3.1 目标状态
|
||||
|
||||
- 浏览器只发送“玩家意图”和必要的展示参数,不直接提交完整运行时真相。
|
||||
- `Express` 后端成为唯一的运行时状态源、规则执行源和 AI 调度源。
|
||||
- 运行时快照、任务状态、NPC 状态、背包、属性、Build、剧情历史全部以后端持久化结果为准。
|
||||
- 前端不再直接 import 正式运行时 AI 逻辑、提示词逻辑和关键规则逻辑。
|
||||
- `server-node` 不再依赖 `src/**` 中的前端实现细节,而是依赖独立共享层。
|
||||
- 编辑器 API、运行时 API、资产生成 API 形成清晰命名空间和权限边界。
|
||||
|
||||
## 3.2 非目标
|
||||
|
||||
- 本轮不追求一次性重写所有玩法系统。
|
||||
- 本轮不再讨论关系型数据库选型切换,当前后端以 `PostgreSQL` 为准。
|
||||
- 本轮不改动已有中文剧情、设定和文案方向。
|
||||
- 本轮不为了“前后端分离”牺牲移动端体验与当前主流程可玩性。
|
||||
|
||||
---
|
||||
|
||||
## 4. 职责边界
|
||||
|
||||
| 领域 | 前端职责 | 后端职责 |
|
||||
| --- | --- | --- |
|
||||
| 页面与流程壳层 | 页面切换、面板开关、布局、自适应、动效、加载态 | 不负责页面 UI |
|
||||
| 用户输入 | 收集点击、拖拽、表单输入、选项选择 | 校验输入是否合法,解释输入对应的运行时动作 |
|
||||
| 游戏状态 | 仅持有当前展示所需 view model 和局部 UI state | 持有完整游戏状态、快照、事件日志、版本号 |
|
||||
| 剧情推进 | 展示文本流、选项、动画时间线 | 生成剧情、决定选项集合、推进故事状态 |
|
||||
| 战斗与数值 | 播放攻击、受击、死亡、位移 | 计算伤害、蓝耗、CD、死亡、掉落、逃跑结果 |
|
||||
| NPC/同伴交互 | 展示面板、聊天输入框、关系反馈演出 | 计算关系变化、招募条件、交易合法性、对话结果 |
|
||||
| 背包/装备/Build | 展示背包、装备栏、Build 面板 | 计算背包变化、装备结果、Build 收益与约束 |
|
||||
| 任务系统 | 展示任务卡片、任务进度、奖励动画 | 生成任务、推进 signal、发放奖励 |
|
||||
| AI 调用 | 不直接请求正式运行时模型 | 统一做 prompt 组装、模型调用、超时重试、日志 |
|
||||
| 持久化 | 最多保留极少量表现态缓存 | 负责存档、设置、用户数据、迁移、恢复 |
|
||||
| 编辑器 | 调用 SDK、展示工具面板 | 负责写盘、生成任务、队列、权限与审计 |
|
||||
|
||||
## 4.1 前端允许保留的状态
|
||||
|
||||
- 当前面板是否打开
|
||||
- 当前动画是否播放中
|
||||
- 当前流式文本已经显示到哪一段
|
||||
- 表单草稿、搜索词、临时筛选条件
|
||||
- 与展示相关的 viewport / media / motion 状态
|
||||
|
||||
## 4.2 前端禁止继续承载的职责
|
||||
|
||||
- function 合法性判定
|
||||
- 怪物/NPC/任务/物品结算
|
||||
- 正式运行时 prompt 组装
|
||||
- 正式运行时 AI fallback
|
||||
- 存档 schema 迁移主逻辑
|
||||
- 以 `localStorage` 作为正式运行时主存储
|
||||
- 编辑器组件直接散落 `fetch('/api/...')` 访问写接口
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前工程问题归纳
|
||||
|
||||
## 5.1 运行时领域逻辑仍然偏前端中心
|
||||
|
||||
- `useStoryGeneration` 仍然是大体量编排热区,承接了剧情、NPC、战斗后续、任务和部分故事引擎逻辑。
|
||||
- `src/services/ai.ts` 体量很大,说明正式运行时 AI 编排尚未完全移出浏览器。
|
||||
- 当前“后端接口 + 前端兜底”的过渡模式,容易让正式逻辑继续双份存在。
|
||||
|
||||
## 5.2 服务端分层还没真正闭合
|
||||
|
||||
- `server-node` 当前仍直接引用 `src/types`、`src/data`、`src/services`。
|
||||
- 这意味着后端虽然有了入口,但核心领域模型仍然绑在前端目录结构上。
|
||||
- 继续沿着这条路开发,会让后端无法独立测试、独立构建和独立演进。
|
||||
|
||||
## 5.3 运行时持久化边界还不够干净
|
||||
|
||||
- 虽然正式存档已经走远端接口,但前端仍承担较重的恢复、归一化、迁移纠偏逻辑。
|
||||
- 这会导致“存档解释权”同时存在于前后端两边,后续迭代容易失配。
|
||||
|
||||
## 5.4 编辑器与运行时 API 仍然混杂
|
||||
|
||||
- 编辑器读写接口目前仍然有散落访问点。
|
||||
- 资产生成、JSON 写盘、运行时 API 还没有形成清晰的接口分域。
|
||||
- 继续混用会让权限控制、生产部署和后续多人协作变得困难。
|
||||
|
||||
## 5.5 当前协议更像“接口迁移”,还不是“后端驱动运行时”
|
||||
|
||||
- 目前很多接口是把已有前端逻辑搬成了远端调用入口。
|
||||
- 但真正理想状态应该是:玩家点击后,后端完成规则结算、状态推进、AI 调用和持久化,再把展示模型返回给前端。
|
||||
|
||||
---
|
||||
|
||||
## 6. 目标架构
|
||||
|
||||
```text
|
||||
Browser
|
||||
├─ 页面 / 动画 / 交互 / ViewModel 渲染
|
||||
├─ 轻量前端 SDK(只负责请求与状态绑定)
|
||||
└─ 局部 UI State
|
||||
|
||||
packages/shared
|
||||
├─ contracts
|
||||
├─ schemas
|
||||
├─ domain-types
|
||||
└─ api-client-types
|
||||
|
||||
server-node
|
||||
├─ src/modules/auth
|
||||
├─ src/modules/runtime-session
|
||||
├─ src/modules/story
|
||||
├─ src/modules/combat
|
||||
├─ src/modules/npc
|
||||
├─ src/modules/inventory
|
||||
├─ src/modules/build
|
||||
├─ src/modules/quest
|
||||
├─ src/modules/custom-world
|
||||
├─ src/modules/editor
|
||||
├─ src/shared/http
|
||||
├─ src/shared/infra
|
||||
└─ src/shared/llm
|
||||
|
||||
storage
|
||||
├─ postgres
|
||||
├─ uploads
|
||||
└─ generated
|
||||
```
|
||||
|
||||
## 6.1 共享层原则
|
||||
|
||||
- `packages/shared` 只放类型、schema、协议、纯函数和序列化约定。
|
||||
- 共享层不放浏览器专属实现,也不放 Node 专属 IO。
|
||||
- 所有可执行运行时规则默认放后端,不放共享层。
|
||||
|
||||
## 6.2 前端目录目标
|
||||
|
||||
前端建议逐步收敛成下面的职责结构:
|
||||
|
||||
```text
|
||||
src/
|
||||
├─ app
|
||||
├─ pages
|
||||
├─ widgets
|
||||
├─ features
|
||||
├─ entities
|
||||
├─ shared/api
|
||||
├─ shared/ui
|
||||
└─ shared/lib
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- `shared/api` 只保留面向后端 contract 的 SDK。
|
||||
- `features` 只组织交互流程和 UI 组合,不再承载正式运行时规则。
|
||||
- 超大 hook 逐步拆成“页面状态协调层 + 远端 action 调用层 + 表现层状态”。
|
||||
|
||||
---
|
||||
|
||||
## 7. 关键协议重构方向
|
||||
|
||||
当前最值得尽快统一的,不是继续加接口数量,而是把协议升级成“意图驱动”。
|
||||
|
||||
推荐核心动作协议:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionId": "runtime-session-id",
|
||||
"clientVersion": 12,
|
||||
"action": {
|
||||
"type": "story_choice",
|
||||
"functionId": "fight_attack",
|
||||
"targetId": "npc_merchant_01",
|
||||
"payload": {
|
||||
"optionId": "opt_02"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
后端统一返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"sessionId": "runtime-session-id",
|
||||
"serverVersion": 13,
|
||||
"viewModel": {},
|
||||
"presentation": {
|
||||
"storyText": "",
|
||||
"options": [],
|
||||
"battlePlayback": null,
|
||||
"toast": null
|
||||
},
|
||||
"patches": [],
|
||||
"meta": {
|
||||
"requestId": "req_xxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
协议约束:
|
||||
|
||||
- 前端不再提交完整 `gameState` 作为后端运算依据。
|
||||
- 前端提交的是“玩家意图”,不是“玩家已经算好的结果”。
|
||||
- 后端返回的是“下一帧该怎么演”的展示模型,而不是只回一个零散字段。
|
||||
|
||||
---
|
||||
|
||||
## 8. 分阶段重构路线
|
||||
|
||||
## P0:先冻结边界,建立共享协议层
|
||||
|
||||
### 本阶段目标
|
||||
|
||||
把“前端只做表现,后端负责运行时真相”从口头原则变成工程边界。
|
||||
|
||||
### 主要任务
|
||||
|
||||
- 提取 `shared contracts`,把 `server-node` 对 `src/**` 的依赖逐步迁出。
|
||||
- 固化统一的 API 响应结构、错误结构、`requestId`、版本字段。
|
||||
- 明确运行时 API 命名空间与编辑器 API 命名空间。
|
||||
- 新功能一律禁止再把正式运行时规则写回前端。
|
||||
- 为关键运行时入口补健康检查、日志字段、耗时统计。
|
||||
|
||||
### 交付物
|
||||
|
||||
- 共享类型与 schema 目录
|
||||
- 统一 API 约定文档
|
||||
- 服务端模块边界草图
|
||||
- 前端 SDK 基础层
|
||||
|
||||
### 验收标准
|
||||
|
||||
- `server-node` 可以不依赖 `src/**` 中的前端运行时实现继续编译。
|
||||
- 新增运行时需求不再允许“前端先写一版、后端再补一版”。
|
||||
|
||||
## P1:把运行时状态与持久化解释权收回后端
|
||||
|
||||
### 本阶段目标
|
||||
|
||||
让后端成为运行时状态、快照、恢复和迁移的唯一解释者。
|
||||
|
||||
### 主要任务
|
||||
|
||||
- 建立 `runtime session` / `snapshot aggregate`。
|
||||
- 将存档恢复、版本迁移、默认值补齐、schema 纠偏迁到后端。
|
||||
- 把前端 `useGamePersistence` 收敛为“拉取快照 + 触发保存 + 接收 view model”。
|
||||
- 设置、快照、自定义世界库统一归入运行时仓储接口。
|
||||
- 明确哪些内容允许本地缓存,哪些必须以后端结果为准。
|
||||
|
||||
### 交付物
|
||||
|
||||
- 统一的运行时 session API
|
||||
- 快照版本迁移服务
|
||||
- 服务端持久化 schema 文档
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 前端不再承担正式存档恢复迁移的主逻辑。
|
||||
- 同一份存档的解释权只存在于后端。
|
||||
|
||||
## P2:把核心规则结算从前端迁到后端
|
||||
|
||||
### 本阶段目标
|
||||
|
||||
把“剧情推进、战斗、NPC、任务、物品、Build”这些真正影响状态的领域结算全部后端化。
|
||||
|
||||
### 主要任务
|
||||
|
||||
- 把 function 合法性过滤迁入后端。
|
||||
- 把战斗结算、蓝耗、伤害、死亡、掉落、逃跑结果迁入后端。
|
||||
- 把 NPC 交互决策、招募条件、关系变化、交易合法性迁入后端。
|
||||
- 把任务推进 signal、奖励结算、运行时物品结果、Build 结果迁入后端。
|
||||
- 前端收到的只是一份下一步展示所需的聚合 view model 与演出计划。
|
||||
|
||||
### 交付物
|
||||
|
||||
- 运行时 action resolver
|
||||
- 统一领域服务接口
|
||||
- 面向 UI 的 view model assembler
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 前端点击一个选项时,发送的是 action,不是本地先算完再上传结果。
|
||||
- 正式运行时的数值、资源、状态迁移不再依赖浏览器逻辑。
|
||||
|
||||
## P3:把 AI 编排彻底收口到后端
|
||||
|
||||
### 本阶段目标
|
||||
|
||||
让浏览器彻底退出正式运行时 AI 调用与 prompt 组装。
|
||||
|
||||
### 主要任务
|
||||
|
||||
- 把剧情生成、角色聊天、NPC 对话、自定义世界生成、任务生成、物品意图生成等统一后端执行。
|
||||
- 清理前端正式运行时代码中的 AI fallback。
|
||||
- 将 prompt 构造、模型容错、超时、重试、日志、SSE 转发统一收口到后端。
|
||||
- 对需要复用的 prompt 纯函数进行共享层抽取,但执行权只留在后端。
|
||||
|
||||
### 交付物
|
||||
|
||||
- 后端 AI orchestration 模块
|
||||
- 统一 SSE/streaming 适配层
|
||||
- 精简后的前端 AI SDK
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 浏览器正式运行时代码不再直接 import 大体量 AI 编排模块。
|
||||
- 无后端时,正式运行时不再默默回退到另一套浏览器逻辑。
|
||||
|
||||
## P4:把编辑器与资产流程独立成正式后端模块
|
||||
|
||||
### 本阶段目标
|
||||
|
||||
让编辑器能力不再作为运行时副产物存在,而是成为有边界的工具后端模块。
|
||||
|
||||
### 主要任务
|
||||
|
||||
- 建立 `/api/editor/*`、`/api/assets/*` 等明确命名空间。
|
||||
- 给编辑器写接口补权限、环境门禁、审计日志。
|
||||
- 统一编辑器 JSON 读写、资产生成、任务查询接口。
|
||||
- 前端编辑器组件全部改走统一 SDK,不再散落直连接口。
|
||||
|
||||
### 交付物
|
||||
|
||||
- editor API contract
|
||||
- 统一 editor client SDK
|
||||
- 生成任务与写盘适配器
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 编辑器写接口不再散落在多个组件内部。
|
||||
- 运行时 API 与编辑器 API 的职责边界清晰。
|
||||
|
||||
## P5:补齐质量门禁、部署路径和观测能力
|
||||
|
||||
### 本阶段目标
|
||||
|
||||
让这次后端化重构可以稳定上线,而不是只在本地联调成立。
|
||||
|
||||
### 主要任务
|
||||
|
||||
- 为后端补单测、接口测试和关键链路 smoke。
|
||||
- 为前端补 contract 测试,确保 UI 不依赖本地规则。
|
||||
- 建立 `Nginx/Caddy -> dist + /api` 的同域部署路径。
|
||||
- 为流式接口补代理配置、超时、取消和日志。
|
||||
- 为数据库迁移、备份、回滚预留脚本。
|
||||
|
||||
### 验收标准
|
||||
|
||||
- `web + server` 可以独立构建、独立测试、联合部署。
|
||||
- 关键主流程至少具备一条可自动验证的 smoke path。
|
||||
|
||||
---
|
||||
|
||||
## 9. 具体迁移清单
|
||||
|
||||
## 9.1 优先迁移对象
|
||||
|
||||
- `src/hooks/useStoryGeneration.ts`
|
||||
- `src/hooks/useGamePersistence.ts`
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `src/services/storageService.ts`
|
||||
- `src/services/authService.ts`
|
||||
- 编辑器持久化模块与 `src/editor/shared/jsonClient.ts`
|
||||
|
||||
## 9.2 优先抽离到共享层的内容
|
||||
|
||||
- 领域类型定义
|
||||
- zod schema 或等价校验协议
|
||||
- API 请求与响应 contract
|
||||
- 纯序列化函数
|
||||
- 前后端都要认识的 enum / id / status 常量
|
||||
|
||||
## 9.3 不建议抽到共享层的内容
|
||||
|
||||
- 依赖数据库、文件系统、LLM、日志的服务
|
||||
- 正式运行时规则执行器
|
||||
- 存档迁移执行器
|
||||
- 资产生成任务调度器
|
||||
|
||||
---
|
||||
|
||||
## 10. 实施顺序建议
|
||||
|
||||
推荐顺序如下:
|
||||
|
||||
1. 先抽共享类型与协议,切断 `server-node -> src/**` 的反向依赖。
|
||||
2. 再把运行时 session、快照解释权、存档迁移收回后端。
|
||||
3. 再迁核心规则结算,让前端从“业务执行层”退回“表现协调层”。
|
||||
4. 然后彻底收口 AI 编排,移除正式运行时浏览器 fallback。
|
||||
5. 最后归整编辑器 API、部署路径、测试门禁和观测能力。
|
||||
|
||||
不建议的顺序:
|
||||
|
||||
1. 先零散把几个接口改成后端。
|
||||
2. 继续保留前端完整 fallback。
|
||||
3. 最后再补共享层和协议。
|
||||
|
||||
这个顺序会把“双份逻辑并存”的过渡期拖得很长,后面会越来越难收口。
|
||||
|
||||
---
|
||||
|
||||
## 11. 风险与控制点
|
||||
|
||||
- 最大风险不是“迁不动”,而是长期维持双份规则。
|
||||
- 后端化期间必须避免再往前端加新的正式运行时规则。
|
||||
- 协议演进要带版本号,否则快照和 UI 很容易错位。
|
||||
- 前端瘦身不能牺牲移动端一屏体验,表现层拆分仍要遵守移动端优先。
|
||||
- 编辑器 API 必须和正式运行时隔离,不要为了方便继续走混用路径。
|
||||
|
||||
---
|
||||
|
||||
## 12. 一句话结论
|
||||
|
||||
这次重构的核心不是“把几个请求改成走 Express”,而是:
|
||||
|
||||
**把项目从“前端主导运行时、后端承接部分接口”的过渡架构,升级成“Express 后端统一持有运行时真相,前端只负责表现和交互”的正式工程架构。**
|
||||
@@ -3,6 +3,8 @@
|
||||
## 当前入口
|
||||
|
||||
- [CURRENT_GAME_ITERATION_PRIORITIES_2026-04-03.md](./CURRENT_GAME_ITERATION_PRIORITIES_2026-04-03.md):当前阶段最值得优先做什么、为什么,以及它和审计/PRD 的对应关系。
|
||||
- [EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md](./EXPRESS_BACKEND_REFACTOR_PLAN_2026-04-08.md):基于“前端只做表现、逻辑与数据全部后端化”的工程重构规划。
|
||||
- [EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md](./EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md):将后端化重构拆成可并行推进、尽量不冲突的任务流与协作顺序。
|
||||
|
||||
## 使用建议
|
||||
|
||||
|
||||
963
docs/prd/ACCOUNT_SYSTEM_AND_LOGIN_ENTRY_PRD_2026-04-09.md
Normal file
963
docs/prd/ACCOUNT_SYSTEM_AND_LOGIN_ENTRY_PRD_2026-04-09.md
Normal file
@@ -0,0 +1,963 @@
|
||||
# 账号系统与登录入口重构 PRD
|
||||
|
||||
更新时间:`2026-04-09`
|
||||
|
||||
## 0. 目标
|
||||
|
||||
这份 PRD 面向当前仓库,要解决的是一个已经非常明确的产品问题:
|
||||
|
||||
**游戏开始界面目前还是“开始游戏”导向,但项目已经进入后端账号模式,真正缺的是一套正式可运营的账号登录入口和账号体系。**
|
||||
|
||||
这次要完成的不是单纯把按钮文案改掉,而是把当前入口、鉴权、存档归属和跨设备使用体验一起重构成完整闭环:
|
||||
|
||||
1. 游戏开始界面从“开始游戏”切换为“账号登录”
|
||||
2. 支持 `手机号验证码登录`
|
||||
3. 支持 `微信登录`
|
||||
4. 微信登录后必须先绑定手机号,绑定完成后才能进入游戏
|
||||
5. 账号与存档、自定义世界、运行时设置统一绑定到后端用户体系
|
||||
6. 整体体验保持移动端优先、界面清爽、规则不堆满前台
|
||||
|
||||
一句话目标:
|
||||
|
||||
**让“登录账号”成为进入游戏的第一步,让手机号和微信成为正式身份入口,并把账号与游戏数据归属真正接到 Express 后端。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前现状
|
||||
|
||||
## 1.1 当前仓库已经有基础鉴权,但不是正式账号系统
|
||||
|
||||
从当前代码看:
|
||||
|
||||
- `src/components/auth/AuthGate.tsx`
|
||||
- 当前会在无 token 时自动创建或恢复匿名账号
|
||||
- `src/services/authService.ts`
|
||||
- 当前支持“用户名 + 密码”直进,且带自动生成游客凭据逻辑
|
||||
- `server-node/src/routes/authRoutes.ts`
|
||||
- 当前只有 `/api/auth/entry`、`/api/auth/me`、`/api/auth/logout`
|
||||
- `server-node/src/auth/authService.ts`
|
||||
- 当前后端仍是“用户名不存在就自动创建,存在就校验密码”的轻量方案
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- 开始页前台主语仍然是“开始游戏 / 新游戏 / 继续游戏”
|
||||
|
||||
这说明当前系统已经有“用户 ID + JWT + 用户隔离存档”,但还没有正式运营可用的:
|
||||
|
||||
- 手机号体系
|
||||
- 微信身份体系
|
||||
- 绑定关系体系
|
||||
- 验证码体系
|
||||
- 会话过期与刷新体系
|
||||
- 账号归并与换绑规则
|
||||
|
||||
## 1.2 当前方案存在的直接问题
|
||||
|
||||
### 1.2.1 入口主语错位
|
||||
|
||||
当前开始页告诉玩家的是:
|
||||
|
||||
- 开始游戏
|
||||
|
||||
但真实系统需要的是:
|
||||
|
||||
- 先确认你是谁
|
||||
- 再把你的存档和世界数据挂到你的账号下
|
||||
|
||||
也就是说,前台入口和后端真实数据归属已经不一致。
|
||||
|
||||
### 1.2.2 匿名自动账号不适合正式用户体系
|
||||
|
||||
当前自动生成随机账号的方案适合开发期快速联调,但不适合正式版本,因为它会带来:
|
||||
|
||||
- 用户无法理解自己的账号是什么
|
||||
- 跨设备登录和找回几乎不可用
|
||||
- 微信登录无法落地
|
||||
- 手机号绑定没有锚点
|
||||
- 用户会误以为“换设备 = 进度丢失”
|
||||
|
||||
### 1.2.3 微信登录缺少落点
|
||||
|
||||
如果只做“微信授权成功即进入游戏”,会出现两个问题:
|
||||
|
||||
1. 账号恢复能力弱
|
||||
- 一旦微信环境变化,恢复和找回仍然不稳。
|
||||
2. 数据归属不稳定
|
||||
- 仅靠微信身份,不利于后续账号运营、客服排查、风控与跨端同步。
|
||||
|
||||
因此:
|
||||
|
||||
**微信登录不是最终归属,手机号绑定才是正式账号落点。**
|
||||
|
||||
### 1.2.4 当前永久 JWT 不适合正式登录系统
|
||||
|
||||
现状文档已经说明当前 JWT 是永久签发。
|
||||
|
||||
这对开发期方便,但对正式账号系统有明显风险:
|
||||
|
||||
- token 泄露后难以及时失效
|
||||
- 多设备会话管理能力不足
|
||||
- 换绑手机号和安全操作缺少会话边界
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计原则
|
||||
|
||||
## 2.1 账号先于游戏
|
||||
|
||||
正式版本中,玩家进入游戏主流程前,应该先完成账号确认。
|
||||
|
||||
前台语义改为:
|
||||
|
||||
- 未登录:账号登录
|
||||
- 已登录:继续冒险 / 选择世界 / 开始新档
|
||||
|
||||
而不是一上来先点“开始游戏”。
|
||||
|
||||
## 2.2 移动端优先,前台保持清爽
|
||||
|
||||
开始界面和登录面板要继续遵循当前项目已经沉淀出的 UI 经验:
|
||||
|
||||
- 手机竖屏优先
|
||||
- 入口动作少而清晰
|
||||
- 不堆大段规则说明
|
||||
- 主按钮只保留关键动作
|
||||
|
||||
所以登录前台默认只呈现:
|
||||
|
||||
- 手机号登录
|
||||
- 微信登录
|
||||
- 开发团队(次级)
|
||||
|
||||
## 2.3 前端只负责表现,账号逻辑全部进 Express 后端
|
||||
|
||||
必须严格遵守当前项目约束:
|
||||
|
||||
- 前端只渲染登录状态、错误态、输入态、成功态
|
||||
- 验证码发送、验证码校验、微信 OAuth、绑定决策、账号归并、token 签发全部由 Express 后端处理
|
||||
|
||||
前端不能自行决定:
|
||||
|
||||
- 账号是否新建
|
||||
- 是否允许绑定
|
||||
- 是否归并到已有账号
|
||||
- 是否允许进入游戏
|
||||
|
||||
## 2.4 微信登录不是免绑定通行证
|
||||
|
||||
微信登录后,如果账号没有绑定手机号,则:
|
||||
|
||||
- 允许展示绑定手机号页
|
||||
- 不允许进入游戏主流程
|
||||
- 不允许创建正式存档
|
||||
- 不允许进入世界选择和冒险流程
|
||||
|
||||
一句话约束:
|
||||
|
||||
**微信授权成功 != 可以开始游戏,绑定手机号成功后才算正式激活账号。**
|
||||
|
||||
## 2.5 一个手机号对应一个正式主账号
|
||||
|
||||
MVP 阶段建议采用最稳妥规则:
|
||||
|
||||
- 一个手机号只能绑定一个正式账号
|
||||
- 一个微信身份只能绑定一个正式账号
|
||||
- 一个正式账号必须有已验证手机号
|
||||
- 微信是可选登录方式,手机号是正式归属方式
|
||||
|
||||
---
|
||||
|
||||
## 3. 产品范围
|
||||
|
||||
## 3.1 本期要做
|
||||
|
||||
1. 开始界面改成账号登录入口
|
||||
2. 手机号验证码登录
|
||||
3. 微信登录
|
||||
4. 微信后强制绑定手机号
|
||||
5. 账号会话管理
|
||||
6. 账号与存档/自定义世界/运行时设置统一绑定
|
||||
7. 基础账号中心与退出登录
|
||||
|
||||
## 3.2 本期不做
|
||||
|
||||
1. 用户名密码注册
|
||||
2. 游客正式入口
|
||||
3. 账号密码找回
|
||||
4. 实名认证
|
||||
5. 社交好友体系
|
||||
6. 多微信绑定同一账号
|
||||
|
||||
说明:
|
||||
|
||||
当前用户名密码模式可仅保留为开发环境兜底能力,不作为正式前台入口。
|
||||
|
||||
---
|
||||
|
||||
## 4. 用户状态设计
|
||||
|
||||
建议把账号状态统一为下面 5 类:
|
||||
|
||||
## 4.1 未登录
|
||||
|
||||
特征:
|
||||
|
||||
- 本地无有效会话
|
||||
- 前台只显示登录入口
|
||||
|
||||
允许动作:
|
||||
|
||||
- 手机号登录
|
||||
- 微信登录
|
||||
- 查看开发团队
|
||||
|
||||
不允许动作:
|
||||
|
||||
- 开始游戏
|
||||
- 选择世界
|
||||
- 进入已有存档
|
||||
|
||||
## 4.2 手机号已登录
|
||||
|
||||
特征:
|
||||
|
||||
- 已完成手机号验证码校验
|
||||
- 已有正式账号
|
||||
|
||||
允许动作:
|
||||
|
||||
- 继续冒险
|
||||
- 开始新档
|
||||
- 选择世界
|
||||
- 查看账号信息
|
||||
- 退出登录
|
||||
|
||||
## 4.3 微信已授权但未绑定手机号
|
||||
|
||||
特征:
|
||||
|
||||
- 已拿到微信身份
|
||||
- 后端已创建待激活账号壳
|
||||
- 账号状态为 `pending_bind_phone`
|
||||
|
||||
允许动作:
|
||||
|
||||
- 绑定手机号
|
||||
- 切换其他登录方式
|
||||
- 退出当前授权态
|
||||
|
||||
不允许动作:
|
||||
|
||||
- 进入游戏
|
||||
- 创建正式存档
|
||||
- 使用正式运行时能力
|
||||
|
||||
## 4.4 微信已授权且已绑定手机号
|
||||
|
||||
特征:
|
||||
|
||||
- 微信身份已归属到正式账号
|
||||
- 手机号已验证
|
||||
|
||||
允许动作:
|
||||
|
||||
- 与手机号登录用户相同
|
||||
|
||||
## 4.5 会话过期或失效
|
||||
|
||||
特征:
|
||||
|
||||
- access token 过期
|
||||
- refresh session 无效
|
||||
- 或账号状态被强制失效
|
||||
|
||||
表现:
|
||||
|
||||
- 前台回到登录入口
|
||||
- 如果是绑定中状态失效,则回到重新登录
|
||||
|
||||
---
|
||||
|
||||
## 5. 开始界面重构方案
|
||||
|
||||
## 5.1 未登录状态下的开始界面
|
||||
|
||||
当前开始界面的主按钮“开始游戏”应被替换为“账号登录”语义。
|
||||
|
||||
建议界面结构:
|
||||
|
||||
### 顶部
|
||||
|
||||
- 游戏名
|
||||
- 一句极短副标题
|
||||
|
||||
副标题只保留类似:
|
||||
|
||||
- 登录后同步你的冒险进度
|
||||
|
||||
不要再出现规则说明式长文案。
|
||||
|
||||
### 中部主按钮
|
||||
|
||||
只保留两个一级主按钮:
|
||||
|
||||
1. `手机号登录`
|
||||
2. `微信登录`
|
||||
|
||||
按钮样式要求:
|
||||
|
||||
- 手机端纵向堆叠
|
||||
- 桌面端仍以单列为主,不做复杂双栏表单
|
||||
- 点击目标区域足够大
|
||||
- 视觉主语明确是“登录方式”,不是“功能菜单”
|
||||
|
||||
### 底部次级入口
|
||||
|
||||
- `开发团队`
|
||||
|
||||
联系方式面板不建议再作为开始页主信息块长期占据核心位置,避免稀释登录主动作。
|
||||
|
||||
## 5.2 微信未绑定状态下的开始界面
|
||||
|
||||
微信授权成功但未绑定手机号时,开始界面应切成“待激活账号”形态。
|
||||
|
||||
只展示:
|
||||
|
||||
- 微信头像/昵称(可选)
|
||||
- 当前提示:请绑定手机号后进入游戏
|
||||
- 绑定手机号按钮
|
||||
- 返回其他登录方式按钮
|
||||
|
||||
这个状态下不要显示:
|
||||
|
||||
- 继续游戏
|
||||
- 新游戏
|
||||
- 世界选择
|
||||
|
||||
## 5.3 已登录状态下的开始界面
|
||||
|
||||
当账号已正式激活后,开始界面才恢复游戏入口动作,但按钮文案要重新组织。
|
||||
|
||||
建议一级动作:
|
||||
|
||||
- `继续冒险`(存在存档时)
|
||||
- `开始新档`
|
||||
- `选择世界`
|
||||
|
||||
建议次级动作:
|
||||
|
||||
- `账号设置`
|
||||
- `退出登录`
|
||||
- `开发团队`
|
||||
|
||||
也就是说:
|
||||
|
||||
**“开始游戏”不再是未登录态按钮,而是登录后的游戏内动作集合。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 核心功能设计
|
||||
|
||||
## 6.1 手机号验证码登录
|
||||
|
||||
### 交互
|
||||
|
||||
用户输入手机号后:
|
||||
|
||||
1. 点击发送验证码
|
||||
2. 收到 6 位短信验证码
|
||||
3. 输入验证码完成登录
|
||||
|
||||
### 规则
|
||||
|
||||
- 验证码有效期:`5` 分钟
|
||||
- 重新发送冷却:`60` 秒
|
||||
- 单手机号日发送上限:需配置
|
||||
- 单 IP / 单设备分钟级频控:需配置
|
||||
- 验证成功后自动登录
|
||||
|
||||
### 账号策略
|
||||
|
||||
- 手机号已存在:登录已有账号
|
||||
- 手机号不存在:创建正式账号并登录
|
||||
|
||||
MVP 阶段不需要单独设置密码。
|
||||
|
||||
## 6.2 微信登录
|
||||
|
||||
微信登录按终端拆分:
|
||||
|
||||
### 微信内 H5
|
||||
|
||||
- 走微信 OAuth 授权
|
||||
- 后端换取 `code`
|
||||
- 优先获取 `unionid`
|
||||
|
||||
### 桌面网页
|
||||
|
||||
- 走微信扫码登录
|
||||
- 用户扫码确认后由后端完成登录回调
|
||||
|
||||
### 普通手机浏览器
|
||||
|
||||
如果不在微信环境内,不强行做复杂跳转,建议:
|
||||
|
||||
- 优先提示使用手机号登录
|
||||
- 或提示“请在微信内打开以使用微信登录”
|
||||
|
||||
这样比做一套体验不稳定的浏览器跳转更稳。
|
||||
|
||||
### 微信账号策略
|
||||
|
||||
- 若微信身份已绑定正式账号:直接登录
|
||||
- 若微信身份首次出现:创建 `pending_bind_phone` 账号壳,并进入绑定手机号流程
|
||||
|
||||
## 6.3 微信后绑定手机号
|
||||
|
||||
这是本期最关键规则。
|
||||
|
||||
### 绑定目标
|
||||
|
||||
把微信身份最终归属到一个已验证手机号的正式账号上。
|
||||
|
||||
### 绑定流程
|
||||
|
||||
1. 用户完成微信授权
|
||||
2. 前台进入“绑定手机号”页
|
||||
3. 输入手机号
|
||||
4. 获取短信验证码
|
||||
5. 后端校验验证码并处理账号归属
|
||||
|
||||
### 绑定结果分两类
|
||||
|
||||
#### 情况 A:手机号未被使用
|
||||
|
||||
结果:
|
||||
|
||||
- 将该手机号绑定到当前微信待激活账号
|
||||
- 账号转为正式激活
|
||||
- 登录成功,进入游戏开始界面已登录态
|
||||
|
||||
#### 情况 B:手机号已绑定已有正式账号
|
||||
|
||||
建议采用最稳的归并策略:
|
||||
|
||||
1. 短信验证码校验通过
|
||||
2. 后端确认该手机号已有正式账号
|
||||
3. 将当前微信身份直接绑定到该正式账号
|
||||
4. 废弃当前待激活账号壳
|
||||
5. 用户登录到已有手机号账号
|
||||
|
||||
这样做的好处是:
|
||||
|
||||
- 规则简单
|
||||
- 不需要做复杂数据合并
|
||||
- 因为未绑定手机号前禁止进入游戏,所以待激活账号壳上不会挂正式存档数据
|
||||
|
||||
## 6.4 账号中心
|
||||
|
||||
MVP 阶段建议至少提供一个轻量账号中心,包含:
|
||||
|
||||
- 当前登录方式
|
||||
- 已绑定手机号(脱敏展示)
|
||||
- 微信绑定状态
|
||||
- 最近登录时间
|
||||
- 退出登录
|
||||
|
||||
二期可以再补:
|
||||
|
||||
- 更换手机号
|
||||
- 退出全部设备
|
||||
- 查看登录设备
|
||||
|
||||
## 6.5 存档与数据归属
|
||||
|
||||
当前项目已有:
|
||||
|
||||
- 存档快照
|
||||
- 自定义世界库
|
||||
- 运行时设置
|
||||
|
||||
这些数据已经在后端按用户隔离。
|
||||
|
||||
本期要求是把它们统一稳定归属到正式账号,而不是匿名随机用户。
|
||||
|
||||
也就是说:
|
||||
|
||||
- 手机号登录后,数据归属到该账号
|
||||
- 微信登录并绑定手机号后,数据归属到绑定后的正式账号
|
||||
- 同一账号跨设备登录,应读取同一份用户数据
|
||||
|
||||
---
|
||||
|
||||
## 7. 后端账号模型设计
|
||||
|
||||
## 7.1 设计思路
|
||||
|
||||
建议保留当前 `users` 主表,但把“登录方式”和“账号归属”拆到独立身份表中。
|
||||
|
||||
正式模型应区分:
|
||||
|
||||
- 用户主实体
|
||||
- 登录身份
|
||||
- 验证码记录
|
||||
- 会话记录
|
||||
|
||||
## 7.2 建议数据表
|
||||
|
||||
### `users`
|
||||
|
||||
建议保留并扩展:
|
||||
|
||||
- `id`
|
||||
- `display_name`
|
||||
- `account_status`
|
||||
- `primary_phone`
|
||||
- `phone_verified_at`
|
||||
- `token_version`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
- `last_login_at`
|
||||
|
||||
其中:
|
||||
|
||||
- `account_status` 需至少支持:
|
||||
- `active`
|
||||
- `pending_bind_phone`
|
||||
- `disabled`
|
||||
|
||||
### `auth_identities`
|
||||
|
||||
用于记录登录身份。
|
||||
|
||||
建议字段:
|
||||
|
||||
- `id`
|
||||
- `user_id`
|
||||
- `provider`
|
||||
- `provider_uid`
|
||||
- `provider_unionid`
|
||||
- `phone_e164`
|
||||
- `is_verified`
|
||||
- `is_primary`
|
||||
- `bound_at`
|
||||
- `last_login_at`
|
||||
- `meta_json`
|
||||
|
||||
其中 `provider` 至少支持:
|
||||
|
||||
- `phone`
|
||||
- `wechat`
|
||||
|
||||
说明:
|
||||
|
||||
- 手机号登录身份存 `phone_e164`
|
||||
- 微信登录身份优先存 `unionid`
|
||||
- 若极端场景拿不到 `unionid`,需明确风险并做降级策略,但正式上线应优先确保 `unionid`
|
||||
|
||||
### `phone_verification_codes`
|
||||
|
||||
用于短信验证码管理。
|
||||
|
||||
建议字段:
|
||||
|
||||
- `id`
|
||||
- `phone_e164`
|
||||
- `scene`
|
||||
- `code_hash`
|
||||
- `expires_at`
|
||||
- `consumed_at`
|
||||
- `send_ip`
|
||||
- `device_id`
|
||||
- `created_at`
|
||||
|
||||
`scene` 建议至少区分:
|
||||
|
||||
- `login`
|
||||
- `bind_phone`
|
||||
- `change_phone`
|
||||
|
||||
### `user_sessions`
|
||||
|
||||
用于会话刷新和设备管理。
|
||||
|
||||
建议字段:
|
||||
|
||||
- `id`
|
||||
- `user_id`
|
||||
- `refresh_token_hash`
|
||||
- `client_type`
|
||||
- `user_agent`
|
||||
- `ip`
|
||||
- `expires_at`
|
||||
- `revoked_at`
|
||||
- `created_at`
|
||||
- `last_seen_at`
|
||||
|
||||
## 7.3 与当前仓库的关系
|
||||
|
||||
当前仓库已有:
|
||||
|
||||
- `users`
|
||||
- JWT 鉴权
|
||||
- `token_version`
|
||||
|
||||
因此本期不是推翻重做,而是:
|
||||
|
||||
1. 保留 `users` 作为账号主表
|
||||
2. 废弃“用户名密码自动注册”作为正式入口
|
||||
3. 增加手机号与微信身份层
|
||||
4. 增加验证码表与会话表
|
||||
|
||||
---
|
||||
|
||||
## 8. 接口设计
|
||||
|
||||
所有接口均由 Express 后端承接。
|
||||
|
||||
## 8.1 手机号登录相关
|
||||
|
||||
### `POST /api/auth/phone/send-code`
|
||||
|
||||
用途:
|
||||
|
||||
- 发送登录验证码
|
||||
|
||||
入参:
|
||||
|
||||
- `phone`
|
||||
- `scene`
|
||||
|
||||
出参:
|
||||
|
||||
- `ok`
|
||||
- `cooldownSeconds`
|
||||
|
||||
### `POST /api/auth/phone/login`
|
||||
|
||||
用途:
|
||||
|
||||
- 使用手机号 + 验证码登录或注册
|
||||
|
||||
入参:
|
||||
|
||||
- `phone`
|
||||
- `code`
|
||||
|
||||
出参:
|
||||
|
||||
- `accessToken`
|
||||
- `accessTokenExpiresAt`
|
||||
- `user`
|
||||
- `bindingStatus`
|
||||
|
||||
## 8.2 微信登录相关
|
||||
|
||||
### `GET /api/auth/wechat/start`
|
||||
|
||||
用途:
|
||||
|
||||
- 获取微信授权跳转地址或扫码会话
|
||||
|
||||
### `GET /api/auth/wechat/callback`
|
||||
|
||||
用途:
|
||||
|
||||
- 微信授权完成后的后端回调
|
||||
|
||||
回调结果分两类:
|
||||
|
||||
1. 已绑定正式账号
|
||||
- 直接签发会话
|
||||
2. 未绑定手机号
|
||||
- 签发临时登录态,并标记 `pending_bind_phone`
|
||||
|
||||
### `POST /api/auth/wechat/bind-phone`
|
||||
|
||||
用途:
|
||||
|
||||
- 微信授权后绑定手机号
|
||||
|
||||
入参:
|
||||
|
||||
- `phone`
|
||||
- `code`
|
||||
|
||||
出参:
|
||||
|
||||
- `accessToken`
|
||||
- `accessTokenExpiresAt`
|
||||
- `user`
|
||||
- `bindingStatus: active`
|
||||
|
||||
## 8.3 会话与账号信息
|
||||
|
||||
### `GET /api/auth/me`
|
||||
|
||||
返回建议扩展为:
|
||||
|
||||
- `user`
|
||||
- `bindingStatus`
|
||||
- `boundPhoneMasked`
|
||||
- `wechatBound`
|
||||
- `availableLoginMethods`
|
||||
|
||||
### `POST /api/auth/logout`
|
||||
|
||||
用途:
|
||||
|
||||
- 当前设备退出登录
|
||||
|
||||
### `POST /api/auth/refresh`
|
||||
|
||||
用途:
|
||||
|
||||
- 刷新 access token
|
||||
|
||||
说明:
|
||||
|
||||
当前仓库已有 Bearer token 调用链,MVP 阶段可继续保留 Bearer access token 的前端接法,但不应再使用永久 token。
|
||||
|
||||
---
|
||||
|
||||
## 9. 会话与安全设计
|
||||
|
||||
## 9.1 token 策略
|
||||
|
||||
建议从“永久 JWT”切为:
|
||||
|
||||
- `access token`:短期有效
|
||||
- `refresh session`:中期有效
|
||||
|
||||
建议时长:
|
||||
|
||||
- access token:`2` 小时
|
||||
- refresh session:`30` 天
|
||||
|
||||
## 9.2 失效策略
|
||||
|
||||
- 退出登录:失效当前 refresh session,并提升 `token_version`
|
||||
- 账号异常:可强制失效全部 session
|
||||
- 换绑手机号:旧高风险会话应重新校验
|
||||
|
||||
## 9.3 验证码风控
|
||||
|
||||
至少要有:
|
||||
|
||||
- 发送频控
|
||||
- 校验次数限制
|
||||
- 图形验证码扩展点
|
||||
- 日志审计
|
||||
|
||||
## 9.4 微信安全要求
|
||||
|
||||
- 校验 `state`
|
||||
- 回调只能由后端处理
|
||||
- 不在前端直接换 token
|
||||
- 优先使用 `unionid` 作为跨应用稳定身份标识
|
||||
|
||||
---
|
||||
|
||||
## 10. 详细用户流程
|
||||
|
||||
## 10.1 手机号登录流程
|
||||
|
||||
1. 用户打开游戏开始界面
|
||||
2. 点击 `手机号登录`
|
||||
3. 输入手机号
|
||||
4. 点击 `获取验证码`
|
||||
5. 输入验证码
|
||||
6. 后端校验验证码
|
||||
7. 若账号存在则登录,若不存在则创建正式账号
|
||||
8. 返回已登录开始界面
|
||||
9. 用户再选择 `继续冒险 / 开始新档 / 选择世界`
|
||||
|
||||
## 10.2 微信登录流程
|
||||
|
||||
1. 用户打开游戏开始界面
|
||||
2. 点击 `微信登录`
|
||||
3. 进入微信授权或扫码授权
|
||||
4. 后端拿到微信身份
|
||||
5. 若该微信已绑定正式账号,则直接登录
|
||||
6. 若该微信未绑定正式账号,则进入 `绑定手机号` 页
|
||||
7. 用户完成手机号验证码校验
|
||||
8. 后端完成绑定或归并
|
||||
9. 返回已登录开始界面
|
||||
|
||||
## 10.3 微信绑定已有手机号账号流程
|
||||
|
||||
1. 用户微信首次登录
|
||||
2. 系统要求绑定手机号
|
||||
3. 用户输入一个已注册手机号
|
||||
4. 用户完成短信验证码校验
|
||||
5. 后端识别该手机号已有正式账号
|
||||
6. 系统将当前微信身份绑定到该正式账号
|
||||
7. 当前待激活账号壳废弃
|
||||
8. 用户直接登录到已有正式账号
|
||||
|
||||
---
|
||||
|
||||
## 11. 前端实现要求
|
||||
|
||||
## 11.1 前端只维护这些状态
|
||||
|
||||
前端主要只需要表现这些状态:
|
||||
|
||||
- `idle`
|
||||
- `sending_code`
|
||||
- `code_sent`
|
||||
- `wechat_authorizing`
|
||||
- `pending_bind_phone`
|
||||
- `authenticated`
|
||||
- `session_expired`
|
||||
- `error`
|
||||
|
||||
## 11.2 前端不做业务裁决
|
||||
|
||||
前端不能自行决定:
|
||||
|
||||
- 当前手机号是新账号还是老账号
|
||||
- 微信是否允许直进
|
||||
- 当前绑定是“绑定”还是“归并”
|
||||
- 当前账号是否已经正式激活
|
||||
|
||||
前端只根据后端返回的:
|
||||
|
||||
- `bindingStatus`
|
||||
- `availableLoginMethods`
|
||||
- `user`
|
||||
- `errorCode`
|
||||
|
||||
来切换页面表现。
|
||||
|
||||
## 11.3 与当前代码结构的建议映射
|
||||
|
||||
建议优先改造这些区域:
|
||||
|
||||
- `src/components/auth/AuthGate.tsx`
|
||||
- 去掉正式环境的匿名自动登录逻辑
|
||||
- `src/components/auth/LoginScreen.tsx`
|
||||
- 重做为手机号 / 微信双入口
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- 将未登录态入口从“开始游戏”调整为“账号登录后进入”
|
||||
- `src/services/authService.ts`
|
||||
- 改为手机号、微信、绑定手机号、刷新会话等服务层
|
||||
- `src/services/apiClient.ts`
|
||||
- 增加 refresh / 过期处理
|
||||
- `packages/shared/src/contracts/auth.ts`
|
||||
- 扩展新的鉴权 contract
|
||||
|
||||
后端建议优先改造:
|
||||
|
||||
- `server-node/src/routes/authRoutes.ts`
|
||||
- `server-node/src/auth/authService.ts`
|
||||
- `server-node/src/repositories/userRepository.ts`
|
||||
- `server-node/src/middleware/auth.ts`
|
||||
|
||||
---
|
||||
|
||||
## 12. 分阶段落地建议
|
||||
|
||||
## 阶段 A:登录入口重构 + 手机号登录 MVP
|
||||
|
||||
目标:
|
||||
|
||||
- 开始界面从“开始游戏”切为“账号登录”
|
||||
- 手机号验证码登录可用
|
||||
- 正式环境关闭匿名自动账号
|
||||
|
||||
建议同时保留一个仅开发环境可开的兜底开关:
|
||||
|
||||
- `AUTH_ALLOW_DEV_GUEST=true`
|
||||
|
||||
但默认不开,不进入正式前台。
|
||||
|
||||
## 阶段 B:微信登录 + 强制绑定手机号
|
||||
|
||||
目标:
|
||||
|
||||
- 微信授权可用
|
||||
- 微信首次登录后强制绑定手机号
|
||||
- 已有手机号账号与微信身份可自动归并
|
||||
|
||||
## 阶段 C:会话完善 + 账号中心
|
||||
|
||||
目标:
|
||||
|
||||
- access/refresh 机制稳定
|
||||
- 账号中心可查看绑定状态
|
||||
- 支持更稳的退出登录与过期恢复
|
||||
|
||||
## 阶段 D:安全与运营补强
|
||||
|
||||
目标:
|
||||
|
||||
- 更细的风控策略
|
||||
- 登录审计
|
||||
- 换绑手机号
|
||||
- 退出全部设备
|
||||
|
||||
---
|
||||
|
||||
## 13. 验收标准
|
||||
|
||||
做到以下几点,才说明这套账号系统真正成立。
|
||||
|
||||
## 13.1 入口验收
|
||||
|
||||
1. 未登录时,开始界面不再出现“开始游戏”作为主按钮。
|
||||
2. 未登录时,前台主动作只剩手机号登录和微信登录。
|
||||
3. 已登录后,才出现继续冒险、开始新档、选择世界等游戏动作。
|
||||
|
||||
## 13.2 功能验收
|
||||
|
||||
1. 手机号验证码登录可稳定完成注册/登录。
|
||||
2. 微信首次登录后不能直接进入游戏,必须绑定手机号。
|
||||
3. 微信绑定一个已存在手机号时,能够归并到已有正式账号。
|
||||
4. 同一正式账号在不同设备登录后能看到同一份用户数据。
|
||||
|
||||
## 13.3 安全验收
|
||||
|
||||
1. 不再使用永久有效 access token。
|
||||
2. 验证码具备有效期、冷却和频控。
|
||||
3. 退出登录后旧会话不能继续访问受保护接口。
|
||||
|
||||
## 13.4 体验验收
|
||||
|
||||
1. 手机竖屏下登录入口一屏内就能看懂并操作。
|
||||
2. 登录页文案简洁,不堆规则说明。
|
||||
3. 微信未绑定状态下,用户能清楚知道下一步就是绑定手机号。
|
||||
|
||||
---
|
||||
|
||||
## 14. 为什么这套方案适合当前仓库
|
||||
|
||||
这套 PRD 不是凭空换一套系统,而是顺着当前仓库现状做升级:
|
||||
|
||||
1. 当前后端已经具备 `users + JWT + 用户隔离存档`
|
||||
- 所以正式账号体系不是从零开始。
|
||||
2. 当前前端已经有 `AuthGate + authService`
|
||||
- 所以登录入口和登录态切换已有承载点。
|
||||
3. 当前项目是移动端优先
|
||||
- 所以“两个主按钮 + 一个绑定流程”的轻量方案比厚重注册页更适合。
|
||||
4. 当前项目明确要求前端只做表现、逻辑下沉 Express
|
||||
- 所以这套方案把所有裁决都压到后端,和现有工程原则一致。
|
||||
|
||||
---
|
||||
|
||||
## 15. 最后结论
|
||||
|
||||
当前项目真正需要的,不是把“开始游戏”按钮换成另一个文案,而是把进入游戏的第一步从“点开始”升级成“确认正式账号身份”。
|
||||
|
||||
最合理的产品路径是:
|
||||
|
||||
1. 用手机号验证码建立正式账号主入口
|
||||
2. 用微信登录补充更低摩擦的登录方式
|
||||
3. 用“微信后必须绑定手机号”保证账号归属稳定
|
||||
4. 用后端统一承接身份、绑定、会话、存档归属
|
||||
|
||||
这样改完之后,玩家进入游戏时感知到的将不再是:
|
||||
|
||||
- “先点开始再说”
|
||||
|
||||
而会更接近:
|
||||
|
||||
- “先登录我的正式账号,再继续我的冒险进度。”
|
||||
File diff suppressed because it is too large
Load Diff
106
docs/technical/EDITOR_ASSET_API_MIGRATION_2026-04-08.md
Normal file
106
docs/technical/EDITOR_ASSET_API_MIGRATION_2026-04-08.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# 编辑器与资产 API 迁移清单(2026-04-08)
|
||||
|
||||
## 1. 任务定位
|
||||
|
||||
对应 [EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md](../planning/EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md) 中的任务 8:编辑器 API 归口与工具链隔离。
|
||||
|
||||
本轮目标是把编辑器写盘、资产生成、生成任务查询从旧的 Vite 本地 API 插件里收口到 `server-node`,并把前端编辑器组件改成通过统一 SDK 访问。
|
||||
|
||||
---
|
||||
|
||||
## 2. 新命名空间
|
||||
|
||||
编辑器写盘与读取:
|
||||
|
||||
- `GET /api/editor/catalog/items`
|
||||
- `GET /api/editor/json/:resourceId`
|
||||
- `POST /api/editor/json/:resourceId`
|
||||
|
||||
资产生成与任务查询:
|
||||
|
||||
- `POST /api/assets/character-visual/generate`
|
||||
- `POST /api/assets/character-visual/publish`
|
||||
- `GET /api/assets/character-visual/jobs/:taskId`
|
||||
- `POST /api/assets/character-animation/generate`
|
||||
- `POST /api/assets/character-animation/publish`
|
||||
- `GET /api/assets/character-animation/jobs/:taskId`
|
||||
- `POST /api/assets/character-animation/import-video`
|
||||
- `GET /api/assets/character-animation/templates`
|
||||
- `POST /api/assets/qwen-sprite/master`
|
||||
- `POST /api/assets/qwen-sprite/sheet`
|
||||
- `POST /api/assets/qwen-sprite/frame-repair`
|
||||
- `POST /api/assets/qwen-sprite/save`
|
||||
|
||||
---
|
||||
|
||||
## 3. 前端接入
|
||||
|
||||
统一入口:
|
||||
|
||||
- `src/editor/shared/editorApiClient.ts`
|
||||
|
||||
已切换的编辑器链路:
|
||||
|
||||
- 角色预设覆盖保存
|
||||
- 敌人预设覆盖保存
|
||||
- 场景预设覆盖保存
|
||||
- 场景角色覆盖保存
|
||||
- NPC 形象覆盖与布局配置保存
|
||||
- 物品目录读取与物品覆盖保存
|
||||
- 状态行为覆盖保存
|
||||
- 角色主形象生成、发布与任务查询
|
||||
- 角色动作生成、导入、发布、模板读取与任务查询
|
||||
- Qwen 精灵主图、精灵表、修帧与资产保存
|
||||
|
||||
---
|
||||
|
||||
## 4. 权限与环境边界
|
||||
|
||||
`server-node` 通过环境变量控制工具接口:
|
||||
|
||||
- `EDITOR_API_ENABLED`:控制 `/api/editor/*`。
|
||||
- `ASSETS_API_ENABLED`:控制 `/api/assets/*`。
|
||||
|
||||
默认策略:
|
||||
|
||||
- 非 `production` 环境默认开启。
|
||||
- `production` 环境默认关闭。
|
||||
- `ASSETS_API_ENABLED` 未设置时跟随 `EDITOR_API_ENABLED`。
|
||||
|
||||
这批接口会读写 `src/data/*.json` 与 `public/generated-*`,不应作为正式运行时 API 使用。
|
||||
|
||||
---
|
||||
|
||||
## 5. 旧工具链隔离状态
|
||||
|
||||
`scripts/dev-server/**` 中的旧 Vite 本地插件已经不再由 `vite.config.ts` 注入,也不再作为当前开发入口使用。
|
||||
|
||||
旧文件保留用途:
|
||||
|
||||
- 作为历史迁移参考。
|
||||
- 对照旧 DashScope 调用与文件写入逻辑。
|
||||
|
||||
新增编辑器或资产能力时,应优先写入:
|
||||
|
||||
- `server-node/src/modules/editor/**`
|
||||
- `server-node/src/modules/assets/**`
|
||||
- `src/editor/shared/editorApiClient.ts`
|
||||
|
||||
不要再新增旧式散落接口:
|
||||
|
||||
- `/api/item-overrides`
|
||||
- `/api/npc-visual-overrides`
|
||||
- `/api/character-overrides`
|
||||
- `/api/character-visual/*`
|
||||
- `/api/animation/*`
|
||||
- `/api/qwen-sprite/*`
|
||||
|
||||
---
|
||||
|
||||
## 6. 当前验收状态
|
||||
|
||||
- `/api/editor/*` 与 `/api/assets/*` 命名空间已落地。
|
||||
- 前端编辑器组件已通过统一 SDK 或资源 ID 访问编辑器 API。
|
||||
- Vite 已代理 `/api/editor` 与 `/api/assets` 到 Node 后端。
|
||||
- 写接口已经有环境门禁。
|
||||
- 旧 Vite 本地插件不再是当前工具链入口。
|
||||
108
docs/technical/EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md
Normal file
108
docs/technical/EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Express 后端接口冻结与集成清单(2026-04-09)
|
||||
|
||||
## 1. 目的
|
||||
|
||||
这份文档补齐 `docs/planning/EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md` 中任务 0 缺失的仓库内产物,用来明确:
|
||||
|
||||
- 当前 contract 的冻结版本
|
||||
- 热点文件的编辑规则
|
||||
- 各类改动进入集成窗口前的最小检查清单
|
||||
|
||||
它不是新的重构计划,而是给当前并行改造提供一个统一落库的“不要互相踩”的边界表。
|
||||
|
||||
---
|
||||
|
||||
## 2. Contract 版本表
|
||||
|
||||
| 范围 | 当前版本 | 源头文件 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| 统一 API envelope | `2026-04-08 / v1` | `packages/shared/src/http.ts` | `ApiResponse`、错误结构、`meta` 字段、envelope 头约定的统一来源。 |
|
||||
| auth contract | `2026-04-08` | `packages/shared/src/contracts/auth.ts` | 前后端都以 shared auth contract 识别登录、用户信息与 token 响应。 |
|
||||
| runtime snapshot/settings contract | `2026-04-08` | `packages/shared/src/contracts/runtime.ts` | 存档、设置、自定义世界会话与库表相关请求/响应来源。 |
|
||||
| runtime story action contract | `2026-04-08` | `packages/shared/src/contracts/story.ts` | `RuntimeStoryActionRequest/Response`、Task5/Task6 function id 与 view model 来源。 |
|
||||
| Node HTTP route meta | `2026-04-08` | `server-node/src/app.ts` | `/api/auth`、`/api/runtime/story`、`/api/editor`、`/api/assets` 都以这一轮 route version 为当前冻结口径。 |
|
||||
| editor/assets route 命名空间 | `2026-04-08` | `server-node/src/modules/editor/editorRoutes.ts`、`server-node/src/modules/assets/**` | 编辑器与资产接口统一走 `/api/editor/*`、`/api/assets/*`。 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 热点文件编辑规则
|
||||
|
||||
以下文件继续视为高冲突入口,默认不要在多个任务里并行大改:
|
||||
|
||||
- `server-node/src/context.ts`
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
- `server-node/src/app.ts`
|
||||
- `src/services/apiClient.ts`
|
||||
- `src/hooks/useStoryGeneration.ts`
|
||||
- `src/hooks/useGameFlow.ts`
|
||||
- `src/components/GameShell.tsx`
|
||||
|
||||
统一规则:
|
||||
|
||||
- 新需求优先新增独立模块,再通过桥接或小入口接入,不要直接把逻辑堆进热点文件。
|
||||
- 需要改 `server-node/src/routes/runtimeRoutes.ts` 时,先确认 shared contract 是否已落库,再补 route 接入。
|
||||
- 需要改 `src/hooks/useStoryGeneration.ts` 时,优先确认是否其实应该落到 `server-node/src/modules/**`、`src/services/runtimeStoryService.ts` 或 `src/hooks/story/**`。
|
||||
- 编辑器链路与正式运行时链路不要混在同一轮提交里。
|
||||
- 如果同一轮同时碰到后端 action 与前端 UI 壳层,先冻结 action/view model,再接 UI。
|
||||
|
||||
---
|
||||
|
||||
## 4. 集成窗口清单
|
||||
|
||||
### 4.1 shared contract 变更
|
||||
|
||||
- 只在 `packages/shared/**` 改类型、schema、纯序列化约定。
|
||||
- 同步检查 `server-node/src/**` 和 `src/**` 是否都已切到 shared contract。
|
||||
- 至少跑一次 `npm run server-node:test`。
|
||||
- 如果前端消费层也改了,再补 `npm run typecheck`。
|
||||
|
||||
### 4.2 runtime action / domain module 变更
|
||||
|
||||
- 业务规则优先写在 `server-node/src/modules/**`,不要直接写回前端 hook。
|
||||
- 如果影响 `RuntimeStoryActionResponse`,同步检查 `packages/shared/src/contracts/story.ts`。
|
||||
- 至少覆盖对应模块测试,或补到 `server-node/src/modules/story/storyActionRoutes.test.ts`。
|
||||
- 合并前至少跑一次 `npm run server-node:test`。
|
||||
|
||||
### 4.3 persistence / repository / config 变更
|
||||
|
||||
- 只把 PostgreSQL 视为正式基线。
|
||||
- 如果改到 `server-node/src/db.ts`、`repositories/**`、迁移脚本,优先确认 `pg-mem` 测试仍通过。
|
||||
- 合并前至少跑一次 `npm run server-node:test`。
|
||||
|
||||
### 4.4 editor / assets 变更
|
||||
|
||||
- 后端入口只放在 `/api/editor/*`、`/api/assets/*`。
|
||||
- 前端统一从 `src/editor/shared/editorApiClient.ts` 或对应 persistence 层进入。
|
||||
- 不要新增旧 Vite 本地插件式散落接口。
|
||||
|
||||
### 4.5 前端壳层接入变更
|
||||
|
||||
- 优先消费 `runtime story state / action response / shared contract`,不要把正式规则写回前端。
|
||||
- 如果恢复流程有改动,优先以后端 runtime state 为准。
|
||||
- 若影响主流程,至少补对应 hook / view model 测试并跑 `npm run typecheck`。
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前剩余非冻结区
|
||||
|
||||
以下几块仍处于“可继续收口但尚未完全冻结”的状态,改动时要额外小心:
|
||||
|
||||
- `server-node/src/bridges/legacyBuildRuntimeBridge.ts`
|
||||
- `server-node/src/bridges/legacyInventoryRuntimeBridge.ts`
|
||||
- `server-node/src/modules/ai/storyOrchestrator.ts`
|
||||
- `server-node/src/modules/ai/chatOrchestrator.ts`
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
|
||||
它们目前仍残留一部分对 `src/**` 历史实现的复用,不建议在没有额外测试兜底时顺手混改。
|
||||
|
||||
---
|
||||
|
||||
## 6. 本轮落库结论
|
||||
|
||||
从 2026-04-09 起,仓库内已经具备任务 0 要求的这几类最小产物:
|
||||
|
||||
- contract 版本表
|
||||
- 热点文件编辑规则
|
||||
- 集成窗口检查清单
|
||||
|
||||
后续如果 shared contract、runtime action 或热点入口发生明显演进,应优先更新这份文档,而不是让口径只停留在聊天记录里。
|
||||
@@ -0,0 +1,109 @@
|
||||
# Express 后端任务 4 AI 编排收口状态(2026-04-08)
|
||||
|
||||
## 1. 结论
|
||||
|
||||
按 `EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md` 的任务 4 定义,本轮已经把正式运行时的 `story / character chat / npc chat / custom world generation / quest intent / runtime item intent` 的主要 AI 编排入口收回到 Express 后端。
|
||||
|
||||
当前可以视为:
|
||||
|
||||
- 正式运行时主链已不再依赖浏览器端大体量 AI 实现作为兜底。
|
||||
- prompt 组装、上游模型请求、SSE 转发已以后端为主。
|
||||
- 前端保留的本地 AI 大模块只通过懒加载方式服务于非正式运行时遗留入口,不再作为正式运行时默认路径。
|
||||
|
||||
---
|
||||
|
||||
## 2. 已完成项
|
||||
|
||||
### 2.1 后端统一 orchestration 入口
|
||||
|
||||
- `server-node/src/modules/ai/storyOrchestrator.ts`
|
||||
- `server-node/src/modules/ai/chatOrchestrator.ts`
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
|
||||
这些模块承接:
|
||||
|
||||
- story prompt 组装
|
||||
- character chat prompt 组装
|
||||
- npc chat / recruit prompt 组装
|
||||
- custom world generation 后端入口封装
|
||||
|
||||
### 2.2 服务层收口
|
||||
|
||||
已收口到后端服务或模块的文件:
|
||||
|
||||
- `server-node/src/services/llmClient.ts`
|
||||
- `server-node/src/services/storyService.ts`
|
||||
- `server-node/src/services/chatService.ts`
|
||||
- `server-node/src/services/customWorldGenerationService.ts`
|
||||
- `server-node/src/services/questService.ts`
|
||||
- `server-node/src/services/runtimeItemService.ts`
|
||||
|
||||
### 2.3 前端正式运行时 fallback 清理
|
||||
|
||||
`src/services/aiService.ts` 已完成以下收缩:
|
||||
|
||||
- story 正式路径不再 fallback 到浏览器本地 AI 编排
|
||||
- character suggestions / summary / reply stream 不再 fallback 到浏览器本地 AI 编排
|
||||
- npc dialogue / recruit stream 不再 fallback 到浏览器本地 AI 编排
|
||||
- 移除了正式运行时对 `VITE_ENABLE_BROWSER_RUNTIME_AI_FALLBACK` 的依赖
|
||||
- 移除了正式运行时对本地轻量离线文案 fallback 的默认依赖
|
||||
- 对 `./ai` 的引用改为懒加载,避免正式运行时默认把大体量 AI 模块打进主路径
|
||||
- 正式运行时主流程 hook 已统一改走 `aiService`,不再直接从 `src/services/ai.ts` 获取 story/chat 主链能力
|
||||
|
||||
### 2.4 旧 bridge 清理
|
||||
|
||||
已移除:
|
||||
|
||||
- `server-node/src/bridges/legacyAiRuntimeBridge.ts`
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前边界说明
|
||||
|
||||
以下项仍然存在于前端目录,但不再属于正式运行时默认 AI 执行路径:
|
||||
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/aiFallbacks.ts`
|
||||
- `src/components/CustomWorldEntityEditorModal.tsx` 中的工具链直连调用
|
||||
|
||||
它们当前主要作为:
|
||||
|
||||
- 兼容性遗留实现
|
||||
- 懒加载的非主路径工具能力
|
||||
- 非本轮正式运行时链路的复用来源
|
||||
|
||||
这不再构成任务 4 的主阻塞,但后续仍应继续配合任务 1 / 任务 7 做彻底分层。
|
||||
|
||||
---
|
||||
|
||||
## 4. 非任务 4 主阻塞但需要记录的事项
|
||||
|
||||
### 4.1 仍属编辑器/工具链范畴的遗留调用
|
||||
|
||||
- `generateCustomWorldSceneImage` 仍通过懒加载复用旧实现。
|
||||
|
||||
原因:
|
||||
|
||||
- 该能力属于自定义世界工具链,不是正式运行时剧情 / 对话主链。
|
||||
- 当前不会再影响“浏览器正式运行时是否依赖本地大 AI 编排”这一任务 4 验收项。
|
||||
|
||||
### 4.2 分层彻底闭合仍需后续任务配合
|
||||
|
||||
尽管任务 4 已完成主链收口,但以下更深层收敛仍建议交由后续任务继续推进:
|
||||
|
||||
- 继续减少 `server-node` 对 `src/**` 纯提示词/纯规则模块的历史复用
|
||||
- 继续把共享 contract / schema 下沉到 `packages/shared`
|
||||
- 继续把工具链与正式运行时拆分
|
||||
|
||||
这些属于任务 1、任务 7、任务 8 的后续工作,不再阻塞任务 4 验收。
|
||||
|
||||
---
|
||||
|
||||
## 5. 本轮建议验收口径
|
||||
|
||||
任务 4 可按以下口径验收:
|
||||
|
||||
- 浏览器正式运行时不再默认兜底到本地大体量 AI 编排
|
||||
- story/chat/custom world generation 主链 prompt 组装与请求执行权在后端
|
||||
- SSE 主链以后端转发为准
|
||||
- upstream timeout / abort / error 统一走后端处理链
|
||||
425
docs/technical/EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md
Normal file
425
docs/technical/EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md
Normal file
@@ -0,0 +1,425 @@
|
||||
# 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 为唯一真相源”。**
|
||||
@@ -11,17 +11,18 @@
|
||||
- 承接运行时鉴权
|
||||
- 承接运行时持久化
|
||||
- 承接运行时 AI 接口
|
||||
- 承接编辑器写盘与资产生成工具接口
|
||||
- 为 Vite 前端提供开发期代理目标
|
||||
|
||||
当前不再使用:
|
||||
|
||||
- Vite 本地 API 插件 `scripts/dev-server/`
|
||||
- Vite 本地 API 插件 `scripts/dev-server/` 作为当前接口入口
|
||||
|
||||
## 2. 技术栈
|
||||
|
||||
- HTTP 框架:`Express`
|
||||
- 语言与构建:`TypeScript` + `tsx` + `esbuild`
|
||||
- 数据库:`better-sqlite3`
|
||||
- 数据库:`PostgreSQL`
|
||||
- JWT:`jose`
|
||||
- 密码哈希:`@node-rs/argon2`
|
||||
- 日志:`pino` + `pino-http` + `pino-roll`
|
||||
@@ -31,12 +32,13 @@
|
||||
推荐命令:
|
||||
|
||||
```bash
|
||||
npm run dev:node
|
||||
npm run dev
|
||||
```
|
||||
|
||||
相关脚本:
|
||||
|
||||
- 根目录联调:`npm run dev:node`
|
||||
- 根目录联调:`npm run dev` / `npm run dev:node`
|
||||
- 仅前端开发:`npm run dev:web`
|
||||
- 单独启动后端开发模式:`npm run server-node:dev`
|
||||
- 构建后端:`npm run server-node:build`
|
||||
- 运行后端测试:`npm run server-node:test`
|
||||
@@ -57,6 +59,9 @@ npm run dev:node
|
||||
|
||||
- `server-node/src/routes/authRoutes.ts`
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
- `server-node/src/modules/editor/editorRoutes.ts`
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
- `server-node/src/modules/assets/qwenSpriteRoutes.ts`
|
||||
|
||||
基础设施:
|
||||
|
||||
@@ -102,8 +107,12 @@ JWT 现状:
|
||||
|
||||
当前数据库:
|
||||
|
||||
- 默认 SQLite 文件:`server-node/data/genarrative.sqlite`
|
||||
- 可通过 `SQLITE_PATH` 覆盖
|
||||
- 当前运行时持久化已切换到 `PostgreSQL`
|
||||
- 连接信息由后端 `DATABASE_URL` 环境变量注入
|
||||
- 不再以本地 `SQLite` 文件作为正式运行时数据库
|
||||
- 后端测试默认使用 `pg-mem` 作为内存级 PostgreSQL 兼容实现
|
||||
- 基础表初始化通过 `schema_migrations` 基线管理
|
||||
- 可通过 `npm run server-node:db:migrate` 主动校验并补齐数据库基线
|
||||
|
||||
当前核心表:
|
||||
|
||||
@@ -153,6 +162,33 @@ JWT 现状:
|
||||
- `POST /api/runtime/items/runtime-intent`
|
||||
- `POST /api/runtime/quests/generate`
|
||||
|
||||
编辑器工具:
|
||||
|
||||
- `GET /api/editor/catalog/items`
|
||||
- `GET /api/editor/json/:resourceId`
|
||||
- `POST /api/editor/json/:resourceId`
|
||||
|
||||
资产工具:
|
||||
|
||||
- `POST /api/assets/character-visual/generate`
|
||||
- `POST /api/assets/character-visual/publish`
|
||||
- `GET /api/assets/character-visual/jobs/:taskId`
|
||||
- `POST /api/assets/character-animation/generate`
|
||||
- `POST /api/assets/character-animation/publish`
|
||||
- `GET /api/assets/character-animation/jobs/:taskId`
|
||||
- `POST /api/assets/character-animation/import-video`
|
||||
- `GET /api/assets/character-animation/templates`
|
||||
- `POST /api/assets/qwen-sprite/master`
|
||||
- `POST /api/assets/qwen-sprite/sheet`
|
||||
- `POST /api/assets/qwen-sprite/frame-repair`
|
||||
- `POST /api/assets/qwen-sprite/save`
|
||||
|
||||
编辑器与资产接口门禁:
|
||||
|
||||
- `EDITOR_API_ENABLED` 控制 `/api/editor/*`
|
||||
- `ASSETS_API_ENABLED` 控制 `/api/assets/*`
|
||||
- 非生产环境默认开启,生产环境默认关闭
|
||||
|
||||
## 8. Story 与 Custom World 现状
|
||||
|
||||
Story:
|
||||
@@ -179,6 +215,13 @@ Custom World:
|
||||
- `src/services/storageService.ts`
|
||||
- `src/services/aiService.ts`
|
||||
|
||||
编辑器与资产工具层:
|
||||
|
||||
- `src/editor/shared/editorApiClient.ts`
|
||||
- `src/editor/shared/useJsonSave.ts`
|
||||
- `src/components/preset-editor/characterAssetStudioPersistence.ts`
|
||||
- `src/tools/qwenSpriteSheetToolPersistence.ts`
|
||||
|
||||
## 10. 当前 Vite 角色
|
||||
|
||||
Vite 当前只负责代理,不再提供本地 API 插件。
|
||||
@@ -187,8 +230,12 @@ Vite 当前只负责代理,不再提供本地 API 插件。
|
||||
|
||||
- `/api/auth`
|
||||
- `/api/runtime`
|
||||
- `/api/editor`
|
||||
- `/api/assets`
|
||||
- `/api/llm`
|
||||
- `/api/custom-world/scene-image`
|
||||
- `/api/ws`
|
||||
|
||||
全部转发到 Node 后端。
|
||||
|
||||
旧 `scripts/dev-server/**` 文件仅保留为迁移参考,不再由 `vite.config.ts` 注入。
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
# Node 后端测试、观测与部署基线
|
||||
|
||||
日期:`2026-04-08`
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
这份文档用于落实 `EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md` 中的任务 9:
|
||||
|
||||
- 给 Node 后端补最小自动回归
|
||||
- 给请求链路补最小可追踪基线
|
||||
- 给部署、回滚、迁移补最小操作清单
|
||||
|
||||
当前目标不是一次性把监控平台、CI/CD、容器编排全部做完,而是先确保:
|
||||
|
||||
- 后端改动后有脚本能快速验证主链路
|
||||
- 线上或联调失败时能快速定位到具体请求
|
||||
- 发布前后有统一检查口径
|
||||
|
||||
## 2. 当前基线命令
|
||||
|
||||
推荐在仓库根目录执行:
|
||||
|
||||
```bash
|
||||
npm run server-node:db:migrate
|
||||
npm run server-node:test:baseline
|
||||
npm run server-node:smoke
|
||||
npm run server-node:smoke:proxy
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `npm run server-node:db:migrate`
|
||||
- 用当前 `DATABASE_URL` 主动校验 PostgreSQL 基线是否可连接、可初始化
|
||||
- 会确保 `schema_migrations` 和运行时基础表已补齐
|
||||
- `npm run server-node:test:baseline`
|
||||
- 当前先固定为任务 9 自己维护的观测基线测试
|
||||
- 已覆盖 `requestId` 回传、访问日志字段、错误日志链路
|
||||
- `npm run server-node:smoke`
|
||||
- 启动一套基于 `pg-mem` 的临时 Express 服务
|
||||
- 不依赖本地 PostgreSQL
|
||||
- 走真实 HTTP 调用验证 `healthz -> auth -> runtime save/settings -> logout`
|
||||
- `npm run server-node:smoke:proxy`
|
||||
- 基于已构建的 `dist + server-node/dist`
|
||||
- 自动拉起 `server-node + 同域反向代理 harness`
|
||||
- 用 `pg-mem` 跑同域反向代理链路 smoke
|
||||
- 验证 `web -> reverse proxy -> /api/* -> server-node` 主链路
|
||||
|
||||
如果要一口气跑完整发布前基线,可执行:
|
||||
|
||||
```bash
|
||||
npm run server-node:check:deploy
|
||||
```
|
||||
|
||||
补充说明:
|
||||
|
||||
- `npm run server-node:test` 仍然可以继续作为更大范围的后端接口套件入口
|
||||
- 但它会跟随其他并行任务一起变化,不应替代任务 9 自己的稳定基线
|
||||
|
||||
## 2.1 任务 9 对照清单
|
||||
|
||||
当前按并行任务规划中的任务 9 逐项对照:
|
||||
|
||||
- 后端接口测试:`npm run server-node:test`
|
||||
- 关键主链路 smoke:`npm run server-node:smoke`
|
||||
- request/response 日志校验:`npm run server-node:test:baseline`
|
||||
- 同域部署基线:本文第 6 节与 `npm run server-node:smoke:proxy`
|
||||
- 反向代理 smoke 测试脚本:`scripts/smoke-same-origin-stack.ts`
|
||||
- 回滚、备份、迁移检查清单:本文第 8 节与 `npm run server-node:db:migrate`
|
||||
- 发布前一键检查:`npm run server-node:check:deploy`
|
||||
|
||||
## 3. 当前 smoke 覆盖范围
|
||||
|
||||
当前 smoke 脚本验证以下链路:
|
||||
|
||||
- `GET /healthz`
|
||||
- `POST /api/auth/entry`
|
||||
- `GET /api/auth/me`
|
||||
- `PUT /api/runtime/save/snapshot`
|
||||
- `GET /api/runtime/save/snapshot`
|
||||
- `PUT /api/runtime/settings`
|
||||
- `GET /api/runtime/settings`
|
||||
- `DELETE /api/runtime/save/snapshot`
|
||||
- `POST /api/auth/logout`
|
||||
|
||||
当前代理 smoke 额外验证:
|
||||
|
||||
- `GET /`
|
||||
- `GET /healthz`(本地反向代理健康探针)
|
||||
- `POST /api/auth/entry` 经反代可用
|
||||
- `GET /api/auth/me` 经反代可用
|
||||
- `PUT /api/runtime/save/snapshot` 经反代可用
|
||||
- `GET /api/runtime/save/snapshot` 经反代可用
|
||||
- `X-Request-Id` 能穿过反向代理返回给调用方
|
||||
|
||||
当前 smoke 的定位是:
|
||||
|
||||
- 优先覆盖后端化后最容易断的基础链路
|
||||
- 优先覆盖前端最依赖的鉴权和持久化能力
|
||||
- 不把 AI 上游依赖拉进最小回归集,避免把第三方波动误判成主链路回归
|
||||
|
||||
## 4. 当前观测基线
|
||||
|
||||
当前请求链路至少要满足以下约束:
|
||||
|
||||
- 支持读取外部传入的 `X-Request-Id`
|
||||
- 如果调用方没有传 `X-Request-Id`,后端自动生成
|
||||
- 响应头回写 `x-request-id`
|
||||
- 访问日志至少包含:
|
||||
- `request_id`
|
||||
- `user_id`
|
||||
- `method`
|
||||
- `path`
|
||||
- `status`
|
||||
- `latency_ms`
|
||||
- 错误日志至少包含:
|
||||
- `request_id`
|
||||
- `user_id`
|
||||
- `err`
|
||||
|
||||
当前目的很明确:
|
||||
|
||||
- 浏览器、反向代理、Node 后端至少有一个共同可追踪的请求标识
|
||||
- 接口失败后,能从日志里快速找到对应请求
|
||||
|
||||
## 5. 部署前检查清单
|
||||
|
||||
发布前至少执行一次:
|
||||
|
||||
- `npm run check:encoding`
|
||||
- `npm run server-node:db:migrate`
|
||||
- `npm run server-node:test:baseline`
|
||||
- `npm run server-node:smoke`
|
||||
- `npm run server-node:build`
|
||||
- `npm run build`
|
||||
- `npm run server-node:smoke:proxy`
|
||||
|
||||
环境变量至少确认:
|
||||
|
||||
- `DATABASE_URL`
|
||||
- `JWT_SECRET`
|
||||
- `NODE_SERVER_ADDR`
|
||||
- `LOG_LEVEL`
|
||||
- `LLM_API_KEY` 或 `ARK_API_KEY`
|
||||
- `DASHSCOPE_API_KEY`
|
||||
|
||||
部署前数据库检查:
|
||||
|
||||
- 确认目标 PostgreSQL 可连接
|
||||
- 确认发布账号具备建表或执行初始化所需权限
|
||||
- 确认已执行 `npm run server-node:db:migrate` 或等效迁移步骤
|
||||
- 确认现网数据已完成备份
|
||||
|
||||
## 6. 同域部署基线
|
||||
|
||||
当前推荐仍然是同域部署:
|
||||
|
||||
- Web 静态资源:`https://game.example.com/`
|
||||
- Node API:`https://game.example.com/api/*`
|
||||
|
||||
最小拓扑:
|
||||
|
||||
```text
|
||||
Browser
|
||||
-> Nginx / Caddy
|
||||
-> dist
|
||||
-> server-node
|
||||
```
|
||||
|
||||
反向代理至少要保留这些头:
|
||||
|
||||
- `Host`
|
||||
- `X-Forwarded-For`
|
||||
- `X-Forwarded-Proto`
|
||||
- `X-Request-Id`
|
||||
|
||||
流式接口还要确保:
|
||||
|
||||
- `proxy_buffering off`
|
||||
- `X-Accel-Buffering: no`
|
||||
|
||||
## 7. 发布后 smoke 清单
|
||||
|
||||
发布完成后至少人工或脚本确认一次:
|
||||
|
||||
1. `GET /healthz` 返回 `200`
|
||||
2. 响应头里能看到 `x-request-id`
|
||||
3. `POST /api/auth/entry` 可正常注册或恢复账号
|
||||
4. `GET /api/auth/me` 可正常识别 token
|
||||
5. `PUT /api/runtime/save/snapshot` 和 `GET /api/runtime/save/snapshot` 正常
|
||||
6. 日志中能用同一个 `request_id` 串起访问记录
|
||||
|
||||
如果线上使用反向代理生成请求 ID,还要额外确认:
|
||||
|
||||
- 代理传入的 `X-Request-Id` 没有在 Node 层丢失
|
||||
- 同域入口 `/` 与 `/api/*` 可以通过同一个站点域名访问
|
||||
|
||||
## 8. 回滚与备份清单
|
||||
|
||||
回滚前先确认:
|
||||
|
||||
- 当前发布包版本号或 commit 可定位
|
||||
- 当前数据库备份可恢复
|
||||
- 当前 `.env` 或 secret 版本可回退
|
||||
|
||||
需要回滚时按顺序执行:
|
||||
|
||||
1. 停止新版本 Node 进程
|
||||
2. 切回上一个稳定前端静态包和 Node 构建产物
|
||||
3. 恢复上一个稳定环境变量版本
|
||||
4. 如果本次发布包含数据库结构变更,先确认是否需要回滚数据
|
||||
5. 回滚后重新执行 `healthz + auth + runtime save` 最小 smoke
|
||||
|
||||
如果本次发布已经写入了不兼容数据结构:
|
||||
|
||||
- 不要只回滚代码不验证数据兼容性
|
||||
- 必须先确认旧版本代码是否还能读取当前数据
|
||||
|
||||
## 9. 后续扩展方向
|
||||
|
||||
任务 9 的下一轮可以继续补:
|
||||
|
||||
- 把 smoke 纳入 CI
|
||||
- 为关键 API 增加结构化 contract 测试
|
||||
- 给上游 AI 调用补 vendor/model/errorCode 维度日志
|
||||
- 增加数据库迁移前后的自动检查脚本
|
||||
- 增加反向代理与正式环境的联调 smoke
|
||||
@@ -5,6 +5,9 @@
|
||||
## 文档列表
|
||||
|
||||
- [NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md](./NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md):当前 Node 运行时后端的技术栈、入口、鉴权、存储与接口知识图谱。
|
||||
- [EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md](./EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md):Express 后端当前 contract 冻结版本、热点文件编辑规则与集成窗口清单。
|
||||
- [EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md](./EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md):按并行工作流文档逐项核对后的完成度审计与剩余收口点。
|
||||
- [EDITOR_ASSET_API_MIGRATION_2026-04-08.md](./EDITOR_ASSET_API_MIGRATION_2026-04-08.md):编辑器写盘、资产生成、任务查询从 Vite 本地插件迁到 Node 后端的接口与工具链清单。
|
||||
- [GO_SERVER_RUNTIME_INTEGRATION_2026-04-07.md](./GO_SERVER_RUNTIME_INTEGRATION_2026-04-07.md):Go 服务端接入、运行时持久化迁移与当前进展记录。
|
||||
- [GO_SERVER_TASKLIST_2026-04-08.md](./GO_SERVER_TASKLIST_2026-04-08.md):Go 服务端已完成与未完成事项的执行清单。
|
||||
- [AI_CHARACTER_ANIMATION_TECHNICAL_SOLUTION_2026-04-04.md](./AI_CHARACTER_ANIMATION_TECHNICAL_SOLUTION_2026-04-04.md):AI 生成角色形象与角色动画的技术路线。
|
||||
|
||||
Reference in New Issue
Block a user