Files
mnote/design/04-tree-domain/done/4-sidebar-pagetree-filetree-rust-web-rebuild-v1.md
T
lix-2026 5f97800489 chore: align local-first control plane and editor fixes
- wire SQLite control-plane access/session paths into Rust web local-folder routes

- preserve local Markdown attachment semantics across upload, reload, and secondary-pane resource tabs

- refresh design governance docs, Reasonix task templates, and bug records

- retire root .mcp.json local MCP config
2026-05-23 23:38:42 +08:00

945 lines
24 KiB
Markdown
Raw 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.
# 4 [done] Sidebar / 页面树 / 文件树 Rust Web 重构方案 v1
> 更新时间:2026-04-22
>
> 当前优先级入口:
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
>
> 关联文档:
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-1-tree-first-graph-kernel-checklist-v2.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/done/3-2-tree-first-graph-kernel-phase3-task-breakdown-v1.md`
> - `/mnt/Data1T/mnote/design/90-reference/90-2-yemianshu.md`
> - `/mnt/Data1T/mnote/design/90-reference/90-1-filetree.md`
> - `/mnt/Data1T/mnote/design/old/04-tree-domain/process/4-1-sidebar-pagetree-filetree-product-gap-analysis-v1.md`
## 1. 文档目的
这份文档回答的问题不是:
- “当前 Sidebar 再怎么局部优化一下”
而是:
> **在 `tree-first graph kernel` 前提下,是否应该把 Sidebar / 页面树 / 文件树直接重构为一个独立的 Rust Web 子系统。**
本文的结论是:
> **可以,而且长期上这是正确方向;但重构对象不是“一个更快的树组件”,而是“一个直接消费 kernel projection 的独立树域执行面”。**
也就是说,目标不是把当前 React 树组件换个语言重写,而是:
- 用 Rust 主导 tree projection
- 用 Rust Web 主导 tree query / command
- 让页面树 / 文件树只作为 kernel 的树投影
- 再决定 UI 壳是否也迁到 Rust 家族
---
## 2. 必须遵守的前提:树不是 UI 数据,而是 kernel 投影
这份方案必须完全服从:
- [tree-first-graph-kernel-v1.md](/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-tree-first-graph-kernel-v1.md)
里面已经固定的几条原则。
### 2.1 树是主骨架
当前长期架构已经冻结为:
- 树是主骨架
- 图是横向扩展
- Sidebar / 页面树 / 文件树 / 阅读流 / Mindmap 都只是 projection
所以这里的页面树 / 文件树不能再被定义为:
- 前端自己拼出来的导航数据
它们必须被定义为:
- `tree-first graph kernel` 的树投影
### 2.2 页面树和文件树不是两套真相
在新架构里:
- 页面树不是独立系统
- 文件树也不是独立系统
两者都来自同一个 kernel,只是投影范围不同:
- `page_tree`
-`page` / `section` / 页面层级为主
- `file_tree`
- 在页面层级基础上,把 `asset` / `mindmap` / `table` / 未来 `book` / `pdf` 一起投影出来
### 2.3 Sidebar 是壳,不是事实源
Sidebar 长期不应再被理解为:
- “一个左侧导航 React 组件”
而应理解为:
- “tree projection 的承载壳”
固定边界应是:
- kernel 持有真相
- projection 输出树
- Sidebar 只负责显示和交互
---
## 3. 当前现状
### 3.1 已经做对的部分
当前代码已经有一些方向是正确的:
- `kernelSidebarProjection`
- `kernelSidebarTree`
- `Sidebar` 主树开始以 `kernelSidebarTree` 为来源
- Rust runtime 和 `mnote-web` 已开始承接 Sidebar 相关 projection 主链
对应代码包括:
- [kernel-sidebar.ts](/mnt/Data1T/mnote/wolai-frontend/src/lib/kernel-sidebar.ts)
- [sidebar-data.ts](/mnt/Data1T/mnote/wolai-frontend/src/lib/sidebar-data.ts)
- [sidebar.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx)
- [kernel.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/kernel.rs)
### 3.2 还没做完的部分
当前真正的问题是:
- 主 Sidebar 仍是超大客户端组件
- 文件树仍然主要在前端继续加工 row model
- `move-embed picker` 等兼容域仍保留旧 `buildDocumentTree(...)`
- 页面树和文件树还没有彻底统一为稳定的 kernel projection family
这说明:
> **现在的瓶颈不只是“UI 重”,而是“树域仍然没有形成独立、稳定、可替换的执行边界”。**
---
## 4. 对参考资料的判断
### 4.1 `/design/cankao/yemianshu.md` 和 `/design/cankao/filetree.md` 能参考什么
这两份参考有价值,但要分层使用。
适合借鉴的部分:
- 树形系统的分层
- VS Code / Notion 风格交互
- 折叠、展开、拖拽、懒加载、多选、右键菜单
不适合直接拿来落当前 Web 主线的部分:
- Ratatui / Cursive / TUI 组件
- egui / iced / Fyrox / GPUI 这类桌面 GUI 组件
原因很简单:
- 这些更适合终端或原生桌面
- 当前 mnote 的主线是 Web + Rust Web + kernel projection
所以它们更适合做:
- 交互语义参考
而不适合做:
- 当前 Web 主线的直接实现模板
### 4.2 更适合作为直接参考的方向
如果这次真要把 Sidebar / 页面树 / 文件树往 Rust 家族重构,应该看两类参考:
#### A. Rust Web 前端框架
优先关注:
- `Leptos`
- `Dioxus`
- `Yew`
本文的建议顺序是:
1. `Leptos`
2. `Dioxus`
3. `Yew`
原因不是抽象喜好,而是贴合度:
- 你们已经在走 Rust kernel + Rust Web + server-first
- 这时最有价值的是“Rust Web 组件 + server integration + 渐进切流”
- 不是终端树,也不是桌面树
#### B. 成熟 Web Tree 的行为模型
即使最终决定用 Rust 家族重写,交互模型也应该优先参考成熟 Web Tree 的做法:
- headless tree 思路
- VS Code Explorer 的 row model
- 大树虚拟化
- DnD 状态机
- selection / focus / keyboard 模型
这里学的是:
- 行为模型
不是:
- 必须沿用 React
---
## 5. 结论:可以直接重构,但应定义成独立大任务
我的明确结论是:
> **可以直接把 Sidebar / 页面树 / 文件树作为独立大任务重构,而且长期上应该这样做。**
但这个重构不能被理解为:
-`sidebar.tsx` 翻译成 Rust
而应被理解为:
- 把树域从旧前端壳里剥离出来
- 形成一个独立的 Rust Web tree shell
也就是:
- 独立 route / shell
- 独立 projection protocol
- 独立 command protocol
- 独立 UI state 边界
这个任务应该单独成立,而不是继续藏在 `Kernel Phase 4` 的一句话里。
---
## 6. 目标架构
## 6.1 新的树域分层
长期建议把树域拆成五层:
### 1. Kernel Truth
只承载:
- `node`
- `edge`
- `subtree`
- `audit`
### 2. Tree Projection Layer
专门输出:
- `sidebar_tree`
- `page_tree`
- `file_tree`
固定输出应包括:
- `projection_id`
- `root_node_id`
- `items`
- `edges`
- `sort key`
- `expand hint`
- `capability flags`
### 3. Tree Command Layer
只处理树域命令:
- create page
- move subtree
- attach asset
- reorder sibling
- archive / restore
- open node
### 4. Tree Shell
树域的独立承载壳,只负责:
- 拉 projection
- 发 command
- 维护局部 UI 状态
### 5. Tree Renderer
最终的可视组件,只负责:
- row 渲染
- 虚拟化
- 选中
- 展开
- 右键菜单
- DnD feedback
---
## 6.2 页面树和文件树的正确关系
在新架构里,这两者不该是并列的两套不同系统,而应是:
### 页面树
只关心:
- `workspace`
- `folder`
- `page`
- `section`
### 文件树
在页面树骨架上再纳入:
- `asset`
- `mindmap`
- `table`
- `book`
- `pdf`
- 未来的 `index_node`
也就是说:
> **文件树不是“另建一棵树”,而是“同一棵树的更宽对象投影”。**
这非常符合 `tree-first graph kernel` 的定义。
---
## 7. 为什么建议用 Rust Web 子系统,而不是继续堆在当前 Sidebar 里
### 7.1 当前 Sidebar 太大
现在的 Sidebar 不只是树:
- 搜索入口
- 成员
- 分享
- 回收站
- 资源操作
- 页面树
- 文件树
- 各种本地对话框
这会导致:
- 状态膨胀
- 切页参与重渲染
- 树逻辑和业务逻辑缠在一起
### 7.2 树域已经足够大,可以独立成系统
页面树 / 文件树本身已经有:
- 自己的数据协议
- 自己的 row model
- 自己的拖拽系统
- 自己的选择模型
- 自己的上下文菜单
- 自己的资源挂载逻辑
这已经不是一个小组件,而是一个完整子系统。
### 7.3 独立之后更符合后续迁移
如果现在就把它切成独立树域子系统,后续:
- Mindmap
- 阅读页结构树
- 搜索结构结果
- Book / PDF 子树
都可以复用同一套 projection / renderer 协议。
---
## 8. 技术路线选择
## 8.1 方案对比
### 方案 A:继续 React,只换数据层
优点:
- 风险最低
- 最快收口旧 helper
缺点:
- 树域仍留在旧前端壳内
- 不能完成“Rust 主执行面”这一步
### 方案 B:独立 Rust Web tree shell,当前主站只挂载它
优点:
- 可以保留整体产品双栈过渡
- 树域先行 Rust 化
-`tree-first graph kernel` 最一致
缺点:
- 需要额外处理嵌入、路由、样式、事件桥接
### 方案 C:直接整站前端重写
优点:
- 理论上最终最纯
缺点:
- 范围失控
- 风险过高
- 与当前阶段目标不匹配
## 8.2 当前建议
本文明确建议:
> **选方案 B:把 Sidebar / 页面树 / 文件树做成独立 Rust Web tree shell。**
---
## 8.3 Rust Web 框架建议
当前优先建议:
### 第一选择:Leptos
原因:
- 更贴近 Rust 全栈 / server-first
- 更适合和 `axum` / `mnote-web` 的方向合并
- 适合做“树域先行”的渐进式替换
### 第二选择:Dioxus
原因:
- 跨 Web / Desktop 能力强
- 如果未来想把树域同时复用到桌面壳,会有价值
### 第三选择:Yew
原因:
- 能做,但相对不如前两者贴合当前迁移方向
所以这份方案的推荐结论是:
> **树域独立重构时,优先按 `mnote-web + Leptos` 设计。**
---
## 8.4 GitHub 参考池
这里不再按“有没有现成 Rust Notion 成品”来选参考,而是按三个层级来选:
- Rust Web 承载框架
- 树域 UI primitives
- 树行为模型与产品结构参考
### A. 直接可参考:Rust Web 主路线
#### `leptos-rs/leptos`
GitHub
- https://github.com/leptos-rs/leptos
适合借鉴:
- `Rust + SSR + islands` 的 Web 承载方式
-`axum` 风格服务端组合
- 渐进式切流,而不是一次性整站替换
为什么适合当前方案:
- 当前 `mnote-web` 已经是 Rust Web 接入点
- 树域后续如果独立成 shell,最需要的是“Rust Web 承载能力”,不是单独一个树控件
结论:
- **这是树域 Rust Web 重构的第一参考。**
#### `DioxusLabs/dioxus`
GitHub
- https://github.com/DioxusLabs/dioxus
适合借鉴:
- Rust 组件化 UI
- Web / Desktop 共享思路
限制:
- 更偏多端壳能力
- 与当前 `mnote-web + axum` 路线的贴合度仍低于 `Leptos`
结论:
- **可作为备选路线参考,但不是当前首选。**
#### `yewstack/yew`
GitHub
- https://github.com/yewstack/yew
适合借鉴:
- Rust Web 组件化基本能力
限制:
- 能做,但对你们当前 server-first 与渐进切流路线支持感不如 `Leptos`
结论:
- **保留为第三选择,不作为当前主实现模板。**
### B. 直接可参考:树域 UI primitives / 组件层
#### `cloud-shuttle/radix-leptos`
GitHub
- https://github.com/cloud-shuttle/radix-leptos
适合借鉴:
- `Leptos` 生态下的 UI primitives 组合方式
- `collapsible``scroll area``menu``overlay`、可访问性细节
- 树域壳层需要的基础交互组件
限制:
- 它不是完整树组件
- 不能直接替代页面树 / 文件树的 row model 与状态机
结论:
- **适合作为树域 shell 的基础件参考。**
#### `thaw-ui/thaw`
GitHub
- https://github.com/thaw-ui/thaw
适合借鉴:
- `Leptos` 组件组织方式
- 通用面板、按钮、菜单等基础 UI
限制:
- 更像通用组件库
- 对树域协议、树行为模型帮助有限
结论:
- **适合作为辅助 UI 库参考,不是树域核心参考。**
#### `KoVal177/leptos-column-browser`
GitHub
- https://github.com/KoVal177/leptos-column-browser
适合借鉴:
- Rust Web 下的层级导航
- 异步懒加载子节点
- 多层树浏览器的交互拆分
限制:
- 项目较新、体量小
- 更接近 column browser,不是当前 Sidebar 单栏树的完整模板
结论:
- **适合借鉴 provider / async loading / column navigation 思路,不适合直接照搬。**
### C. 高价值参考:树行为模型与产品结构
#### `lukasbach/headless-tree`
GitHub
- https://github.com/lukasbach/headless-tree
适合借鉴:
- row model
- selection / focus / keyboard 模型
- DnD 状态机
- 虚拟化树行为拆分
为什么值得看:
- 你们后续真正难的不是“画一棵树”,而是把树行为从具体 UI 框架中抽出来
- 这正对应 `tree-first graph kernel -> projection -> shell -> renderer` 的分层思想
限制:
- 不是 Rust
- 不能直接进入实现层
结论:
- **非常适合作为树行为模型参考。**
#### `AppFlowy-IO/AppFlowy`
GitHub
- https://github.com/AppFlowy-IO/AppFlowy
适合借鉴:
- “工作区 / 页面树 / 文档”这类产品结构
- Rust 统一管理部分内核能力的思路
- Notion 类产品如何收敛页面树语义
限制:
- 主前端不是你们要走的 `Leptos Web` 路线
- 不能作为当前树域 Web 重构的直接模板
结论:
- **适合作为产品结构与边界参考,不适合作为实现模板。**
#### `toeverything/AFFiNE`
GitHub
- https://github.com/toeverything/AFFiNE
适合借鉴:
- Notion / knowledge base 类产品的页面树体验
- 页面、知识库、画布等多视图并存时的交互组织
限制:
- 技术栈不是 Rust
- 更适合借鉴交互与产品层结构
结论:
- **适合作为页面树 / 知识库产品交互参考。**
## 8.5 外部参考的使用原则
为了避免“看了很多仓库,但最后没有真正推进”,这里固定使用原则:
- `Leptos` 用来确定树域 Rust Web shell 的主承载路线
- `radix-leptos` / `thaw` 用来补树域壳层 primitives
- `headless-tree` 用来借 row model、selection、keyboard、DnD 的行为模型
- `AppFlowy` / `AFFiNE` 用来参考产品层交互与树域边界
- 不引入终端树、桌面树、TUI/GUI 框架作为当前 Web 主线实现模板
也就是说,后续不是“找一个仓库直接替换 Sidebar”,而是:
> **把外部参考拆成承载层、基础件层、行为模型层、产品结构层,分别吸收。**
---
## 9. 重构范围
## 9.1 本次应纳入的范围
- Sidebar 主树域
- 页面树
- 文件树
- move / embed picker 的树域部分
- 树域 command
- 树域 projection route
## 9.2 本次不纳入的范围
- 搜索主面板
- AI 主面板
- Mindmap 主画布
- `BlockNote` 编辑器
- 旧前端壳整体删除
原因:
- 这些属于后续 phase
- 本次只做树域切换,保持边界清晰
---
## 10. 新协议定义建议
## 10.1 Tree Projection Protocol
建议统一成一套 tree row 协议,而不是 page tree、file tree 各自手写结构。
最小字段建议:
- `row_id`
- `node_id`
- `parent_node_id`
- `node_type`
- `projection_kind`
- `depth`
- `position`
- `title`
- `icon_hint`
- `expandable`
- `expanded_by_default`
- `capabilities`
- `resource_meta`
其中:
- 页面树主要消费 `page/folder/section`
- 文件树再多消费 `asset/mindmap/table/book/pdf`
### 10.2 Tree Command Protocol
建议统一成:
- `tree.node.create`
- `tree.subtree.move`
- `tree.node.rename`
- `tree.node.archive`
- `tree.node.restore`
- `tree.asset.attach`
- `tree.asset.detach`
这些 command 最终应映射到 kernel command,而不是直接绑在前端 UI 行为上。
---
## 11. 分阶段实施建议
下面这组 phase 不再按“最初方案假设”维护,而按 **2026-04-18 当前仓库代码状态** 重写。
这意味着:
- 已经落地的部分要明确勾掉
- 还没真正开始的部分不能因为存在实验壳就误写成已完成
- 如果长期目标已经固定为“主执行面最终也迁到 Rust 家族”,那么当前主线应直接推进 `Phase C + Phase D`
## 11.1 Tree Shell Phase A:协议冻结
这一阶段的目标不是开始写 UI,而是把树域协议冻结到后续不会反复返工。
**当前状态:`COMPLETED(协议、共享类型、状态边界与 contract tests 已完成封板)`**
### 完成 checklist
- [x]`page_tree` 的现有字段提升为当前协议基线:
- `row_id`
- `node_id`
- `parent_node_id`
- `node_type`
- `projection_kind`
- `depth`
- `position`
- `title`
- `capabilities`
- `resource_meta`
- [x] 树域主路径已统一到 `kernelSidebarTree -> page_tree projection -> visible rows` 这一协议家族
- [x]`sidebar_tree``page_tree``file_tree` 的共用字段与差异字段正式写成共享类型/文档,不再只散落在前端映射代码里
- [x] 定义并冻结 `file_tree` 扩展字段:
- `resource_kind`
- `asset_kind`
- `icon_hint`
- `expandable`
- `expanded_by_default`
- [x] 第一批树域命令已经收口到共享 command client
- `documents.create`
- `documents.title.update`
- `documents.move`
- `documents.delete`
- `documents.restore`
- `documents.purge`
- `documents.embed`
- `documents.copy_tree`
- [x] 冻结树域 command protocol 的长期命名面,并补齐 `documents.* -> tree.*` 的兼容映射说明
- [x] 明确哪些状态属于 projection,哪些状态只能留在 UI 本地,并形成 Rust/前端共识文档:
- `expanded`
- `selected`
- `hover`
- `focus`
- `dragging`
- `drop target`
- [x] 已有 projection / rows / sidebar-data / tree-stream 基础测试,避免主路径再次回到本地 synthetic projection
- [x] 给协议补一组更明确的 fixture / contract tests,覆盖 `sidebar_tree / page_tree / file_tree / command protocol`
## 11.2 Tree Shell Phase BRust route 与 projection 输出
这一阶段的目标是让 `mnote-web` 成为树域 projection 与 command 的正式出口,而不是继续让前端自己拼树。
**当前状态:`COMPLETEDRust route、projection mapper、契约测试与兼容边界已进入正式主线)`**
### 完成 checklist
- [x] `mnote-web` 已具备树域相关 route
- `kernel projection route`
- `kernel subtree route`
- `tree command route`
- `tree shell route`
- [x] `page_tree` 已经是当前页面树 / 文件树 / picker 的共同协议骨架
- [x] `/api/tree/commands` 已能承接第一批树域命令并映射到 Rust/Convex bridge 主链
- [x] route 已带 request/trace 上下文与基础测试,不再只是占位骨架
- [x] 把树域读取出口补成更明确的正式 projection route 族:
- `sidebar_tree`
- `page_tree`
- `file_tree`
- [x]`file_tree` 从“前端 adapter 拼装”继续下沉为 Rust 侧直接输出的 projection
- [x] 在 Rust 侧补齐 `asset` / `mindmap` / `table` / `book` / `pdf` 的 projection 映射层
- [x] 明确树域 command route 的长期协议面,避免一直停留在 `documents.*` 兼容命名
- [x] 把鉴权、错误码、兼容 fallback、trace、workspace 解析补成完整 route 契约
- [x]`sidebar_tree / page_tree / file_tree / commands` 补齐 route tests、fixture tests、兼容入口 tests
- [x] 让 Next 侧进一步只保留 transport / compat,不再残留结构真相拼装逻辑
## 11.3 Tree Shell Phase C:正式树域壳
这一阶段的目标是把树域从旧 Sidebar 中剥离为独立、可验证、可持续替换的正式执行面。
**当前状态:`COMPLETEDLeptos scaffold、Rust tree_shell 模块、统一 surface 与 iframe 主路径下线已完成)`**
### 完成 checklist
- [x] 已经证明“树域可以从旧 `sidebar.tsx` 中剥离成独立 Rust Web 壳”,而不是只能留在 React 组件里
- [x]`Leptos` 搭建最小正式 tree shell
- tree loader
- command dispatcher
- local UI state store
- [x] 接入可验证的最小 renderer 主干与稳定 `data-testid`
- [x] 接入展开 / 折叠状态
- [x] 接入选中 / focus / keyboard 导航
- [x] 接入 DnD 状态机
- [x] 接入右键菜单与基础上下文动作
- [x] 支持 `page_tree``file_tree` 两种渲染模式共用同一 renderer/surface 家族
- [x] 支持 picker 场景复用同一 tree shell 的轻量模式
- [x] 保持正式 UI 壳不持有结构真相,只持有局部交互状态
- [x] 去掉主路径对 `iframe + postMessage` 的依赖,把它降回纯兼容/调试用途
## 11.4 Tree Shell Phase DNext 中挂载并切流
这一阶段的目标是把新树域壳真正挂到当前产品里,而不是停留在独立 demo。
**当前状态:`COMPLETEDSidebar / filetree / picker 默认切流、快速回退与网页 smoke 已完成)`**
### 完成 checklist
- [x] 在当前主站中预留 tree shell 挂载位
- [x] 用 feature flag 控制新旧树域切换
- [x] 已经为 Sidebar / 文件树 / picker 提供实验壳挂载接缝
- [x] 保留快速回退到旧树域实现的开关
- [x] 已验证“3104 不可用时主站仍可进入页面”,避免实验壳阻塞首屏
- [x] 让 Sidebar 主树默认进入正式新 shell
- [x] 再让页面树 / 文件树默认进入正式新 shell
- [x] 再让 move/embed picker 切到正式新 shell 的轻量模式
- [x] 补齐切页、展开、拖拽、右键菜单、搜索跳转等高频路径的正式切流回归
- [x] 记录真实用户流量下的性能指标:
- 首包
- 首次可交互
- 切页延迟
- 大树展开延迟
## 11.5 Tree Shell Phase E:收敛旧 helper
这一阶段的目标是收掉旧树域真相层残留,避免双轨长期并存。
**当前状态:`COMPLETED(主路径统一到同一套 surface/adapter 家族,旧实验壳退出主路径)`**
### 完成 checklist
- [x] 删除 `buildDocumentTree(...)` 在树域中的最后运行时入口
- [x] 主路径 consumer 已统一改读 projection protocol,而不是旧对象数组拼树
- [x] 清理了只服务于旧树域主路径的一批测试、fixture、兼容代码
- [x] 删除剩余的 page tree / file tree 主路径特殊拼装逻辑
- [x] 清理旧 Sidebar 超大组件中的树域状态与 helper,把非树逻辑和树逻辑继续拆开
- [x] 把 picker / 文件树 / 页面树统一到同一套 renderer 或 row adapter 家族
- [x] 在正式新壳稳定后,下线 `iframe + postMessage` 的实验树壳主路径职责
- [x] 更新架构文档、checklist、harness 状态
### 长期优化建议
- 继续把 `Leptos` scaffold 深化为更完整的 Rust-first renderer,但这不再阻塞当前 Sidebar / page tree / filetree 重建完成判定。
- 持续采集生产环境下的树规模、切页延迟与 fallback 触发频率,把本轮开发机 smoke 指标升级为长期趋势指标。
- 对 move/embed picker 的搜索结果路径补异步索引可见性指标,但这属于搜索链路优化,不再作为当前树域切流 gate。
---
## 12. 验收标准
只有同时满足下面几条,才建议把这次树域 Rust Web 重构视为成立:
- 页面树与文件树都直接消费 kernel projection
- Sidebar 不再自己定义树结构真相
- 树域已有独立 Rust Web shell
- 至少一条真实用户流量默认进入新 tree shell
-`buildDocumentTree(...)` 不再处于主路径
- move/embed picker 等兼容树域也已切到统一 projection
---
## 13. 风险与约束
### 风险 1
如果在 projection 协议未冻结前就开始重写 UI,容易重写两遍。
### 风险 2
如果把搜索、AI、Mindmap 一起塞进树域重构,范围会立即失控。
### 风险 3
如果只重写 UI,不改 projection / command / shell 分层,最终只是“换皮”,不是根治。
---
## 14. 最终结论
这次页面树 / 文件树的长期正确方向,不是:
- 再修补当前 `sidebar.tsx`
- 或者简单找一个 Rust 树控件来替换
而是:
> **在 `tree-first graph kernel` 前提下,把树域独立成一个 Rust Web 子系统。**
这个子系统应当满足:
- 树是 kernel projection
- Sidebar 只是树域壳
- 页面树和文件树来自同一 truth,不再是两套系统
- Rust 主导 query / command / projection
- UI 壳可以逐步迁到 `Leptos` 一类 Rust Web 前端框架
所以,这次不是“参考某个树组件”,而是:
> **参考成熟树域行为模型,结合 `tree-first graph kernel`,把 Sidebar / 页面树 / 文件树整体提升为独立的 Rust Web tree shell。**