Files
Nexus/docs/design/specs/2026-05-29-push-round3-design.md
T
Your Name 5958c21048
Nexus CI/CD / test (push) Waiting to run
Nexus CI/CD / deploy (push) Blocked by required conditions
Nexus Pre-commit Checks / quick-check (push) Waiting to run
feat: 推送页面 Round 4 — 服务器搜索 / Diff对比 / 排错诊断 / 源路径输入 / 批量重试
5 项新功能:
- H2: 服务器搜索过滤 — 目标服务器下拉加搜索框实时过滤
- H3: 推送对比 Diff 视图 — 预览文件列表加 diff 按钮对比本地与远程差异
- H4: 推送排错面板 — 失败行加诊断按钮检查SSH/磁盘/权限
- H5: 源路径直接输入 — 支持直接输入服务器本地路径推送
- H6: 批量重试 — 一键重试所有失败服务器

新增后端端点:
- POST /api/sync/validate-source-path (H5)
- POST /api/sync/diagnose (H4)
- POST /api/sync/file-diff (H3)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 21:29:41 +08:00

6.1 KiB

2026-05-29 推送页面迭代 Round 3 — 设计文档

背景与目标

推送页面 Round 1(WS 进度/分组/历史/文件操作/校验)和 Round 2(同步说明/在线标识/失败重试/Telegram 通知/文件预览)已完成全部 10 项功能。基于实际运维场景,仍有 6 项体验/效率缺陷:

  1. 推送无法取消 — 推送 50 台发现配错,只能等全部超时,无中止机制
  2. 推送页无法直接调度 — 想凌晨推送需跳到调度页重新配置源路径/服务器/模式,操作割裂
  3. 无推送模板/收藏 — 常用推送组合每次手动选,重复劳动
  4. 推送历史无法筛选 — 历史只有最近 15 条无分页,无法按服务器/状态/日期过滤
  5. 无浏览器推送完成通知 — 用户离开页面后不知推送结果(Telegram 有但浏览器没有)
  6. 不支持拖拽上传 ZIP — 文件选择器不够直观

方案对比

G1 推送取消

方案 优点 缺点
A: Redis 取消标记 + 引擎轮询 简单可靠,无进程间通信 最多延迟一个 rsync 周期(5min)才取消
B: asyncio.Task.cancel() 即时取消 多 worker 下无法跨进程取消
C: kill rsync 子进程 最直接 需跟踪 PID,复杂且风险高

选定方案 A — Redis sync:cancel:{batch_id} 键,sync_engine 的 _rsync_push() 每次执行前检查。前端显示"取消推送"按钮,取消后已完成的保留结果,未启动的跳过。简单可靠,无进程间通信问题。

G2 推送页面直接调度

方案 优点 缺点
A: 推送按钮旁加"定时推送"按钮 复用当前表单配置 需新增调度 API 调用
B: 调度选择器嵌入推送页 更灵活 页面变重

选定方案 A — "开始推送"按钮旁增加" 定时推送"按钮,弹出时间选择器后直接调用 POST /api/schedules/。推送页已有所需全部字段(server_ids, source_path, sync_mode)。

G3 推送模板/收藏

方案 优点 缺点
A: 浏览器 localStorage 无后端改动 仅本机可见
B: 后端 PushTemplate 表 跨设备共享 需 DB 迁移 + API

选定方案 A — localStorage 存储推送模板。模板包含名称、源路径、目标路径、同步模式、服务器 ID 列表。运维人员通常固定在一台电脑操作,localStorage 足够。若未来需跨设备可迁移到后端。

G4 推送历史筛选

方案 优点 缺点
A: 后端分页 + 前端筛选下拉 大数据量友好 需改 API
B: 纯前端筛选 无后端改动 15 条太少无法筛选

选定方案 A — 后端 GET /api/servers/logs 已有 limit 参数,增加 status/server_id/page 参数,前端加筛选控件+分页。

G5 浏览器推送完成通知

方案 优点 缺点
A: Notification API 系统级通知,即使页面在后台也可见 需用户授权
B: 页面 title 闪烁 无需授权 仅标签页可见

选定方案 A — Web Notification API。推送开始时请求授权,完成时发浏览器通知。降级:授权拒绝时 title 闪烁。

G6 拖拽上传 ZIP

方案 优点 缺点
A: 拖拽区域 + click 回退 直观 需前端改动

选定方案 A — 将文件上传区改为拖拽区 + click 选择,标准 HTML5 拖拽实现。

选定方案及理由

全部选方案 A(最简方案),理由:

  • G1: Redis 标记是跨 worker 最可靠的取消方案
  • G2: 复用推送表单 + 现有调度 API,零后端新端点
  • G3: localStorage 模板无需 DB 迁移,符合运维单人操作场景
  • G4: 后端分页是大数据量唯一正确方案
  • G5: Notification API 是唯一真正"后台通知"的方案
  • G6: 拖拽上传是现代标准 UX

接口/数据模型

G1: 推送取消

  • Redis key: sync:cancel:{batch_id} (SET, TTL=3600s)
  • sync_engine_v2._rsync_push(): 执行前检查 Redis key,存在则返回 {exit_code: -1, stderr: "推送已取消"}
  • sync_engine_v2.sync_files(): 每个任务启动前检查取消标记
  • 前端: POST /api/sync/cancel{batch_id: str} → 写 Redis key + 审计日志
  • WS 消息: 取消的服务器 status="cancelled"

G2: 推送页面直接调度

  • 无新端点,复用 POST /api/schedules/
  • 前端: " 定时推送"按钮 → 弹出 datetime-local 选择器 → 调用调度 API

G3: 推送模板

  • localStorage key: nexus_push_templates — JSON 数组
  • 模板结构: {name, source_path, target_path, sync_mode, server_ids[]}
  • 前端: 模板下拉选择 + 保存/删除按钮

G4: 历史筛选

  • 后端 GET /api/servers/logs 增加: status: Optional[str], server_id: Optional[int], page: int = 1, per_page: int = 20
  • 返回增加: total, page, pages
  • 前端: 状态/服务器筛选 + 分页控件

G5: 浏览器通知

  • 推送开始时 Notification.requestPermission()
  • 推送完成时 new Notification("Nexus 推送完成", {body: "X 成功, Y 失败"})
  • 降级: 授权拒绝时 document.title 闪烁

G6: 拖拽上传

  • <div> 拖拽区域 + dragover/drop 事件
  • 保留原有 <input type="file"> 作为 click 回退
  • 拖拽时高亮边框

安全与性能约束

  • G1: 取消端点需 JWT 认证 + 审计日志;Redis key 有 TTL 防止泄漏
  • G2: 复用调度 API,已有 JWT 认证 + 审计
  • G3: localStorage 无安全风险(不含密码/密钥)
  • G4: 分页查询有索引 idx_sync_logs_srv_start
  • G5: Notification 需用户主动授权,非强制
  • G6: 拖拽文件仍走现有 upload-zip 端点校验

验收标准

  1. G1: 推送进行中 → 点击"取消推送" → 未启动的服务器跳过 → 已完成的保留结果
  2. G2: 配置推送 → 点击"定时推送" → 选择时间 → 调度页出现对应任务
  3. G3: 保存模板 → 刷新页面 → 下拉选择模板 → 表单自动填充
  4. G4: 历史区筛选状态/服务器 → 分页翻页 → 结果正确
  5. G5: 推送完成 → 浏览器弹出通知(页面在后台也可见)
  6. G6: 拖拽 ZIP 到上传区 → 文件上传解压成功