Files
mnote/design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md
T
Agent Board b798f628ee chore: land tree view-state, vault, Pi module split, and repo hygiene
Persist PageTree expand state via control-plane view-state and align
chevron/DOM with restored expansion; keep Sidex-style shallow page-tree
scan and drop the unused recursive scanner that only added cargo noise.

Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi
into a module package, and retire Hermes/ACP/OpenHub recycle + root
harness evidence from the index while gitignoring recycle and local
diag dumps.

Archive superseded design/bugs docs under old/, point architecture at
ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor
regressions so the working tree can stay clean.
2026-07-21 05:13:05 +08:00

599 lines
18 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.
# 3 [reference] Rust Web 长期架构方案 v1
> 更新时间:2026-05-09
>
> 当前状态:`reference`。本文保留 Rust Web 长期架构边界;当前实现队列以 `design/10-review/process/21-mvp-post-architecture-closure-checklist-v1.md` 和对应 `done/` 证据为准。
>
> 相关文档:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-kernel-cutover-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/process/ai-frontend-simplification-plan-v1.md`
## 1. 文档目的
本文回答的是长期架构问题,而不是短期优化问题:
> **当 mnote 要继续沿着 Rust 主导路线演进时,Web 层到底应不应该一起 Rust 化;如果要 Rust 化,应该如何分层,而不是只说一句“改成 Rust”。**
本文重点不是:
- 再做几处懒加载
- 再精简几个前端面板
- 再给现有 Next 页面补一些缓存
本文重点是:
- Rust 内核和 Web 承载层如何分工
- 前端哪些部分应该退出当前重 React 壳
- `axum``Leptos` 这类 Rust Web 方案是否值得采用
- 页面 AI 应如何作为 Hermes 页面内客户端接入,并让 mnote 通过 Hermes skill/plugin 暴露业务能力
- 默认主编辑器已经切到页面内 `leptos-tiptap` island 后,剩余重编辑兼容链应如何继续收口
---
## 2. 先给结论
结论分三句:
### 2.1 不能只说“用 Rust”
如果只说“以后 Web 也改成 Rust”,但不明确:
- 谁负责 HTTP / SSE / WebSocket / 路由
- 谁负责 SSR 页面壳
- 谁负责 islands / hydration 模型
- 谁负责保留必须存在的浏览器重交互模块
那么最后大概率只是:
- Rust 内核继续存在
- 旧前端继续承担页面运行时主负担
这不叫根治。
### 2.2 长期推荐方案不是“只上 `axum`”,而是分层方案
长期推荐采用:
- **业务执行面:现有 Rust workspace 继续作为唯一业务真执行面**
- **Web 承载层:`axum`**
- **页面渲染模型:`Leptos Islands`**
- **AI 会话与编排面:Hermes**
- **mnote AI 能力面:Hermes skill/plugin -> Rust runtime / kernel**
- **最后保留的重编辑兼容孤岛:少量编辑器 runtime(当前默认主编辑器已是页面内 `leptos-tiptap` island`BlockNote` 仅保留为 `recycle/` 历史参考副本)**
一句话概括:
> **mnote 的长期正确方向不是“Next 外壳上继续打补丁”,也不是“只把 API 改成 Rust”,而是“Rust 内核 + Rust Web 壳 + server-first 页面 + 少量交互孤岛”。**
### 2.3 重编辑兼容链不是第一刀,而是最后一刀
当前真正难替代的主要是:
- 以旧 `BlockNote` 编辑器副本、转换链和剩余兼容保存链为代表的重编辑 runtime
而下面这些能力,从长期看都可以先退出当前大前端壳:
- Sidebar / 页面树 / 文件树
- 搜索面板
- Mindmap
- AI 面板
- 评论 / 回链 / 历史 / 页面选项
- 大部分页面级壳与详情面板
所以长期路线应当是:
> **先把能 Rust 化、能 server-first 化、能 island 化的东西全部迁走,最后再处理重编辑兼容链。**
---
## 3. 为什么当前问题不能靠“只做 Rust 内核”解决
结合当前仓库状态,可以确认一个关键事实:
- `/mnt/Data1T/mnote/rust/` 已经是业务协议、桥接、CLI、Convex bridge 的 Rust workspace
- 但它现在还不是 Web 页面承载层
- 它没有直接接管文档页、页面树、搜索壳、阅读页 SSR、浏览器交互分层
这意味着当前 Rust 已经影响了:
- 业务命令面
- 查询面
- AI tools / bridge 的真执行面
- CLI 化能力
但它**还没有从根上决定“网页怎么加载”**。
所以之前用户体感到的页面切换卡顿,本质仍然主要来自:
- 页面运行模型
- 客户端挂载链
- 重编辑器与周边面板的初始化方式
而不是“后端是不是 Rust”这一件事本身。
换句话说:
> **Rust 内核已经在替换业务执行平面,但网页访问性能要根治,还必须补上 Rust Web 层与页面运行模型重构。**
---
## 4. 为什么长期要引入 Rust Web 层,而不是停在现状
如果继续维持现在的分工:
- Rust 只负责业务执行
- Next/React 继续负责几乎全部页面壳和交互壳
那么会长期存在三个问题。
### 4.1 页面访问链仍然受制于重前端应用模型
即使业务调用已经走 Rust,页面还是会在浏览器里经历:
- 布局挂载
- 客户端组件挂载
- 动态导入
- 面板初始化
- 编辑器初始化
这类成本不会因为底层业务改成 Rust 自动消失。
### 4.2 Web 层仍然会保留第二套复杂运行语义
如果页面系统继续主要靠当前大前端维护,那么:
- 页面壳逻辑
- 面板装配逻辑
- 浏览器状态拼装逻辑
- 部分对象读取与表现层规则
仍会长期留在现有前端系统里。
这会让“Rust 已成为唯一主线”变成一句不完整的话。
### 4.3 很难把页面访问做成真正的 server-first
用户真正想要的是:
- 页面先出来
- 阅读先可用
- 交互只在局部发生
如果继续沿用大范围客户端 hydration 的页面模型,这个目标很难彻底实现。
---
## 5. `axum` 在这个体系里的正确位置
根据 `axum` 官方文档,它非常适合承担:
- Router
- Handler
- Middleware
- JSON / Form / Query 提取
- WebSocket
- SSE
- 基于 `tokio` 的服务承载
这使它非常适合 mnote 长期担任:
- 主 API 层
- 文档查询与聚合层
- 树结构装配层
- 搜索服务层
- Hermes client proxy 与 mnote tool bridge 层;页面 AI 会话真相归 Hermes,mnote 业务工具最终回到 Rust runtime / kernel
- 页面 SSR 外壳承载层
- 流式更新、通知、事件推送层
但也必须明确一件事:
> **`axum` 是优秀的 Rust Web 服务框架,但它不是页面交互模型本身。**
也就是说,`axum` 可以很好地承接:
- HTTP
- API
- 页面响应
- 流式接口
但它并不会直接回答:
- 哪些页面内容不该 hydrate
- 哪些交互应该变成 island
- `BlockNote` 之外还有多少东西需要进浏览器
所以:
> **长期方案不能只有 `axum`,还必须有“页面如何 server-first 输出、如何只给少量模块 hydration”的明确答案。**
---
## 6. 为什么推荐 `Leptos Islands`
根据 Leptos 官方 Islands 文档,它最重要的特征是:
- 默认可以让大量内容保持服务端输出
- 只有显式声明为 island 的部分进入客户端 hydration
- 父级服务端组件可以保留纯服务端逻辑
- 页面可以由少量交互岛包住,而不是整页一起变成大前端应用
这和 mnote 现在想解决的问题高度匹配。
因为 mnote 现在最需要的不是“再换一个前端框架”,而是:
- 把页面阅读恢复成轻页面
- 把交互缩到真正必要的模块
- 把大块浏览器运行时代码压缩成少量孤岛
Leptos Islands 很适合承接下面这类长期目标:
- 页面树 / 文件树作为轻交互 island
- 搜索输入与结果面板作为轻交互 island
- AI 面板作为独立 island
- 文档工具栏作为轻交互 island
- `BlockNote` 作为最后的重交互 island
- 其余阅读内容保持服务端输出
所以它的价值不是“因为它是 Rust 前端”,而是:
> **它天然支持 server-first + 少量 islands 的页面运行模型,这正是 mnote 当前最缺的东西。**
---
## 7. 为什么不建议只说“就 Rust”,也不建议直接押注别的 Rust 前端路线
### 7.1 不建议只说“就 Rust”
因为这句话缺少架构含义。
如果没有 Web 承载层和页面模型的明确选型,最后通常只会得到:
- Rust 业务内核
- 旧网页壳继续不变
这解决不了根因。
### 7.2 不建议把 `axum` 单独当成完整答案
`axum` 很强,但它解决的是:
- 服务承载
- HTTP / 流式能力
- 路由与 middleware
它不直接解决:
- islands
- 页面 hydration 边界
- 大前端退场策略
所以单独采用 `axum`,只够完成“Rust BFF / Rust API 化”,不够完成“页面运行模型重构”。
### 7.3 不把 Dioxus / Yew 作为当前主推荐
不是说它们不能用,而是它们不是当前最贴合目标的第一选择。
原因很简单:
- mnote 当前最核心的问题不是“缺一个 Rust UI 框架”
- 而是“如何让绝大多数页面不再变成整页重 hydration 应用”
从这个目标出发,`Leptos Islands` 比较直接地支持:
- server-first 页面
- 局部 hydration
- 少量交互孤岛
因此当前更适合作为第一推荐。
---
## 8. mnote 长期推荐分层
## 8.1 总体结构
长期推荐结构如下:
1. **Rust Core**
- `core-domain`
- `core-protocol`
- `bridge-runtime`
- `storage-convex-bridge`
- `index-fts`
2. **Rust Web**
- `axum` 作为主 HTTP / SSE / WS / API / SSR 承载
3. **Rust View Shell**
- `Leptos Islands` 作为页面壳、阅读态、轻交互 islands
4. **Browser Islands**
- 搜索框
- Sidebar 树
- AI bridge panel
- Mindmap 交互页
- `BlockNote` 编辑岛
5. **外挂或外部编辑器**
- OnlyOffice
- 后续可替换的在线表格 / 飞书文档插件
### 8.2 运行原则
长期运行原则应改成:
- 阅读优先
- 服务端先输出
- 浏览器只接必要交互
- 重交互能力单独孤岛化
- 业务规则全部留在 Rust 内核
### 8.3 实施治理口径
为了避免长期路线再次滑回“Rust 内核 + 重前端页面壳”的临时态,实施时必须额外固定四个治理口径:
1. **阶段边界固定**
- `Phase 0` 先冻结旧壳扩张、产出基线和 islands 候选
- `Phase 1` 先把 Rust Web 承载层立起来
- `Phase 2` ~ `Phase 6` 迁阅读页、Sidebar、搜索、AI、Mindmap
- `Phase 7` 最后处理 `BlockNote`
- `Phase 8` 再清理旧壳
2. **依赖顺序固定**
- 没有 `Phase 1` 的 Rust Web 入口,就不算真正进入长期主线
- 没有阅读态/编辑态分离,就不允许继续扩大编辑器默认挂载链
- 没有横向能力(trace、缓存、权限、回归脚本),就不允许每个模块各自发明运行语义
3. **横向能力固定**
- 统一 `request_id` / `trace_id`
- 统一缓存与预取口径
- 统一页面壳、对象、AI bridge 的权限边界
- 统一回归脚本和性能采样口径
4. **最终验收固定**
- 文档打开先看到阅读态,而不是编辑器 loading
- Sidebar/搜索/AI/Mindmap 已退出当前重前端主壳
- Rust Web 已能承接主 API、页面壳和主流式链路
- `BlockNote` 已降级为最后的重交互孤岛
对应的执行细节、逐阶段清单和可验证项,当前应先以 `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md` 确认优先级;`/mnt/Data1T/mnote/design/03-rust-web/reference/3-1-rust-web-long-term-checklist-v2.md` 保留为 Rust Web 分阶段全景参考。
### 8.4 当前已落地的最小里程碑(2026-05-09)
到目前为止,长期路线里已经有几条可以被源码直接证明的最小里程碑:
- `mnote-web` 已经不是只停留在 crate 骨架;`3000` 公开入口已由 Rust Web 主壳承接,`3104` 已退到仅显式 debug / internal 边界。
- Rust Web 主壳已经接入 `/api/tree/events` snapshot / delta / resync consumer,双 pane 也已复用同一条 tree realtime 主链,而不是每个页面壳各自维护第二条流。
- 文档页读取已收口到 Rust `/api/page-aggregate/:id``mnote.page_aggregate.v1` snapshot`/api/documents/page` 已降级为显式退场的 compat 边界,不再参与运行时主路径。
- 默认主编辑区已经切到页面内 `leptos-tiptap` island;阅读态、页头、页面设置和页面内 AI 面板都在 `3000` 主壳上继续收口,`BlockNote` 只保留为 `recycle/` 历史参考 / 对照材料。
- Sidebar 已形成“服务端首包 + 客户端局部 island”的最小边界,导航数据聚合契约不再散落在布局层。
- SearchPalette 与页面级 AI 面板都已经收成轻 host + 按需 runtime island,重量运行态不再默认跟随主布局常驻。
- Global AI 继续保留为实验入口,但不再回到 app layout 主链,避免长期路线再次滑回“全局大面板常驻”模式。
- Mindmap 已经具备独立页能力,文档内嵌形态也已降为轻预览/轻交互入口。
---
## 9. 各模块长期归位建议
### 9.1 文档阅读页
目标:
- 先直接返回可阅读页面
- 不等待编辑器初始化
- 不让评论、历史、AI、回链等阻塞正文出现
归位:
- 页面壳迁到 `axum + Leptos`
- 文档阅读内容默认服务端输出
- 编辑入口点击后才挂载编辑 island
### 9.2 Sidebar / 页面树 / 文件树
目标:
- 从当前大布局中的重量级客户端组件,变成轻交互 island
归位:
- 数据查询与聚合走 Rust
- 页面壳服务端输出
- 展开、拖拽、快捷过滤、局部刷新才在 island 内运行
### 9.3 搜索系统
目标:
- 搜索框与搜索结果只做局部交互
- 不再把整个页面切换都拖进搜索运行时
归位:
- 索引、召回、聚合全部 Rust 化
- 搜索输入与结果列表作为 island
- 搜索页本身保持 server-first
### 9.4 AI 面板
目标:
- 作为 Hermes 页面内客户端运行
- 不再承担前端本地 orchestration 或私有会话存储
- 不再成为常驻大壳的一部分
归位:
- 面板只保留 Hermes chat/session/run/tool event 的页面内子集 UI 与当前页面上下文桥接
- ACP/Hermes runtime 持有执行层 session / message / usage / modelMNote 产品层运行态索引、权限和审计默认由 SQLite control-plane 持有
- mnote 通过 Hermes skill/plugin 暴露页面、树、artifact、edge 工具,最终执行回到 Rust runtime / kernel
- 面板按页面需要懒挂载成单独 island
### 9.5 Mindmap
目标:
- 从 BlockNote 自定义块逻辑中进一步解耦
- 变成独立对象和独立页面能力
归位:
- 对象读写继续走 Rust
- 独立页面优先改成 Rust Web 壳 + 独立交互岛
- 文档内嵌版本退化为预览卡片或轻交互嵌入
### 9.6 OnlyOffice
目标:
- 维持外挂页面定位
归位:
- 继续独立页面或外部容器打开
- 只保留必要的签名、代理、回调
- 不参与主文档访问性能判断
### 9.7 `BlockNote`
目标:
- 最终变成单独的重交互编辑岛
归位:
- 阅读页不默认依赖它
- 编辑态按需挂载
- 它之外的能力尽量不再绑在同一前端运行时里
---
## 10. 为什么这是“根治路线”,不是“临时路线”
因为它改的不是几个组件,而是四个底层前提:
### 10.1 改的是页面运行模型
从:
- 先进入前端应用
变成:
- 先进入页面
### 10.2 改的是业务归属
从:
- Web 层和业务层长期混写
变成:
- 业务规则只留在 Rust
### 10.3 改的是浏览器职责
从:
- 浏览器承担整页大运行时
变成:
- 浏览器只承担必要的交互岛
### 10.4 改的是迁移顺序
从:
- 一上来就想替掉最难的 `BlockNote`
变成:
- 先清走外围大块能力
- 最后再处理 `BlockNote`
---
## 11. 推荐迁移顺序
长期上推荐按下面顺序推进,而不是乱序推进。
### Phase A:先把 Rust Web 层立起来
目标:
- 建立 `axum` 主承载层
- 建立 Rust 侧统一 Web 入口
- 接住 API、SSE、WS、文档 SSR 壳
此阶段不追求一次性替换全部页面,只追求:
- 先把“Rust 也能承接 Web 层”这件事落地
### Phase B:先迁轻页面与高频结构页
优先对象:
- Sidebar
- 页面树 / 文件树
- 搜索页
- 文档阅读页壳
- AI 面板壳
这些东西的特点是:
- 高频访问
- 强烈影响页面切换体感
- 又不像 `BlockNote` 那么难替换
### Phase C:把 Mindmap 独立化
目标:
- 让 Mindmap 从当前 BlockNote 共生结构里进一步脱离
- 独立页面优先 Rust 化
- 文档内嵌形态缩成轻版本
### Phase D:最后处理 `BlockNote`
只有当前三阶段基本稳定后,才建议处理:
- `BlockNote` 编辑器本体
- 文档编辑态与阅读态的最终分离
- 自定义 block 的最终重构边界
---
## 12. 最终建议
如果只问一句“是不是要参考 Rust 的 Web 框架,比如 `axum`,还是只要 Rust 就行”,最终答案是:
> **要参考,而且必须明确采用 Rust Web 分层;不能只说“就 Rust”。**
更具体的推荐是:
- **不是**“只保留现有 Rust 内核,网页继续主要靠当前重前端”
- **不是**“只引入 `axum` 做 API,然后页面模型不变”
- **而是**“Rust 内核 + `axum` Web 承载 + `Leptos Islands` 页面壳 + `BlockNote` 最后孤岛化”
这是当前最符合 mnote 长期目标的路线,因为它同时满足:
- 真正减少页面访问时的前端运行负担
- 继续强化 Rust 作为唯一业务执行平面
- 支持绝大部分功能逐步 CLI 化、服务化、AI 可编辑化
- 不要求一开始就碰最难替换的 `BlockNote`
---
## 13. 官方依据
本方案涉及的 Rust Web 判断,主要基于以下官方资料方向:
- `axum` 官方文档与 README
- 重点能力:Router、Handler、Middleware、JSON、WebSocket、SSE、`tokio` 服务承载
- Leptos 官方文档的 Islands 章节
- 重点能力:只有显式 island 进入客户端 hydration,其余内容可保持服务端输出
因此本文的判断不是“因为 Rust 很快所以推荐 Rust”,而是:
> **因为 mnote 需要的是 server-first 页面模型、少量交互孤岛、统一业务执行面,而 `axum + Leptos Islands + Rust Core` 正好能形成这套长期结构。**