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

19 KiB
Raw Blame 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. 新目标架构

单仓收口后的目标结构应是:

/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 事件/索引层

这意味着:

  1. 前端只认 /mnt/Data1T/mnote
  2. Rust 也只存在于 /mnt/Data1T/mnote/rust
  3. 启动、构建、联调都只从 /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 发起。

执行方式:

  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-logindex-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,再通过 buildDocumentBridgeContextWithActorbuildDocumentCommandEnvelopeexecuteMediaAssetWritebackBridgeCommand 构造和执行与 storage-convex-bridge 对齐的运行时 request。
  3. Rust 侧已补 core-protocol::ReplaceMediaAssetStoragestorage-convex-bridgemedia.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.tomlrust/Cargo.lock
  5. 不动 mnote 主前端壳
  6. 不复制 mnote-rust 的第二套产品前端壳

当前状态:

  • 以上动作已经完成
  • bridge/ 已初始化最小说明目录,但 scripts/fixtures/tests/ 仍未初始化
  • mnote-cli 已并入当前 workspaceadapter-* 仍未并入

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-bridgeread_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.updatedocuments.stats.updatedocuments.options.updatedocuments.save 补上与 storage-convex-bridge::build_write_request 对齐的最小运行时接缝,会先生成 functionName/payloadJson/args 形式的 bridge mutation request,再交给统一执行器落到 Convex
  3. 但主仓 API route 仍未直接调用 Rust cratedocuments.contentblocks.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. 不要让 mnotemnote-rust 长期各维护一套产品前端
  3. 不要跨仓链接代码来“假装已迁移”
  4. 不要把对象页壳、诊断页、smoke 页当作主产品实现复制进来
  5. 不要把 Rust 内容散落复制到 mnote 根目录多个平行源码根

11. 一句话路线判断

最优路线不是:

继续在 mnote-rust 里补前端,再想办法替换 mnote

而是:

mnote-rust 的必要 Rust 内核真实复制进 /mnt/Data1T/mnote/rust/,保留 mnote 现有成熟前端作为唯一主产品壳,最终只在 /mnt/Data1T/mnote 这个单仓里启动和保存。