# 4-36 [done][bug] 本地文件夹切回云空间后进入空白 workspace v1

> 更新时间：2026-05-15
>
> 分类归属：
> - `04-tree-domain/done`
> - 涉及边界：workspace source switch、本地文件夹入口、Convex workspace 恢复、Sidebar File Tree/Page Tree projection
>
> 用户反馈：
> - 点击进入本地文件夹后，再点击“云空间”，会得到空白的空间页面。
> - 截图：`/mnt/Data1T/mnote/tmp/image copy 101.png`。
> - 点击垃圾箱后才能找回之前空间的页面。

## 1. 问题定义

从 Convex 云空间切到本地文件夹，再通过工作区来源菜单切回“云空间”时，页面应恢复到之前的 Convex workspace，并展示原有 Page Tree / File Tree。

当前异常表现是：切回后页面壳仍显示“开发用户的空间”和文档编辑区，但左侧 Explorer 为空，提示“暂无文件或页面”。这会让用户误以为云空间数据丢失；进入垃圾箱后又能看到原空间内容，说明更像是 workspace source / workspaceId 恢复错误，而不是数据真的被删除。

## 2. 初步根因

已确认一个高风险代码点：

- `rust/crates/mnote-web/src/ssr/pages/layout.rs` 中 `openLocalFolderRoot()` 在离开云空间前调用 `rememberCloudWorkspaceId(resolveWorkspaceId(document.body))`。
- `resolveWorkspaceId(document.body)` 只检查当前元素和祖先，再回退到 URL 的 `workspaceId` 或 `"default"`；它不会读取页面子树里的真实 `data-workspace-id`。
- 当云空间入口 URL 没有显式 `workspaceId` 时，这会把 `"default"` 记为上次云空间 workspace。
- 之后 `switchToCloudWorkspace()` 读取这个错误的 last cloud workspace id，跳到 `/?workspaceId=default&sourceKind=convex_workspace`，从而得到空白 workspace。

## 3. 复现路径

1. 进入 `http://localhost:3000` 的真实云空间，确保侧边栏有页面。
2. 点击左上角工作区来源菜单或文件夹入口，进入一个本地文件夹。
3. 再打开工作区来源菜单，点击“云空间”。
4. 观察 URL、`localStorage.mnote.workspace.lastCloudWorkspaceId`、Page Tree / File Tree row。

期望：

- URL 应带回真实云空间 `workspaceId`，不能是 `default`。
- Page Tree / File Tree 应恢复云空间页面。
- 不需要通过垃圾箱或其它入口才能找回原空间。

## 4. 验收标准

- 新增 smoke 覆盖：云空间有至少一个页面 -> 打开本地文件夹 -> 切回云空间 -> 原云空间页面 row 仍可见。
- `mnote.workspace.lastCloudWorkspaceId` 不得在有真实 workspace id 时被写成 `default`。
- `switchToCloudWorkspace()` 不能携带 `rootUri`，也不能落到本地文件夹空树。
- 修复后真实浏览器复核截图中的路径不再出现“暂无文件或页面”的空白 Explorer。

## 5. 当前状态

当前状态：`done`

2026-05-15 已修复并验证：

- `rust/crates/mnote-web/src/ssr/pages/layout.rs` 不再在进入本地文件夹前用 `document.body` 推导 workspaceId；改为从当前 URL / DOM 子树读取真实云空间 workspaceId，并忽略 synthetic `default`。
- `scripts/task441-local-folder-cloud-switch-smoke.js` 通过：打开云空间 -> 进入本地文件夹 -> 切回云空间后，URL、`lastCloudWorkspaceId`、Page Tree / File Tree 都恢复到原 workspace，且原云空间页面 row 仍可见。
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web sidebar_workspace_source_switch_remembers_real_cloud_workspace_before_local_folder -- --nocapture` 通过。
