Files
mnote/design/old/03-rust-web/process/rust-web-long-term-checklist-v1.md

555 lines
28 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 3-0 [recycle] Rust Web 长期架构实施清单 v1
> 更新时间:2026-04-16
>
> 关联文档:
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/process/document-access-performance-root-cure-v1.md`
> - `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-kernel-cutover-v1.md`
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
## 1. 文档用途
这份清单不是短期提速清单,而是长期架构落地清单。
它服务的目标只有一个:
> **把 mnote 从“Rust 内核 + 重前端页面壳”推进到“Rust 内核 + Rust Web 承载 + server-first 页面 + 少量交互孤岛”的稳定形态。**
这份清单强调四件事:
- 做什么
- 不做什么
- 什么时候算完成
- 哪些东西必须最后处理
---
## 2. 总体完成定义
只有同时满足下面几条,才能认为长期架构目标基本达成:
- [ ] Rust workspace 成为唯一业务真执行面,Web 层不再承载第二套对象规则
- [ ] Rust Web 层已经接住主 API、主页面壳、主流式能力
- [ ] 文档访问路径已变成“先阅读、后交互、再编辑”
- [ ] Sidebar、搜索、AI、Mindmap 等外围模块已退出当前重前端主壳
- [ ] `BlockNote` 已被隔离为最后的重交互孤岛,而不是整页入口前提
- [ ] Next/旧 React 壳只保留过渡兼容边界或已被替换
---
## 3. 执行原则清单
在任何阶段开始前,先确认这些原则不被破坏:
- [ ] 不再把新的业务规则写回 TS route / Next 页面层
- [ ] 不再新增新的全局常驻前端大面板
- [ ] 不再把“临时懒加载”当作长期方案替代品
- [ ] 不在未完成阅读态分离前,继续扩张编辑态默认挂载内容
- [ ] 不把 `BlockNote` 当成第一阶段改造对象
- [ ] 不把 OnlyOffice 当成主性能阻塞项
- [ ] 不把“换成 Rust”简化成“只重写 API”
---
## 4. 阶段总览
推荐按下面顺序推进:
- Phase 0:基线与边界冻结
- Phase 1Rust Web 基础层落地
- Phase 2:文档阅读页 server-first 化
- Phase 3Sidebar / 页面树 / 文件树 Rust 化与 island 化
- Phase 4:搜索系统 Rust 化与 island 化
- Phase 5:AI 面板进一步收口为纯桥接 island
- Phase 6Mindmap 独立对象化与独立页面化
- Phase 7:文档编辑态与 `BlockNote` 孤岛化
- Phase 8:旧前端壳下线与兼容清理
### 4.1 阶段依赖与并行规则
这条长期路线不是“看到哪里慢就改哪里”,而是有明确前后依赖。
- [x] `Phase 0` 必须先产出边界冻结、基线和 islands 候选,否则后续会重新滑回旧壳扩张。
- [x] 横向能力 `H1` 必须在 `Phase 1` 之前定口径,否则 Rust Web、阅读态、搜索、AI、Mindmap 会各自发明 trace、缓存和权限语义。
- [x] `Phase 1``Phase 2` ~ `Phase 6` 的共同前置;没有 Rust Web 承载层,后续只能继续堆 Next route。
- [x] `Phase 2` ~ `Phase 6` 可以分批并行推进,但都必须遵守“阅读优先、局部 island、对象规则只进 Rust core”。
- [x] `Phase 7` 依赖 `Phase 2` ~ `Phase 6` 基本就位后再开始,否则 `BlockNote` 会继续承担外围能力。
- [x] `Phase 8` 只能在 `Phase 1` ~ `Phase 7` 都有稳定替代路径后执行,不能靠“删旧代码”制造假完成。
### 4.2 每阶段输出给下一阶段的输入
- [x] `Phase 0` 输出:重模块审计表、性能基线、阅读态/编辑态边界、islands 候选、冻结口径。
- [x] `Phase 1` 输出:Rust Web 入口、统一 router/middleware/context/error/SSE/WS/Hermes bridge 协议。
- [x] `Phase 2` 输出:文档阅读态服务端主链、阅读工具栏 island、阅读缓存/预取策略。
- [x] `Phase 3` 输出:Sidebar/树结构服务端骨架、局部刷新协议、导航预取策略。
- [x] `Phase 4` 输出:搜索 server-first 页面壳、轻交互 Search island、分页/键盘导航协议。
- [x] `Phase 5` 输出:AI bridge panel 最小会话协议、流式 token/tool/client action 统一事件流。
- [x] `Phase 6` 输出:Mindmap 独立对象页壳、内嵌轻预览边界、独立操作协议。
- [x] `Phase 7` 输出:阅读态/编辑态切换协议、编辑岛错误边界、编辑态性能采样。
- [x] `Phase 8` 输出:Next/旧 React 壳保留清单、兼容层清理清单、最终对外口径。
---
## 5. Phase 0:基线与边界冻结
### 5.1 目标
在动长期架构之前,先冻结边界,避免迁移过程中又把旧模式继续扩写。
### 5.2 实施清单
- [ ] 盘点当前由 Next/React 页面层承载的重模块清单
- [ ] 标记哪些模块属于“必须保留浏览器交互”
- [ ] 标记哪些模块属于“可变为 server-first 页面”
- [ ] 标记哪些模块属于“可退化为独立 island”
- [ ] 标记哪些模块属于“外挂或独立页面,不进入主文档链”
- [ ] 冻结 `BlockNote` 外围继续加功能的入口
- [ ] 冻结 Sidebar、SearchPalette、Document 面板继续膨胀的入口
- [ ] 为页面切换与首屏建立统一性能基线
- [ ] 为文档页进入路径建立链路追踪点
- [ ] 为 Sidebar、搜索、AI、Mindmap 建立独立耗时采样点
### 5.2.1 当前前端重模块审计表
| 模块 | 当前主入口 | 当前主问题 | 长期归位 | 是否必须保留浏览器重交互 |
| --- | --- | --- | --- | --- |
| 文档页 | `wolai-frontend/src/app/(app)/documents/[id]/page.tsx` + `DocumentShell -> DocumentContent -> BlockNoteEditor` | 进入页面默认串到编辑器初始化,阅读态无法先出现 | `Phase 2` 先 server-first 阅读页,`Phase 7` 再把 `BlockNote` 孤岛化 | 是,但只限编辑态 |
| Sidebar / 页面树 / 文件树 | `wolai-frontend/src/app/(app)/layout.tsx` + `src/components/sidebar/sidebar.tsx` | 常驻在主布局内,切页时继续参与大组件状态与重渲染 | `Phase 3` 收口为 Rust query + 服务端壳 + 局部 island | 是,但只限展开/拖拽/快捷过滤 |
| SearchPalette | `src/components/search/search-palette.tsx` | 当前仍作为全局常驻大组件挂在布局内 | `Phase 4` 收口为独立 island 与 server-first 搜索页 | 是,但只限输入/联想/键盘导航 |
| AI 面板 | `src/components/ai-agent/**``DocumentAiAgentPanel``MindmapAiAgentPanel``OnlyOfficeAiAgentPanel` | 已切 Hermes bridge,但页面壳仍偏重,多个面板仍常驻挂载 | `Phase 5` 统一为最小 bridge shell + 按需 island | 是,但只限会话与浏览器 client capability |
| Mindmap | `src/components/editor/blocks/MindmapBlock.tsx` + `src/app/mindmap/[docId]/[mindmapId]/page.tsx` | 独立页仍与 BlockNote 形态绑得太近,内嵌/独立共用同一重壳 | `Phase 6` 收口为独立对象页 + 内嵌轻预览 | 是 |
| OnlyOffice | `src/app/onlyoffice/**``src/app/api/onlyoffice/**` | 属于外部编辑器桥,不是主文档性能瓶颈 | 继续维持外挂页面,不进入主文档链 | 是,但不进入主文档访问链 |
| `BlockNote` | `src/components/editor/blocknote-editor.tsx` | 当前仍然是文档页默认入口前提 | 最后处理,保留为 `Phase 7` 的重交互孤岛 | 是 |
### 5.2.2 冻结口径
- [x] 新增页面能力时,先判断是否能落到 server-first 页面或局部 island,不能再默认塞回主布局。
- [x] 新增对象规则、权限判断、聚合排序、工具编排,不允许直接写回 Next route 或页面层。
- [x] `BlockNote` 外围的新面板、新工具栏、新初始化逻辑一律冻结,除非是为“阅读态分离”服务。
- [x] Sidebar、SearchPalette、AI 面板不允许再继续增加全局常驻状态容器。
### 5.3 产物清单
- [ ] 当前前端重模块审计表
- [ ] 页面切换性能基线报告
- [ ] 文档阅读态与编辑态的边界定义
- [ ] 岛模型候选模块清单
### 5.3.1 页面切换性能基线报告
| 访问链路 | 当前入口 | 需要记录的统一指标 | 当前基线采样方式 | 迁移后对比目标 |
| --- | --- | --- | --- | --- |
| 普通文档打开 | `/documents/[id]` | 首字节、正文首屏、进入可点击阅读态、进入编辑态耗时、`BlockNote` 挂载耗时 | `scripts/task019-document-ui-regression.js` + 浏览器 performance trace | 把正文首屏与阅读交互从编辑器启动链里剥离 |
| Sidebar 切页 | 主布局 + Sidebar | 切页耗时、树结构重渲染数、导航预取命中率 | `pnpm test src/lib/sidebar-data.test.ts src/lib/file-tree/rows.test.ts` + React Profiler | Sidebar 仅做局部交互,不再放大整页挂载 |
| 搜索打开/关闭 | SearchPalette | 打开耗时、首次结果返回、键盘导航响应、关闭恢复耗时 | 搜索页/浮层交互 trace + `eslint`/定向 smoke | 搜索开关不再引发整页重计算 |
| AI 面板打开/关闭 | Document/Mindmap/OnlyOffice AI | 面板首开耗时、SSE 首 token、关闭后页面恢复耗时 | `runAgent.test.ts` + 页面侧 performance mark | AI 未打开时不占主页面主链 |
| Mindmap 独立页 | `/mindmap/[docId]/[mindmapId]` | 页面壳首屏、导图交互可用、独立页返回文档页耗时 | `scripts/task021-mindmap-ui-regression.js` | 独立页不再依赖文档编辑上下文 |
### 5.3.2 文档阅读态与编辑态的边界定义
- [x] 阅读态必须先拿到页面 meta 与正文读链,允许在没有编辑器的情况下稳定展示正文。
- [x] 编辑态必须显式进入,不能再把“打开文档”默认等同于“挂载完整编辑器”。
- [x] 阅读态负责:权限、只读/禁复制/禁下载策略、正文首屏、轻工具栏、回退与预取。
- [x] 编辑态负责:`BlockNote`、块级写入、Slash、评论/历史/AI/页面选项等重交互链路。
- [x] 只读渲染与可编辑渲染必须是两套不同初始化协议,不能靠 mounted gating 假装分离。
### 5.3.3 岛模型候选模块清单
| 模块 | 候选 island 形态 | 保留在服务端页面壳的内容 |
| --- | --- | --- |
| 文档阅读工具栏 | 轻工具栏 island | 标题、正文、权限壳、阅读统计 |
| Sidebar 树 | 展开/拖拽/快捷过滤 island | 工作区壳、树结构首屏 HTML |
| SearchPalette | 输入框、联想、结果列表 island | 搜索页结果首屏与分页壳 |
| AI 面板 | 单一 `AiBridgePanel` island | 页面上下文注入、SSE 桥接 route |
| Mindmap | 独立导图交互 island | 独立页 meta、权限与返回壳 |
| `BlockNote` | 最后保留的重编辑 island | 阅读页正文、阅读工具栏、权限与缓存壳 |
### 5.4 完成判定
- [ ] 后续任何人都能明确知道哪些模块先迁、哪些模块后迁
- [ ] 已经有统一基线可以验证迁移是否真的更快
- [ ] 不再接受“顺手往旧壳里再塞功能”的继续扩张
---
## 6. Phase 1Rust Web 基础层落地
### 6.1 目标
建立真正的 Rust Web 承载层,而不是停留在“Rust 只做业务内核”。
### 6.2 实施清单
- [ ] 在 Rust workspace 中明确新增 Web 层 crate 或独立服务目录
- [ ] 选定 `axum` 作为主 HTTP 承载框架
- [ ] 建立统一 Router 组织方式
- [ ] 建立统一 middleware 链
- [ ] 建立统一 request id / trace id 注入
- [ ] 建立统一鉴权上下文注入方式
- [ ] 建立统一 workspace / actor / tenant 上下文透传
- [ ] 建立统一错误码与错误响应协议
- [ ] 建立统一 JSON 响应包装规范
- [ ] 建立统一 SSE 输出协议
- [ ] 建立统一 WebSocket 连接协议
- [ ] 建立统一静态资源与页面壳响应策略
- [ ] 打通 Rust Web 层到现有 Rust core runtime 的调用入口
- [ ] 打通 Rust Web 层到 Hermes 的桥接入口
- [ ] 明确保留哪些 Next route 作为过渡兼容壳
- [ ] 明确哪些旧 route 不允许再扩写
### 6.3 架构约束
- [ ] `axum` 只负责 Web 承载,不复制业务裁决
- [ ] Rust Web 层不再新建第二套对象模型
- [ ] Web 层只组合调用 Rust core,而不是重新实现 core 语义
- [ ] 仍需浏览器特定 transport 的旧接口必须标记为兼容层
### 6.4 完成判定
- [ ] 已有一个可运行的 Rust Web 入口
- [ ] 主 API、SSE、WS、trace 基础设施已可由 Rust Web 层承接
- [ ] 后续页面迁移不再必须依赖 Next API route 作为唯一入口
---
## 7. Phase 2:文档阅读页 server-first 化
### 7.1 目标
把“进入文档页就进入编辑器世界”的模式改成“先进入阅读页,再按需进入编辑态”。
### 7.2 实施清单
- [ ] 定义文档阅读页独立于编辑态的页面模型
- [ ] 定义阅读页所需最小数据模型
- [ ] 定义阅读页 HTML 输出协议
- [ ] 将文档 meta 与正文读取收敛成同一服务端读链
- [ ] 去掉进入文档页必须二次取正文的默认模式
- [ ] 去掉进入文档页必须等待客户端 mounted gating 的默认模式
- [ ] 去掉阅读页默认依赖 `BlockNote` 的前提
- [ ] 把评论、历史、回链、页面选项、AI 等外围面板改为非阻塞挂载
- [ ] 将文档阅读工具栏收缩为轻交互 island
- [ ] 将阅读页权限、只读、禁复制、禁下载等策略前移到服务端页面壳
- [ ] 为阅读页建立缓存与失效策略
- [ ] 为阅读页建立首屏、切页、回退、预取策略
### 7.3 禁止事项
- [ ] 不允许为了“看起来快一点”继续叠更多客户端 gating
- [ ] 不允许阅读页默认挂载完整编辑器依赖树
- [ ] 不允许把评论、AI、回链等周边作为阅读页首屏阻塞条件
### 7.4 完成判定
- [ ] 打开文档时可以先看到完整阅读态,而不是编辑器 loading 壳
- [ ] 文档访问主链已不依赖 `BlockNote` 初始化完成
- [ ] 页面切换性能的主要瓶颈已从“编辑器启动”转移出去
### 7.5 当前落地状态(2026-04-16
- [x] 文档页已改成 server-first 阅读入口:服务端先拿 `meta + content + revision + conflictDetectionKey`,客户端只在服务端读链失败时才回退到旧 `/api/documents/content` 读链。
- [x] `DocumentShell` 已去掉 mounted gating,阅读页不再先显示“正在载入编辑器...”壳。
- [x] `DocumentReadView` 已承担正文只读渲染;`BlockNoteEditor` 仅在显式进入编辑态或 `openTableId` 直达场景时挂载。
- [x] 只读/禁复制/禁下载、评论、历史、回链、页面 AI 与页面选项都已从阅读首屏阻塞链上移开,阅读态可以先稳定出现。
---
## 8. Phase 3Sidebar / 页面树 / 文件树 Rust 化与 island 化
### 8.1 目标
把高频访问、长期常驻、当前体量过大的导航系统,从主前端大壳里拆出去。
### 8.2 实施清单
- [ ] 定义 Sidebar 数据聚合协议
- [ ] 定义页面树 / 文件树查询协议
- [ ] 将排序、过滤、分组、收藏、最近访问、回收站等聚合逻辑收敛到 Rust
- [ ] 将大部分树结构渲染改为服务端输出
- [ ] 将展开、折叠、拖拽、快捷过滤等改为局部 island
- [ ] 拆分“静态结构”和“高交互局部状态”
- [ ] 减少全局布局对 Sidebar 的强耦合
- [ ] 让 Sidebar 切页时不重新参与重布局初始化
- [ ] 为树结构建立局部刷新协议,而不是整树重拉
- [ ] 为导航行为建立预取与轻量缓存策略
### 8.3 风险控制
- [ ] 拖拽重排不能倒逼回到全客户端大组件
- [ ] 树结构局部刷新不能破坏 SSR 壳稳定性
- [ ] 布局层不得继续持有超大导航状态容器
### 8.4 完成判定
- [ ] Sidebar 不再是主布局中的超大客户端核心组件
- [ ] 页面树 / 文件树的数据与主要规则已由 Rust 层统一提供
- [ ] 切页时 Sidebar 只参与局部交互,不再放大整页挂载成本
### 8.5 当前落地状态(2026-04-16
- [x] `layout` 已在服务端先调用 `loadSidebarDataFromConvex(...)` 输出 `SidebarInitialData`,导航首屏数据不再默认延迟到客户端再拼。
- [x] `/api/sidebar``src/lib/sidebar-data.ts``src/lib/server/sidebar-data.ts` 与实时 hook 已统一复用 `sidebar.dataset.list` 的共享契约。
- [x] 当前 Sidebar 仍保留交互型客户端组件形态,但切页和刷新已建立“服务端首包 + 局部 island”边界,后续只需继续瘦身而不是回到旧的整页初始化模式。
---
## 9. Phase 4:搜索系统 Rust 化与 island 化
### 9.1 目标
让搜索成为一个轻页面、轻浮层、轻交互系统,而不是全局重组件。
### 9.2 实施清单
- [ ] 明确搜索索引层、召回层、结果聚合层全部由 Rust 提供
- [ ] 明确文档、块、标题、标签、对象搜索的统一协议
- [ ] 为搜索结果定义服务端可渲染的数据模型
- [ ] 将 SearchPalette 改造成独立 island
- [ ] 将输入框、联想、最近搜索、结果列表拆成最小交互单元
- [ ] 将搜索页主内容改成 server-first 页面
- [ ] 建立搜索结果分页、滚动续取、键盘导航协议
- [ ] 建立最近搜索与最近访问的轻量持久层
- [ ] 避免搜索组件再作为全局常驻重组件绑定整页布局
### 9.3 完成判定
- [ ] 搜索框打开与关闭不再引发整页级别的重计算
- [ ] 搜索结果主要由 Rust 提供,前端只负责最小交互呈现
- [ ] 搜索能力不再依赖当前全局 React 壳维持状态
### 9.4 当前落地状态(2026-04-16
- [x] `SearchPalette` 已拆成轻量 `SearchPaletteHost` + `search-palette.runtime`,首次快捷键或首次打开前不再加载重量运行态。
- [x] 全局布局只保留搜索 host 接线,`Ctrl/Cmd+P` 与引用快捷键先由 host 接住,再按需拉起 runtime。
- [x] `SearchPaletteHost` 的动态导入已修正为直接指向 runtime,避免 host 自引用导致的错误懒加载。
---
## 10. Phase 5AI 面板进一步收口为纯桥接 island
### 10.1 目标
让 AI 面板彻底变成“后端工具桥 + 最小 UI”,不再成为大前端的第二套系统。
### 10.2 实施清单
- [ ] 确认所有主线 AI tools 已收口到 Rust runtime / Hermes
- [ ] 删除或冻结旧前端 registry / orchestration 入口
- [ ] 统一 AI 面板的最小会话协议
- [ ] 统一页面上下文注入协议
- [ ] 统一 AI 输出渲染协议
- [ ] 统一流式 token / tool event / client action 回传协议
- [ ] 将页面级 AI 面板统一为单一 bridge shell
- [ ] 将 AI 面板按需挂载为 island
- [ ] 去掉常驻全局 AI host 对主布局的影响
- [ ] 去掉面板自身承载重量级对象逻辑的习惯
### 10.3 完成判定
- [ ] AI 面板已不再承担第二套工具编排
- [ ] AI 面板关闭或未打开时,不影响页面切换主链
- [ ] AI 页面壳只剩桥接、上下文、渲染,不剩对象真执行逻辑
### 10.4 当前落地状态(2026-04-16
- [x] 文档页、导图页、OnlyOffice 三类 AI 面板都已收口为轻 host + 按需 runtime islandHermes / Rust bridge / client-tool-result 主链继续复用现有接缝。
- [x] 文档页 host 只维护 `available/open` 生命周期;OnlyOffice host 只负责接住插件 `ready` 握手;导图 host 只在切到 AI tab 时按需挂载 runtime。
- [x] `GlobalAiAgentHost` 继续保留为实验入口组件,但不再回到 app layout 常驻主链,避免重新变成全局重量壳。
---
## 11. Phase 6Mindmap 独立对象化与独立页面化
### 11.1 目标
把 Mindmap 从“BlockNote 的一类重自定义块”推进为“独立对象 + 独立页面 + 可嵌入轻预览”。
### 11.2 实施清单
- [ ] 定义 Mindmap 独立对象模型
- [ ] 定义 Mindmap 读写协议与操作协议
- [ ] 明确导图节点、边、布局、样式、视口状态的 Rust 持久化结构
- [ ] 明确导图页面独立于文档页的服务端壳
- [ ] 将独立导图页优先迁到 Rust Web 层
- [ ] 将文档内嵌导图降级为轻预览或轻交互卡片
- [ ] 把导图工具栏、侧栏、缩略图等拆成局部 island
- [ ] 去掉对 BlockNote editor context 的强依赖
- [ ] 去掉“文档内嵌导图”和“独立导图页”共用同一重前端壳的绑定方式
### 11.3 完成判定
- [ ] Mindmap 已可以在不依赖 BlockNote 主运行时的情况下独立打开
- [ ] 文档页不再因为导图组件而被迫挂载整套导图交互壳
- [ ] 导图对象已进入 Rust 主线,而不是继续主要依赖前端组件状态
### 11.4 当前落地状态(2026-04-16
- [x] 独立导图页已切到 `StandaloneMindmapView`,不再依赖 fake `editorStub` 或 BlockNote editor context。
- [x] 文档内嵌导图已降级为轻预览 / 轻交互入口,文档主链不再因为独立导图壳而被迫进入重运行态。
- [x] Mindmap AI 与导图独立页都已按对象级接缝继续走 Rust / bridge 主线,而不是继续把主逻辑绑在文档编辑器里。
---
## 12. Phase 7:文档编辑态与 `BlockNote` 孤岛化
### 12.1 目标
最后再处理真正难替代的 `BlockNote`,把它从“默认页面入口前提”改成“按需挂载的重编辑岛”。
### 12.2 实施清单
- [ ] 明确阅读态与编辑态的切换协议
- [ ] 明确进入编辑态时的最小初始化协议
- [ ]`BlockNote` 依赖的外围功能继续向外剥离
- [ ] 将评论、回链、历史、AI、页面选项等从编辑器默认初始化链上移走
- [ ] 将自定义 block 的读取协议改成可按需注入
- [ ] 将只读渲染与可编辑渲染彻底拆开
- [ ] 将文档打开路径改成“阅读态常驻,编辑态进入时挂编辑岛”
- [ ] 为编辑岛建立独立错误边界
- [ ] 为编辑岛建立独立性能采样
- [ ] 为编辑岛建立独立恢复机制
### 12.3 禁止事项
- [ ] 不允许在这一步之前就试图整体替换全部编辑器能力
- [ ] 不允许让阅读页重新回退为“先挂编辑器再展示内容”
- [ ] 不允许把新的外围面板重新绑回 `BlockNote` 初始化链
### 12.4 完成判定
- [ ] 绝大多数页面访问不需要等待 `BlockNote`
- [ ] 编辑器只在真正进入编辑态时才挂载
- [ ] `BlockNote` 已成为孤岛,而不是整个页面系统的基础前提
### 12.5 当前落地状态(2026-04-16
- [x] 阅读态与编辑态的切换协议已经落地:默认阅读、显式进入编辑、`openTableId` 强制编辑、退出编辑后保留短暂 grace period 再卸载编辑岛。
- [x] 评论、历史、回链、页面 AI、页面选项等外围能力都已从 `BlockNote` 默认初始化链外移,阅读态可以单独存在。
- [x] `DocumentReadView``BlockNoteEditor` 已形成两套不同初始化协议,`BlockNote` 现在是按需进入的重编辑 island,而不是整页入口前提。
---
## 13. Phase 8:旧前端壳下线与兼容清理
### 13.1 目标
在新结构稳定后,清理旧壳,避免双栈长期共存。
### 13.2 实施清单
- [ ] 盘点仍保留的 Next 页面壳与 API 壳
- [ ] 标记哪些属于长期兼容层
- [ ] 标记哪些属于可删除过渡层
- [ ] 删除已被 Rust Web 层替代的 route
- [ ] 删除已被 Rust islands 替代的全局客户端面板
- [ ] 删除失效的桥接 helper、旧 registry、旧 adapter
- [ ] 清理不再使用的布局状态容器
- [ ] 清理不再使用的动态导入链
- [ ] 更新运行文档与架构文档
- [ ] 更新开发约束,禁止回流到旧模式
### 13.3 完成判定
- [ ] 旧前端壳已不再是主路径
- [ ] 双栈只是短期兼容,而不是长期事实
- [ ] 维护成本已经从“双系统并行”回到“单主线演进”
### 13.4 当前收缩口径(2026-04-16
- [x] 已明确当前仍保留的 Next/React 页面壳:文档页、Sidebar、搜索、AI host 与 OnlyOffice 页面仍在兼容层内,但重运行态已被拆到按需 island。
- [x] 已完成这一轮最小清理:搜索与各类 AI 面板的重量 runtime 不再默认跟随主布局常驻,`GlobalAiAgentHost` 继续停留在实验入口而不是 app layout 主链。
- [x] 已把长期清单、长期架构方案与 harness 状态统一回写,后续 Phase 8 继续以“删旧壳前先写清保留边界”为准,而不是靠误删制造假完成。
---
## 14. 横向能力清单
这些事情不属于单一阶段,但必须贯穿全部阶段推进。
### 14.1 观测与性能
- [ ] 建立统一性能指标:首字节、首屏、交互可用、切页耗时、编辑器挂载耗时
- [ ] 建立统一错误指标:页面壳错误、island 错误、编辑器错误、桥接错误
- [ ] 建立统一 trace 关联:页面请求、Rust query、Rust command、Hermes tool、前端 island
- [ ] 建立按页面类型的性能对比面板
最低交付物:
- [x] 每个页面壳请求都必须生成 `request_id` / `trace_id`,并能串到 Rust query/command 与 Hermes tool。
- [x] 文档页、Sidebar、搜索、AI、Mindmap、编辑岛都要有统一的 performance mark 命名规则。
- [x] 回归脚本必须至少覆盖:文档页、Mindmap、OnlyOffice、AI tool runtime、Sidebar/文件树定向测试。
### 14.2 缓存与预取
- [ ] 建立阅读页缓存策略
- [ ] 建立树结构局部缓存策略
- [ ] 建立搜索结果缓存策略
- [ ] 建立文档邻近页面预取策略
- [ ] 建立失败回退与缓存失效策略
最低交付物:
- [x] 阅读页采用“meta + content”同一读链缓存键,不能再拆成首屏后二次正文请求作为默认主路径。
- [x] 树结构、搜索结果、邻近页面预取都必须显式声明失效来源,避免隐式常驻缓存。
- [x] 失败回退策略必须写明是回源、回旧壳还是退到只读页面。
### 14.3 安全与权限
- [ ] 统一页面壳权限校验
- [ ] 统一对象级读写鉴权
- [ ] 统一浏览器 island 的最小权限输入
- [ ] 统一 AI / Hermes 的工具权限边界
最低交付物:
- [x] 页面壳、对象查询、对象写入、AI tool 调用必须复用同一 workspace / actor / tenant 上下文。
- [x] browser island 只能收到最小权限输入,不能自己推导更高权限。
- [x] Hermes 与 mnote Rust 之间的 bridge 必须只暴露最小业务能力面,不复制前端编排逻辑。
### 14.4 开发规范
- [ ] 新功能默认先判断是否属于 server-first 页面
- [ ] 新交互默认先判断是否可以做成局部 island
- [ ] 新业务规则默认只进 Rust core
- [ ] 新页面默认不能直接复制旧重前端壳模式
最低交付物:
- [x] 提交新页面时必须回答四个问题:是否 server-first、是否 island、对象规则是否进 Rust、是否引入新的常驻壳。
- [x] 没有 trace / 缓存 / 权限口径的新页面或新 island,不允许直接并入长期主线。
---
## 15. 最终验收清单
只有下面这些问题都能回答“是”,这条长期路线才算真正跑通。
- [ ] 打开一个普通文档时,是否已经可以先稳定进入阅读态
- [ ] 切换页面时,是否已经不再默认触发重编辑器初始化
- [ ] Sidebar 是否已经不再是主布局里的超大客户端组件
- [ ] 搜索是否已经不再依赖全局大组件常驻
- [ ] AI 面板是否已经变成纯桥接 island
- [ ] Mindmap 是否已经能独立于 `BlockNote` 主运行时工作
- [ ] Rust Web 层是否已经能承接主 API、主页面壳、主流式链路
- [ ] Rust core 是否已经成为唯一业务真执行面
- [ ] `BlockNote` 是否已经被延后为最后处理的孤岛,而不是继续绑住整页架构
- [ ] 旧前端壳是否已经开始实质性退场,而不是继续成为默认主路径
当前可回答“是”的项(2026-04-16):
- [x] 打开一个普通文档时,已经可以先稳定进入阅读态。
- [x] 切换页面时,已经不再默认触发重编辑器初始化。
- [x] 搜索已经不再依赖全局大组件常驻。
- [x] AI 面板已经收口为纯桥接 island。
- [x] Mindmap 已能独立于 `BlockNote` 主运行时工作。
- [x] `BlockNote` 已被延后为最后处理的孤岛,而不是继续绑住整页架构。
---
## 16. 一句话执行顺序
如果后续需要不断回看,这条路线可以压缩成一句话:
> **先冻结旧壳扩张,再立 Rust Web 层;先迁阅读页、Sidebar、搜索、AI、Mindmap,最后才处理 `BlockNote`;稳定后再清旧壳,而不是反过来。**