Files
mnote/design/old/10-review/done/05-tree.md
T
Agent Board b798f628ee chore: land tree view-state, vault, Pi module split, and repo hygiene
Persist PageTree expand state via control-plane view-state and align
chevron/DOM with restored expansion; keep Sidex-style shallow page-tree
scan and drop the unused recursive scanner that only added cargo noise.

Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi
into a module package, and retire Hermes/ACP/OpenHub recycle + root
harness evidence from the index while gitignoring recycle and local
diag dumps.

Archive superseded design/bugs docs under old/, point architecture at
ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor
regressions so the working tree can stay clean.
2026-07-21 05:13:05 +08:00

8.3 KiB
Raw Blame History

[recycle] 05 Tree 历史审查

执行状态:本文已归档到 design/old/10-review/done/,是 10-review 阶段的树域判断历史记录,不再作为待办清单直接执行。Resource Tree / File Tree / Page Tree 真源合同已由 /mnt/Data1T/mnote/design/04-tree-domain/done/4-24-resource-tree-filetree-pagetree-source-contract-checklist-v1.md 承接;主编辑区 Object Tab、mindmap object editor、index.md 隔离已由 /mnt/Data1T/mnote/design/05-editor-mainline/done/5-12-main-editor-object-tab-resource-alignment-checklist-v1.md 承接。后续只需按 06-execution-checklist-and-acceptance.md 保留 smoke 防回归。

结论 我基本同意你的方向,但要把“文件树为根源”说得更精确:不应让“文件树 UI 组件”成为真源,而应让 Rust kernel 中的 workspace resource tree / file tree projection 背后 的资源层级 成为页面、附件、mindmap、OnlyOffice 等对象的组织根源。页面树则是从这棵资源/对象树派生出的导航投影,类似快捷方式、收藏视图或文档视图。

对当前 bug 来说,最核心的规则应固定为:

  1. index.md 只代表页面正文,即 Page Aggregate body。
  2. mindmap 不是主编辑区正文替身,而是页面内某个 block 关联的 object / asset editor。
  3. 文件树点击 mindmap 应打开 mindmap object editor,不能被 index.md 吞掉,也不能用临时 mindmap-only bootstrap 覆盖真实页面正文。
  4. 页面树不应再持有独立结构真相,只显示“文档导航关系”;文件树显示“资源组织关系”。

主编辑区与插件 主编辑区应该是一个工作区 tab host,而不是只等于文档正文编辑器。index.md 是其中一种 tabmindmap、OnlyOffice、附件预览、代码附件都是其他 object tab/model。

Siyuan 这里值得借鉴:doc 和 asset 是不同 model/tabasset 打开不伪装成 doc 正文;插件、widgets、assets、.sy 文档也在存储层分开。mnote 也应采用类似原则:插件/附 件/mindmap 可以嵌入页面,但它们的持久化真源不能变成页面正文本身,只能通过 block-asset relation 被 Page Aggregate 引用。

文件树与页面树 我建议改成三层表述:

  • Resource Tree:长期 canonical 对象组织树,Rust kernel 持有语义,Convex 只是底层存储。
  • File TreeResource Tree 的主组织投影,展示页面文件夹、index.md、附件、mindmap、OnlyOffice、代码附件等。
  • Page Tree:面向阅读/导航的快捷投影,只显示页面关系,不拥有排序、父子、附件归属的最终真相。

这样你的“文件树为根源”可以落地,但不会和现有 tree-first graph kernel 冲突。更准确地说:文件树背后的 resource hierarchy 是根源,页面树是它的页面导航视图。

建议路线 短期先修当前 bug:保留 /mindmap/{doc}/{asset} 作为 object editor,但彻底隔离草稿 key、保存 command 和 Page Aggregate bodysmoke 必须真实网页验证“点击 mindmap、 编辑长中文、保存、切回 index.md、再打开 mindmap 内容仍在”。

中期做主编辑区 asset tabindex.md | mindmap.json | xxx.docx,每个 tab 有自己的 object identity 和保存命令。

长期补 resource projection / block-asset relation:文件树 row、页面内 mindmap block、mindmap projection 必须来自同一关系索引,而不是前端临时按路由拼。

推荐路线 我建议采用“分阶段收口 Resource Tree”的方案,不做一次性大重构。

可选方案有三种:

  • 只修 mindmap bug:最快,但会继续留下页面树/文件树真源分裂。
  • 分阶段建立 Resource Tree -> File Tree/Page Tree projection:最稳,能解决当前 bug,也能承接附件、OnlyOffice、插件对象。
  • 全量重写 tree/page/resource 模型:理论干净,但当前工作区和主链都很活跃,风险太高。

我推荐第二种。

阶段 0:冻结合同 历史建议曾是:先把 design/10-review/05-tree.md 升级为正式设计合同,后续移动或补一份到:

  • design/04-tree-domain/process/4-24-resource-tree-filetree-pagetree-source-contract-v1.md
  • 或 design/05-editor-mainline/process/5-11-main-editor-object-tab-resource-tree-alignment-v1.md

合同里固定四句话:

  • Resource Tree 是组织真源。
  • File Tree 是资源组织主投影。
  • Page Tree 是页面导航投影/快捷视图。
  • index.md、mindmap、OnlyOffice、附件是不同 object model,不能互相伪装。

阶段 1:先关闭当前 mindmap bug 目标:文件树 mindmap 仍可编辑保存,但不污染 index.md。

重点文件:

  • rust/crates/mnote-web/src/ssr/pages/layout.rs
  • rust/crates/mnote-web/src/routes/mindmap_shell.rs
  • rust/spikes/leptos-tiptap-spike/src/lib.rs
  • scripts/task169-mindmap-realtime-smoke.js

验收必须是真实浏览器链路:

  1. 从文件树点击 mindmap asset。
  2. 进入明确的 mindmap object editor。
  3. 输入长中文并保存。
  4. 切回同页 index.md,正文仍是 Page Aggregate body。
  5. 再打开 mindmap,刚才内容仍在。
  6. 确认没有用真实 documentId 写 standalone 草稿 key。

阶段 2:补 Resource Projection 协议 在 Rust 协议层明确资源节点和 block-asset 关系。

建议新增或扩展:

  • ResourceNode
  • ResourceKind: page | index | mindmap | attachment | onlyoffice | code
  • ObjectIdentity: { objectKind, documentId, blockId?, assetId? }
  • BlockAssetRelation: { documentId, blockId, assetId, assetKind }

落点优先看:

  • rust/crates/core-protocol/
  • rust/crates/bridge-runtime/
  • rust/crates/mnote-web/src/tree_shell/

这个阶段不要求立刻迁移所有数据,只要协议和 projection 能表达清楚。

阶段 3:让 File Tree 从 Resource Tree 派生 当前 file tree 已有 resourceMeta、assetKind、file_tree projection 基础。下一步是收口为:

  • 页面节点下面固定有 index.md
  • mindmap/附件/OnlyOffice 都是同一 Resource Tree 下的 child resource
  • 文件树 row 不再临时从多份前端数据拼出第二真相

同时保留 tree.asset.open,但它必须只表达 object open intent,不直接决定“把谁当正文”。

阶段 4Page Tree 降级为导航投影 Page Tree 不再拥有资源归属、附件归属、mindmap 归属。它只显示页面导航关系:

  • 页面标题
  • 页面层级
  • 快捷入口/收藏/最近打开这类导航语义

如果页面树需要显示某个资源状态,也只读 Resource Projection,不自己维护。

阶段 5:主编辑区变成 Object Tab Host 这是中期关键体验:

  • index.md tab:加载 Page Aggregate body。
  • mindmap.json tab:加载 mindmap projection/command。
  • xxx.docx tab:打开 OnlyOffice object editor。
  • attachment tab:预览/代码编辑/外部打开。

这样 mindmap 不会被 index.md 吞掉,也不会伪装成正文。

阶段 6:命令面统一 后续命令应逐步收口到:

  • tree.asset.attach
  • tree.asset.detach
  • tree.resource.rename
  • tree.resource.move
  • page.body.save
  • mindmap.command.apply

关键规则:改资源关系走 tree/resource command,改页面正文走 page command,改导图内容走 mindmap command。

落地入口

以上判断已落实到两个主线 done checklist

  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-24-resource-tree-filetree-pagetree-source-contract-checklist-v1.md 用于冻结 Resource Tree / File Tree / Page Tree 的真源合同和 projection / command 边界。
  • /mnt/Data1T/mnote/design/05-editor-mainline/done/5-12-main-editor-object-tab-resource-alignment-checklist-v1.md 用于落实主编辑区 Object Tab、mindmap object editor、草稿隔离和真实浏览器 smoke 验收。

执行顺序固定为:

  1. 先完成 4-24:协议、projection、command 边界必须能表达 index.md、mindmap、OnlyOffice、附件、代码附件的不同 object identity,并确认 Page Tree 只是页面导航投影。
  2. 再完成 5-12:主编辑区只消费 4-24 输出的 object identity / resourceMeta / open intent,先关闭 mindmap 污染 index.md 的 P0 bug,再推进 Object Tab Host。
  3. 验收以真实浏览器 smoke 为准,尤其是 scripts/task169-mindmap-realtime-smoke.js 覆盖“打开 mindmap、长中文编辑、保存、切页、回 index.md、再开 mindmap”的链路。