# 3-16 [done] 本地 Markdown 上传误走云端 media asset 修复 v1

> 创建时间：2026-05-18
>
> 状态：`[done]`
>
> 所属主线：`03-rust-web` / `local_folder` / `local markdown`

## 问题

本地文件夹模式下，`.md` 页面内上传图片或附件沿用了云端 `/api/media/upload` 链路，会生成 Convex media asset，并在正文中写入云端 URL 或 OnlyOffice assetId 链接。

这会破坏本地 Markdown 的可迁移性：离开 MNote 后文件引用不可读，也无法符合 local folder “文件系统即资源真源”的边界。

## 修复

- 新增 `POST /api/local-folder/assets/upload`。
- 本地上传复制到当前 Markdown 同目录下的 `{mdBase}.assets/`。
- 返回给编辑器的 `sourcePath` / `file_url` 使用相对当前 Markdown 目录的路径。
- 前端在 `sourceKind=local_folder` 时分流到本地上传入口，云端页面继续走 `/api/media/upload`。
- 本地附件插入普通相对路径链接，不再生成 OnlyOffice assetId URL。
- 本地图片保存时写回标准 Markdown 图片语法：`![alt](relative/path)`。

## 验证

```bash
cargo fmt --manifest-path rust/Cargo.toml --all --check
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_ -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_folder -- --nocapture
```

临时 HTTP smoke：

```bash
MNOTE_WEB_BIND=127.0.0.1:13001 MNOTE_WEB_PUBLIC_BIND=127.0.0.1:13001 cargo run --manifest-path rust/Cargo.toml -p mnote-web --bin mnote-web
curl -sS -X POST \
  -F "file=@/etc/hosts;filename=photo.png;type=image/png" \
  -F "rootUri=file:///tmp/mnote-local-smoke-..." \
  -F "documentId=local-md:README.md" \
  -F "kind=image" \
  http://127.0.0.1:13001/api/local-folder/assets/upload
```

结果：

- `local_markdown_`：19 passed
- `local_folder`：36 passed
- `cargo fmt --check`：通过
- HTTP smoke：返回 `sourcePath=README.assets/photo-1.png`，落盘文件存在且 size=188

## 剩余

- 尚未跑真实浏览器 smoke：本地 `.md` 页面上传图片/附件、刷新后恢复、文件树可见。
