# 5-15 主编辑区 Resource Tab 与 VSCode 打开目标对齐 v1

> 状态：done
>
> 日期：2026-05-20

## 目标

把当前资源打开行为从“资源点击直接 `window.open` 或单独右侧 pane”收口为 VSCode 风格的打开目标模型：

- `active-tab`：在主编辑区打开或激活 resource tab。
- `side`：保留当前右侧 pane 打开能力。
- `new-window`：显式在新浏览器窗口打开。

本轮重点实现 `active-tab`，并保持已有右侧 pane 与新窗口路径不退化。

## VSCode 对齐口径

VSCode Explorer 不按文件类型散落处理打开行为，而是把资源交给 editor service：

- 普通打开进入当前 editor group。
- `Open to the Side` 进入 side group。
- 同一资源应激活已有 editor tab，而不是无限重复打开。
- side group 与主 editor group 可以同时持有各自 tab。

MNote 对应关系：

- 主编辑区 tab host 对应 VSCode active editor group。
- 当前 secondary document pane 对应 VSCode side group。
- 浏览器新窗口只作为显式外部打开目标。

## 资源编辑规则

`.md`、`.markdown`、`.txt`、常见代码文件在主编辑区 resource tab 中继续使用 tiptap runtime 打开。

关键约束：

- 页面正文 tiptap 保存到 Page Aggregate body / 页面 Markdown。
- 资源 tiptap 保存到对应 resource 文件本身。
- resource tab 必须使用独立 object identity 与独立 session key。
- resource tab 保存不得调用 `page.body.save` 或 `/api/page-body/write`。
- 上传的 `.md` 资源不能因为用 tiptap 打开而重新变成 File Tree / Page Tree 页面。

## 最小实现范围

本轮只做浏览器内主编辑区 resource tab host 的最小闭环：

- 在文档 workspace 顶部增加 tab strip。
- 默认页面正文是一个固定 page tab。
- 点击本地上传或文件树资源时打开 resource tab。
- Office tab 内嵌 `/onlyoffice?...`。
- PDF / 图片使用 iframe/img 预览。
- `.md` / text / code 使用 tiptap runtime 编辑，并保存回本地资源文件。
- 右键菜单保留“在右侧边栏打开”和“在新窗口打开”。

Convex 远端资源本轮仅保留新窗口 fallback；主闭环优先覆盖 local-first 资源。

## 详细 Checklist

- [x] 定义前端 open target：`active-tab`、`side`、`new-window`。
- [x] 为本地资源生成稳定 `objectIdentity`：`resource:file:<rootUri>:<relativePath>`。
- [x] 新增本地资源读写 API：
  - [x] `GET /api/local-folder/resource/read?rootUri=&path=`
  - [x] `POST /api/local-folder/resource/write`
  - [x] 读写均复用 root escape 校验。
  - [x] 写入返回 `fileVersion` / `conflictDetectionKey`。
- [x] 主编辑区新增 resource tab strip：
  - [x] page tab 默认存在。
  - [x] resource tab 重复打开时激活已有 tab。
  - [x] 关闭 resource tab 后回到 page tab。
  - [x] 打开 resource tab 不关闭 secondary pane。
- [x] tiptap resource editor：
  - [x] `.md` / `.markdown` / `.txt` / code 资源挂载 tiptap。
  - [x] session key 与页面正文 session key 隔离。
  - [x] 保存写 `/api/local-folder/resource/write`。
  - [x] 保存 payload 中保留 `tiptapDocument`，服务端转 Markdown / text 后写回文件。
- [x] Office / PDF / 图片 resource tab：
  - [x] Office 使用 `/onlyoffice?...` iframe，主编辑区默认 `mode=view`。
  - [x] PDF 使用 iframe。
  - [x] 图片使用 img。
  - [x] 不触发页面正文保存。
- [x] 菜单与默认行为：
  - [x] 文件树资源普通点击默认 `active-tab`。
  - [x] 附件普通点击默认 `active-tab`。
  - [x] “在右侧边栏打开”继续走 `side`。
  - [x] “在新窗口打开”继续走 `new-window`，Office 保留 `mode=edit`。
- [x] Smoke：
  - [x] 上传 `.md` 后点击资源，在主编辑区出现 resource tab 和 tiptap。
  - [x] 编辑 `.md` resource tab 后文件内容写回资源文件，不写页面正文。
  - [x] 上传 Office 后点击资源，在主编辑区出现 Office resource tab。
  - [x] 显式新窗口打开仍打开 `/onlyoffice` 或文件 URL。

## 非目标

- 不在本轮实现多 tab 持久化恢复。
- 不在本轮实现 Convex 远端资源的主编辑区写回。
- 不在本轮引入完整代码编辑器或语法高亮。
- 不改变 Resource Tree / File Tree / Page Tree 的真源关系。
