Files

657 lines
19 KiB
Markdown
Raw Permalink Normal View History

# [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` 这个单仓里启动和保存。