Prune stale docs and update .hermes content

Delete a large set of outdated documentation (many files under docs/ and .hermes/plans/, including audits, design, prd, technical, planning, assets, and todos). Update and consolidate .hermes content: refresh shared-memory pages (decision-log, development-workflow, document-map, pitfalls, project-overview, team-conventions) and several skills/references under .hermes/skills. Also modify AGENTS.md, README.md, UI_CODING_STANDARD.md, docs/README.md and .encoding-check-ignore. Purpose: clean up stale planning/audit material and keep current hermes documentation and related top-level docs in sync.
This commit is contained in:
2026-05-15 06:24:07 +08:00
parent 2eded08bc7
commit 3cb3efb4d0
708 changed files with 4033 additions and 142328 deletions

View File

@@ -1,553 +0,0 @@
# 前端应迁后端逻辑审计2026-04-21
更新时间:`2026-04-21`
## 0. 审计目标
这份文档只回答一个问题:
**当前前端代码里哪些逻辑已经明显越过“前端只做表现Express 后端负责逻辑、数据与存储”的边界,应该继续迁到后端。**
本轮不改业务代码,只做:
1. 基于当前仓库状态给出高置信度候选点
2. 标明代码证据
3. 给出迁移优先级
4. 说明迁移后前端应该保留什么、移走什么
---
## 1. 结论先行
结合当前代码与已有边界文档,前端里仍有 7 类逻辑应该继续后移:
1. **运行时快照前置写入与本地镜像解释**
2. **鉴权 token 的浏览器本地真相**
3. **平台浏览历史的本地真相与迁移状态**
4. **NPC 待接委托“换单”仍由前端直接触发正式生成**
5. **quest/runtime item 的双环境混合编排**
6. **浏览器侧大型 AI orchestration 与 prompt/repair/fallback 主链**
7. **NPC 招募对白之后的正式结算链路**
一句话判断:
**当前前端已经不是最早那种“大量主算”的状态,但仍然保留了运行时镜像、生成编排和部分正式真相。后端边界还需要再收一轮,前端才算真正退回表现层。**
---
## 2. 审计依据
### 2.1 文档依据
1. `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
2. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
3. `docs/technical/RUNTIME_STORY_BACKEND_BOUNDARY_MIGRATION_2026-04-19.md`
4. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`
5. `docs/audits/engineering/CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`
### 2.2 当前代码依据
1. `src/hooks/story/runtimeStoryCoordinator.ts`
2. `src/services/apiClient.ts`
3. `src/services/platformBrowseHistory.ts`
4. `src/components/game-shell/PreGameSelectionFlow.tsx`
5. `src/hooks/story/npcEncounterActions.ts`
6. `src/services/questDirector.ts`
7. `src/services/runtimeItemAiDirector.ts`
8. `src/services/ai.ts`
---
## 3. 当前高置信度应后移逻辑
## 3.0 本轮已完成后移
以下链路已在本轮或上一轮连续落地中完成后移,不再属于“仍残留在前端”的正式主链:
1. access token 浏览器本地真相
2. browse history 本地真相
3. runtime story 前置 `PUT /runtime/save/snapshot`
4. NPC 待接委托 `replace / abandon / accept`
5. custom world profile 正式浏览器入口
6. `questDirector` / `runtimeItemAiDirector` 浏览器正式编排
7. NPC 招募正式结算
其中 NPC 招募已从“前端本地改 companions / roster / npcStates / storyHistory”收回到后端 runtime action。
## 3.1 运行时快照前置写入仍在前端
### 代码证据
`src/hooks/story/runtimeStoryCoordinator.ts` 当前仍存在以下链路:
1. `syncRuntimeSnapshot(...)`
2. `syncRuntimeSnapshot(...)` 内部直接调用 `putSaveSnapshot(...)`
3. `loadServerRuntimeOptionCatalog(...)` 在请求 `getRuntimeStoryState(...)` 之前先写本地快照
4. `resolveServerRuntimeChoice(...)` 在请求 `resolveRuntimeStoryAction(...)` 之前先写本地快照
对应位置:
1. `src/hooks/story/runtimeStoryCoordinator.ts:21`
2. `src/hooks/story/runtimeStoryCoordinator.ts:25`
3. `src/hooks/story/runtimeStoryCoordinator.ts:36`
4. `src/hooks/story/runtimeStoryCoordinator.ts:99`
### 当前问题
这意味着运行时正式动作发起前,前端仍会先落一份自己的快照真相,再去请求后端。
这条链的问题不是“有没有缓存”,而是:
1. 前端仍在承担正式提交前的状态镜像
2. 快照解释权没有完全收回到后端
3. 运行时主链仍处于“本地镜像 + 服务端会话”并存状态
### 迁移建议
后端继续承接:
1. 运行时快照写入
2. 快照版本解释
3. 动作提交前的状态一致性校验
前端只保留:
1. 当前展示用的 view model
2. 可选的只读恢复缓存
3. 纯表现态的 loading / transition / animation state
### 优先级
`P0`
---
## 3.2 鉴权 token 仍由前端 localStorage 持有真相
### 代码证据
`src/services/apiClient.ts` 当前仍直接访问 `window.localStorage` 保存 access token
1. `getStoredAccessToken()`
2. `setStoredAccessToken(...)`
3. `clearStoredAccessToken(...)`
4. `withAuthorizationHeaders(...)` 直接从本地 token 组装请求头
对应位置:
1. `src/services/apiClient.ts:333`
2. `src/services/apiClient.ts:341`
3. `src/services/apiClient.ts:362`
4. `src/services/apiClient.ts:382`
### 当前问题
第三批清理已经收掉了“自动登录用户名/密码”本地真相,但 access token 仍然由浏览器长期持有。
这在当前项目边界下仍有两个问题:
1. 正式鉴权真相仍没有完全收回后端 session 边界
2. 前端 SDK 仍然负担 token 生命周期的关键部分
### 迁移建议
后端继续承接:
1. session / refresh / cookie 真相
2. 鉴权状态续期
3. token 更新与失效策略
前端只保留:
1. 当前是否已登录的展示态
2. 统一的请求封装
3. 401 后的 UI 响应
### 优先级
`P0`
---
## 3.3 平台浏览历史仍是“前端本地历史 + 后端回填”的双真相
### 代码证据
`src/services/platformBrowseHistory.ts` 当前仍维护一整套本地历史真相:
1. `readPlatformBrowseHistory(...)`
2. `writePlatformBrowseHistory(...)`
3. `hasPendingPlatformBrowseHistoryMigration(...)`
4. `markPlatformBrowseHistoryMigrated(...)`
对应位置:
1. `src/services/platformBrowseHistory.ts:77`
2. `src/services/platformBrowseHistory.ts:103`
3. `src/services/platformBrowseHistory.ts:151`
4. `src/services/platformBrowseHistory.ts:164`
`src/components/game-shell/PreGameSelectionFlow.tsx` 当前仍显式做:
1.`writePlatformBrowseHistory(...)`
2. 再调用 `upsertProfileBrowseHistory(...)`
3. 同步成功后 `markPlatformBrowseHistoryMigrated(...)`
4. 启动阶段读取 `readPlatformBrowseHistory(...)`
5. 根据 `hasPendingPlatformBrowseHistoryMigration(...)` 决定是否补同步
对应位置:
1. `src/components/game-shell/PreGameSelectionFlow.tsx:383`
2. `src/components/game-shell/PreGameSelectionFlow.tsx:392`
3. `src/components/game-shell/PreGameSelectionFlow.tsx:394`
4. `src/components/game-shell/PreGameSelectionFlow.tsx:433`
5. `src/components/game-shell/PreGameSelectionFlow.tsx:466`
### 当前问题
这条链已经不是单纯缓存,而是:
1. 本地历史存储
2. 本地同步标记
3. 后端历史持久化
三套状态同时存在。
### 迁移建议
后端继续承接:
1. 浏览历史唯一持久化真相
2. 历史去重、排序、截断
3. 迁移完成标记
前端只保留:
1. 展示缓存
2. 弱网下的临时 optimistic UI
3. 刷新后重新拉取远端结果
### 优先级
`P1`
---
## 3.4 NPC 待接委托“换单”仍由前端直接发起正式生成
### 代码证据
`src/hooks/story/npcEncounterActions.ts` 当前仍保留:
1. `replacePendingNpcQuestOffer = async () => { ... }`
2. 内部直接调用 `generateQuestForNpcEncounter(...)`
对应位置:
1. `src/hooks/story/npcEncounterActions.ts:1561`
2. `src/hooks/story/npcEncounterActions.ts:1595`
### 当前问题
聊天后是否挂出待接委托已经后移,但“换一份委托”这条分支仍然是:
1. 前端组装上下文
2. 前端决定调用生成
3. 前端直接把结果写回当前 story UI
这仍属于正式运行时任务编排没有收干净。
### 迁移建议
后端继续承接:
1. NPC 待接委托换单决策
2. 是否允许换单
3. 换单后的任务草案生成
4. 对应聊天态快照回填
前端只保留:
1. 点击“换一份委托”
2. loading / error 展示
3. 消费后端返回的新 pending quest offer
### 优先级
`P0`
---
## 3.5 questDirector 仍是前端 SDK 与生成编排混合体
### 代码证据
`src/services/questDirector.ts` 当前同时承担:
1. `generateQuestForNpcEncounter(...)`
2. 浏览器路径 `requestJson('/api/runtime/quests/generate')`
3. 非浏览器路径 `requestChatMessageContent(...)`
4. 本地 `compileQuestIntentToQuest(...)` fallback
对应位置:
1. `src/services/questDirector.ts:213`
2. `src/services/questDirector.ts:242`
3. `src/services/questDirector.ts:267`
4. `src/services/questDirector.ts:256`
5. `src/services/questDirector.ts:281`
6. `src/services/questDirector.ts:293`
### 当前问题
这类文件虽然浏览器正式路径已经优先走后端,但职责仍混在一起:
1. 前端 SDK
2. Quest prompt 编排
3. Quest intent 解析
4. deterministic fallback compile
这会导致边界长期模糊,也让前端仍像“半个服务端”。
### 迁移建议
后端继续承接:
1. quest intent 生成
2. prompt 组装
3. JSON 解析
4. fallback compile
前端只保留:
1. `requestGenerateQuest(...)` 这类轻量 SDK
2. 请求参数组装
3. 结果消费
### 优先级
`P1`
---
## 3.6 runtimeItemAiDirector 仍是前端 SDK 与意图生成混合体
### 代码证据
`src/services/runtimeItemAiDirector.ts` 当前同时承担:
1. `generateRuntimeItemAiIntents(...)`
2. 浏览器路径 `requestJson('/api/runtime/items/runtime-intent')`
3. 非浏览器路径 `requestChatMessageContent(...)`
4. 本地 `buildRuntimeItemAiIntent(...)` fallback
对应位置:
1. `src/services/runtimeItemAiDirector.ts:84`
2. `src/services/runtimeItemAiDirector.ts:94`
3. `src/services/runtimeItemAiDirector.ts:118`
### 当前问题
它和 `questDirector` 是同类问题:
1. 正式浏览器路径已经走后端
2. 但前端文件仍然承担完整生成逻辑认知
3. 文件职责仍然是双环境混合
### 迁移建议
后端继续承接:
1. runtime item intent prompt
2. 模型调用
3. 结果解析与 fallback
前端只保留:
1. 轻量请求 SDK
2. 结果到 UI 的映射
### 优先级
`P1`
---
## 3.7 `src/services/ai.ts` 仍是浏览器侧正式 AI orchestration 热点
### 代码证据
当前 `src/services/ai.ts` 仍直接承担以下正式链路:
1. `requestChatMessageContent(...)`
2. `requestPlainTextCompletionFromClient(...)`
3. `streamPlainTextCompletionFromClient(...)`
4. `generateCustomWorldProfile(...)`
5. `generateInitialStory(...)`
6. `generateNextStep(...)`
7. `streamNpcChatDialogue(...)`
8. `streamNpcRecruitDialogue(...)`
对应位置:
1. `src/services/ai.ts:1732`
2. `src/services/ai.ts:1868`
3. `src/services/ai.ts:2038`
4. `src/services/ai.ts:2339`
5. `src/services/ai.ts:2447`
6. `src/services/ai.ts:2487`
7. `src/services/ai.ts:2529`
8. `src/services/ai.ts:2570`
并且文件内仍保留:
1. JSON repair
2. prompt 组装
3. response normalize
4. fallback/offline 响应
5. 角色聊天建议与摘要生成
### 当前问题
这说明浏览器端并不只是“请求一个后端接口”,而是还在承担:
1. prompt source
2. 生成策略
3. 错误修复
4. fallback 编排
5. 多类业务场景的正式 AI 出口
这与“前端只做表现”存在明确冲突。
### 迁移建议
后端继续承接:
1. story / npc / recruit / custom-world 的 prompt 编排
2. JSON repair
3. fallback 策略
4. streaming orchestration
5. 模型调用与日志
前端只保留:
1. 轻量 AI SDK
2. SSE 文本流展示
3. UI fallback 呈现
### 优先级
`P0`
---
## 3.8 NPC 招募对白之后的正式结算链路已完成后移
### 本轮前状态
迁移前,`src/hooks/story/npcInteraction.ts` 中的 `buildRecruitmentOutcome / executeRecruitment / startRecruitmentSequence` 仍在前端本地正式结算:
1.`npcStates`
2.`companions`
3.`roster`
4.`currentEncounter / inBattle / sceneHostileNpcs`
5. 直接写 `storyHistory`
6. 再触发后续剧情推进
这与“前端只做表现,所有正式逻辑、数据都放到 Express 后端”直接冲突。
### 本轮后状态
本轮已完成:
1. `server-node/src/modules/story/runtimeSession.ts`
- 正式承接完整 `companions`
- 正式承接 `roster`
2. `server-node/src/modules/npc/npcInteractionService.ts`
- `npc_recruit` 已支持正常入队
- `npc_recruit` 已支持满员换队招募
3. `src/hooks/story/npcInteraction.ts`
- 前端只保留招募对白流式展示
- 正式招募结算改为调用后端 runtime action
### 当前判断
这一项已不再属于前端残留正式逻辑。
---
## 4. 可以暂时保留在前端的部分
下面这些内容即使和上述模块同文件出现,也不属于必须后移的对象:
1. 面板开关、loading、error、streaming 文本展示
2. 动画时间线、过场状态、临时 UI 回显
3. 表单草稿、筛选词、排序选项
4. 只影响表现、不影响正式真相的 view model 拼接
迁移时要注意:
**不是把所有前端代码都往后端搬,而是把“正式状态解释、规则裁决、生成编排、持久化真相”搬走。**
---
## 5. 推荐迁移顺序
## 5.1 第一阶段
先收最危险的正式真相:
1. `runtimeStoryCoordinator.ts`
2. `apiClient.ts`
3. `npcEncounterActions.ts` 里的 quest replace 分支
原因:
1. 这三处最直接影响运行时真相和动作主链
2. 不先收这些,前端仍然不是纯表现层
## 5.2 第二阶段
再拆双环境混合服务:
1. `questDirector.ts`
2. `runtimeItemAiDirector.ts`
3. `platformBrowseHistory.ts`
原因:
1. 这几处已经有后端承接基础
2. 迁移成本相对可控
## 5.3 第三阶段
最后继续压缩浏览器 AI orchestration
1. `src/services/ai.ts`
2. 相关 prompt builder / repair helper / offline fallback
原因:
1. 这部分体量大
2. 链路多
3. 更适合在前两阶段把 contract 稳住后集中拆
---
## 6. 建议产出物
如果后续按这份文档继续落地,建议每一批都至少同步产出:
1. 一份落地文档,说明迁移了哪条链
2. 一组 contract/route 变更说明
3. 一组前端 SDK 收缩说明
4. 一组防回退测试
---
## 7. 一句话结论
当前前端最需要继续后移的,不是零散小工具,而是:
**运行时快照前置写入、鉴权 token、本地浏览历史真相、NPC 委托换单、quest/runtime item 双环境混合编排,以及 `src/services/ai.ts` 里仍然留在浏览器的正式 AI orchestration。**