# 5-24 [done][bug] page.body.save 上传图片与附件持久化字段丢失 v1

> 发现时间：2026-05-18
>
> 状态：`[done]`
>
> 关联主线：`05-editor-mainline`

## 1. 问题定义

主编辑区文本保存修复后，继续验证上传图片与附件发现两个持久化缺陷：

- 附件能插入到编辑器，并且 `/api/documents/save` 返回 200，但 `/api/documents/content` 回读时链接 mark 被降级成纯文本。
- 图片能上传并触发保存，但 `/api/documents/content` 回读时图片块只剩 `type: "image"`，`props.src / alt / title / tiptapImage` 为空。

这会导致刷新或跨浏览器打开后，附件不能作为 OnlyOffice 附件链接恢复，图片也缺少可渲染的资源地址。

## 2. 根因

保存链优先使用 `editorDocument` 生成 canonical legacy content 后再写入当前 Convex legacy substrate。

两个字段在这一步丢失：

- `legacy_content_from_editor_document` 只用 `legacy_text_from_editor_block()` 生成纯文本，未保留 `ContentNode.attrs.styles.link`。
- `EditorBlockDocument` 反序列化时 `BlockProps.extra` 不是 flatten 字段，前端传来的 image `props.src / alt / title / tiptapImage` 会被 serde 忽略；`hydrate_editor_document_props_from_raw` 旧实现只回填 mindmap props，没有回填 image props。

## 3. 修复

- `legacy_content_from_editor_document` 对带结构化样式的 inline 节点输出 legacy inline content 数组，保留 `styles.link` 等样式；普通纯文本段落仍保持旧的字符串 content。
- `hydrate_editor_document_props_from_raw` 增加 image 分支，从原始 `editorDocument.blocks[].props` 回填 `src / alt / title / tiptapImage`。
- `legacy_props_from_editor_block` 对 image 块输出回填后的直接 props 与 `tiptapImage`。

## 4. 验证

单测：

```bash
cargo fmt --manifest-path rust/Cargo.toml --all --check
cargo test --manifest-path rust/Cargo.toml -p bridge-runtime legacy_content_from_editor_document_preserves_inline_link_styles -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p bridge-runtime documents_save_hydrates_image_props_from_raw_editor_document -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p bridge-runtime documents_save_command_plan_prefers_valid_editor_document_over_other_sources -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web documents_save_route_executes_page_body_save_command -- --nocapture
```

浏览器验证：

- 以测试账号登录 `http://127.0.0.1:13000`。
- 新建临时页面。
- 通过 slash 上传 `.docx` 附件和 `.png` 图片。
- 断言两次 `/api/documents/save` 均返回 200。
- 断言 `/api/documents/content` 回读包含：
  - image `props.src`
  - 附件 inline `styles.link`
- 刷新页面后，编辑器 DOM 中仍能找到附件链接与图片节点。

结果：通过；临时测试页面已 purge。

## 5. 剩余边界

当前仍是 legacy content substrate 下的过渡修复。完整 EditorBlockDocument 原生落库完成后，图片/附件 props 应由原生 schema 和迁移校验继续收紧。
