Files
mnote/design/old/08-legacy-rust-kernel/process/rust-kernel-backport-plan.md
T

657 lines
19 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.
# [recycle] mnote 单仓收口 Rust 内核回迁计划
> 更新时间:2026-04-14
>
> 当前状态:已完成第一批 P0 crate 与核心设计文档的真实复制,复制目标目录为 `/mnt/Data1T/mnote/rust/`。
## 1. 结论
基于当前代码现状、`/mnt/Data1T/mnote-rust/design/` 的长期原则,以及你现在明确提出的要求:
- 不希望长期维护两个仓库
- 不希望跨仓链接
- 最终只希望在一个文件夹里启动和保存
当前最合适的路线已经明确并开始落地:
1. **停止把 `/mnt/Data1T/mnote-rust/` 继续当作未来主产品仓推进**
2. **把 `mnote-rust` 的必要 Rust 内核内容真实复制进 `/mnt/Data1T/mnote/`**
3. **最终只保留 `/mnt/Data1T/mnote/` 作为唯一主仓**
4. **`/mnt/Data1T/mnote/wolai-frontend/` 继续承担主产品前端壳**
5. **Rust 内核在 `/mnt/Data1T/mnote/rust/` 下统一收口**
一句话版:
> **不是双仓回接,而是单仓收口:把必要 Rust 内核复制进 `mnote`,最终只在 `/mnt/Data1T/mnote` 启动与保存。**
---
## 2. 为什么要改成单仓复制,而不是继续双仓
## 2.1 先做 Rust 内核本身没有错
`/mnt/Data1T/mnote-rust/design/blueprint/ai-native-note-architecture-blueprint-v0.md``/mnt/Data1T/mnote-rust/design/phases/phase5/packaging-and-shell-strategy-v0.md` 已明确长期原则:
1. Convex 仍是主事实层
2. Rust 负责统一协议、命令、查询、事件、索引、adapter
3. 前端主壳继续复用成熟 React/Next
也就是说:
- “先写 Rust 内核”是对的
- “不重写一套新前端主栈”也是对的
真正要调整的是载体:
- 不再把 `mnote-rust` 作为第二个长期主仓
- 不再维持“一个仓写内核,一个仓跑产品前端”的长期分裂状态
## 2.2 双仓会持续制造启动、保存、认知和迁移成本
如果继续保留:
- `/mnt/Data1T/mnote/`
- `/mnt/Data1T/mnote-rust/`
长期并行,会持续出现四类成本:
1. **启动成本**
- 需要判断到底从哪个目录启动
- 脚本、环境变量、依赖路径容易双份化
2. **保存口径成本**
- 用户会天然希望“最终只有一个真实主仓”
- 双仓天然让“哪个仓是现在的真主线”不断摇摆
3. **迁移成本**
- 每做一项功能,都要先判断该落在 `mnote` 还是 `mnote-rust`
- 这会导致团队持续在仓库边界上损耗
4. **认知成本**
- 新协作者很难快速判断:
- 哪个仓是产品主线
- 哪个仓只是实验壳
- 哪些文档是真约束
## 2.3 当前真正成熟的是 `mnote` 前端,而不是 `mnote-rust` 前端
当前成熟可直接承载产品面的能力主要在:
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/`
- `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/`
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/`
`mnote-rust` 当前前端更多是:
1. 联调壳
2. smoke 壳
3. 协议验证壳
4. 部分对象页桥接壳
因此,单仓收口时,正确的继承关系应该是:
- **保留 `mnote` 前端主壳**
- **复制 `mnote-rust` 的内核与协议成果**
而不是反过来复制一整套 `mnote-rust` 的 Next 前端壳。
---
## 3. 新目标架构
单仓收口后的目标结构应是:
```text
/mnt/Data1T/mnote/
wolai-frontend/ # 唯一主前端
wolai-backend/ # 现有辅助后端
infra/convex/ # 现有 Convex 基础设施
src/components/onlyoffice/
scripts/ # 仓库级统一启动入口
design/ # 全局设计与总览
rust/ # 新增:Rust 内核统一收口目录
```
连接关系应变成:
```text
mnote 前端
-> mnote 内部 API / BFF / bridge
-> rust/ 内核协议层
-> Convex 主事实层 + Rust 事件/索引层
```
这意味着:
1. 前端只认 `/mnt/Data1T/mnote`
2. Rust 也只存在于 `/mnt/Data1T/mnote/rust`
3. 启动、构建、联调都只从 `/mnt/Data1T/mnote` 发起
---
## 4. 单仓目录落位方案
推荐把 Rust 相关内容整体收进:
- `/mnt/Data1T/mnote/rust/`
而不要把 `crates/``design/``scripts/` 直接摊到仓库根。
目标结构:
```text
/mnt/Data1T/mnote/
wolai-frontend/
wolai-backend/
infra/convex/
src/components/onlyoffice/
scripts/
design/
rust/
Cargo.toml
Cargo.lock
crates/
core-domain/
core-protocol/
event-log/
storage-convex-bridge/
index-fts/
bridge-runtime/ # Phase 1 最小真实执行器
mnote-cli/ # Phase 2 已落位,先冻结 --json 协议
adapter-onlyoffice/ # 后置按需引入
adapter-mindmap/ # 后置按需引入
adapter-legacy-mnote/ # 后置按需引入
bridge/
design/
INDEX.md
core/
blueprint/
phases/
scripts/
fixtures/
tests/
```
### 4.1 `rust/` 下各目录职责
- `rust/crates/`
放所有 Rust workspace 成员,保持 Cargo workspace 语义集中。
- `rust/bridge/`
放 Rust 侧桥接层、协议适配、生成代码、FFI/IPC glue。
- `rust/design/`
放 Rust 专属设计、阶段文档、路线图。
- `rust/scripts/`
放 Rust 专属构建、测试、检查、保存脚本。
- `rust/fixtures/` / `rust/tests/`
放 Rust 侧测试资源与测试代码。
### 4.2 根目录哪些保持不动
以下现有目录建议明确保持不动:
- `/mnt/Data1T/mnote/wolai-frontend/`
- `/mnt/Data1T/mnote/wolai-backend/`
- `/mnt/Data1T/mnote/infra/convex/`
- `/mnt/Data1T/mnote/src/components/onlyoffice/`
- `/mnt/Data1T/mnote/recycle/`
- `/mnt/Data1T/mnote/scripts/`
- `/mnt/Data1T/mnote/design/`
其中:
- `design/` 继续承担全局总览和跨系统路线说明
- Rust 的详细阶段文档放进 `rust/design/`
---
## 5. 启动与保存口径必须怎么统一
## 5.1 启动口径
统一口径只有一个:
> 所有开发、构建、联调命令都从 `/mnt/Data1T/mnote` 发起。
执行方式:
1. 仓库级脚本统一保留在 `/mnt/Data1T/mnote/scripts/`
2. Rust 命令只作为子任务存在,例如:
- `cargo --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml ...`
3. 不再保留“先进 `mnote-rust` 再进 `mnote`”的双仓启动方式
## 5.2 保存口径
统一口径只有一个:
> 页面、块、文档、任务、索引的最终保存都只认 Convex 主事实层。
这意味着:
1. 人工操作、CLI、Agent 的写入都应先进入 Rust 统一命令层,再落到 Convex
2. Rust 的 `event-log``index-fts`、fixtures、本地缓存都只是派生层
3. 文件系统只保存:
- 静态资源
- 附件
- 导出物
- 缓存
- 测试数据
4. 文件系统不承载主业务真相
---
## 5.3 当前已落地的首批复制结果
截至 2026-04-13,以下内容已经真实复制进 `/mnt/Data1T/mnote/rust/`
### 已复制的 workspace 根文件
- `/mnt/Data1T/mnote/rust/Cargo.toml`
- `/mnt/Data1T/mnote/rust/Cargo.lock`
### 已复制的 P0 crate
- `/mnt/Data1T/mnote/rust/crates/core-domain/`
- `/mnt/Data1T/mnote/rust/crates/core-protocol/`
- `/mnt/Data1T/mnote/rust/crates/event-log/`
- `/mnt/Data1T/mnote/rust/crates/storage-convex-bridge/`
- `/mnt/Data1T/mnote/rust/crates/index-fts/`
### 已复制的核心设计文档
- `/mnt/Data1T/mnote/rust/design/INDEX.md`
- `/mnt/Data1T/mnote/rust/design/core/01-domain-model-v0.md`
- `/mnt/Data1T/mnote/rust/design/core/02-command-query-tool-protocol-v0.md`
- `/mnt/Data1T/mnote/rust/design/core/03-storage-event-indexing-v0.md`
- `/mnt/Data1T/mnote/rust/design/core/04-onlyoffice-integration-boundary-v0.md`
这一状态意味着:
1. `mnote` 主仓里已经存在可继续扩展的 Rust workspace 根
2. P0 内核定义已经不再只存在于 `/mnt/Data1T/mnote-rust/`
3. 后续回迁工作可以直接以 `/mnt/Data1T/mnote/rust/` 为唯一落位继续推进
---
## 6. 第一阶段应该真实复制进 `mnote` 的内容
子 agent 的结论一致:第一阶段应复制“定义真相和协议”的内核,而不是复制第二套产品前端。
## 6.1 必须复制的 crate
### P0:第一阶段必须复制
以下 crate 应真实复制到:
- `/mnt/Data1T/mnote/rust/crates/`
#### `core-domain`
来源:
- `/mnt/Data1T/mnote-rust/crates/core-domain`
复制后职责:
1. 领域模型
2. 一等对象定义
3. ID / revision / 时间 /审计基础类型
#### `core-protocol`
来源:
- `/mnt/Data1T/mnote-rust/crates/core-protocol`
复制后职责:
1. `Command / Query / Tool` 统一协议壳
2. actor/source/target/meta 结构
3. `CreatePage / InsertBlock / SearchPages` 等协议模型
#### `event-log`
来源:
- `/mnt/Data1T/mnote-rust/crates/event-log`
复制后职责:
1. 命令日志
2. 领域事件
3. 写入后的事件生成规则
#### `storage-convex-bridge`
来源:
- `/mnt/Data1T/mnote-rust/crates/storage-convex-bridge`
复制后职责:
1. 协议到 Convex 的桥接
2. 命令执行与回写
3. 命令日志和事件落账
#### `index-fts`
来源:
- `/mnt/Data1T/mnote-rust/crates/index-fts`
复制后职责:
1. 可重建的索引与搜索层
2. 事件投影
3. page/block 搜索
### P1:建议第二阶段复制
#### `mnote-cli`
来源:
- `/mnt/Data1T/mnote-rust/crates/mnote-cli`
复制后职责:
1. 批处理入口
2. 导入导出入口
3. 内核 smoke 与排障入口
### P2:按需后置复制
#### `adapter-onlyoffice`
来源:
- `/mnt/Data1T/mnote-rust/crates/adapter-onlyoffice`
复制后职责:
1. OnlyOffice 资产定位
2. 会话定位
3. 任务边界适配
#### `adapter-mindmap`
来源:
- `/mnt/Data1T/mnote-rust/crates/adapter-mindmap`
复制后职责:
1. 思维导图结构化 ops
2. 节点读取与引用边界
#### `adapter-legacy-mnote`
来源:
- `/mnt/Data1T/mnote-rust/crates/adapter-legacy-mnote`
复制后职责:
1. 旧逻辑兼容
2. 迁移期桥接
## 6.2 必须复制的设计资产
建议同步复制到:
- `/mnt/Data1T/mnote/rust/design/`
### 必复制
- `/mnt/Data1T/mnote-rust/design/INDEX.md`
- `/mnt/Data1T/mnote-rust/design/core/01-domain-model-v0.md`
- `/mnt/Data1T/mnote-rust/design/core/02-command-query-tool-protocol-v0.md`
- `/mnt/Data1T/mnote-rust/design/core/03-storage-event-indexing-v0.md`
- `/mnt/Data1T/mnote-rust/design/core/04-onlyoffice-integration-boundary-v0.md`
原因:
1. 这些是长期稳定规范
2. 直接对应 `core-domain / core-protocol / event-log / storage-convex-bridge / index-fts / adapter-onlyoffice`
### 暂不建议第一阶段复制的设计资产
以下内容先留在 `mnote-rust` 作为参考,不作为第一阶段主迁移目标:
- `design/blueprint/**`
- `design/phases/**`
- `design/execution/**`
- `design/UI/**`
原因:
1. 这些更多是阶段叙事与历史推进资料
2. 不是必须进入主仓的长期规范
---
## 7. 第一阶段明确不应复制的内容
这里要明确“禁止误复制”的范围。
## 7.1 不应继续作为第一阶段复制目标的前端内容
### 不复制为主线
- `/mnt/Data1T/mnote-rust/app/documents/[id]/mindmap/page.tsx`
- `/mnt/Data1T/mnote-rust/app/documents/[id]/office/page.tsx`
- `/mnt/Data1T/mnote-rust/components/sidebar/sidebar.tsx`
- `/mnt/Data1T/mnote-rust/app/page.tsx`
- `/mnt/Data1T/mnote-rust/app/onlyoffice/page.tsx`
原因:
1. 它们大多属于对象页壳、诊断页、smoke 页或单文件硬拼壳
2. 不应再形成第二套产品前端主线
## 7.2 只能保留为参考 / smoke / 实验的内容
以下内容可以保留在 `mnote-rust` 参考,但不作为第一阶段复制目标:
1. `app/documents/[id]/mindmap/page.tsx` 里的 diagnostics 区
2. `app/documents/[id]/office/page.tsx` 里的 diagnostics 区
3. `app/onlyoffice/OnlyOfficeClientPage.tsx` 里的环境兼容 hack
4. `app/page.tsx` 的 smoke 首页文案
5. `phase7` 中已经标注为历史错误方向的文档
## 7.3 可复制的少量薄桥接代码
以下内容可以作为后续参考性复制对象,但仍不是第一阶段主目标:
- `components/editor/document-shell.tsx`
- `components/editor/document-content.tsx`
- `components/editor/blocknote-editor.tsx`
- `hooks/use-convex-sidebar-data.ts`
- `lib/sidebar-tree.ts`
- `lib/file-tree/rows.ts`
- `lib/document-embeds.ts`
- `app/layout.tsx`
原因:
1. 这些属于宿主桥接、投影层或 provider 接线
2. 不是完整产品前端壳
---
## 8. 单仓路线下,`mnote` 里最先该接入的 5 条能力链
这 5 条仍然是最值得优先打通的主线。
## 8.1 文档正文命令链
接入目标:
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/save/route.ts`
目标:
1. 保留现有成熟 BlockNote 前端
2. 把正文保存逐步切到 Rust command 层
3. 让 block 操作、正文快照、stats 逐步进入统一协议
## 8.2 页面元信息与页面属性链
接入目标:
- `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx`
目标:
1. 标题更新
2. 页面选项
3. 文档统计
4. 页面属性变更
## 8.3 Sidebar 数据聚合链
接入目标:
- `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/sidebar.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/private-tree.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/components/sidebar/file-tree.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/hooks/use-convex-sidebar-data.ts`
目标:
1. 保留现有 UI
2. 逐步让数据聚合层走 Rust query / index 层
## 8.4 Mindmap 数据链
接入目标:
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/mindmap/mindmapLocalStore.ts`
目标:
1. 保留现有成熟思维导图前端
2. 逐步把数据读写、ops 和边界纳入 Rust adapter / protocol
## 8.5 OnlyOffice 边界链
接入目标:
- `/mnt/Data1T/mnote/wolai-frontend/src/app/onlyoffice/`
- `/mnt/Data1T/mnote/wolai-frontend/src/app/api/onlyoffice/`
- `/mnt/Data1T/mnote/src/components/onlyoffice/`
目标:
1. 保留现有 OnlyOffice 页面和静态资源
2. 把对象解析、回调、签名和桥接逐步回到 Rust adapter 统一边界
当前补记:
1. `OnlyOffice callback` 已从 route 里直接调用 `api.mediaAssets.replaceStorageFromUpload`,推进到最小 `media.assets.replace_storage` bridge 命令边界。
2. 当前主仓实现会先在 `wolai-frontend/src/app/api/onlyoffice/callback/route.ts` 下载 ONLYOFFICE 输出文件、上传到 Convex Files 获得 `storageId`,再通过 `buildDocumentBridgeContextWithActor``buildDocumentCommandEnvelope``executeMediaAssetWritebackBridgeCommand` 构造和执行与 `storage-convex-bridge` 对齐的运行时 request。
3. Rust 侧已补 `core-protocol::ReplaceMediaAssetStorage``storage-convex-bridge``media.assets.replace_storage -> mediaAssets:replaceStorageFromUpload` 映射;因此 OnlyOffice 附件写回现已进入与页面元信息、正文保存一致的协议接缝,只是最终执行器仍在 TypeScript 侧落到 Convex mutation。
---
## 9. 推荐实施顺序
## Phase A:先把 Rust 内核真实复制进 `mnote`
第一阶段执行动作:
1.`/mnt/Data1T/mnote/` 下建立 `/rust/`
2. 复制 `P0` crate
3. 复制 `design/core` 四份长期文档和 `design/INDEX.md`
4. 建立新的 `rust/Cargo.toml``rust/Cargo.lock`
5. 不动 `mnote` 主前端壳
6. 不复制 `mnote-rust` 的第二套产品前端壳
当前状态:
- 以上动作已经完成
- `bridge/` 已初始化最小说明目录,但 `scripts/``fixtures/``tests/` 仍未初始化
- `mnote-cli` 已并入当前 workspace`adapter-*` 仍未并入
## Phase B:在 `mnote` 中建立 Rust bridge 接口
执行动作:
1.`mnote` 现有 API/BFF 层加 Rust command/query 入口
2. 保留当前 UI,不先大改组件
3. 先打通低风险调用链
当前建议的第一批 bridge 入口落位:
1. `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/content/route.ts`
- 作为优先读入口,后续先接 `storage-convex-bridge``read_path`
2. `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/save/route.ts`
- 作为优先写入口,后续先接 `write_path`
3. `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/title/route.ts`
- 作为页面标题更新的低风险写入口
4. `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/stats/route.ts`
- 作为页面统计的低风险入口
5. `/mnt/Data1T/mnote/wolai-frontend/src/app/api/sidebar/route.ts`
- 作为 Sidebar 聚合读入口,后续切 Rust query / index
6. `/mnt/Data1T/mnote/wolai-frontend/src/app/api/blocks/patch/route.ts`
- 作为块级局部写入口,适合正文链路第二步接入
当前判断:
1. `storage-convex-bridge` crate 内已经具备 `context / validation / read_path / write_path / mapping` 的桥接骨架
2. `mnote` 主仓已为 `documents.title.update``documents.stats.update``documents.options.update``documents.save` 补上与 `storage-convex-bridge::build_write_request` 对齐的最小运行时接缝,会先生成 `functionName/payloadJson/args` 形式的 bridge mutation request,再交给统一执行器落到 Convex
3. 但主仓 API route 仍未直接调用 Rust crate`documents.content``blocks.patch` 等链路也还没有切到同一层执行器,因此 Phase B 还不能视为完全关闭
## Phase C:先接低风险元信息,再接正文链
顺序建议:
1. 页面标题 / 页面选项
2. Sidebar 数据聚合
3. BlockNote 正文保存
## Phase D:再接 Mindmap 与 OnlyOffice
原则:
1. 前端仍然在 `mnote`
2. 数据、ops、边界逐步切到 Rust adapter / protocol
## Phase E:让 `mnote-rust` 退出主产品角色
处理方式:
1. `mnote-rust` 可保留为历史参考或过渡仓
2. 但不再承担短期产品主线
3. 最终只保留 `/mnt/Data1T/mnote/` 作为可启动、可保存主仓
4. 历史资料分类与主仓维护边界统一以 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-single-repo-maintenance-boundary.md` 为准
---
## 10. 最不该做的事
1. 不要继续把 `mnote-rust` 的 Next 前端补成完整产品前端
2. 不要让 `mnote``mnote-rust` 长期各维护一套产品前端
3. 不要跨仓链接代码来“假装已迁移”
4. 不要把对象页壳、诊断页、smoke 页当作主产品实现复制进来
5. 不要把 Rust 内容散落复制到 `mnote` 根目录多个平行源码根
---
## 11. 一句话路线判断
最优路线不是:
> 继续在 `mnote-rust` 里补前端,再想办法替换 `mnote`
而是:
> 把 `mnote-rust` 的必要 Rust 内核真实复制进 `/mnt/Data1T/mnote/rust/`,保留 `mnote` 现有成熟前端作为唯一主产品壳,最终只在 `/mnt/Data1T/mnote` 这个单仓里启动和保存。