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

285 lines
44 KiB
Markdown
Raw Normal View History

# [recycle] mnote 单仓收口 Rust 内核阶段 Checklist
> 更新时间:2026-04-14
>
> 主工作路径:`/mnt/Data1T/mnote`
>
> 第二工作路径:`/mnt/Data1T/mnote-rust`(仅作为历史资产来源,不作为主执行仓)
>
> 对齐文档:`/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/process/rust-kernel-backport-plan.md`
>
> 目标:把 `mnote-rust` 的必要 Rust 内核逐步回迁到 `mnote` 主仓,并始终维持“单仓启动、单仓保存、主前端不分叉”的执行口径。
## 1. 执行口径与硬边界
- [x] 只保留 `/mnt/Data1T/mnote` 作为唯一主产品仓。
- [x] `/mnt/Data1T/mnote-rust` 只保留为历史资产来源、参考实现和待吸收规范,不再承担主线执行入口。
- [x] `wolai-frontend` 继续承担唯一主产品前端壳,不复制 `mnote-rust` 的第二套 Next 前端壳。
- [x] Rust 内核统一收口到 `/mnt/Data1T/mnote/rust/`,不再在主仓根目录散落多个 Rust 源码根。
- [x] 最终保存只认 Convex 主事实层;Rust 的事件、索引、缓存、fixtures 都属于派生层。
- [x] 不通过跨仓软链接、硬链接或路径偷接来假装完成迁移。
- [x] 第一阶段不迁入 `design/phases/**``design/execution/**``design/UI/**` 这类历史叙事文档。
- [x] 第一阶段不迁入 `mnote-cli``adapter-onlyoffice``adapter-mindmap``adapter-legacy-mnote`
- [x] Mindmap 继续以 `mnote` 当前实现为主:BlockNote 自定义块为主形态,独立全屏页为辅助形态。
- [x] OnlyOffice 继续保持“正文只嵌文件入口、编辑器在独立页面运行”的产品形态,不回嵌 BlockNote。
- [x] `wolai-frontend/``wolai-backend/``infra/convex/``src/components/onlyoffice/` 默认保持不动,除非后续阶段明确接线需要。
## 2. 当前已确认基线(2026-04-13 已核对)
### 2.1 已完成事实
- [x] `/mnt/Data1T/mnote/rust/Cargo.toml``/mnt/Data1T/mnote/rust/Cargo.lock` 已存在。
- [x] `/mnt/Data1T/mnote/rust/crates/` 下已落位 `core-domain``core-protocol``event-log``storage-convex-bridge``index-fts``bridge-runtime``mnote-cli`
- [x] `/mnt/Data1T/mnote/rust/design/INDEX.md``design/core/01~04` 核心设计文档已落位。
- [x] workspace members 仅指向 `/mnt/Data1T/mnote/rust/crates/*`
- [x] 已验证 `cargo metadata --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml --format-version 1` 可通过。
- [x] 已验证 `cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml` 可通过。
- [x] 已核对 `/mnt/Data1T/mnote/rust/` 下未发现直接引用 `/mnt/Data1T/mnote-rust` 的残留路径。
- [x] 已确认当前主前端链路仍在 `mnote`:文档页为 `DocumentShell -> DocumentContent -> BlockNoteEditor`Mindmap 仍复用现有 `MindmapBlock` 体系,OnlyOffice 仍为独立页面型编辑器。
### 2.2 当前仍未开始或未初始化的事实
- [x] `/mnt/Data1T/mnote/rust/bridge/` 已初始化最小说明目录,`crates/bridge-runtime` 已提供 Phase 1 最小真实执行样板。
- [x] `/mnt/Data1T/mnote/rust/scripts/` 当前未初始化。
- [x] `/mnt/Data1T/mnote/rust/fixtures/` 当前未初始化。
- [x] `/mnt/Data1T/mnote/rust/tests/` 当前未初始化。
- [x] `mnote-cli` 已并入 `/mnt/Data1T/mnote/rust/crates/`,当前已冻结 `page/block/search/sidebar/tool` 的最小命令面与 `--json` 输出协议。
- [x] `adapter-onlyoffice``adapter-mindmap``adapter-legacy-mnote` 尚未并入主仓。
- [x] `/api/documents/content``/api/documents/save``/api/documents/title``/api/documents/stats``/api/sidebar``/api/blocks/patch` 已接入主仓当前 bridge 包装层并统一返回 `request_id/trace_id` 元信息;其中 `documents/title``documents/stats``documents/options``documents/save` 已进一步收口到统一的 bridge mutation request 运行时接缝,可先构造与 `storage-convex-bridge::build_write_request` 对齐的 `functionName/payloadJson/args` 对象再落到 Convex,但整条链仍未直接切到 `core-protocol -> storage-convex-bridge` 的真实 Rust crate 执行链。
2026-04-15 Phase 1/2 补记:`documents.content.get``documents.title.update``documents.save` 这 1 读 2 写链现已从主仓 Next route 真实进入 `crates/bridge-runtime`,再由 TS 仅做 Convex transport;同时 `crates/mnote-cli` 已在主仓 workspace 落位,并通过 `page/block/search/sidebar/tool` 五类最小命令面的 `--json` 计划输出冻结当前 CLI 协议。
## 3. Phase ARust workspace 落位(主目标已完成)
完成目标:
- `/mnt/Data1T/mnote/rust/` 成为唯一 Rust workspace 根。
- P0 crate 与核心规范文档已在主仓内有真实副本。
- 新 workspace 已具备最小自检能力。
Checklist
- [x] 固定 `/mnt/Data1T/mnote/rust/` 为唯一 Rust workspace 根,后续 Rust 命令统一从这里发起。
- [x] 固定 workspace members 只指向 `crates/core-domain``crates/core-protocol``crates/event-log``crates/storage-convex-bridge``crates/index-fts`
- [x] 复制并落位 `core-domain``core-protocol``event-log``storage-convex-bridge``index-fts`
- [x] 复制并落位 `rust/design/INDEX.md``rust/design/core/01-domain-model-v0.md``02-command-query-tool-protocol-v0.md``03-storage-event-indexing-v0.md``04-onlyoffice-integration-boundary-v0.md`
- [x] 统一 workspace 级别的 `edition``license``version``authors` 约定。
- [x] 跑通 `cargo metadata --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml --format-version 1`
- [x] 跑通 `cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml`
- [x] 已补跑 `cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-domain``cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-protocol`
- [x] 已在本 checklist 第 1 节固定“第一阶段禁止迁入清单”,明确 `mnote-cli``adapter-*``design/phases/**``design/execution/**`、第二套 Next 前端壳均不属于本阶段交付。
Phase A 验收:
- [x] Cargo 可在主仓内解析 workspace。
- [x] 主仓内已有 P0 内核与长期规范副本。
- [x] 当前未出现对第二工作路径的直接 Cargo 路径依赖。
- [x] 已完成 crate 单测与文档级禁止迁入清单,Phase A 可视为关闭。
## 4. Phase Bbridge 入口与 Convex 桥接
完成目标:
-`mnote` 主仓内形成唯一 Rust command/query 入口。
- 首批读写入口从“前端 API 直接调 Convex”切到“前端 API -> Rust bridge -> Convex”。
当前起点(已确认):
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/content/route.ts` 当前直接 `query(api.documents.getContent)`
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/save/route.ts` 当前已改为构造稳定 envelope 后交给 `save-command-adapter` 执行。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/title/route.ts` 当前已不再直接拼 `mutation(api.documents.updateTitle)` 参数,改为构造稳定 envelope 后交给页面元信息 command adapter 执行。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/stats/route.ts` 当前已不再直接拼 `mutation(api.documents.updateStats)` 参数,改为构造稳定 envelope 后交给页面元信息 command adapter 执行。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/sidebar/route.ts` 当前直接聚合多个 Convex query 结果。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/blocks/patch/route.ts` 当前直接读取文档内容、替换 block 树后回写 Convex。
Checklist
- [x] 已在 `wolai-frontend/src/lib/documents/bridge.ts` 固定当前 bridge 入口,先由主仓 API route 统一走同一层包装。
- [x] 已固定首批 bridge envelope`request_id``trace_id``workspace_id``actor``source``idempotency_key`
- [x] 约定所有新命令和查询都先进入 `core-protocol` envelope,再转给 `storage-convex-bridge`
- [x] 已把 `documents/content``sidebar` 两条低风险读链接入当前 bridge query 包装层。
- [x] 已把 `documents/title``documents/stats``documents/save``blocks/patch` 接入当前 bridge command 包装层。
- [x] 已为 `documents/title``documents/stats` 收口稳定的页面元信息 command adapter,冻结 route 到 Convex 之间的 payload/target/meta 映射,避免 route 继续直接耦合 `updateTitle/updateStats` 的参数细节。
- [x] 已为首批 4 条写链固定当前 `bridge -> Convex` 的函数名、payload 结构和 workspace scope;其中 `documents.title``documents.stats``documents.options``documents.save` 已先收口到 `buildDocumentBridgeMutationRequest` 这层最小运行时接缝,统一构造与 `storage-convex-bridge::build_write_request` 对齐的 `functionName/payloadJson/args`,再由同一执行器落到 Convex`blocks.patch` 仍未收口到该执行层,且整条链尚未直接切到 Rust crate 内统一执行。
- [x] 已在 `wolai-frontend/convex/schema.ts` 新增 `command_logs``domain_events` 两张表,并新增 `wolai-frontend/convex/bridgeLogs.ts``src/lib/documents/bridge-log.ts` 承接首批写链日志落账。
- [x] 首批 4 条写链(`documents/title``documents/stats``documents/save``blocks/patch`)当前会在成功路径同时写入 command log 与 domain event;失败态、回滚态和统一事务性仍待后续补齐。
- [x] 当前已接入的查询链(`documents/content``sidebar`)保持只读,不产生写副作用。
- [x] 已统一 `documents/content``documents/save``documents/title``documents/stats``sidebar` 的首批 bridge 错误返回结构。
- [x] 当前 bridge 仅负责协议校验、请求映射与响应元信息包装,尚未吞并产品 UI 逻辑。
2026-04-14 B 阶段补记:已在 `rust/crates/core-protocol` 中补齐 `documents.meta.get``documents.content.get``sidebar.dataset.list``documents.save``blocks.patch` 的最小 query/command 协议对象,并在 `rust/crates/storage-convex-bridge` 中补齐对应的 query/command name -> Convex function 映射与单测。当前主仓新增链路已统一先构建稳定 envelope,再由后续真实 Rust bridge 执行链消费;本轮已通过 `cargo test -p core-protocol -p storage-convex-bridge``cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml` 验证协议与映射闭环。
2026-04-14 B 阶段第三刀补记:已在 `wolai-frontend/src/lib/documents/bridge.ts` 新增 `buildDocumentBridgeMutationRequest` 与统一执行器,把 `documents.title.update``documents.stats.update``documents.options.update``documents.save` 进一步推进到最小可运行的 Rust bridge 风格接缝。当前这些写链会先生成与 `storage-convex-bridge::build_write_request` 对齐的 `functionName/payloadJson/args` 运行时对象,再由适配层调用 Convex mutation;配套 `src/lib/documents/bridge.test.ts` 已新增 request builder 断言,确认标题更新与正文保存两条链的运行时 request 形状稳定。
Phase B 验收:
- [x] 当前至少已有 2 条查询链(`documents/content``sidebar`)和 4 条写链(`documents/title``documents/stats``documents/save``blocks/patch`)通过当前 bridge 包装层读写 Convex。
- [x] 已补 `/api/bridge/trace``/api/bridge/request` 回查入口,并已切到 `wolai-frontend/convex/bridgeLogs.ts` 查询主线;`convex/audit.ts` 当前保留为并行旧实现线,不作为本轮回查入口。
- [x] 当前已接入的请求错误结构已统一到 bridge 错误响应,不再直接抛出临时调试字符串。
- [x] 本批改动只改 API route 与调用 payload,未改页面结构与 UI 外观。
建议验证:
- [x] `cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml`
- [x] 已对 `/api/documents/content``/api/sidebar` 做最小读链 smoke:当前主仓实例固定为 `http://127.0.0.1:3001``/api/sidebar` 已返回 `activeWorkspaceId=ws-smoke-temp`,新建文档后 `/api/documents/content` 可正常返回内容与 `requestId/traceId`
- [x] 已对 `/api/documents/title``/api/documents/stats``/api/documents/save``/api/blocks/patch` 做最小写链 smoke:真实写入成功,且随后 `/api/documents/content` 已读回 `blocks.patch` 改写后的正文。
- [x] 已完成真实 Convex 运行前置验证:`infra/convex/docker-compose.yml` 可启动本地自托管 Convex`pnpm exec convex dev --once --tail-logs disable --env-file ../.env.all --run ping:ping` 已通过。
- [x] 已用真实 Convex CLI 对 `bridgeLogs:recordCommandLog``bridgeLogs:recordDomainEvent``bridgeLogs:listByTrace``bridgeLogs:listByRequest` 做最小 smoke,确认 command log、domain event、trace/request 字段能同时落账并回查。
- [x] 已完成网页/API 级 smoke:从真实 `/api/documents/title``/api/documents/stats``/api/documents/save``/api/blocks/patch` 返回的 `requestId/traceId`,可继续经 `/api/bridge/trace``/api/bridge/request` 回查到对应 `command_logs/domain_events`。本轮同时修复 `src/lib/documents/bridge-log.ts``getAuthedConvexClient()` 返回值解构错误(此前会导致写链落账时报 `client.mutation is not a function`)。
## 5. Phase C:页面元信息、Sidebar 与正文保存接入
完成目标:
- 在不更换主前端壳的前提下,把文档元信息、Sidebar 聚合、BlockNote 正文保存逐步切到 Rust 协议层。
- 执行顺序严格按 `C1 页面元信息 -> C2 Sidebar 聚合 -> C3 正文保存` 推进,不跳步。
### C1 页面元信息
- [x] 已盘点并锁定文档页元信息读写边界:`src/app/(app)/documents/[id]/page.tsx` 负责元信息入口,`document-content.tsx` 负责标题/页面选项/统计信息写入,`document-shell.tsx` 仅继续透传既有 UI 壳参数。
- [x] 已锁定并接入当前 C1 最小读链:`src/app/(app)/documents/[id]/page.tsx` 原先直调 `api.documents.getMeta`,现已改为经 `GET /api/documents/meta` 进入现有 bridge query 包装层;新增的服务端 helper 仅负责透传当前请求认证/追踪头并发起同源 bridge route 请求。
- [x] 已把标题更新、页面属性、页面选项、统计信息这批低风险页面元信息操作切到统一的当前协议/适配边界:标题、统计信息、页面选项 3 条写链都已接入当前 bridge command 包装层;其中 `documents.title.update``documents.stats.update``documents.options.update` 已统一收口到 `wolai-frontend/src/lib/documents/metadata-command-adapter.ts`route 只保留 validation、`buildDocumentBridgeContext``buildDocumentCommandEnvelope` 与稳定错误模型。`documents.options` 本轮不再内联 `client.mutation(api.documents.updateOptions, ...)`。同时已补齐 `rust/crates/core-protocol``UpdatePageTitle``UpdatePageStats``UpdatePageOptions` 结构与 `storage-convex-bridge` 的 command name -> Convex mutation 映射测试;2026-04-14 又进一步把这 3 条写链切到 `buildDocumentBridgeMutationRequest`,先构造与 Rust `ConvexMutationRequest` 对齐的最小运行时 request,再交给统一执行器落到 Convex,为后续真实 Rust 执行链留出稳定接缝。
- [x] 当前最小替换已保持现有页面 UI、权限判断、动态导入结构不变:`DocumentShell` 入参、`readOnly/disableDownload/disableCopy` 计算、`notFound()` 分支与页面结构保持不变,仅将元信息读取入口切到 `documents.meta` bridge query。
- [x] 已统一页面元信息链当前口径:`documents.meta` 读链与 `documents.title/stats/options` 写链均复用 `buildDocumentBridgeContext` / envelopequery payload 与 command payload 已固定 `documentId/workspaceId`target.pageId 固定文档 business id,回传元信息统一为 `requestId/traceId/queryName|commandId|commandName`actor/source 也统一来自 bridge context。
- [x] 已为标题更新、页面属性、统计信息补齐当前最小回归验证。
当前最小验证:已对页面选项写链补跑相关文件 eslint / vitest,并完成真实 HTTP smoke,确认在主仓 `http://127.0.0.1:3001` 实例下以 `ws-smoke-temp` 工作区调用 `POST /api/documents/options` 后,会返回 `requestId=req_aef4159e-24f2-43a8-b168-864c4b2b2c6c``traceId=trace_3cbc114e-db01-410f-933c-e63d8bd83393``commandId=cmd_2cb6871d-9075-4252-b698-a7c4ea069bfd`,且后续 `/api/bridge/request``/api/bridge/trace` 已能回查到对应 `command_logs/domain_events`。本轮同时保留 `documents.meta` 读链最小验证:真实 `GET /api/documents/meta?documentId=...&workspaceId=ws-smoke-temp` 已返回 `doc + meta.requestId/traceId/queryName=documents.meta.get`。另外 `documents/stats` 写链的真实 HTTP smoke 也已完成并可回查。2026-04-14 新增一轮真实复测:同一 `documentId` 连续执行 `POST /api/documents/options {showToc:true,layoutDensity:\"compact\"}``POST /api/documents/stats {wordCount:12,characterCount:34,blockCount:2,todoTotal:5,todoDone:3}` 后,紧跟 5 次 `GET /api/documents/meta` 均稳定返回本次写入值,未再复现“同次写入后 meta 读回不稳定”的现象。为避免历史脏数据导致偶发漂移,已把 `convex/documents.ts` 的关键 `by_document_id` 读写收口到 deterministic canonical record 选择逻辑,并补了重复 business id 的回归测试。
2026-04-14 第二批真实收口:已将仍直接依赖 `by_document_id.first()` 的高风险页面/文档关联路径继续切到同一 canonical document helper,当前已覆盖 `convex/documentShares.ts``convex/documentGroupShares.ts``convex/documentStars.ts``convex/comments.ts``convex/references.ts`。这批路径分别影响页面共享权限判定、群组公开、收藏可见性、评论线程读写与反链标题读取;此前若同一 business `documentId` 存在重复物理记录,会继续存在命中漂移风险。本轮已补跑目标文件 `eslint``src/lib/documents/document-record.test.ts`,并用源码扫描确认这批目标文件内已不再残留 `by_document_id.first()`;当前未继续扩到 `mediaAssets.ts``mindmaps.ts` 等非本批最小闭环路径。
2026-04-14 第三批真实收口:继续只处理剩余 still-high-risk 的 `documents.by_document_id` 直接命中点,已新增 `convex/_utils/documentRecord.ts#getCanonicalParentDocumentId`,并把 `convex/comments.ts``convex/documents.ts` 中共享/权限祖先链扫描统一改到该 helper,避免同一 business `documentId` 的重复物理记录在父链遍历时再次漂移。同时已把 `convex/mindmaps.ts` 的 owner 校验从 `by_document_id.first()` 切到 `requireCanonicalOwnedDocument`,并将 `convex/mediaAssets.ts#createWithStorage` 的页面归属校验改为 `getCanonicalDocumentByBusinessId`,以覆盖页面内容附件上传这一仍会直接命中旧记录的高风险入口。本批最小验证目标为:补充 canonical helper 单测、对上述目标文件跑 `eslint`,并再次用源码扫描确认 `comments/documents/mindmaps/mediaAssets` 内不再残留直接依赖 `documents.by_document_id` 的实现。
2026-04-14 第四批真实收口:按本轮 C1 要求只处理 `convex/documentStars.ts` 剩余两个父链祖先扫描点,已将 `resolveSharePermission``resolveGroupSharePermission` 中手写的 `documents.by_document_id` 父级推进统一改为 `getCanonicalParentDocumentId`。同时已补充 `src/lib/documents/document-record.test.ts` 的 helper 回归用例,验证重复 business `documentId` 下即使旧记录已删除,父链 helper 仍稳定返回 canonical 父页面 id;并已补跑目标文件 `eslint``vitest`。本轮源码扫描确认 `wolai-frontend/convex/` 业务路径中已不再残留直接 `withIndex(\"by_document_id\")` 命中点,当前仅剩 `convex/_utils/documentRecord.ts` 作为底层 canonical helper 持有该查询。
C1 验收:
- [x] 页面元信息至少已有 3 条低风险链路切入 Rust 层。
- [x] 文档页外观与交互未退化。
- [x] trace 字段已可回查到页面级写入:`documents.title.update``documents.stats.update``documents.options.update` 的真实 HTTP 写入均已返回 `requestId/traceId`,且后续 `/api/bridge/request``/api/bridge/trace` 已复核可查到对应 `command_logs/domain_events`
2026-04-14 C1 浏览器回归补记:已新增 `/mnt/Data1T/mnote/scripts/task019-document-ui-regression.js` 并在真实本地实例 `http://127.0.0.1:3001` 上执行。脚本会创建临时页面,确认 Sidebar 主导航与“私有 / 我的页面”分区可见、文档页标题输入框与 BlockNote 编辑区正常渲染,然后实际修改标题与正文,等待 `/api/documents/title``/api/documents/save` 成功返回并出现“已保存”,最后刷新页面确认标题与正文仍保留,再调用 `/api/documents/purge` 清理临时页面。实跑结果通过,说明本轮协议层切换后文档页主交互未退化。
### C2 Sidebar 聚合
- [x] 盘点 Sidebar 真实数据来源,锁定 `sidebar.tsx``private-tree.tsx``file-tree.tsx``use-convex-sidebar-data.ts``sidebar-tree.ts`
- [x] 先把 Sidebar 的查询聚合逻辑抽象成 Rust query 目标,避免继续在前端和 API 中重复拼树。
- [x] 为 Sidebar 建立最小查询契约,至少覆盖页面列表、层级关系、文件树行模型和展开状态所需字段。
- [x] 保留现有 Sidebar UI 和交互,不引入第二套导航壳,也不从 `mnote-rust` 复制 `sidebar.tsx` 覆盖现实现。
- [x] 把 Mindmap、表格、媒体等派生资源的聚合边界整理成后续 Rust query 可接入的明确目标。
2026-04-14 盘点补记:当前主入口已确认位于 `wolai-frontend/src/components/sidebar/sidebar.tsx`,私有树/文件树分别位于 `components/sidebar/private-tree.tsx``components/sidebar/file-tree.tsx`;数据侧同时存在 `/api/sidebar` 聚合 route、`hooks/use-convex-sidebar-data.ts` 实时订阅组装,以及 `lib/sidebar-tree.ts` 的树/section 构建逻辑,说明 C2 的真实起点是“API 聚合 + 前端二次拼装”的双层结构。
2026-04-14 契约补记:当前最小 Rust query 目标已明确为兼容 `SidebarInitialData` 的单查询返回,至少覆盖 `active_workspace_id``workspaces``documents``trashed_documents``media_assets``trashed_media_assets``mindmap_assets``trashed_mindmap_assets``table_assets``trashed_table_assets``mindmap_docs``mindmap_asset_children`,从而先替换聚合来源而不改 `buildDocumentTree/buildVisibleRows` 的前端渲染逻辑。
2026-04-14 边界补记:当前已明确必须保持不变的 UI/交互包括 `starred/public/shared/private/templates` 分区语义、`sort_order -> created_at` 排序口径、`doc/index.md/asset-folder/asset` 文件树行语义、拖拽/剪贴板协议,以及回收站双 tab 与资源计数行为;Mindmap、表格、媒体三类派生资源的聚合边界已被明确列为 Rust query 后续接入目标。
2026-04-14 C2 第一刀收口补记:已新增 `wolai-frontend/src/lib/sidebar-data.ts``wolai-frontend/src/lib/server/sidebar-data.ts`,把 `src/app/(app)/layout.tsx``src/app/api/sidebar/route.ts``src/hooks/use-convex-sidebar-data.ts` 之间重复的 `SidebarInitialData` 组装统一收口到共享 helper;同时修复 hook 链路中 `mindmapAssetChildren` 长期为空的漂移,补充 `src/lib/sidebar-data.test.ts`,并通过 `pnpm test src/lib/sidebar-data.test.ts src/lib/file-tree/rows.test.ts` 与定向 `eslint` 验证。基于本轮复核,当前已可确认“多个前端位置不再重复拼装同一棵树”这一验收点达成;但由于 SidebarInitialData 仍未冻结为明确 Rust query contract`C2` 其余验收项暂不提前勾选。
2026-04-14 C2 第二刀补记:已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/process/sidebar-rust-query-target.md`,把 `sidebar.dataset.list` 的最小 payload/result、Rust query 与前端投影职责边界、以及“不复制第二套导航壳/不直接输出前端渲染树”的约束固定成文档。当前可确认 Sidebar 查询聚合目标已经从“散落在 route 和 hook 中的实现细节”收口为明确的 Rust query 接入目标。
C2 验收:
- [x] Sidebar 至少一条主查询已经改由 Rust query 供给。
- [x] 文档树、文件树、回收站等视图语义保持一致。
- [x] 不再需要在多个前端位置重复拼装同一棵树。
2026-04-14 C2 第三刀补记:已新增 `wolai-frontend/convex/sidebar.ts`,把页面列表、回收站、Mindmap、媒体、表格等数据集收口成单个 `sidebar.datasetList` 主查询;`src/lib/server/sidebar-data.ts``src/hooks/use-convex-sidebar-data.ts` 均已切换为消费这条单查询返回,再通过既有 `SidebarInitialData` 投影层驱动 UI。配合 `src/lib/sidebar-data.test.ts` 的契约冻结、`src/lib/file-tree/rows.test.ts` 的文件树行语义验证,以及定向 `eslint`,当前可确认文档树、文件树、回收站双 tab 依旧沿用原有前端投影逻辑,没有因数据源切换而改变语义。
2026-04-15 C2 第四刀补记:`/api/sidebar` 现已从“先直跑 Convex helper,再额外挂 meta”推进为真实 Rust query transport。当前 route 会先执行 `buildDocumentQueryEnvelope(name=\"sidebar.dataset.list\") -> resolveRustBridgeQueryPlan -> executeRustBridgeQueryTransport`,再把 `sidebar:datasetList` 的结果投影回 `SidebarInitialData`;这意味着 Sidebar API 主链已经真正进入 Rust runtime/bridge,而不再只是挂一个 envelope 名字。
### C3 BlockNote 正文保存
- [x] 盘点正文保存链路,锁定 `blocknote-editor.tsx``schema.ts`、文档保存 API 当前入口。
- [x] 先把正文保存切成“前端快照采集”和“Rust command 提交”两个边界。
- [x] 为正文保存定义最小协议对象,至少包含 `page_id``workspace_id``revision``actor``source`、block 快照、冲突检测字段。
- [x] 先接入低风险保存模式,例如显式保存或节流保存,不先处理复杂协同细节。
- [x] 确保正文链与页面元信息链、Sidebar 链共用同一 identity 口径,不再出现多套 page id 映射。
C3 验收:
- [x] 正文保存至少一条正式链路已经通过 Rust command 回写 Convex。
- [x] 保存失败时可返回稳定错误模型。
- [x] 保存成功时可回查 command log、domain event 与 trace。
2026-04-14 C3 第一刀收口:已为 `documents.getContent` / `documents.save` 增加独立 `content_revision``content_conflict_key`,避免标题/统计信息更新污染正文 revision;`/api/documents/content` 现会透传 `revision/conflictDetectionKey``BlockNoteEditor` 会在自动保存时携带 `revision``conflictDetectionKey``snapshotCapturedAt``blockCount`,并在成功后刷新本地保存元数据。`save-command-adapter` 现把 Convex 冲突归一为 `409 REJECTED` bridge 错误,编辑器右上角也会展示保存失败信息。当前最小验证已补 `save-contract`/`bridge` 单测,并完成定向 eslint;结果为无 error,仅保留仓库既有 warnings。
2026-04-14 C3 第二刀补记:源码复核确认 `BlockNoteEditor` 当前通过 `useDebouncedCallback(saveContent, 800)` 以防抖自动保存作为最小低风险保存模式,没有把复杂协同状态直接并入正文写链;同时 `documents.meta/title/stats/options/save` 这些 route 都把同一个 `normalizedDocumentId` 作为 `target.pageId``documents.content/save` payload 也统一使用 `documentId/workspaceId``sidebar.dataset.list` 则以同一 `workspace_id` 作用域返回 `documents[].id` 作为页面业务 id,因此当前正文链、页面元信息链与 Sidebar 聚合链已不存在第二套 page id 映射口径。
2026-04-14 C3 第三刀补记:在此前真实 `/api/documents/save -> /api/bridge/request|trace` smoke 已确认可回查的基础上,本轮又补了 `src/lib/documents/bridge.test.ts` 的成功路径断言,明确 `executeSaveBridgeCommand` 在 revision/conflictDetectionKey 新协议下仍会调用 `recordBridgeCommandArtifacts`,并把同一 `requestId/traceId/commandId` 暴露给回查入口。因此当前“保存成功时可回查 command log、domain event 与 trace”已具备历史 HTTP smoke 与当前单测的双重闭环。
2026-04-14 C3 第四刀补记:`save-command-adapter` 已进一步切到与页面元信息链一致的最小运行时接缝。当前 `documents.save` 会先构造 `functionName=documents:updateContent``payloadJson``args` 组成的 bridge mutation request,再由统一执行器实际调用 Convex;这让正文保存不再长期停留在“adapter 内直接手写 `client.mutation(...)`”的临时态,同时保留现有冲突归一和落账逻辑不变。
2026-04-15 Phase 5 第一刀补记:`search.documents``search.recent` 已补齐到主仓 Rust query/runtime 主链。当前 `rust/crates/core-protocol` 新增 `SearchDocuments/SearchRecent``storage-convex-bridge``bridge-runtime` 已支持 query name -> Convex function 映射和运行时分发;`rust/crates/index-fts` 新增 `evaluate_search_documents`,负责标题/正文/思维导图/表格/附件的召回合并、排序、高亮 snippet 与 OCR 待补队列决策。`wolai-frontend/src/app/api/search/documents/route.ts` 现仅保留参数整理、原始数据装载与 HTTP 回传,不再持有 TS 侧的核心 ranking/snippet 逻辑;`/api/search/recent` 继续只承担最近访问写入 side-effect。
## 6. Phase DMindmap 与 OnlyOffice 边界接入
完成目标:
- 保留 `mnote` 当前成熟的 Mindmap 与 OnlyOffice 前端实现。
- 把数据边界、对象边界和回调边界逐步纳入 Rust adapter / protocol 规划,而不是复制第二套对象页壳。
Checklist
- [x] 锁定 Mindmap 当前主组件和嵌入链路,确认 `MindmapBlock.tsx` 同时服务 BlockNote 内嵌块与独立全屏页。
- [x] 盘点 Mindmap 数据入口,锁定 `mindmapLocalStore.ts``mindmapOps.ts``app/api/mindmap/**``app/mindmap/**`
- [x] 把 Mindmap 的前端交互状态与本体数据/ops 边界拆开,后者逐步映射到 Rust 协议层。
- [x] 明确 `mnote-rust/app/documents/[id]/mindmap/page.tsx` 等对象页壳不进入主仓主线。
- [x] 为 Mindmap 设计最小 adapter 目标,至少覆盖节点树、节点引用、节点操作日志和与 page/block 的绑定关系。
- [x] 锁定 OnlyOffice 当前页面和 API 边界,确认 `src/app/onlyoffice/``src/app/api/onlyoffice/**``src/components/onlyoffice/` 的职责分工。
- [x] 保留根目录 `src/components/onlyoffice/` 的静态资源、插件和数据目录,不做误删、不做迁移式替换。
- [x] 把 OnlyOffice 的对象解析、签名、callback、forcesave、代理请求边界整理成 Rust adapter 的明确目标。
- [x] 继续保持“正文只嵌文件入口,OnlyOffice 在独立页面运行”的产品形态。
- [x] 统一 Mindmap 与 OnlyOffice 的页面标识、附件标识、页面归属和追踪字段。
2026-04-14 Phase D 盘点补记:已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/mindmap-onlyoffice-boundary.md`,固定 `MindmapBlock.tsx` 与独立全屏页共用同一核心组件、`mindmapLocalStore.ts`/`mindmapOps.ts`/`app/api/mindmap/**` 的数据与 ops 边界,以及 OnlyOffice 的 `page -> client -> sign/proxy/callback/forcesave` 职责分层。文档同时明确 `MediaBlock` 仅作为 Office 附件入口、`/onlyoffice` 继续作为独立编辑页面,且历史仓中的对象页壳与第二套 sidebar 只保留为参考实现。
2026-04-14 Phase D 收口补记:已把 Mindmap API 与组件侧统一到与 OnlyOffice 对齐的业务标识口径。当前 Mindmap 统一使用 `pageId=documentId``attachmentId=mindmapId``workspaceId` 作为页面归属,并在 `/api/mindmap/**` 返回稳定的 `requestId/traceId` 元信息;OnlyOffice 继续使用 `documentId + assetId` 作为页面/附件标识,因此两条链后续接 Rust adapter 时不再需要第二套 page/attachment 映射。
2026-04-14 Phase D 浏览器回归补记:已新增 `/mnt/Data1T/mnote/scripts/task021-mindmap-ui-regression.js` 并在真实本地实例 `http://127.0.0.1:3001` 上执行。脚本使用当前共享的 `MindmapBlockView` 全屏入口 `/mindmap/[docId]/[mindmapId]`,验证页面 `data-page-id/data-document-id/data-attachment-id/data-mindmap-id/data-workspace-id` 元信息、工具栏与“大纲”侧栏渲染、子节点新增与删除后的持久化、以及 `/api/mindmap/**` 返回的 `requestId/traceId` 会同步回 DOM。考虑到内嵌块与独立页共用同一核心组件,这轮浏览器回归可视为覆盖当前共享交互/保存内核,实跑未见退化。
2026-04-15 Phase D OnlyOffice callback 收口补记:已为 `OnlyOffice callback` 新增最小命令 `media.assets.replace_storage`,同步补齐 `rust/crates/core-protocol``ReplaceMediaAssetStorage``rust/crates/storage-convex-bridge` 的 command name -> Convex mutation 映射,以及主仓 `buildDocumentBridgeMutationRequest` 的运行时接缝。`src/app/api/onlyoffice/callback/route.ts` 现保留下载文件、上传到 Convex Files 获得 `storageId` 的现有流程,但最终写回已改为经 `buildDocumentBridgeContextWithActor -> buildDocumentCommandEnvelope -> executeMediaAssetWritebackBridgeCommand` 进入统一 bridge 边界,再调用 `api.mediaAssets.replaceStorageFromUpload`。配套 `src/app/api/onlyoffice/callback/route.test.ts``src/lib/documents/bridge.test.ts`、Rust 单测与 `scripts/task022-onlyoffice-ui-regression.js` 已通过,确认 `storage_id` 在真实浏览器里继续发生变化。
Phase D 验收:
- [x] Mindmap 与 OnlyOffice 的前端界面仍以 `mnote` 当前实现为主,没有引入第二套主壳。
- [x] Mindmap 的节点/操作边界与 OnlyOffice 的签名/callback/forcesave 边界都已进入统一规划。
- [x] `src/components/onlyoffice/` 保持可用且未被误删。
- [x] `adapter-onlyoffice``adapter-mindmap` 仍作为后置实现项,而不是本阶段强行复制进主线。
## 7. Phase E:历史收口与单仓执行统一
完成目标:
- `mnote-rust` 正式退出主产品角色。
- `mnote` 主仓成为唯一启动、保存、规划和验证入口。
Checklist
- [x] 统一团队口径:主产品仓只有 `/mnt/Data1T/mnote``/mnt/Data1T/mnote-rust` 只保留为历史参考和资产来源。
- [x] 把所有新的设计、执行清单、架构说明优先写入 `/mnt/Data1T/mnote/design/``/mnt/Data1T/mnote/rust/design/`
- [x] 复查仓库脚本和说明文档,去掉“先进 `mnote-rust` 再启动”的旧叙事。
- [x] 统一根目录脚本入口,让仓库级脚本只从 `/mnt/Data1T/mnote/scripts/` 发起,再按需调用 `cargo --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml ...`
- [x] 对仍需保留的 `mnote-rust` 资料按“核心规范 / 历史阶段 / 参考实现 / 错误方向”分类,避免后续误复制。
- [x] 把已确认不应主线保留的对象页壳、diagnostics 页、smoke 页继续留在历史仓,不进入主仓实现。
- [x] 对主仓内新增的 Rust 目录建立最小维护约定,明确谁负责 workspace、谁负责 bridge、谁负责接入链。
- [x] 重新审查 `ARCHITECTURE.md``AGENTS.md``rust-kernel-backport-plan.md` 与本 checklist,保证四者口径一致。
- [x] 固定“哪些目录默认不动”的硬边界,特别是 `wolai-frontend/``wolai-backend/``infra/convex/``src/components/onlyoffice/`
Phase E 验收:
- [x] 后续协作默认只进入 `mnote` 主仓规划和开发。
- [x] 主仓文档和脚本不再把 `mnote-rust` 叙述为主执行入口。
- [x] 历史仓的保留范围、参考价值和禁止误复制范围都已固定下来。
2026-04-14 Phase E 收口补记:已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-single-repo-maintenance-boundary.md`,统一记录主仓执行入口、历史仓资料分类、禁止误复制清单与 workspace/bridge/接入链责任面;同时已复查根 `package.json``scripts/desktop-hot.js`,确认仓库级脚本仍只从 `/mnt/Data1T/mnote/scripts/` 发起,且 `ARCHITECTURE.md` 已移除把 `mnote-rust` 写成未来执行承载面的表述。
## 8. 发布前总审计(跨阶段)
- [x]`/mnt/Data1T/mnote/rust/` 补基础验证矩阵,至少覆盖 `cargo metadata``cargo check`、必要 crate 单测。
- [x] 为 bridge 入口补集成 smoke,验证最小查询、最小写入、日志生成、事件生成和错误返回。
- [x] 为文档页元信息、Sidebar、BlockNote 保存链补端到端回归,确认 UI 未因为协议层切换而退化。
- [x] 为 Mindmap 补交互回归,重点验证内嵌块、独立页、数据保存、节点操作和工具栏/侧栏行为。
- [x] 为 OnlyOffice 补回归,重点验证签名、代理、callback、forcesave、文档打开和静态资源可用性。
- [x] 检查主仓启动路径,确保开发者只需进入 `/mnt/Data1T/mnote` 就能完成前端、后端、Rust、OnlyOffice 相关联调。
- [x] 检查保存口径,确认页面、块、文档、索引的最终真相仍然落在 Convex,而不是被临时缓存目录劫持。
- [x] 检查 `trace_id``request_id``workspace_id``page_id` 在前端、bridge、Convex、日志中的一致性。
- [x] 对本次回迁引入的所有新目录和新文档做一次清点,确认没有误带入 `mnote-rust` 的历史噪音。
- [x] 为统一观测面补正式 Rust 能力面,至少包含 `bridge_request_get``bridge_trace_get``bridge_command_get``event_replay``index_rebuild` 这组 query/job/tool,并确认 Web 回查入口不再私有直连。
2026-04-14 发布前审计补记:已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-backport-audit-inventory.md`,清点主仓 `rust/` 已并入的 workspace/crates/设计文档、本轮新增的根 `design/` 文档,以及当前仍未并入主线的 `adapter-*``mnote-cli``bridge/scripts/fixtures/tests` 目录。文档同时核对了 `package.json``scripts/desktop-hot.js``AGENTS.md` 的主仓启动口径,确认开发者只需进入 `/mnt/Data1T/mnote` 即可找到前端、后端、Rust 与 OnlyOffice 的联调入口。
- 2026-04-15 task-034 补记:已在 `rust/crates/core-protocol` 增补 `GetBridgeRequest/GetBridgeTrace/GetBridgeCommand` 以及 `bridge_request_get``bridge_trace_get``bridge_command_get``event_replay``index_rebuild` 五个统一观测/恢复工具;`rust/crates/storage-convex-bridge` 已补 query name -> Convex `bridgeLogs:*` 映射;`rust/crates/bridge-runtime` 已支持这组 query/job 的 plan/result 输出,并把 `index-fts::rebuild_from_events` 暴露为正式 `index_rebuild` 恢复入口。前端 `/api/bridge/request``/api/bridge/trace` 已切到 `buildDocumentQueryEnvelope -> resolveRustBridgeQueryPlan -> executeRustBridgeQueryTransport` 主链,同时支持按 `commandId` 过滤与统一排序返回;`src/lib/documents/bridge-log.ts` 也已把命令日志/领域事件状态显式化,为后续失败态、冲突态与补偿落账提供稳定边界。配套验证已通过全量 `cargo test --manifest-path rust/Cargo.toml` 与 bridge 定向 eslint。
- 2026-04-15 OnlyOffice 升级与实跑补记:已把 `8082` 文档服务从旧仓 `mnote-rust/infra/onlyoffice/docker-compose.yml` 迁回当前主仓 `/mnt/Data1T/mnote/infra/onlyoffice/docker-compose.yml`,并升级到 `onlyoffice/documentserver:9.3.1`。同时修复了 `/onlyoffice/plugins/*` 被 middleware 重定向到 `/auth` 导致自定义插件桥无法 ready 的问题,为 `wolai-frontend/public/onlyoffice/plugins/agent-tools/` 补齐非可视插件配置与 `plugins.js` 加载。最终 `scripts/task022-onlyoffice-ui-regression.js` 已在真实浏览器中通过,覆盖文档打开、`oo_insert_text` 插件调用、`同步保存`、callback 写回以及 `storage_id` 刷新变化闭环。
- 2026-04-15 OnlyOffice callback bridge 补记:本轮在复跑 `scripts/task022-onlyoffice-ui-regression.js` 前,曾因 `/auth` 快速登录触发 `POST /api/auth -> Could not find public function for 'auth:signIn'` 导致浏览器脚本卡在登录页;已通过 `cd /mnt/Data1T/mnote/wolai-frontend && pnpm exec convex dev --once --tail-logs disable --env-file ../.env.all --run ping:ping` 重新注册 Convex functions 后恢复。恢复后同一浏览器脚本再次通过,确认新接入的 `media.assets.replace_storage` bridge 命令没有破坏 OnlyOffice 打开、插件桥、forcesave、callback 与 `storage_id` 更新闭环。
- 2026-04-14 浏览器实跑补记:`task-019-document-ui-regression.js` 已在真实浏览器中覆盖“首页进入文档页 -> Sidebar 可见 -> 修改标题 -> 修改 BlockNote 正文 -> 等待保存成功 -> 刷新后仍保留”的最小闭环。运行前曾因本地 Convex 实例缺少 `workspaces:ensureDefaultWorkspace` 导致首页 `500`,本轮已通过 `pnpm exec convex dev --once --tail-logs disable --env-file ../.env.all --run ping:ping` 重新注册函数后恢复;最终浏览器脚本通过,且临时页面已清理。
- [x] 对以下禁止事项做最终复查:不双仓并行、不跨仓链接、不复制第二套产品前端壳、不把对象页壳/diagnostics/smoke 页带入主线、不散落多个 Rust 源码根。
- [x] 产出最终 cutover 文档,按能力域列清哪些 route 已仅剩 transport,哪些旧 TS 执行面必须继续迁移或后续删除。
- [ ] 以“单仓路径可启动、可保存、可验证、可继续演进”作为发布前收口标准。
2026-04-14 实跑记录:已重新执行 `cargo metadata --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml --format-version 1``cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml``cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-domain``cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-protocol``cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p storage-convex-bridge`,均通过;其中 `cargo metadata` 已再次确认 workspace members 固定为 `core-domain``core-protocol``event-log``storage-convex-bridge``index-fts` 五个 crate。
2026-04-14 源码审计补记:已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/release-readiness-source-audit.md`。该文档基于当前 route、adapter、Convex bridgeLogs 与定向测试,确认 bridge 入口已经覆盖最小查询/写入/日志/事件/错误返回闭环;确认正文、页面元信息、块补丁与 OnlyOffice 附件写回的最终真相仍然落在 Convex mutation;确认 `trace_id``request_id``workspace_id``page_id` 在 route、bridge、Convex 日志与回查入口之间使用统一口径;并完成“不双仓并行、不跨仓链接、不复制第二套前端壳、不把 diagnostics/smoke 页带入主线、不散落多个 Rust 源码根”的源码级复查。
2026-04-15 task-035 补记:已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-kernel-cutover-v1.md`,把主仓当前 TS 执行面按 `RUST_OWNER / TS_TRANSPORT_KEEP / TS_COMPAT_PENDING / TS_LEGACY_DELETE` 四类状态完成盘点。文档明确了页面、块、查询聚合、AI、Mindmap、OnlyOffice 的当前归属,也明确了 `documents/create-child``documents/embed``documents/empty-trash``documents/purge``documents/template``mindmap-trash/empty``mindmap-ai/**``ai-agent` 非 Rust 核心工具面属于 Phase 8 前必须继续处理的旧面;同时为“何时允许宣布 Rust 成为唯一业务执行平面”补齐了四组 gate。
2026-04-15 task-040/task-042/task-043/task-044 补记:AI 非 `doc_*` 核心工具中的 `search_web``image_read``slash_run` 已完成第一批 Rust Tool runtime cutover`ai-agent/run` 不再保留这些工具的 TS 真执行兜底;`bridge-log/runtime` 已补齐统一失败态、冲突态与补偿态的第一批状态闭环,并覆盖页面主写链与 AI/Mindmap 写链;同时已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-kernel-legacy-delete-list.md`,把 `documents/create-child``documents/embed``documents/empty-trash``documents/purge``documents/template``mindmap-trash/empty``builtins/**` 固定为第一批 `TS_LEGACY_DELETE`。至此 Phase 8 的文档口径已经允许在源码审计层面使用“Rust 已成为 mnote 的唯一业务执行平面;Web route 只保留 transport、auth、session、streaming、proxy 与 callback 壳”这句统一结论。