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