新增 OTA WatchDog 编排与车队健康/报警后端。

覆盖包库回传、任务下发、CDM 任务同步与报警采集,并为包/任务 ID 与上传文件名加上路径安全校验。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zhaowei.huang
2026-07-26 11:31:51 +08:00
co-authored by Cursor
parent f4f4cd1d1b
commit 4223a572c5
25 changed files with 3552 additions and 6 deletions
@@ -0,0 +1,117 @@
# 迷榖 OTAWatchDog)实现计划
> **状态:** 核心任务已落地(后端 API + 前端工作台)。联调 WatchDog 实车需现场验证。
> **面向 AI 代理的工作者:** 按任务顺序实现;每完成一大任务做一次验证。规格:`docs/superpowers/specs/2026-07-19-migu-ota-watchdog-design.md`。
**目标:** 车辆运维改为「运维总览 + OTA」,平台编排 WatchDog 完成包库/下发/任务/配置/自定义文件/设置与延迟检测。
**架构:** MiGu.Server `api/ota/*` 出站调 WatchDog `:9776`;包与任务落盘 `data/ota/`;前端 `OtaWorkbenchView` 只调平台 API。
**技术栈:** ASP.NET Core 8、Vue 3、Element Plus、HttpClient、现有 JWT/RBAC。
---
## 文件结构
### 后端(新建)
| 文件 | 职责 |
|------|------|
| `MiGu.Server/Ota/OtaOptions.cs` | DataRoot、WatchDogPort、超时、本机接收端口 |
| `MiGu.Server/Ota/OtaModels.cs` | Package/Target/Job/Settings/VehicleRow DTO |
| `MiGu.Server/Ota/OtaPathMap.cs` | MDC 路径与组件键 |
| `MiGu.Server/Ota/OtaHash.cs` | MD5 Base64 去 `-` |
| `MiGu.Server/Ota/OtaStore.cs` | packages/target/jobs/settings/history 读写 |
| `MiGu.Server/Ota/WatchDogClient.cs` | getMDCInfo、update*、get*json、getmdcsexe、latency |
| `MiGu.Server/Ota/OtaPackageReceiver.cs` | 供 WatchDog 回传 upload-mdcs* 的内部端点宿主或同进程路由 |
| `MiGu.Server/Ota/OtaJobRunner.cs` | 分批、限速、状态机、重试/取消 |
| `MiGu.Server/Ota/OtaVehicleSource.cs` | 从 SimpleLite projection 取车列表 |
| `MiGu.Server/Controllers/OtaController.cs` | `/api/ota/*` |
| `MiGu.Server/Controllers/OtaReceiveController.cs` | WatchDog 回传 `/api/ota/receive/upload-mdcs*` |
### 后端(修改)
| 文件 | 变更 |
|------|------|
| `MiGu.Server/Program.cs` | 注册 OTA 服务 |
| `MiGu.Server/appsettings.json` | `Ota` 节 |
### 前端(新建)
| 文件 | 职责 |
|------|------|
| `src/api/ota.ts` | API 客户端 |
| `src/types/ota.ts` | 类型 |
| `src/views/shared/ota/OtaWorkbenchView.vue` | 左导航壳 + 顶条 |
| `src/views/shared/ota/OtaVehiclesPane.vue` | 车辆升级 |
| `src/views/shared/ota/OtaPackagesPane.vue` | 版本库 |
| `src/views/shared/ota/OtaJobsPane.vue` | 任务中心 |
| `src/views/shared/ota/OtaConfigPane.vue` | 配置同步 |
| `src/views/shared/ota/OtaCustomFilePane.vue` | 自定义文件 |
| `src/views/shared/ota/OtaSettingsPane.vue` | 设置 |
| `src/composables/useOtaWorkbench.ts` | 目标版本、设置、刷新 |
### 前端(修改)
| 文件 | 变更 |
|------|------|
| `src/views/shared/VehicleHubView.vue` | Taboverview \| ota;重定向旧 tab |
---
## 任务
### 任务 1:后端基础(Options / Models / Store / Hash
1. 创建 `OtaOptions``OtaModels``OtaPathMap``OtaHash``OtaStore`
2. Settings 默认:bandwidth=0(不限)、maxCar=2、latencyEnabled=false、rttThresholdMs=200、overThreshold=`skip`、backupPeriodMinutes=60、backupExe=false。
3. `Program.cs` + `appsettings.json` 注册。
4. 验证:`dotnet build MiGu.Server/MiGu.Server.csproj` 通过。
### 任务 2WatchDogClient + 车辆源 + Receive
1. `WatchDogClient`MDCInfo、组件上传(multipart)、JSON get/put、触发 getmdcsexe、TCP/HTTP RTT。
2. `OtaVehicleSource`HttpClient 调 SimpleLite `http://127.0.0.1:8222/api/agv/list` 或 projection cars(与现有一致优先 projection)。
3. `OtaReceiveController`:接收 upload-mdcs* 写入当前 pull 会话目录。
4. 验证:build 通过。
### 任务 3JobRunner + OtaController API
实现规格 §4.2 全部端点;JobRunner 支持 sync/custom/config 三类 job;审计写入 `OpsAuditStore``data/ota/audit.json`
验证:build 通过;手动 curl GET settings/packages。
### 任务 4:前端 API + 类型 + Hub Tab 切换
1. `types/ota.ts``api/ota.ts`
2. `VehicleHubView` 仅 overview/ota;挂载 `OtaWorkbenchView`
3. 验证:前端 typecheck/dev 可加载。
### 任务 5:OTA 工作台 UI(六子页)
按规格 §5 实现各 Pane;延迟检测开关在车辆升级工具条。
验证:页面可切换、设置可保存、无目标时下发被拦截。
### 任务 6:联调与验收
对照规格 §9 验收清单;修明显 bug。
---
## 关键实现约定
- MD5`Convert.ToBase64String(MD5.HashData(bytes)).Replace("-", "")`(与参考工具一致则对照其实现)。
- 组件键:`M.exe` `M.dll` `M.pdb` `D.exe` `C.exe` `C.dll` `C.pdb`
- Job kind`sync` | `customFile` | `configPush`
- 进度字段:`doneSteps` / `totalSteps`;每车每组件 `status`pending|running|succeeded|failed|skipped。
- 拉取包:平台记录 `pendingPullId` + 本机可达 URL,调车 `getmdcsexe?time=`;车推到 `/api/ota/receive/...`
---
## 规格覆盖自检
| 规格项 | 任务 |
|--------|------|
| IA / 删维护策略与生命周期 | 4 |
| WatchDog 编排 | 23 |
| 包库/目标/任务/设置/延迟 | 3、5 |
| 配置同步/自定义文件 | 3、5 |
| 审计 | 3 |
| 验收 §9 | 6 |
@@ -0,0 +1,258 @@
# 迷榖车辆运维 OTAWatchDog)设计规格
**日期:** 2026-07-19
**状态:** 已批准并实现中
**范围:** 在迷榖「车辆运维」中交付完整 OTA 能力;车上协议沿用 WatchDog;管理面由 MiGu.Server 编排。
---
## 1. 背景与目标
### 1.1 参考实现
`E:\Work\FRLD\OTA\ota` 为 Electron OTA 管理工具:版本拉取/管理、多车 M/D/C 同步、自定义文件、配置 JSON 下发、带宽限速与分批。车上依赖 WatchDog(`:9776`)。参考工具缺少任务状态机、可靠进度与正式回滚。
### 1.2 迷榖现状
- 「车辆运维」=`VehicleHubView`:运维总览 / 维护策略 / 车队生命周期。
- OTA 仅为 `OtaPolicy`enabled / batchSize / rollbackOnFail)只读占位,无包库、下发、进度或审计。
### 1.3 目标
1. 车辆运维顶部仅保留 **运维总览****OTA**
2. 删除「维护策略」「车队生命周期」Tab 及维护策略配置页(本期不迁移)。
3. OTA 全面对齐参考工具能力,并补齐平台侧任务进度、失败重试、审计。
4. 车上协议 **沿用 WatchDog**;浏览器不直连车辆。
5. UI 按迷榖运维工作台语言重做,不照搬 Electron 通用后台壳。
### 1.4 非目标(本期)
- 差分/增量包、签名验签、A/B 双分区
- 空闲时段自动升级
- 浏览器直连 WatchDog
- 维护策略配置的任何入口保留或迁移
---
## 2. 架构决策
**选定:方案 A — 平台编排。**
| 组件 | 职责 |
| ------------------ | ---------------------------- |
| 前端 | 仅调用 `/api/ota/`*,展示对照/进度/设置 |
| MiGu.Server OTA 模块 | 包存储、目标版本、任务状态机、分批、限速、延迟探测、审计 |
| 车队名单 | 复用现有投影/车辆列表(IP、名称、状态) |
| WatchDog `:9776` | 装包、读版本、回传包、读写 JSON、自定义文件 |
---
## 3. 信息架构
### 3.1 车辆运维 Tab
| Tab | 内容 |
| ---- | ------------------ |
| 运维总览 | 保持现有:健康卡片、维护态、车队分配 |
| OTA | 新工作台 |
- 路由:`/admin/config/vehicle-hub?tab=ota`(监控侧同理)。
-`?tab=maintenance` / `?tab=fleet` 深链重定向到 `ota`
### 3.2 OTA 子导航(左侧)
1. **车辆升级** — 版本对照、勾选、分组件/全量同步、延迟检测开关
2. **版本库** — 从车拉取 / 本地上传、设为目标、清理
3. **任务中心** — 进行中/历史、进度、重试、取消
4. **配置同步** — Medulla/Detour/Clumsy JSON 浏览、编辑、多车下发
5. **自定义文件** — 文件 + 车上路径 + 重启策略
6. **设置** — 带宽、并发、备份、延迟检测阈值与门禁策略
### 3.3 与运维总览的边界
| 能力 | Tab |
| ------------------------------------ | ---- |
| 健康、电量、报警、维护态、车队分配、开车上页 | 运维总览 |
| 版本对照、包库、下发、JSON/自定义文件、任务、OTA 设置、延迟检测 | OTA |
运维总览不强制展示完整 MDC 哈希;若后续加「版本落后」标记,仅作跳转 OTA 的入口。
---
## 4. 后端:存储、API、任务
### 4.1 存储布局
根目录:`MiGu.Server/data/ota/`(可配置)
| 路径 | 用途 |
| ---------------- | ----------------------- |
| `packages/{id}/` | 一次拉取或上传的 M/D/C 文件树 |
| `target.json` | 当前目标版本(等价参考 `ota.json` |
| `jobs/` | 任务元数据与事件日志 |
| `history/` | 定时备份(JSON ± exe |
- 版本标识:文件 **MD5Base64,去除 `-`**,与 WatchDog `getMDCInfo` 对齐。
- 组件映射:内置/可配置 `MDCPath`Medulla / Detour / Clumsy 的 exe·dll·pdb)。
### 4.2 API
| 方法 | 路径 | 作用 |
| ------- | ------------------------------------- | ------------------------ |
| GET | `/api/ota/vehicles` | 车列表 + 车上 MDC 版本 +(可选)RTT |
| POST | `/api/ota/packages/pull` | 从指定车拉取包 |
| POST | `/api/ota/packages/upload` | 管理端上传包 |
| GET | `/api/ota/packages` | 版本库列表 |
| POST | `/api/ota/packages/{id}/activate` | 设为目标版本 |
| DELETE | `/api/ota/packages/{id}` | 清理(当前目标不可删) |
| GET | `/api/ota/target` | 当前目标 |
| POST | `/api/ota/jobs` | 创建下发任务(全量/组件/自定义文件/JSON) |
| GET | `/api/ota/jobs` · `/jobs/{id}` | 列表与详情进度 |
| POST | `/api/ota/jobs/{id}/retry` · `cancel` | 重试失败项 / 取消未开始 |
| GET/PUT | `/api/ota/settings` | 带宽、maxCar、备份、延迟检测 |
| GET/PUT | `/api/ota/config/{carId}/{app}` | 单车 JSONmedulla |
| POST | `/api/ota/config/push` | JSON 多车下发(走 job |
| GET | `/api/ota/latency` | 按需批量 RTT(受设置开关约束) |
权限:JWT/RBACPlatform 全量写;Monitor 可读 + 受控执行(`ops.ota.`*)。写操作进入审计。
### 4.3 任务状态机
```
pending → probing(可选) → running → succeeded
↘ failed | partial
↘ cancelled
```
- **分批:** `maxCar`(兼容原 `ota.batchSize` 语义)
- **限速:** 服务端上传流按 `bandwidth` kb/s 节流
- **进度:** 按「车 × 组件」;SSE 或短轮询推到任务中心
- **重试:** 仅重跑失败车辆/组件
- **取消:** 仅 `pending` / 未开始批次;已在传的组件尽量完成并标记
- **延迟门禁:** 任务可带 `requireLatencyCheck`;超阈值按设置跳过或二次确认后仍下发
### 4.4 WatchDog 映射
| 能力 | WatchDog |
| ---- | --------------------------------------------------------- |
| 读版本 | `GET /getMDCInfo` |
| 拉包 | `GET /getmdcsexe` → 车推到平台接收端(或平台主动拉,实现时选更稳方案) |
| 下发 | `/updateMedullaExecutable` 等 + `/updateFile/{name}/{op}/` |
| JSON | `get*json` / `update*json` |
| 备份 | `gethistoryexe` + 平台 `history/` |
参考工具 Express `:8000` 接收能力收进 MiGu(内部端点,仅供 WatchDog 回传)。服务端对 WatchDog 统一超时与有限重试。
---
## 5. UI 设计
**Design Read** 工业 B2B 运维工作台;延续运维总览玻璃卡片 + 状态色 + JetBrains Mono;密度偏驾驶舱。
**Dial** Variance 4 / Motion 3 / Density 7。使用 `--mg-`* 与 `--mg-status-`*。
### 5.1 骨架
左子导航 + 右工作区;顶条固定:**当前目标版本摘要**(M/D/C 短哈希 + 名称)+ 进行中任务角标。
### 5.2 车辆升级
- 工具条:搜索、车队筛选、「仅显示不一致」、**网络延迟检测开关**、刷新、同步全部/分组件
- 主表:勾选 | 车名/ID | IP | Medulla | Detour | Clumsy | RTT | 维护态
- 与目标一致 → 绿;不一致 → 琥珀;不可达 → 灰
- 延迟检测关:RTT 为「—」;开:数值 + 超阈值着色
- 有勾选时底栏粘性操作条:已选数、预计批次、开始下发(二次确认)
### 5.3 版本库
包列表(时间、来源 IP、体积、是否目标)+ 包内文件树与哈希;操作:拉取、上传、激活、删除。
### 5.4 任务中心
进行中(车×组件进度)+ 历史;详情含错误摘要、重试失败项、取消未开始。
### 5.5 配置同步 / 自定义文件 / 设置
- 配置:选车 → JSON 树 → 编辑 → 多车下发(进任务)
- 自定义文件:文件、车上路径、重启策略(无/M/D/C/WatchDog)、多车 → 任务
- 设置:传输(带宽、maxCar)、延迟检测(默认开关、RTT 阈值、超限策略)、备份、展示名
### 5.6 交互原则
- 下发二次确认,写清目标版本与车辆数
- 延迟开且超阈值:默认排除并提示;设置可改为「仍允许但确认」
- 任务进度可离页后续看(持久化)
- 动效克制:进度与状态点过渡即可
---
## 6. 错误处理与审计
| 场景 | 行为 |
| --------------- | ---------------------------- |
| WatchDog 不可达/超时 | 该车失败,不阻塞同批其他车;任务可为 `partial` |
| 上传中断/哈希不匹配 | 组件级失败;可按失败项重试 |
| 延迟超阈值 | 依设置跳过或确认后下发 |
| 无目标版本却同步 | 前端拦截 + API 400 |
| 磁盘满/包损坏 | 拉取/上传失败,不激活残包 |
| 任务取消 | 仅未开始批次 |
审计覆盖:激活目标、创建/取消/重试任务、改设置、推 JSON/自定义文件(操作者、时间、摘要)。
---
## 7. 前端改动要点(实现指引)
- `VehicleHubView`Tab 改为 `overview` | `ota`;移除 `VehicleMaintenanceView` / `FleetLifecycleView` 挂载。
- 新增 `views/.../OtaWorkbenchView.vue`(及子页/composables/api)。
- 新增 `src/api/ota.ts` 对接 `/api/ota/`*。
- 路由/深链:`maintenance`/`fleet``ota`
- 删除或停用对维护策略页、FleetLifecycle 只读 OTA 页的导航依赖;`FleetLifecycleConfig.ota` 可迁移到 `/api/ota/settings` 后废弃只读 UI。
---
## 8. 后端改动要点(实现指引)
- 新增 OTA Controller / Service / 存储 / Job runner / WatchDog HttpClient。
- 配置项:OTA 数据根路径、WatchDog 端口(默认 9776)、超时。
- RBAC`ops.ota.`*;与现有 Ops 审计集成或并行 OTA audit store。
- 包接收端点替代原 Express `:8000``upload-mdcs`* / `upload-history`*。
---
## 9. 验收标准
1. 车辆运维仅见「运维总览」「OTA」;旧 Tab 深链落到 OTA。
2. 可从车拉取或上传包,激活为目标,在车辆升级页看到绿/琥珀对照。
3. 可分批全量或分组件下发;任务中心可见进度;失败可重试;可取消未开始。
4. 延迟检测开关生效:关不探测;开显示 RTT 并按阈值门禁。
5. 配置 JSON 多车下发、自定义文件同步可用。
6. 设置可持久化(带宽、并发、备份、延迟策略)。
7. 写操作有审计;浏览器不直连 `:9776`
---
## 10. 已确认决策摘要
| 决策 | 选择 |
| ------ | ---------------------- |
| 车上协议 | WatchDog |
| IA | 运维总览 + OTA;去掉维护策略与生命周期 |
| 维护策略配置 | 本期删除 |
| 功能范围 | 全面对齐参考工具 + 平台任务/进度/重试 |
| 架构 | MiGu.Server 平台编排 |
| 延迟检测 | OTA 内按钮开关;开才检测 |