Files
mnote/design/01-tree-first-graph-kernel/process/1-7-local-workspace-root-page-bundle-checklist-v1.md
T
lix-2026 b4c8bcb647 收口本地工作区清理与资源投影
清理历史 Electron、Graphify、沙箱和截图等仓库跟踪残留,补充 CodeGraph 与 Convex active deploy source 协作说明。

新增 tree-first 下一阶段设计稿和 2026-05-20 清理总结,记录本地工作区、路径身份和 Zed/Lapce/VSCode 参考收口方向。

扩展 Rust Web 本地文件夹、DocumentBuffer、mindmap 资源、tree runtime 和页面聚合链路,并补充 task455 local-folder mindmap clean smoke。

验证:git diff --check 通过;pnpm store status --store-dir .pnpm-store 通过;npm ls --depth=0 --json 通过;find -L node_modules 未发现断链。cargo test -p mnote-web 当前 418 passed / 35 failed。
2026-05-20 10:43:38 +08:00

259 lines
11 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.
# 1-7 Local Workspace Root Page Bundle Checklist v1
## 背景
当前默认本地工作区初始化会创建 `pages/``assets/``mindmaps/``ai-sessions/` 等顶层目录。这更像早期产品内部布局,不像用户真实打开的 VSCode 文件夹,也不利于页面导出。
本轮收口方向:
- 默认工作区只保留用户内容根目录和 `.mnote/` 系统目录。
- 页面树允许把 `页面.md + 页面/` 解释成一个页面节点与其子页面容器。
- 文件树必须真实展示文件系统,不合并、不隐藏同名 `.md` 和目录。
- 新建页面使用 `新页面HHMMSS` 命名,避免重复创建同名 `新页面.md`
- 新建页面时同时创建 `新页面HHMMSS.md``新页面HHMMSS/`
- 附件、思维导图等页面资源默认进入同名目录下,而不是顶层 `assets/` / `mindmaps/`
## 参考代码位置
- 当前默认工作区初始化:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
- `create_default_local_workspace_for_actor_at_base`
- `ensure_default_workspace_directories`
- `ensure_default_workspace_home_page`
- 当前本地页面创建:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
- `execute_local_tree_command`
- `create_local_markdown_page`
- 当前本地资源上传:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
- `write_local_markdown_asset`
- 当前文件树真实扫描:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
- `load_local_folder_file_tree_snapshot`
- `scan_directory`
- 当前页面树扫描:`rust/crates/mnote-web/src/routes/local_folder_source.rs`
- `load_local_folder_page_tree_snapshot`
- `scan_markdown_page_tree`
- 当前根入口默认初始化测试:`rust/crates/mnote-web/src/routes/gateway.rs`
- `root_entry_initializes_default_local_workspace_page`
- 当前上传 smoke`scripts/task443-local-markdown-asset-upload-smoke.js`
## 目标目录契约
### 默认初始化
默认工作区初始化后应该是:
```text
my-space/
.mnote/
workspace.json
trash/
初始化的新页面.md
```
不再默认创建:
```text
pages/
assets/
mindmaps/
ai-sessions/
```
`ai-sessions` 后续如果要落本地,应放入 `.mnote/ai-sessions/`,本轮只禁止默认创建顶层 `ai-sessions/`
### 新建页面
在父目录下新建页面时,默认标题若为 `新页面`,真实落盘应为:
```text
新页面HHMMSS.md
新页面HHMMSS/
```
例如:
```text
新页面061240.md
新页面061240/
```
要求:
- `HHMMSS` 使用本地时间或现有时间工具生成,精确到秒。
- 即使有时间戳,也必须做磁盘冲突检查;同秒冲突时使用 `-2``-3` 追加。
- `documentId` 仍使用路径型 `local-md:<relative_path>`
- `.md` 正文标题应使用最终安全标题,例如 `# 新页面061240`
### 页面树和文件树边界
- 页面树:允许把 `X.md` 与同目录 `X/` 解释为一个页面 `X`,并把 `X/` 内 Markdown 作为页面 `X` 的子页面。
- 文件树:必须真实展示 `X.md``X/` 两个磁盘条目。不得把二者合并为一个节点。
### 页面资源
`X.md` 上传附件或图片时,默认写入:
```text
X/assets/<file>
```
对 mindmap,后续默认写入:
```text
X/mindmaps/<file>
```
本轮先完成 `write_local_markdown_asset` 的附件/图片路径迁移。正文链接相对 `X.md` 应为:
```markdown
![](X/assets/photo.png)
[spec.pdf](X/assets/spec.pdf)
```
## 顺序执行 Checklist
### A0 基线保护
- [x] 记录当前 `git status --short`,不要清理与本任务无关的脏改动。
- [x] 运行当前相关定向测试,确认改前基线:
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web create_default_local_workspace_uses_managed_data_root -- --nocapture`
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_asset_upload_copies_next_to_markdown_with_relative_path -- --nocapture`
验收:
- [x] 基线通过。两项测试均 ok。
### A1 默认工作区目录最小化
- [x] 修改 `ensure_default_workspace_directories`:默认只创建 `.mnote/trash`
- [x] 修改 `ensure_default_workspace_home_page`:初始化页改为 `root/初始化的新页面.md`,不再放入 `pages/`
- [x] 更新 `create_default_local_workspace_uses_managed_data_root`
- 断言 `初始化的新页面.md` 位于 root 下。
- 断言 `pages/``assets/``mindmaps/`、顶层 `ai-sessions/` 不存在。
- 保留 `.mnote/workspace.json``.mnote/trash` 断言。
- [x] 更新 `root_entry_initializes_default_local_workspace_page`
- 断言 root 下存在 `初始化的新页面.md`
- 不再断言 `pages/初始化的新页面.md`
验收:
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web create_default_local_workspace_uses_managed_data_root -- --nocapture` — ok
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web root_entry_initializes_default_local_workspace_page -- --nocapture` — ok
### A2 新建页面创建 `.md + 同名目录`
- [x] 新增 helper `determine_page_stem`
- 输入默认标题 `新页面` 输出 `新页面HHMMSS`(本地时间 HHMMSS,失败时回退 UTC)。
- 对非默认标题,仍使用用户标题的安全文件名。
- 对冲突同时检查 `<name>.md``<name>/`,追加 `-2``-3`
- [x] 修改 `create_local_markdown_page`
- 创建 `<name>.md`
- 同步创建 `<name>/`
- 返回的 `relativePath` 仍是 `<name>.md`
- 返回的 `documentId` 仍是 `local-md:<relative_path>`
- [x] 增加单测 `local_tree_command_create_page_creates_timestamped_markdown_and_sibling_folder`
- 执行 `execute_local_tree_command(..., "create", ..., Some("新页面"))`
- 断言产生 `新页面\d{6}.md` 和同名目录。
- 断言返回 `documentId` 指向 `.md`
验收:
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_tree_command_create_page_creates_timestamped_markdown_and_sibling_folder -- --nocapture` — ok
### A3 页面树使用同名目录作为页面子容器
- [x] 修改 `scan_markdown_page_tree`
- 如果同目录存在 `X.md``X/`,页面树只显示 `X.md` 对应的页面节点。
- `X/` 内的 Markdown 节点挂在 `X.md` 页面节点下。
- 没有同名 `.md` 的普通目录,如果包含 Markdown,继续作为 page group 显示。
- [x] 增加单测:
- 构造 `Root.md``Root/Child.md`
- 页面树断言 `Child.md``parent_node_id``Root.md``documentId`
- 页面树断言没有单独的 `local:page-group:Root` 行。
验收:
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_tree_uses_sibling_directory_as_page_children_container -- --nocapture` — ok
### A4 文件树保持真实
- [x] 确认 `scan_directory` 不做任何同名 `.md + folder` 合并。
- [x] 增加单测:
- 构造 `Root.md``Root/Child.md`
- 文件树断言同时存在 `Root.md` markdown 行和 `Root` folder 行。
验收:
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_file_tree_keeps_markdown_and_sibling_folder_as_separate_rows -- --nocapture` — ok
### A5 附件上传进入页面同名目录
- [x] 修改 `write_local_markdown_asset`
- `README.md` 的附件目录从 `README.assets/` 改为 `README/assets/`
- 返回的 `sourcePath` / `file_url` 相对 Markdown 文件目录,例如 `README/assets/photo.png`
- 保留重复文件名 `photo-1.png` 逻辑。
- [x] 更新单测 `local_markdown_asset_upload_copies_next_to_markdown_with_relative_path`
- [x] 更新 `scripts/task443-local-markdown-asset-upload-smoke.js` 中对 `README.assets/...` 的断言为 `README/assets/...`
- [x] 只改本地 local_folder 上传路径,不改 cloud / Convex media 路径。
验收:
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_asset_upload_copies_next_to_markdown_with_relative_path -- --nocapture` — ok
- [x] `node scripts/task443-local-markdown-asset-upload-smoke.js` — ok,证据:`tmp/task443-local-markdown-asset-upload-smoke/result.json`
### A6 重命名 bundle 规则最小收口
- [x] 检查 `rename_local_entry`
- 当重命名 `X.md` 且同目录存在 `X/` 时,同步重命名目录为新标题目录。
- 如果目标目录已存在,使用与文件一致的冲突策略或返回可解释错误,禁止覆盖。
- [x] 增加单测:
- `Old.md + Old/Child.md` 重命名为 `New`
- 断言 `New.md``New/Child.md` 存在。
- 页面树中 `Child.md` 仍挂在 `New.md` 下。
验收:
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_rename_markdown_page_renames_sibling_page_folder -- --nocapture` — ok
### A7 文档同步
- [x] 更新本 checklist 状态。
- [x] 本 checklist 已明确覆盖旧的默认顶层 `pages/assets/mindmaps/ai-sessions` 初始化结构;未大范围改旧 done 文档。
验收:
- [x] checklist 中已记录实际完成情况。
### A8 最终验证
- [x] `cargo fmt --check --all --manifest-path rust/Cargo.toml` — ok
- [x] `cargo check --manifest-path rust/Cargo.toml -p mnote-web` — ok
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web create_default_local_workspace_uses_managed_data_root -- --nocapture` — ok
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_tree_command_create_page_creates_timestamped_markdown_and_sibling_folder -- --nocapture` — ok
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_tree_uses_sibling_directory_as_page_children_container -- --nocapture` — ok
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_file_tree_keeps_markdown_and_sibling_folder_as_separate_rows -- --nocapture` — ok
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_asset_upload_copies_next_to_markdown_with_relative_path -- --nocapture` — ok
- [x] `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_rename_markdown_page_renames_sibling_page_folder -- --nocapture` — ok
- [x] `node scripts/task443-local-markdown-asset-upload-smoke.js` — ok
浏览器验收由 Codex 复核执行:
- [x] 使用临时 `MNOTE_LOCAL_WORKSPACE_BASE_DIR=/mnt/Data1T/mnote/tmp/page-bundle-data` 启动 `mnote-web`
- [x] 登录/注入测试 actor 后打开首页。
- [x] 截图保存到 `tmp/`
- `tmp/page-bundle-home-3003.png`
- `tmp/page-bundle-after-create-3003.png`
- `tmp/page-bundle-filetree-3003.png`
- [x] 检查磁盘:
- root 下有 `初始化的新页面.md`
- root 下没有默认 `pages/``assets/``mindmaps/`、顶层 `ai-sessions/`
- 新建页面后有 `新页面HHMMSS.md``新页面HHMMSS/`
- 文件树能看到 `.md` 与同名目录两个真实条目。
- 页面树把同名目录内子页面挂到 `.md` 页面下。
## 非目标
- 不迁移用户历史数据。
- 不删除正式 `/mnt/Data1T/Mnote_data/users` 下旧测试目录。
- 不实现完整 mindmap 新路径落盘;本轮只定义默认目标并完成附件/图片上传路径迁移。
- 不把文件树改成页面语义树。
- 不重新引入 `mnote_id` frontmatter。