555 lines
28 KiB
Markdown
555 lines
28 KiB
Markdown
# 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 1:Rust Web 基础层落地
|
|||
|
|
- Phase 2:文档阅读页 server-first 化
|
|||
|
|
- Phase 3:Sidebar / 页面树 / 文件树 Rust 化与 island 化
|
|||
|
|
- Phase 4:搜索系统 Rust 化与 island 化
|
|||
|
|
- Phase 5:AI 面板进一步收口为纯桥接 island
|
|||
|
|
- Phase 6:Mindmap 独立对象化与独立页面化
|
|||
|
|
- 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 1:Rust 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 3:Sidebar / 页面树 / 文件树 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 5:AI 面板进一步收口为纯桥接 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 island,Hermes / Rust bridge / client-tool-result 主链继续复用现有接缝。
|
|||
|
|
- [x] 文档页 host 只维护 `available/open` 生命周期;OnlyOffice host 只负责接住插件 `ready` 握手;导图 host 只在切到 AI tab 时按需挂载 runtime。
|
|||
|
|
- [x] `GlobalAiAgentHost` 继续保留为实验入口组件,但不再回到 app layout 常驻主链,避免重新变成全局重量壳。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. Phase 6:Mindmap 独立对象化与独立页面化
|
|||
|
|
|
|||
|
|
### 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`;稳定后再清旧壳,而不是反过来。**
|