# 3-17 [recycle] Convex Export Web Entry v1

状态：`recycle / old`

归档说明（2026-05-22）：CLI 迁移闭环已具备并有 smoke 证据；但当前 Convex 默认运行时、根 functions 与自托管入口已退役到历史 / compat / sync replica 边界，本文的 Web 管理入口设想不再作为 active 或 reference 执行入口。若未来重新做 cloud/import UI，应按当前 SQLite control-plane 和 local-first 口径新建设计稿。

## 目标

旧 Convex workspace 迁移到本地 workspace 时，用户应能在 Web 控制台完成：

1. 选择 Convex workspace。
2. 选择目标本地 root。
3. 先 dry run，查看计划、冲突和预计写入。
4. apply 后得到 manifest、冲突报告、索引重建结果。
5. 需要时按 manifest rollback。

## 当前基础

CLI 已具备最小迁移闭环：

- `scripts/export-convex-workspace-to-local.js --fixture <fixture.json> --out <dir>`
- `--dry-run`
- `--manifest <file>`
- `--conflict-report <file>`
- `--rollback <manifest.json>`

验证：

- `node scripts/task444-convex-workspace-export-local-fixture-smoke.js`
- `node scripts/task455-convex-export-plan-rollback-smoke.js`

## Web 入口设计

入口位置：管理员控制台 `/admin` 新增“Convex 迁移”面板。

字段：

- `workspaceId`
- `targetRootUri`
- `mode=dryRun | apply | rollback`
- `manifestPath`，rollback 时必填
- `conflictPolicy=stop`，默认只支持 stop，不覆盖目标文件

## API 设计

### `GET /api/admin/convex-export/workspaces`

返回当前可导出的 Convex workspace 列表。

最小返回：

```json
{
  "ok": true,
  "workspaces": [
    { "workspaceId": "ws_1", "name": "默认空间", "documentCount": 12 }
  ]
}
```

### `POST /api/admin/convex-export/plan`

输入：

```json
{
  "workspaceId": "ws_1",
  "targetRootUri": "file:///mnt/Data1T/Mnote_data/users/user_1/workspaces/imported"
}
```

行为：

- 导出 Convex workspace fixture / snapshot 到临时计划。
- 调用迁移 planner，等价于 CLI `--dry-run`。
- 写入 `<target>/.mnote/migration-plan.json` 或控制面 job 目录。
- 不写正文文件。

### `POST /api/admin/convex-export/apply`

输入：

```json
{
  "workspaceId": "ws_1",
  "targetRootUri": "file:///mnt/Data1T/Mnote_data/users/user_1/workspaces/imported",
  "manifestPath": "/mnt/Data1T/Mnote_data/users/user_1/workspaces/imported/.mnote/migration-manifest.json"
}
```

行为：

- 默认 `conflictPolicy=stop`。
- 目标文件存在时返回 409 和 conflict report。
- 成功后写 `.mnote/migration-manifest.json`、`.mnote/index/search-index.json`。

### `POST /api/admin/convex-export/rollback`

输入：

```json
{
  "manifestPath": "/mnt/Data1T/Mnote_data/users/user_1/workspaces/imported/.mnote/migration-manifest.json"
}
```

行为：

- 按 manifest 删除本次新增文件。
- 如 manifest 存在备份文件，则恢复备份。
- 不删除 manifest 本身，追加 rollback report。

## 权限

- 只有 admin 可以从任意 Convex workspace 导出。
- 普通用户只能导出自己拥有的 workspace 到自己有 write grant 的本地 root。
- 所有 `targetRootUri` 必须通过 local access policy 校验。
- Web API 不能接受任意 shell 命令；CLI 迁移逻辑应抽成 Rust/Node 可调用模块或由受控 job runner 调用固定脚本和固定参数。

## 状态与报告

任务状态包含：

- `queued`
- `planning`
- `blocked_by_conflict`
- `applying`
- `indexing`
- `completed`
- `failed`
- `rolled_back`

报告包含：

- `documentCount`
- `resourceCount`
- `aiSessionCount`
- `operationCount`
- `createdFiles`
- `conflicts`
- `indexRefresh`
- `manifestPath`
- `conflictReportPath`

## 后续落码顺序

1. 把 CLI planner/apply/rollback 拆成可被 Web route 复用的模块。
2. 新增 admin API 的 dry-run route。
3. 新增 admin UI “Convex 迁移”面板。
4. 新增 apply / rollback route。
5. 补 browser smoke：dry-run 不写文件、冲突 409、不覆盖、rollback 后 root 恢复。
