# Changelog — 推送页 Round4 H5/H6 SPA 补齐

**日期**：2026-06-07

## 摘要

Vue 推送页按 `docs/design/plans/2026-05-29-push-round4.md` 补齐 **H5 源路径验证** 与 **H6 批量重试失败**；禁止未验证路径直接推送，修复「填了路径但容器内不存在 → 全部失败」的常见误用。

## 动机

Round4 后端 `POST /api/sync/validate-source-path` 与重试队列早已存在，SPA 重构后前端缺失：
- 用户可在「推送源路径」随意输入未验证路径并触发 rsync，导致 Telegram「文件推送全部失败」
- 失败后无法一键提交重试任务

## 涉及文件

- `frontend/src/composables/push/usePushForm.ts` — `validateSourcePath()`、`validatedSource`、表单校验
- `frontend/src/composables/push/usePushProgress.ts` — 捕获 `retry_job_id`、`retryAllFailed()`
- `frontend/src/composables/push/types.ts` — `ValidatedSource`、`ServerProgress.retryJobId`
- `frontend/src/components/push/PushZipUpload.vue` — ZIP / 普通文件 / 主机路径三选一
- `server/api/sync_v2.py` — `POST /api/sync/upload-files` 普通文件暂存
- `tests/test_sync_upload_staging.py` — 暂存上传单测
- `frontend/src/components/push/PushToolbar.vue` — 移除源路径（迁至源文件卡片）
- `frontend/src/components/push/PushProgressList.vue` — 「重试全部失败」按钮
- `frontend/src/pages/PushPage.vue` — 接线

## 迁移 / 重启

- 仅前端静态资源；`vite build` 后部署 `web/app/` 即可
- 无 DB / API 变更

## 验证

```bash
cd frontend && npm run build
# type-check + vite build 通过

# 手动（推送页 #/push）：
# 1. 仅输入源路径不点「验证路径」→ 推送应被拦截
# 2. 验证通过后显示文件数/大小，可推送
# 3. 推送部分失败后进度区显示「重试全部失败 (N)」
```

## 行为说明

| 源 | 规则 |
|----|------|
| ZIP 上传 | 解压至 `/tmp/nexus_upload_*`，与主机路径/普通文件互斥 |
| 普通文件 | `POST /api/sync/upload-files`，可多选，暂存同目录后 rsync |
| 主机源路径 | 须点击「验证路径」调用 `/api/sync/validate-source-path` |
| 目标路径 | 留空用各机 `servers.target_path`（与 a225b65 一致） |
| 失败重试 | WS/HTTP 返回的 `retry_job_id` → `POST /api/retries/{id}/retry` |
