From bf331240ebe75e2b85cc9e01470426c95567a211 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Mon, 3 Aug 2026 23:48:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(fleet):=20HOLD=20=E9=80=9A=E7=9F=A5=20admi?= =?UTF-8?q?n=20status/retry=20=E7=AB=AF=E7=82=B9=20changelog=20(#5446)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._5446_HOLD-通知管理端状态查询与受控重试.md | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 changelogs/2026-08/2_5446_HOLD-通知管理端状态查询与受控重试.md diff --git a/changelogs/2026-08/2_5446_HOLD-通知管理端状态查询与受控重试.md b/changelogs/2026-08/2_5446_HOLD-通知管理端状态查询与受控重试.md new file mode 100644 index 0000000..9bd2d1c --- /dev/null +++ b/changelogs/2026-08/2_5446_HOLD-通知管理端状态查询与受控重试.md @@ -0,0 +1,115 @@ +--- +schema: "hl-changelog/v2" +ticket: "5446" +title: "HOLD 通知管理端状态查询与受控重试" +consumer: "admin" +author: "wx(GIT)" +change_type: "新增接口" +backend_status: "deployed" +gateway_status: "not_required" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "后端 PR 待合并到 dev-v3;合并后按验收回填部署 task ID 与网关证据。管理端可领取适配。" +updated_at: "2026-08-03" +base: "dev-v3" +generated: "2026-08-03T23:19:24+08:00" +--- + +# HOLD 通知管理端状态查询与受控重试 + +## 关联 + +- Issue: [#5446](https://git.1814.love:8443/wx/HL/issues/5446) +- Backend tracking: [#5366 B10](https://git.1814.love:8443/wx/HL/issues/5366) +- PR: 待合并后回填 + +## 变更接口 + +| 方法 | 路径 | 来源 | +|---|---|---| +| `GET` | `/admin/fleet/assignments/hold-notification/status` | `hl-fleet-service/src/main/java/com/hulalv/fleet/messagetemplate/controller/AssignmentHoldNotificationAdminController.java` | +| `POST` | `/admin/fleet/assignments/hold-notification/retry` | 同上 | + +路径前缀 `/admin/fleet/**` 已由网关登录/角色校验与 `FleetAdminRoleGuardInterceptor`(VEHICLE_MANAGER / SUPER_ADMIN)收口,无需新增网关规则。 + +## 1. 状态查询 `GET /admin/fleet/assignments/hold-notification/status` + +请求参数(query): + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `assignmentGroupId` | `String(Long)` | 是 | 派车组 ID | +| `notificationGeneration` | `String(Long)` | 是 | HOLD 通知代际 | +| `attemptId` | `String` | 否 | 调用方生成的 attempt 标识(幂等/审计定位),≤64 字符 | + +响应 `data`: + +| 字段 | JSON 类型 | 可空 | 说明 | +|---|---|---|---| +| `assignmentGroupId` | `String(Long)` | 否 | 回显 | +| `notificationGeneration` | `String(Long)` | 否 | 回显 | +| `assignmentStatus` | `String` | 是 | 派车状态;HOLDING=仍在待确认,其余=已离开 holding | +| `deliveryStatus` | `String` | 否 | `NOT_FOUND/PENDING/SENT/FAILED/AMBIGUOUS/INVALIDATED`;`SENT` 只表示系统发送成功,不表示通道送达回执 | +| `messageLogId` | `String(Long)` | 是 | 本地通知日志 ID | +| `outboxEventId` | `String(Long)` | 是 | 可靠通知 Outbox 事件 ID | +| `outboxStatus` | `String` | 是 | `PENDING/PROCESSING/QUARANTINED/SUCCESS` | +| `retryCount` | `Integer` | 是 | Outbox 累计处理重试次数 | +| `sentAt` | `String(date-time)` | 是 | 有可信发送成功事实时返回 | +| `dispatchAttemptedAt` | `String(date-time)` | 是 | 最近一次向通知中心发起分发的时间 | +| `lastError` | `String` | 是 | 最近失败/对账留痕(脱敏) | +| `canRetry` | `Boolean` | 否 | 是否允许管理端重试:仅明确失败且未发送成功且未取消时为 `true` | +| `lastReplayAttemptId` | `String` | 是 | 上次管理端重试 attemptId | +| `lastReplayReason` | `String` | 是 | 上次管理端重试原因 | +| `lastReplayedBy` | `String(Long)` | 是 | 上次重试操作人 | +| `lastReplayedAt` | `String(date-time)` | 是 | 上次重试时间 | +| `attemptStatus` | `String` | 是 | 本次请求 attempt 处理状态:`ACCEPTED/SUCCEEDED/REJECTED/AMBIGUOUS`(持久幂等:同一 attemptId 重复提交直接返回已记录结果) | +| `attemptResultNote` | `String` | 是 | 本次 attempt 处理结果摘要(脱敏) | + +错误码:400 参数校验 / `100001` 派车组不存在 / `100003` 通知代际已过期 / 401 未登录。 + +## 2. 受控重试 `POST /admin/fleet/assignments/hold-notification/retry` + +请求体: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `assignmentGroupId` | `String(Long)` | 是 | 派车组 ID | +| `notificationGeneration` | `String(Long)` | 是 | HOLD 通知代际 | +| `attemptId` | `String` | 是 | 本次重试 attempt 标识(幂等键组成部分 + 审计),≤64 字符 | +| `reason` | `String` | 是 | 核查失败原因后的重试说明,≤200 字 | + +行为约束: + +- 幂等键 = `assignmentGroupId:notificationGeneration:attemptId`,持久化于 `fleet_hold_notification_retry_attempt` 唯一索引,重复提交(含 Redis 防重窗口过期后)幂等返回已记录结果,不重复发送、不重复写 Outbox; +- 仅允许明确失败(`FAILED`,Outbox `QUARANTINED` 或 `PENDING`+错误)的 HOLD 通知重试;`QUARANTINED` 重置失败预算,`PENDING`+错误立即重试; +- `UNKNOWN/AMBIGUOUS`(dispatching)先按通知中心供应商发送日志对账:存在真实外部成功则补记发送事实并返回 `SENT`,仍无法判定则拒绝重试(fail closed); +- stale(代际过期)/missing(派车组或日志不存在)/wrong identity 一律拒绝; +- 重试复用原 Outbox 事件与供应商幂等键,不新建事件、不直接外呼,不改变派车状态; +- 操作人、原因、attemptId 记入 Outbox 审计列(`last_replay_*`)。 + +响应:同状态查询 `data`(重试后最新事实)。 + +错误码:400 参数校验 / `100001` 派车组或通知日志不存在 / `100003` 通知代际已过期或已取消 / `100503` 资源竞争(并发重试)/ 401 未登录。 + +## 契约影响文件 + +- `hl-fleet-service/src/main/java/com/hulalv/fleet/messagetemplate/controller/AssignmentHoldNotificationAdminController.java` +- `hl-fleet-service/src/main/java/com/hulalv/fleet/messagetemplate/service/AssignmentHoldNotificationAdminService.java` +- `hl-fleet-service/src/main/java/com/hulalv/fleet/messagetemplate/vo/AssignmentHoldNotificationStatusReqVO.java` +- `hl-fleet-service/src/main/java/com/hulalv/fleet/messagetemplate/vo/AssignmentHoldNotificationStatusRespVO.java` +- `hl-fleet-service/src/main/java/com/hulalv/fleet/messagetemplate/vo/AssignmentHoldNotificationRetryReqVO.java` +- `hl-fleet-service/src/main/java/db/migration/V20260803_008__add_outbox_hold_replay_attempt_id.java` + +## 前端/调用方动作 + +管理后台新增适配:派车详情/司机通知维度展示 `deliveryStatus` 与 `canRetry`;`canRetry=true` 时提供重试按钮,重试需携带调用方生成的 `attemptId` 与原因;`AMBIGUOUS` 不提供重试入口(等待自动对账)。所有 Long ID 按 String 消费。 + +## 验证证据 + +- 定向测试:`AssignmentHoldNotificationAdminServiceTest` 24 项 / `AssignmentHoldNotificationAdminControllerTest` 5 项 / `HoldNotificationRetryAttemptMapperTest` 2 / `WechatMessageLogMapperTest` 2 / `AssignmentInsuranceOutboxMapperTest` 18 / 迁移可重入测试 2(Fleet reactor verify 3047 项 0 failures,1 项 Docker 环境型 error 与本任务无关) +- Spotless: check 通过 +- 网关验证:待部署后按验收回填 +- 兼容性结论:纯新增端点,无既有字段或行为变更