Files
mnote/bugs/05-editor-mainline/done/2026-05-21-office-edit-sign-plugin-gap-review-v1.md
lix-2026 1882db7681 收口 MNote P0 P1 P2 审查尾项
- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目
- 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线
- 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径

验证:
- cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1
- cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1
- git diff --check
- git diff --cached --check
- codegraph index . --force && codegraph status .
- codegraph sync . && codegraph status .
2026-06-01 09:29:12 +08:00

7.6 KiB
Raw Permalink Blame History

Office local-first 预览、编辑与插件噪音缺口审查 v1

状态

  • 状态:done

背景

本轮只审查 OnlyOffice 与 MNote local-first 工作区之间的三个接口缺口:

  1. /api/media/sign 对 local-folder asset 返回 404。
  2. Office 附件默认只读,但需要三点菜单提供“使用编辑模式打开”。
  3. OnlyOffice 自定义 annotation 插件存在 404 / pageerror 噪音。

上一轮浏览器验证已经确认:中文 docx 上传后可在 resource tab 中只读打开,errorCode=-18 的 WebSocket 连接问题已通过 doc key 安全化和 /onlyoffice-server 反代修复。因此本轮不把“只读预览可见”重新定义为失败。

官方依据

Context7 查询 /onlyoffice/api.onlyoffice.com 得到的关键口径:

  • editorConfig.mode 支持 "view" / "edit",只是初始化编辑器模式。
  • 保存必须配置 editorConfig.callbackUrl,后端在 callback status === 2status === 6 时下载 body.url 并写回文件,成功返回 { "error": 0 }
  • onRequestEditRights 是 view 模式切 edit 的官方事件;触发后集成方必须以 edit mode 重新初始化编辑器。
  • 插件通过 editorConfig.plugins.autostarteditorConfig.plugins.pluginsData 连接;annotation / custom assistant 类插件 404 属于可选插件加载链路,不等于主文档渲染失败。

代码现状

  • rust/crates/mnote-web/src/routes/media.rs/api/media/sign 当前只服务 Convex media asset,内部查询 mediaAssets:getById / mediaAssets:refreshUrl。local-folder asset 形如 local:asset:<path>,不在 Convex media 表中,所以返回 404 是现状契约不匹配。
  • rust/crates/mnote-web/src/routes/onlyoffice.rs/onlyoffice 页面在 resolveAssetUrlAndKey() 中只要有 assetId 就请求 /api/media/sign;失败后静默保留传入的 fileUrl。这就是“当前 view 模式不阻断打开”的原因。
  • local-folder Office 预览已经可以直接使用 /api/local-folder/files/open?rootUri=...&path=... 作为 fileUrl,不需要经过 /api/media/sign
  • /api/onlyoffice/callback 已由 5-36 补齐 local-folder status 2/6 -> 下载 body.url -> 原文件覆盖写回 的后端契约;legacy Next 代理仍保留为 cloud/compat 边界。
  • layout.rs / browser runtime 已提供“使用编辑模式打开”入口,默认打开保持 mode=view,显式 edit 保留 guard。
  • annotation/custom assistant 插件噪音已由 5-37 / 5-40 分类:插件噪音不等于主文档失败,真实 errorCode=-18、WebSocket 失败或 iframe 空白不能被噪音掩盖。

根因判断

1. /api/media/sign local-folder 404

根因不是权限失效,而是端点 ownership 错位:/api/media/sign 是历史 Convex media asset 签名端点,local-folder 文件已经有 local open route,二者不应混用。

P0 目标不是让 /api/media/sign 接管所有本地文件,而是让 OnlyOffice local 路径不再无意义请求该端点,避免误导日志和后续测试。

2. 编辑模式入口

OnlyOffice mode=edit 并不等于 MNote 已支持保存。没有 callback 写回闭环时,直接默认编辑会制造“看似能改、实际不能保存”的假功能。

P0 目标:

  • 默认打开仍为 view
  • 菜单提供“使用编辑模式打开”入口。
  • 编辑入口必须带 guard:清楚标记为实验能力,或在 local-folder writeback 未闭环时阻止/提示。

P1 目标是实现 local-folder callback 写回;该项已由 5-36 完成后端契约。

3. annotation 插件 404 / pageerror

插件链路属于可选增强。若配置了 autostart / pluginsData 但静态资源不存在,会产生 404 或 pageerror。只要正文渲染和 OnlyOffice 主 WebSocket 正常,这不是打开失败。

P0 目标:

  • 不把可选插件 404 当成 Office 打开失败。
  • 不让缺失插件反复污染测试结论。
  • 若当前 MNote 并未真正依赖 annotation 插件,则应禁用 autostart 或明确过滤为 non-critical。

Checklist 拆分

  • 5-34-local-folder-media-sign-office-url-contract-v1.md

    • P0OnlyOffice local-folder 打开不再请求 /api/media/sign
    • P1:补回归测试,确认 local asset 仍可只读打开。
  • 5-35-office-edit-mode-menu-and-guard-v1.md

    • P0:正文附件与文件树资源菜单增加“使用编辑模式打开”。
    • P0:默认打开保持只读。
    • P0:若保存闭环未完成,编辑入口必须有 guard / 实验标记。
  • 5-36-onlyoffice-local-edit-save-callback-contract-v1.md

    • P1local-folder callback 写回。
    • P1:覆盖 status 2/6、下载 URL rewrite、路径权限、冲突保护。
  • 5-37-onlyoffice-annotation-plugin-noise-policy-v1.md

    • P0:定位 annotation 404 来源。
    • P0:禁用无效 autostart / pluginsData 或把该类错误降级为 non-critical 测试噪音。

不做事项

  • 不默认以 edit 模式打开 Office。
  • 不在没有保存闭环时承诺“Office 可编辑保存”。
  • 不把 local-folder 文件任意暴露给 /api/media/sign,除非经过 rootUri / workspace / allowed roots 校验。
  • 不把 annotation 插件 404 等同于主文档渲染失败。

验收要求

  • cargo test -p mnote-web -- --test-threads=1
  • codegraph sync . 后确认索引健康。
  • Reasonix clean browser 测试:全新 browser context,登录测试账号,上传 /home/lix/Downloads/重庆发展特殊化妆品可行性报告_政府汇报版.docx,打开默认只读,截图确认内容可见;打开三点菜单确认编辑入口;点击编辑入口后截图和日志证明行为符合 guard / edit URL 预期。
  • Codex 必须复核 Reasonix 的 result.json 和截图,再自行做一次浏览器截图核查。

当前执行结论

  • P0 已处理:
    • local-folder Office 打开跳过 /api/media/sign,继续使用 /api/local-folder/files/open
    • Office 默认打开为 mode=view
    • 菜单提供“使用编辑模式打开”,进入前有实验 guard。
    • 已存在 Office resource tab 从 view 切 edit 会刷新同一 iframe URL,不再只激活旧 tab。
    • annotation/custom assistant 插件 404 已归类为 non-critical noise,不作为主文档打开失败。
  • P1 已拆分并收口:
    • 5-36local-folder Office edit/save callback 写回后端契约已完成,覆盖 status 2/6、非写状态、未认证、路径越界。
    • 5-35onRequestEditRights 事件会重新初始化为 mode=edit URL,不只 reload 当前 view。
    • 本 umbrella review 仅作为缺口审查和拆分记录归档;后续真实 Office 编辑保存端到端浏览器验收若发现新问题,应另建具体 bug。
  • 浏览器证据:
    • Reasonixtmp/reasonix-office-view-edit-plugin-2026-05-21/result.json 与截图。
    • Codextmp/codex-office-view-edit-plugin-2026-05-21/result.json01-office-view-mode.png02-office-edit-mode.png
  • 2026-06-01 验证:
    • cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_page -- --test-threads=1
    • cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_callback -- --test-threads=1
    • cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_local_callback -- --test-threads=1
    • cargo test --manifest-path rust/Cargo.toml -p adapter-onlyoffice callback_preparation -- --test-threads=1
    • node --check scripts/task463-onlyoffice-resolver-smoke.js
    • MNOTE_UI_BASE_URL=http://127.0.0.1:3301 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3301 node scripts/task463-onlyoffice-resolver-smoke.js
    • node --check scripts/task518-onlyoffice-real-iframe-session-scope-smoke.js
    • MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3301 node scripts/task518-onlyoffice-real-iframe-session-scope-smoke.js