# 3-10 [done] Rust Web 3000 Tree / Editor Runtime Integration Checklist v1

> 更新时间：2026-04-29

>

> 纠偏补充（2026-04-29）：用户复核发现此前“完成”口径只覆盖 API / 直达文档页 smoke，没有覆盖默认根页真实 UI 工作流。默认 `3000 /` 重新接入既有 Rust page tree / file tree renderer 与 UI 新建到 `leptos-tiptap` 的闭环，详见 `/mnt/Data1T/mnote/design/03-rust-web/done/3-11-rust-web-3000-existing-tree-editor-runtime-relink-checklist-v1.md`。

>

> 对应计划：

> - `/mnt/Data1T/mnote/design/03-rust-web/done/3-9-rust-web-3000-tree-editor-runtime-integration-plan-v1.md`

>

> 参考输入：

> - 当前 3000 截图：`/mnt/Data1T/mnote/tmp/image copy 32.png`

> - 当前 shell parity checklist：`/mnt/Data1T/mnote/design/03-rust-web/done/3-8-rust-web-3000-wolai-ui-parity-checklist-v1.md`

> - Page Aggregate 对齐主线：`/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`

## 1. 当前结论

当前已经完成的是：

- [x] `3000` 默认由 `mnote-web` 监听。

- [x] `3000` 根页已经有 Wolai 风格 workspace shell。

- [x] 根页包含左栏、顶栏、右下浮动按钮和 `data-mnote-shell="workspace"`。

[x] `/documents/:id` 已有 Rust Web document shell、Page Aggregate marker 和 `data-editor-host="leptos_tiptap_island"` marker。

当前没有完成的是：

- [x] 左栏 `我的页面` 显示真实 file/page tree rows，而不是空 section。

- [x] 根页正文不再使用设计稿静态链接列表作为伪主内容。

- [x] active page selection 能从 projection / recent / URL 一致落到 sidebar 和 document shell。

- [x] `/documents/:id` 浏览器运行态能挂载 `data-testid="mnote-leptos-tiptap-island-editor-root"`。

- [x] `.ProseMirror[contenteditable="true"]` 可见、可输入、可保存、reload 后可读回。

- [x] smoke 能区分“只有外壳 UI”与“真实树和编辑器已接入”。

一句话判断：

> **本轮已完成 tree/editor runtime parity 收口；3-8 作为 shell/UI parity 基线已迁入 done。**

## 2. 不可误判为完成的情况

- [x] 只看到 `data-testid="wolai-sidebar"`，不算页面树接入。

- [x] 只看到 `我的页面` 文案，不算真实树接入。

- [x] 只看到正文静态链接列表，不算 Page Aggregate 主内容接入。

- [x] 只看到 `data-editor-host="leptos_tiptap_island"`，不算 editor island 已 hydrate。

- [x] 只看到 `#mnote-editor-island` 空占位，不算主编辑区完成。

- [x] 只在 fixture gateway 下通过，不算当前真实 `3000` 主链完成。

## 3. Phase E-0：冻结真实树和编辑器失败用例

目标：让当前截图暴露的问题可以自动失败。

- [x] 新增 `scripts/task120-rust-web-tree-integration-smoke.js`。

- [x] `task120` 通过 `POST /api/tree/commands action=create` 创建临时根页面。

- [x] `task120` 创建临时子页面并记录 `workspaceId` / `documentId`。

- [x] `task120` 断言 `GET /` 或 `/documents/:id` 的左栏包含 `data-testid="wolai-sidebar-row"`。

- [x] `task120` 断言临时页面 row 的 `data-node-id` 等于真实 document id。

- [x] `task120` 断言 active row 有 `data-active="true"` 或等价稳定标记。

- [x] `task120` 点击 row 后能打开 Rust Web `/documents/:id`。

- [x] `task120` 用 `purge` 清理临时页面。

- [x] 新增 `scripts/task121-rust-web-editor-island-hydration-smoke.js`。

- [x] `task121` 断言 `data-testid="mnote-leptos-tiptap-island-editor-root"` 可见。

- [x] `task121` 断言 `.editor-surface .ProseMirror[contenteditable="true"]` 可见。

- [x] `task121` 输入唯一文本并触发保存。

- [x] `task121` reload 后仍能读回唯一文本。

- [x] `task121` 拉取 `/api/page-aggregate/:id` 后能读回保存内容或版本变化。

- [x] `task119` 增加负向断言，不能只靠 `.mnote-home-links` 静态列表通过。

验证命令：

```
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task120-rust-web-tree-integration-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task121-rust-web-editor-island-hydration-smoke.js
```

## 4. Phase E-1：workspace sidebar 接入真实 projection rows

目标：左栏 `我的页面` 不再是空 section，而是 projection 驱动的真实页面树。

- [x] `WorkspaceShellProjection.myPageItems` 来源于 `sidebar_tree` / `sidebar.dataset.list` / kernel projection。

- [x] `WorkspaceShellProjection.starredItems` 来源于真实 projection，不硬编码。

- [x] `render_workspace_shell_sidebar_html` 输出 `data-testid="wolai-sidebar-row"`。

- [x] 每个 row 输出 `data-node-id`。

- [x] 子页面 row 输出 `data-parent-id` 或等价层级标记。

- [x] active row 输出 `data-active="true"`。

- [x] 空 workspace 输出明确 empty state，不回到设计稿静态链接列表。

- [x] Cargo 测试覆盖 root/child/active/empty 四类输入。

验证命令：

```
cd /mnt/Data1T/mnote/rust
cargo test -p mnote-web workspace_shell
```

## 5. Phase E-2：根路径接入 active page / empty workspace

目标：`GET /` 选择真实 active page 或显示真实空 workspace，不再把设计稿静态首页当主编辑区。

- [x] `gateway.rs::root_entry` 选择顺序固定为 `pageId` > recent cookie > projection active > first page > empty workspace。

- [x] 有 active page 时，根路径渲染或跳转到真实 document shell。

- [x] 无 active page 时，根路径显示空 workspace state。

- [x] 根页不再输出 `.mnote-home-links` 静态设计稿列表作为主内容。

- [x] recent page cookie 与 document shell 打开行为一致。

- [x] Rust 测试覆盖 root selection 顺序。

- [x] `task118` / `task119` 仍通过。

验证命令：

```
cd /mnt/Data1T/mnote/rust
cargo test -p mnote-web root_entry
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task118-rust-web-wolai-ui-parity-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task119-rust-web-wolai-visual-regression-smoke.js
```

## 6. Phase E-3：document shell 接上真实 Page Aggregate 与 page tree

目标：文档页标题、页面树、正文 bootstrap 来自同一份 Page Aggregate / projection。

- [x] `/documents/:id` 标题来自 Page Aggregate `head.title`。

- [x] breadcrumb / topbar active title 与 Page Aggregate 标题一致。

- [x] 左栏 active row 与当前 document id 一致。

- [x] 页面内 page tree / subtree 使用 Page Aggregate `tree.pageSubtree` 或 kernel `page_tree` projection。

- [x] HTML 内嵌 `__MNOTE_PAGE_AGGREGATE__`。

- [x] HTML 内嵌 `__MNOTE_EDITOR_BOOTSTRAP__`。

- [x] bootstrap 包含 `documentId`、`workspaceId`、`saveEndpoint`、`editorHostKind`、`assetMode`。

- [x] 不从 URL 或静态 fallback 重新推导第二份页面真相。

验证命令：

```
cd /mnt/Data1T/mnote/rust
cargo test -p mnote-web document_shell page_aggregate
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task115-rust-web-document-shell-smoke.js
```

## 7. Phase E-4：挂载 `leptos-tiptap` island 并证明可编辑

目标：主编辑区不是 marker，而是浏览器内真实可编辑 runtime。

- [x] Rust document shell 输出稳定 mount root。

- [x] 前端 island adapter 能读取 `__MNOTE_PAGE_AGGREGATE__`。

- [x] 前端 island adapter 能读取 `__MNOTE_EDITOR_BOOTSTRAP__`。

- [x] `leptos_tiptap_island` 成为 active host。

- [x] 页面出现 `data-testid="mnote-leptos-tiptap-island-editor-root"`。

- [x] 页面出现 `.editor-surface .ProseMirror[contenteditable="true"]`。

- [x] `data-editor-host-active="leptos_tiptap_island"` 或等价 observability 可见。

- [x] BlockNote 没有成为默认主编辑器。

- [x] 输入文本能保存。

- [x] reload 后文本仍在。

验证命令：

```
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task121-rust-web-editor-island-hydration-smoke.js
```

## 8. Phase E-5：树事件与编辑保存联动回归

目标：树和编辑器不是一次性 SSR，而是接入当前 Rust Web transport / realtime 主链。

- [x] 新建页面后 `/api/tree/events` 或 projection reload 可看到新增节点。

- [x] 重命名页面后 sidebar row title 更新。

- [x] 删除 / purge 页面后 sidebar row 消失。

- [x] 编辑保存走 `/api/documents/save` 或约定 Rust Web save endpoint。

- [x] 保存后 `/api/page-aggregate/:id` 能看到正文变化或 revision 变化。

- [x] `task114`、`task115`、`task118`、`task119`、`task120`、`task121` 在当前 3000 全部通过。

验证命令：

```
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task114-rust-web-gateway-entry-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task115-rust-web-document-shell-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task118-rust-web-wolai-ui-parity-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task119-rust-web-wolai-visual-regression-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task120-rust-web-tree-integration-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task121-rust-web-editor-island-hydration-smoke.js
```

## 9. Harness 映射建议

本 checklist 建立阶段不直接修改 `harness-tasks.json`。若进入执行，建议追加：

| 新任务 | Phase | 标题 | 优先级 |
| --- | --- | --- | --- |
| `task-034` | E-0 | 冻结真实树和编辑器 hydration 失败用例 | P0 |
| `task-035` | E-1 | workspace sidebar 接入真实 projection rows | P0 |
| `task-036` | E-2 | 根路径接入 active page / empty workspace | P0 |
| `task-037` | E-3 | document shell 接上真实 Page Aggregate 与 page tree | P0 |
| `task-038` | E-4 | 挂载 leptos-tiptap island 并证明可编辑 | P0 |
| `task-039` | E-5 | 树事件与编辑保存联动回归 | P1 |

## 10. 完成判定

- [x] `task120` 在当前 `3000` 通过。

- [x] `task121` 在当前 `3000` 通过。

- [x] 左栏页面树来自真实 projection。

- [x] 根页不再用设计稿静态列表伪装主内容。

- [x] 文档页有真实 `leptos-tiptap` 可编辑 surface。

- [x] 保存后 Page Aggregate / reload 可读回。

- [x] `3-8` 可移动到 `done` 后，本 checklist 才能进入完成评估。
