# Rust Web 长期架构实施清单 v2

> 更新时间：2026-04-16
>
> 基于以下实际状态重写：
> - 当前未提交代码
> - `/mnt/Data1T/mnote/harness-tasks.json` 中 `task-059` ~ `task-069`
> - `/mnt/Data1T/mnote/design/rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/rust-web-long-term-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/tree-first-graph-kernel-v1.md`

## 1. 这版为什么要重写

这次重写的原因很明确：

- `task-059` ~ `task-069` 目前在 `harness-tasks.json` 里已经被标为 `completed`
- 但从当前未提交代码实际看，很多项只证明了：
  - 文档已补
  - 骨架已建
  - 局部组件已拆
  - `eslint` / `cargo check` 可过
- **并不能证明对应长期阶段已经真正完成**

因此这版 checklist 的目标不是重复愿景，而是：

> **把长期路线重新落回“真实代码状态”，明确哪些已经落地、哪些只是最小接缝、哪些仍未开始。**

---

## 2. 当前总判断

从当前代码看，长期路线的真实状态是：

### 2.1 已有明确进展

- [x] `Phase 0` 的文档化边界梳理已经完成
- [x] `Phase 1` 已落了一个最小 `axum` Web 骨架：`rust/crates/mnote-web/`
- [x] `Phase 1` 已不再只是空骨架，现已包含 kernel / bridge / compat sidebar 的真实查询接缝
- [x] `Phase 2` 文档阅读态分离已经有实质代码
- [x] `Phase 3` 主 Sidebar 已出现 `kernelSidebarTree` 消费接缝
- [x] `Phase 4` 搜索已做 host/runtime 拆分，并开始返回 `nodeId` / `subtreeRootId` / `evidence`
- [x] `Phase 5` AI 面板已做 host/runtime 拆分，并开始向 Hermes bridge 传递 `node` / `subtree` / `outline` / `evidence`
- [x] `Phase 6` Mindmap 独立页已去掉 `editorStub` 主入口
- [x] `Phase 7` 阅读态已直接消费 `pageSubtree`，`BlockNote` 也已不是文档页默认唯一入口

### 2.2 但大部分阶段都只是“部分落地”

- [ ] `Phase 1` 还不是主 Web 路径，只是 Rust Web skeleton
- [ ] `Phase 3` Sidebar 仍是超大客户端组件，其他树域也未统一切到 kernel projection
- [ ] `Phase 4` 搜索仍是前端 runtime 主导，不是 server-first 搜索页
- [ ] `Phase 5` AI runtime 仍然很重，只是懒挂载了
- [ ] `Phase 6` Mindmap 仍然是重前端交互壳，不是独立对象页壳
- [ ] `Phase 7` 文档页外围面板仍集中在 `DocumentContent`
- [ ] `Phase 8` 旧 Next/React 主路径完全没有完成切换

### 2.3 结论

> **当前真实状态不是“Phase 0 ~ 8 已全部完成”，而是“Phase 0 基本完成，Phase 1/2/4/5/6/7 处于不同程度的部分落地，Phase 3 和 Phase 8 仍远未完成”。**

---

## 3. 重新定义状态口径

为了避免再次把“有骨架”写成“已完成”，v2 统一使用下面三种状态：

### `DONE`

定义：

- 代码主路径已经切换
- 不是只有文档或骨架
- 用户可感知行为已经变了
- 后续只剩清理和补强

### `PARTIAL`

定义：

- 已有真实代码改动
- 但仍是局部接缝、最小骨架、阶段性拆分
- 主路径尚未彻底切换

### `NOT_STARTED`

定义：

- 还停留在设计或口径层
- 或只有零散基础，不足以算阶段开始

---

## 4. 基于真实代码的阶段总览

| 阶段 | v1 口径 | 当前真实状态 | 说明 |
| --- | --- | --- | --- |
| Phase 0 | 边界冻结 | `DONE` | 文档、候选模块、边界口径已经成形，但性能基线更多还是文档定义，不是完整观测系统 |
| Phase 1 | Rust Web 基础层 | `PARTIAL` | `mnote-web` 已创建，`axum` 骨架已存在，且已补 bridge route、通用 query transport 与 Sidebar compat 切流入口，但仍不是整个产品的主 Web 入口 |
| Phase 2 | 文档阅读页 server-first 化 | `PARTIAL` 接近 `DONE` | 阅读态/编辑态已明显分离，但仍有旧链回退和大量客户端状态集中在 `DocumentContent` |
| Phase 3 | Sidebar / 树结构 Rust 化 | `PARTIAL` 偏早期 | 主 Sidebar 已以 `kernelSidebarTree` 作为主树来源，但整体仍是超大客户端组件 |
| Phase 4 | 搜索 Rust 化与 island 化 | `PARTIAL` | host/runtime 懒加载拆分已做，结果形状也开始带 `nodeId` / `subtreeRootId` / `evidence`，但仍未完成 server-first 搜索页 |
| Phase 5 | AI 面板 bridge island 化 | `PARTIAL` | host/runtime 拆分已做，且已开始把 `node` / `subtree` / `outline` / `evidence` 送入 Hermes，但 runtime 仍重，协议也未统一到真正“最小壳” |
| Phase 6 | Mindmap 独立对象化 | `PARTIAL` | 独立页脱离 editor stub 主入口，并补出 `standalone` / `documentBridge` 边界，但仍是客户端重壳 |
| Phase 7 | BlockNote 孤岛化 | `PARTIAL` | 阅读态已直接消费 `pageSubtree`，编辑器按需挂载，但外围 drawer/panel 仍集中在同一内容组件 |
| Phase 8 | 旧前端壳下线 | `NOT_STARTED` | 当前主入口仍是 Next/React，不能宣称主路径切换完成 |

---

## 5. Phase 0：基线与边界冻结

**当前状态：`DONE`**

### 5.1 已有事实

- [x] 已有长期架构文档
- [x] 已有长期 checklist 文档
- [x] 已有 `tree-first graph kernel` 文档
- [x] 已对文档页、Sidebar、Search、AI、Mindmap、OnlyOffice、`BlockNote` 做了模块级边界识别

### 5.2 当前仍不足的地方

- [ ] 真正可自动回归的性能基线系统仍未建立
- [ ] 统一 performance trace 采样点仍未进入运行时
- [ ] “冻结旧壳继续膨胀”目前更多靠文档与人工约束，不是代码级 guardrail

### 5.3 v2 完成判定

- [x] 设计层边界冻结已完成
- [ ] 运行时观测层冻结仍未完成

---

## 6. Phase 1：Rust Web 基础层落地

**当前状态：`PARTIAL`**

### 6.1 已落地事实

- [x] Rust workspace 已并入 `mnote-web`
  - [Cargo.toml](/mnt/Data1T/mnote/rust/Cargo.toml)
- [x] 已存在 `axum` Web 骨架
  - [Cargo.toml](/mnt/Data1T/mnote/rust/crates/mnote-web/Cargo.toml)
- [x] 已有统一 app/router 骨架
  - [app.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/app.rs)
  - [mod.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/mod.rs)
- [x] 已有 request context / middleware
  - [context.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/context.rs)
  - [request_context.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/middleware/request_context.rs)
- [x] 已有最小 Hermes bridge route
  - [hermes.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes.rs)
- [x] 已有 SSE / WS / compat route 骨架
- [x] 已有真实 bridge / compat 接缝
  - [bridge.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/bridge.rs)
  - [compat.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/compat.rs)
- [x] kernel sidebar route 已通过 `sidebar.dataset.list` runtime plan + 通用 query transport 读取数据集
  - [kernel.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/kernel.rs)

### 6.2 明确还没完成

- [ ] `mnote-web` 还不是主 Web 服务入口
- [ ] 还没有主页面壳 SSR
- [ ] 还没有主 API 大面积从 Next route 切到 Rust Web
- [ ] 当前 `compat_next_base_path` 仍说明它还带有兼容层属性，不是唯一承载层
- [ ] fixture 已收口到测试/开发边界，但这还不等于整个产品流量已经全面切到 Rust Web
- [ ] 还不能说“后续页面迁移已不依赖 Next API route 作为唯一入口”，只能说“已经开始脱钩”

### 6.3 v2 后续任务

- [ ] 把 `mnote-web` 从 skeleton 提升为真实服务入口
- [ ] 先把 sidebar kernel route 上的 fixture fallback 收到测试/开发边界，再承接一条真实页面壳或真实查询主链
- [ ] 明确 Next -> Rust Web 的流量切换边界
- [ ] 增加主 API / 页面壳级集成验证，而不只是 `cargo check`

---

## 7. Phase 2：文档阅读页 server-first 化

**当前状态：`PARTIAL`，但已经是最实的进展之一**

### 7.1 已落地事实

- [x] 文档页已在服务端预取 `meta + content`
  - [page.tsx](/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx)
- [x] `DocumentShell` 已去掉 mounted gating
  - [document-shell.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-shell.tsx)
- [x] `DocumentReadView` 已作为阅读态渲染器落地
  - [document-read-view.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-read-view.tsx)
- [x] `DocumentContent` 已有 `isEditing` / `keepEditorMounted`
  - [document-content.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx)
- [x] `BlockNoteEditor` 已不是默认唯一入口

### 7.2 当前还没完成

- [ ] 服务端读链失败时仍回退旧链
- [ ] 阅读态与编辑态虽已分开，但大量页面状态仍集中在 `DocumentContent`
- [ ] 评论、历史、回链、AI、页面选项虽然不是首屏阻塞，但仍在同一组件层集中管理
- [ ] 阅读页还不是一个真正极薄的 server-first 页面壳

### 7.3 v2 完成判定

- [x] “先阅读、后编辑”的主行为已经出现
- [ ] “阅读页已经彻底轻壳化”还不能成立

---

## 8. Phase 3：Sidebar / 页面树 / 文件树 Rust 化与 island 化

**当前状态：`PARTIAL` 偏早期**

### 8.1 已落地事实

- [x] Sidebar 数据 query 契约此前已经有 Rust 化前进
- [x] 布局服务端会先加载 `sidebarInitialData`
  - [layout.tsx](/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/layout.tsx)
- [x] `sidebar-data.ts` 已生成 `kernel_sidebar_projection` 与 `kernelSidebarTree`
  - [sidebar-data.ts](/mnt/Data1T/mnote/wolai-frontend/src/lib/sidebar-data.ts)
- [x] 主 Sidebar 已以 `sidebarData.kernelSidebarTree` 作为初始树与同步来源
  - [sidebar.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx)
- [x] 已补统一 `page_tree` projection protocol，并让 `PrivateTree` / 文件树 / move-embed picker 共用
  - [tree-projection.ts](/mnt/Data1T/mnote/wolai-frontend/src/lib/tree-projection.ts)

### 8.2 当前真实问题

- [ ] `Sidebar` 仍然是超大客户端组件
  - [sidebar.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx)
- [ ] 页面树 / 文件树虽然已统一协议，但整体执行面仍主要在客户端
- [ ] `buildDocumentTree(...)` 仅剩兼容 helper 与旧单测，不再位于树域主路径
- [ ] 主布局仍然默认常驻挂载 Sidebar
- [ ] 还不能叫“服务端输出 + 局部 island”，现在更像“服务端首包 + 超大客户端壳”

### 8.3 v2 后续任务

- [ ] 先拆 Sidebar 自身为 host / runtime 或分片 island
- [ ] 把树结构首包与交互态严格分层
- [x] 把主 Sidebar 之外的 page tree、file tree、embed/move picker 也统一切到 kernel projection
- [ ] 把局部刷新协议显式化
- [ ] 给 Sidebar 建立真正的切页重渲染基线

---

## 9. Phase 4：搜索系统 Rust 化与 island 化

**当前状态：`PARTIAL`**

### 9.1 已落地事实

- [x] `SearchPalette` 已收口为轻量 host
  - [search-palette.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/search/search-palette.tsx)
- [x] 搜索 runtime 已按需动态加载
  - [SearchPaletteHost.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/search/SearchPaletteHost.tsx)
  - [search-palette.runtime.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/search/search-palette.runtime.tsx)
- [x] 搜索结果契约已开始带 `nodeId` / `subtreeRootId` / `evidence`
  - [search-query-adapter.ts](/mnt/Data1T/mnote/wolai-frontend/src/lib/search/search-query-adapter.ts)
  - [search.ts](/mnt/Data1T/mnote/wolai-frontend/src/types/search.ts)

### 9.2 当前还没完成

- [ ] 主布局仍然默认挂载搜索 host
- [ ] 搜索仍主要是纯前端 runtime
- [ ] 没有真正的 server-first 搜索页
- [ ] 没有看到搜索 UI 直接接入 Rust Web 页面壳
- [ ] 结果形状虽已开始 kernel-aware，但检索真相层仍不是 Rust Web / kernel 真正主链
- [ ] 不能宣称“搜索系统 Rust 化”已完成，只能说“搜索 UI 体量开始拆分，结果契约开始收口”

### 9.3 v2 后续任务

- [ ] 把搜索页与浮层分开
- [ ] 先建立服务端搜索结果页壳
- [ ] 让 host 只保留热键与打开逻辑
- [ ] 减少全局常驻 store 对搜索的依赖
- [ ] 把 `nodeId` / `subtreeRootId` / `evidence` 结果形状继续推进到更真实的 Rust/kernel 检索主链

---

## 10. Phase 5：AI 面板进一步收口为纯桥接 island

**当前状态：`PARTIAL`**

### 10.1 已落地事实

- [x] 文档页 AI 已拆为 host + runtime
  - [DocumentAiAgentPanel.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.tsx)
  - [DocumentAiAgentPanel.runtime.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx)
- [x] Mindmap / OnlyOffice 也有类似 runtime 拆分
- [x] `GlobalAiAgentHost` 已不在 `(app)/layout.tsx` 主布局中挂载
- [x] 文档页 AI 已开始把 `node` / `subtree` / `outline` / `evidence` 传给 Hermes bridge
  - [DocumentAiAgentPanel.runtime.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx)
  - [route.ts](/mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts)

### 10.2 当前还没完成

- [ ] runtime 组件仍然非常重
- [ ] “最小会话协议、统一流式协议、页面上下文协议”还更多体现在组件内部，不是系统级协议层
- [ ] 还不能说 AI 面板已经变成“纯桥接壳”
- [ ] 页面级 AI adapter 仍然很大，只是改成了懒加载
- [ ] AI 已能消费 `node` / `subtree` / `outline` / `evidence` 上下文，但还不是统一的 kernel-first tool 协议

### 10.3 v2 后续任务

- [ ] 继续下沉 runtime 内状态与协议
- [ ] 把会话、tool event、client action 收口到共享协议层
- [ ] 让 runtime 再减重，而不只是拆文件
- [ ] 把当前上下文注入进一步收口为更稳定的 kernel node / subtree / edge bridge

---

## 11. Phase 6：Mindmap 独立对象化与独立页面化

**当前状态：`PARTIAL`**

### 11.1 已落地事实

- [x] Rust 侧已有 Mindmap 对象协议与操作
- [x] 独立页已先在服务端抓 initial projection，再交给客户端页面壳
- [x] 独立页已直接使用 `StandaloneMindmapView`
  - [page.tsx](/mnt/Data1T/mnote/wolai-frontend/src/app/mindmap/[docId]/[mindmapId]/page.tsx)
- [x] 旧 `editorStub` 依赖已经不在独立页入口上
- [x] `MindmapBlock.tsx` 中已有 `standalone` / `documentBridge` 边界
  - [MindmapBlock.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx)
- [x] 文档内嵌导图已默认走 preview-first 入口

### 11.2 当前还没完成

- [ ] 独立导图页仍是客户端页面，不是独立对象页壳
- [ ] 仍然直接复用同一个重前端组件
- [ ] 文档内嵌导图虽然已经 preview-first，但进入编辑/沉浸态后仍复用同一套重组件
- [ ] Mindmap 还没有脱离“重交互前端壳优先”的事实
- [ ] 导图数据真相仍未通过 kernel subtree / command 形成稳定主链

### 11.3 v2 后续任务

- [ ] 把独立导图页壳和导图操作壳分离
- [ ] 让文档内嵌导图先变成轻预览/轻入口
- [ ] 继续把对象真相留在 Rust，而不是留在前端组件状态

---

## 12. Phase 7：文档编辑态与 BlockNote 孤岛化

**当前状态：`PARTIAL`**

### 12.1 已落地事实

- [x] `DocumentContent` 已存在阅读态/编辑态切换
- [x] `BlockNoteEditor` 已变成按需挂载
- [x] `keepEditorMounted` 说明已开始按进入编辑态再保留编辑器
  - [document-content.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx)
- [x] 阅读态已直接消费 `pageSubtree`
  - [document-content.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx)
  - [document-read-view.tsx](/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-read-view.tsx)

### 12.2 当前还没完成

- [ ] `DocumentContent` 仍然同时管理：
  - `DocumentAiAgentPanel`
  - `DocumentHistoryDrawer`
  - `DocumentCommentsDrawer`
  - `PageBacklinksPanel`
  - `PageOptionsSidebar`
- [ ] `pageSubtree` 当前仍在前端内容层生成和消费，不是更薄的 Rust/kernel 输出边界
- [ ] 搜索/AI/阅读态虽然开始共享 `node` / `subtree` / `outline` / `evidence` 口径，但还没有回到统一的 kernel projection / subtree 真相协议面
- [ ] 这说明外围能力虽然不再阻塞首屏，但仍未真正完全从编辑器宿主层拆开
- [ ] `BlockNote` 还不能算“完全孤岛化”，只能算“默认不再首屏强挂”

### 12.3 v2 后续任务

- [ ] 把外围 drawer/panel 再次拆层
- [ ] 让编辑宿主只负责编辑
- [ ] 让阅读宿主只负责阅读
- [ ] 把 `pageSubtree` 的生成与消费继续下沉到更稳定的 server/kernel 边界

---

## 13. Phase 8：旧前端壳下线与兼容清理

**当前状态：`NOT_STARTED`**

### 13.1 直接证据

- [x] 当前主应用入口仍是 Next App Router
  - [layout.tsx](/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/layout.tsx)
- [x] 当前主文档页仍是 Next 页面
  - [page.tsx](/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx)
- [x] 当前主搜索、主 Sidebar、主 Mindmap 页都仍在旧前端壳内

### 13.2 因此不能成立的说法

- [ ] “Rust Web 主路径切换已完成”
- [ ] “双栈收缩已完成”
- [ ] “旧 Next/React 页面壳已清理”

### 13.3 v2 后续任务

- [ ] 先定义哪条真实流量先切到 `mnote-web`
- [ ] 先建立一条真实主路径，而不是只有 compat bridge
- [ ] 等真正有主路径后，再谈 Phase 8 清理

---

## 14. 与 task-059 ~ task-069 的关系重定义

这组任务不应再被理解成：

- “长期 Phase 0 ~ 8 已全部完成”

更准确的理解应是：

- `task-059` ~ `task-061`
  - 主要完成了长期路线的**设计与口径定义**
- `task-062`
  - 完成了 `mnote-web` 的**最小骨架落地**
- `task-063`
  - 完成了文档阅读态分离的**核心第一步**
- `task-064`
  - 只证明 Sidebar 主树已出现 kernel projection 消费接缝，不代表 Sidebar 重构完成
- `task-065`
  - 只证明搜索运行时开始拆重，不代表搜索系统完成 server-first 重构
- `task-066`
  - 只证明 AI host/runtime 拆分，不代表最小协议壳已经完成
- `task-067`
  - 只证明独立导图页切走 editor stub 主入口，并补出 `standalone` / `documentBridge` 边界，不代表 Mindmap 独立对象页完成
- `task-068`
  - 只证明 BlockNote 默认首屏强挂已解除，不代表完整孤岛化完成
- `task-069`
  - 只能算“统一回写了阶段口径”，不能算“Phase 8 真完成”

---

## 15. v2 推荐执行顺序

如果从真实代码继续往前推进，建议顺序改成：

1. `Phase 1` 继续做实
   - 先让 `mnote-web` 承接一条真实页面壳或真实查询主链
2. `Phase 2` 收尾
   - 把文档阅读页进一步轻壳化
3. `Phase 3`
   - 先打 Sidebar 本体，而不是继续写“已完成”
4. `Phase 4` / `Phase 5`
   - 继续减 Search / AI runtime 重量
5. `Phase 6`
   - 让 Mindmap 真正从“重前端壳”中继续独立
6. `Phase 7`
   - 再拆 `DocumentContent` 外围面板
7. 最后才进入 `Phase 8`

---

## 16. 最终结论

当前未提交代码的真实含义是：

> **长期架构方向是对的，且已经开始进入真实代码；但 59-69 当前被标记为 `completed` 的口径明显偏乐观。**

更准确的结论应是：

- `Phase 0`：基本完成
- `Phase 1`：已开始，骨架已落
- `Phase 2`：已明显落地，但未完全收尾
- `Phase 3`：仍远未完成
- `Phase 4`：只完成轻量拆分
- `Phase 5`：只完成轻量拆分
- `Phase 6`：只完成独立页去耦第一步
- `Phase 7`：只完成阅读/编辑分离第一步
- `Phase 8`：尚未开始

因此，从当前实际代码出发，接下来最需要的不是继续宣布完成，而是：

> **把 v1 的“愿景式 checklist”，改成 v2 的“基于真实代码状态的 checklist”，并据此重排后续 harness 任务状态。**
