Files
mnote/design/04-tree-domain/done/4-35-convex-filetree-title-md-source-alignment-v1.md
T
lix-2026 f292c6710a feat: EditorRuntimeActor - 三层缓存/delta/事件架构
Phase A — EditorRuntimeActor 内存缓存层
- 新增 editor_actor.rs: EditorBlockDocument 内存态 + apply_command + load_or_init
- block.rs 四个写工具(replace/insert/delete/move)接入 actor 路径
- editor_actor feature flag(MNOTE_WEB_ENABLE_EDITOR_ACTOR=true 默认开启)
- bridge-runtime 三个核心函数公开化
- rust-toolchain: 1.89 → stable(修复 spike WASM 编译阻塞)

Phase B — 编辑器增量 delta channel
- BlockDelta/DeltaOperation 类型 + actor.build_block_delta()
- leptos-tiptap spike: mnote:editor:block-delta CustomEvent 监听 + JSON patch
- DocumentAiAgentPanel: 拦截 blockDelta → window dispatchEvent
- 工具响应含 blockDelta 字段供前端消费

Phase C — 事件 stream delta
- broadcast channel 在 AppState/actor/SSE 三层贯通
- tree_events SSE 端点发 block.delta 事件
- 旧客户端降级兼容

环境修复
- rustc recursion_limit = 1024(修复 Leptos SSR 类型深度溢出)
- run-convex-deploy.js(封装 Convex function 部署到本地后端 3210)

ref: design/07-ai/process/7-13-page-block-editor-runtime-actor-v1.md
2026-05-16 22:03:30 +08:00

12 KiB
Raw Blame History

4-35 [done] Convex File Tree 标题即 Markdown 文件名体系切换 v1

更新时间:2026-05-15

背景:

  • 用户反馈本地文件夹中新建页面会先显示 /mnt/Data1T/mnote/tmp/image copy 98.png,再转回 新页面.md
  • 用户判断这是在线文件夹与本地文件夹的冲突,后续希望“统一而不是继续局部修改”。
  • 目标倾向:不再采用 Convex page -> index.md 体系,而是采用直接 新页面.md 体系,文件名与标题相同;在线文件夹尽量向本地文件夹靠拢。

1. 决策问题

当前 convex_workspace 的 File Tree 长期以复合资源树表达页面:

page/document
  index.md
  mindmap asset
  attachment asset

local_folder 则天然以真实文件系统表达:

新页面.md
图片.png
子目录/

这两种形态同时存在时,UI、active row、rename、新建、外部 watcher、projection refresh 容易出现不一致。用户观察到的“先显示 tmp 图片路径,再转回新页面.md”就是这类冲突的症状之一:同一套 File Tree UI 里混入了本地路径资源、Convex 页面容器、index.md 伪文件和异步投影校准。

本设计稿用于冻结新的方向:后续 Convex File Tree 应逐步向本地文件夹模型靠拢,把页面在文件树中的默认表现改为直接的 Markdown 文件行,例如 新页面.md,而不是页面容器下的 index.md

2. 建议结论

建议新建一个设计文档,而不是只建 bug 修补。

原因:

  1. 这会改变 file_tree projection 合同,不只是修一个显示名称。
  2. 这会影响 ObjectIdentity、active row、rename/title sync、resource parent、trash、restore、search、open intent 和 smoke 期望。
  3. 现有 4-24 / 5-12 已把 index.md 作为 Page Aggregate body 的 object identity 收口到 done;如果要废弃或弱化该 UI 体系,必须有新的迁移设计覆盖旧口径,不能在代码里零散改。
  4. Convex 存储层仍然是 document record,不等于必须在 File Tree UI 中展示 index.md 伪文件。可以先改 projection / UI 语义,再决定是否迁移底层存储。

3. 范围

本设计只讨论 convex_workspace 在 File Tree 中的页面呈现与命令语义,不改变 local_folder 已有真实文件系统规则。

纳入范围:

  • Convex 页面在 File Tree 中显示为 {title}.md
  • 新建页面时直接出现 新页面.md,不先出现 page/index.md 或临时资源路径。
  • 重命名页面时,标题与文件名同源:新标题 对应 新标题.md
  • 点击 {title}.md 打开 Page Aggregate body。
  • mindmap、附件、OnlyOffice、代码附件继续作为同一页面下的资源对象,但不能再依赖可见的 index.md 子行作为锚点。
  • Active / reveal 以 {title}.md row 或明确 asset row 为准。

暂不纳入范围:

  • 立即迁移 Convex 底层 documents 表结构。
  • 自动双向同步 local folder 与 Convex。
  • Markdown 文件名与标题的所有非法字符、大小写、重名冲突最终规则;本稿先冻结方向,具体规则后续 checklist 补齐。

4. 新旧模型对比

旧模型:

新页面
  index.md
  mindmap-mindmap_xxx.json
  image.png

新目标模型:

新页面.md
  mindmap-mindmap_xxx.json
  image.png

解释:

  • 新页面.md 是页面正文对象的 File Tree row。
  • 该 row 的 object identity 可继续内部映射到 Page Aggregate body,但 UI 不再展示 index.md
  • 资源行仍然挂在页面正文对象下面,表达“属于该页面/正文 block 关联资源”。
  • Page Tree 仍可显示 新页面,不带 .md,作为页面导航 projection。

5. 关键合同变更

5.1 File Tree row

Convex 页面正文 row

  • rowKind=markdown_page 或沿用 index 但对 UI 隐藏 index.md 语义,需要后续冻结。
  • title="{pageTitle}.md"
  • objectIdentity="page:markdown:{documentId}" 或兼容映射到既有 page:index:{documentId},但对外不再暴露为 index.md
  • documentId 仍是 Convex document id。
  • resourceMeta.sourceKind="convex_workspace"

本地 .md row

  • 保持真实文件名。
  • objectIdentity 与本地 page identity 绑定,不以裸路径作为长期唯一 id。

5.2 Rename / title sync

Convex workspace 中:

  • 文件树重命名 新标题.md 应写入页面标题 新标题
  • 页面标题编辑应能同步更新 File Tree 行显示为 新标题.md
  • .md 扩展名是 projection/UI 层文件语义,不应直接写进页面标题。
  • 重名冲突必须返回结构化 preflight,不允许静默覆盖或临时跳成其它资源路径。

Local folder 中:

  • 继续以真实文件名为主,标题优先级仍按现有本地 Markdown 规则处理。

5.3 Create

Convex workspace 新建页面:

  • 命令结果中应直接携带最终 File Tree row identity 与 title="新页面.md"
  • UI 乐观插入时不得先显示本地 tmp 路径、上传文件名或 index.md fallback。
  • 如果后端 title 去重为 新页面 2,前端最终只校准成 新页面 2.md,中间不出现无关资源名。

5.4 Resource parent

mindmap / attachment 等资源仍挂在页面正文对象下,但 parent row 从旧 index:{documentId} 或 page container 迁移到新的 markdown page row。

需要特别验证:

  • 点击 mindmap asset 后 active row 不跳回 {title}.md,除非确实打开的是页面正文。
  • 删除 {title}.md 进入页面垃圾箱;删除资源进入资源垃圾箱。
  • purge 页面时 Convex document 与其资源关系按正式命令同步清理或标记孤儿处理。

6. 与既有设计的覆盖关系

本稿不否定 4-24 / 5-12 的单一真源目标,只调整 File Tree 的可见模型:

  • 仍然保留 Page Aggregate body 是页面正文真源。
  • 仍然保留 mindmap / attachment / OnlyOffice 是独立 resource object。
  • 仍然要求 object identity 隔离,避免 mindmap 污染页面正文。
  • 变化是:Convex File Tree 不再必须通过可见 index.md 行表达页面正文对象。

后续如执行本设计,必须同步更新以下旧口径:

  • design/04-tree-domain/done/4-24-resource-tree-filetree-pagetree-source-contract-checklist-v1.md 中“页面节点下固定派生 index.md row”的可见 UI 表达。
  • design/05-editor-mainline/done/5-12-main-editor-object-tab-resource-alignment-checklist-v1.mdindex.md tab 的命名口径,可迁移为 markdown page tab{title}.md tab
  • design/10-review/done/05-tree.md 作为历史记录不直接改写,但 README 或新设计需说明其 index.md 口径已被本稿覆盖。

7. 建议实施阶段

P0:只改 Convex File Tree projection 的页面正文显示

  • 新建页面后 File Tree 直接出现 {title}.md
  • 点击 {title}.md 打开 Page Aggregate body。
  • Page Tree 仍显示无扩展名标题。
  • 保持底层 object identity 兼容,减少一次性改动。

P1Active / reveal / object identity 迁移

  • active page body 映射到 {title}.md row。
  • mindmap asset 打开后保持 asset active,不降级为页面正文 row。
  • 长列表 reveal 稳定。

P2Rename / create / conflict preflight

  • 文件树 rename {title}.md 与页面标题同步。
  • 新建同名页面明确生成 新页面 2.md 或返回冲突选择。
  • 不再出现临时 tmp 路径或资源文件名作为页面 row title。

P3:旧 index.md UI 退场

  • 默认 Convex File Tree 不显示 index.md
  • 如仍需 debug,可通过显式 debug/projection inspector 展示旧 identity。
  • 更新 smoke 和设计口径,避免后续继续围绕 index.md 修补 UI。

8. 验收标准

  • 在 Convex workspace 新建页面后,File Tree 首次可见 row 就是 新页面.md 或去重后的 {title}.md,不得短暂显示 /tmp/...、图片文件名、index.md 或其它 fallback。
  • 点击 {title}.md 打开页面正文;点击 mindmap asset 打开 mindmap object editor,二者 active row 不互相覆盖。
  • 页面标题编辑与 File Tree rename 最终保持一致:标题 ABC 对应 File Tree ABC.md
  • 同名冲突、非法字符、扩展名输入等情况有结构化 preflight 和可预测结果。
  • Local folder 与 Convex workspace 共用同一 File Tree UI 组件、selection/focus/reveal/context menu/keyboard 行为;差异只来自 source capability 与 executor。
  • 真实浏览器 smoke 覆盖:新建页面、重命名、点击页面正文、点击 mindmap、滚动下半部分点击、删除进垃圾箱、restore 后 reveal。

9. 当前状态

当前状态:done

本文已从 process/ 迁入 done/。Convex File Tree 默认可见页面正文行当前以 doc:<documentId> + {title}.md 为准;旧设计稿中的可见 index.md 仅作为历史 object identity / 兼容语义理解,不再作为默认 UI 模型继续派生新任务。

2026-05-15 已完成 P0/P1/P2 的最小切片:

  • bridge-runtime 的 Convex file_tree projection 不再为页面正文派生可见 index.md row。
  • Convex 页面正文 row 继续使用 rowKind=document / rowId=doc:<documentId>,但标题改为 {pageTitle}.md
  • mindmap / attachment / table 等资源继续挂在 doc:<documentId> 下。
  • 3000 主文档壳本地 create apply 同步改为只插入 doc:<documentId>,标题显示为 {title}.md,不再插入 index:<documentId>
  • File Tree 当前页面 selected / focused 默认改为 doc:<documentId>
  • task169 的“回到页面正文”验证从点击 index:<documentId> 改为点击 doc:<documentId>object identity 仍为 page
  • File Tree inline rename 对页面正文 row 输入 {title}.md 时,提交给 tree.node.rename 前会剥离 .md,页面标题保持 {title}File Tree 显示保持 {title}.md
  • File Tree inline rename 已加入主壳内校验:空名、非法文件名字符、同级同名页面会停留在输入框内并显示结构化提示,不提交 rename command。

已通过验证:

cargo test --manifest-path rust/Cargo.toml -p bridge-runtime file_tree_projection -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web file_tree_projection -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web sidebar_filetree_runtime_uses_markdown_page_row_without_local_index_child -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_shell_filetree_renderer_outputs_initial_nested_html_contract -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web sidebar_tree_runtime -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_shell -- --nocapture
MNOTE_UI_BASE_URL=http://127.0.0.1:3428 node scripts/task426-mnote-web-main-no-reload-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3428 node scripts/task438-filetree-title-md-active-reveal-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3428 node scripts/task439-filetree-title-md-rename-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3428 node scripts/task440-page-title-filetree-md-sync-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3428 node scripts/task169-mindmap-realtime-smoke.js

真实浏览器结果文件:

  • tmp/task426-mnote-web-main-no-reload-smoke/result.json
  • tmp/task438-filetree-title-md-active-reveal-smoke/result.json
  • tmp/task439-filetree-title-md-rename-smoke/result.json
  • tmp/task440-page-title-filetree-md-sync-smoke/result.json
  • tmp/task169-mindmap-realtime-smoke/result.json

本轮 P3 收口:

  • 页面标题编辑反向同步到 File Tree {title}.md 已由真实浏览器 smoke scripts/task440-page-title-filetree-md-sync-smoke.js 覆盖:标题栏输入 {title} 后,File Tree 显示 {title}.md,Page Tree 与标题输入框保持 {title},且不出现 index:<documentId> 行。
  • tree_shell/filetree_renderer.rs 的默认 nested fixture 已从可见 index.md 子行改为页面 markdown row 下挂 mindmap assetrowKind=index 仍只作为历史 projection / 命令兼容解析保留,不再作为默认 Convex File Tree UI 口径。
  • 旧设计中的“可见 index.md”表述由本稿覆盖:后续 UI / smoke / review 应以 doc:<documentId> + {title}.md 作为 Convex 页面正文 row;如果文档讨论历史 index.md,必须明确它是兼容身份或历史记录,不是默认可见行。

仍保留的后续增强:

  • 删除进垃圾箱、restore 后 reveal、双浏览器 resync、搜索过滤下 reveal 等更宽场景继续由 4-284-34 与后续 tree domain checklist 覆盖。