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

238 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 长期以复合资源树表达页面:
```text
page/document
index.md
mindmap asset
attachment asset
```
`local_folder` 则天然以真实文件系统表达:
```text
新页面.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. 新旧模型对比
旧模型:
```text
新页面
index.md
mindmap-mindmap_xxx.json
image.png
```
新目标模型:
```text
新页面.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.md``index.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。
已通过验证:
```bash
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 asset`rowKind=index` 仍只作为历史 projection / 命令兼容解析保留,不再作为默认 Convex File Tree UI 口径。
- 旧设计中的“可见 `index.md`”表述由本稿覆盖:后续 UI / smoke / review 应以 `doc:<documentId>` + `{title}.md` 作为 Convex 页面正文 row;如果文档讨论历史 `index.md`,必须明确它是兼容身份或历史记录,不是默认可见行。
仍保留的后续增强:
- 删除进垃圾箱、restore 后 reveal、双浏览器 resync、搜索过滤下 reveal 等更宽场景继续由 `4-28``4-34` 与后续 tree domain checklist 覆盖。