# 后端契约缺口交付包(供后端项目经理建票) Status: ready-for-human Labels: ready-for-human Category: handoff Blocked by: None 本文件是 [25: 后端契约缺口待办(跨领域两项 + 补契约清单)](../issues/25-backend-contract-gaps.md) 的交付资产:把复核后**仍然缺失**的后端工作写成可直接建票的草案,交给后端项目经理排期,不需要 agent 再加工。 **已建票(2026-09-18)**:五张草案已在 Gogs `shaoy/pipe-ner-server` 建成真实工单(标签 `needs-triage`,待后端 PM 排期与裁定): | 草案 | Gogs 票号 | 状态 | | --- | --- | --- | | BT-1 | [#59](http://192.168.110.30:3000/shaoy/pipe-ner-server/issues/59) | ✅ 已交付并关闭(2026-09-18) | | BT-2 | [#60](http://192.168.110.30:3000/shaoy/pipe-ner-server/issues/60) | ✅ 已交付并关闭(2026-09-18,走路径①完整) | | BT-3 | [#61](http://192.168.110.30:3000/shaoy/pipe-ner-server/issues/61) | ✅ 已交付并关闭(2026-09-18) | | BT-4 | [#62](http://192.168.110.30:3000/shaoy/pipe-ner-server/issues/62) | ✅ 已交付并关闭(2026-09-18) | | BT-5 | [#63](http://192.168.110.30:3000/shaoy/pipe-ner-server/issues/63) | 🔄 进行中(2026-09-18:`map-snapshot` 第 1/22 片已接真实库,票未关) | BT-6 为可选票,未建。若后端 PM 确认需要,再按下面草案建。 复核基线(2026-09-17,2026-09-18 第三轮复验无变化): - 后端仓库 `E:\pipe-ner-server`,本地 HEAD `ed0ace5`(`test(cockpit): add contract integration environment and handoff (#43)`)。 - 远端 `origin` HEAD 仍是 `e2b4e45`(#42)——**#43 尚未推送**,联调前请确认部署来源是其预期提交。 - 复核方式:只读阅读控制器、响应类、适配器与 `docs/cockpit/README.md`;未改动后端任何文件,未跑构建或调试命令。 ## 一、完成情况总览 票 25 列出的缺口,今天的状态如下(后端 Gogs #33–#43 已交付的切片): | 项 | 内容 | 状态 | 证据 | | --- | --- | --- | --- | | A1 | 跨设备当前事件流 | ✅ 已交付 | `GET /api/cockpit/v1/events/current`(`mode` 必填,`level`/`industry`/`status`/分页);`CockpitCurrentEventsResponse.EventItem` 含 `eventNo/eventType/level/levelColor/status/value/unit/deviceCode/location/industry/longitude/latitude/workOrderSummary` + `sections{events,workOrders}` + `mapFilter.deviceCodes` | | A2 | 跨设备历史事件流 + 时间范围 | ✅ 已交付 | `GET /api/cockpit/v1/events/history-analysis`(`eventFamily` 必填 + `startTime`/`endTime`);回显 `Range{type,startTime,endTime}` | | B | 趋势时间范围可声明 | ⚠️ 仅剩一处 | `monitoring/situation`、`infrastructure/operating-information`、`events/history-analysis`、`events/handling-efficiency`、`events/multidimensional-analysis` 均已支持范围参数;`overview/warning-settings` 仍只有 `mode`(→ 见 BT-3) | | C | 响应/关闭时长聚合 | ✅ 已交付 | `GET /api/cockpit/v1/events/handling-efficiency`:`averageDuration{value,unit,sampleCount,state,reason}` + `durationTrend[]` + 工单 `durationHours`;口径已冻结 `basis = CLOSED_WORK_ORDERS_OVER_TOTAL_EVENTS` | | D | 应急保障域三件套 | ✅ 已交付 | `GET /api/cockpit/v1/infrastructure/emergency-support` | | E | 管理信息域 | ✅ 已交付 | `GET /api/cockpit/v1/infrastructure/management-information` | | F | 设施/行业运行信息 | ✅ 已交付 | `GET /api/cockpit/v1/infrastructure/operating-information` | | G1 | 全局行业筛选落到地图点位 | ❌ 未交付(且路径待裁定) | `map-snapshot` 入参仍只有 `page/pageSize/snapshotAt`;但 `/monitoring/distribution`(#37)已带 `industry`/`deviceType`/`pointStatus`/`region` 与逐点 `industry`/`deviceType`(→ 见 BT-2) | | G2 | 点位摘要补 `industry`、类型、徽标 | ❌ 未交付 | `CockpitMonitoringPointSummary` 仍只有 `pointCode/pointName/pointStatus/statusReasons/longitude/latitude/coordinateValidation` | | G3 | 未关联设备补 `industry`、设备类型 | ✅ 已交付 | `CockpitMonitoringDistributionResponse.UnassociatedEquipmentMarker` | | G4 | 设备编码回联点位(WS 增量可用) | ❌ 未交付 | 四个增量 DTO 均只有 `deviceCode` + 状态,无 `monitoringPointCode`(→ 见 BT-1) | | H | 跨设备设备状态清单 | ✅ 已交付 | `GET /api/cockpit/v1/monitoring/situation`:`abnormalEquipment[]{deviceCode,deviceName,deviceType,industry,region,abnormalType,status,statusReasons,longitude,latitude,coordinateValidation}` + 分页 + `mapFilter.deviceCodes` | 另有 #43 交付的**移交与联调手册**:`docs/cockpit/README.md`(契约总则、字典冻结、端点清单、分页/快照/错误口径、WebSocket 增量、启动与联调检查表、容器化评估、已知未验证项)。这份手册本身已解答了票 25 里「字段名、语义、字典」类的问题,不需要再建票。 ## 二、真实数据接线状态(程序级缺口) 后端目前交付的是**契约**,不是**数据**: - 23 个 cockpit 适配器接口中,**22 个只装配了 `Empty*Adapter`**(`@Service`,直接返回 `...Snapshot.empty(...)`)。 - 唯一接入真实数据的是工单读模型:`BusinessCockpitWorkOrderReadAdapter`(`@Primary`,覆盖 `EmptyCockpitWorkOrderReadAdapter`)。 - 各切片在 `docs/cockpit/` 下的 `*-demo.html` 用的是内嵌 fixtures,不代表真实库数据。 - 计数口径:若不计 `/foundation` 契约自检,则为 22 个读模型接口 / 21 个空实现。 后果:前端把适配层切到真实接口后会拿到**全空快照**(200 + `freshness.state = EMPTY`),mock 阶段不受影响。这项工作需要一个程序级排期(→ 见 BT-5)。 ## 三、建议新建的后端工单 以下每节即一张工单草案,标题与正文可直接复制到 Gogs(`shaoy/pipe-ner-server`)。顺序即建议优先级。 ### BT-1 Cockpit device-to-point linkage(REST + WebSocket)→ Gogs #59 ✅ 已交付 **背景与证据** - `CockpitMapSnapshotService.monitoringPoint()` 只把 `CockpitMapSnapshot.SourceMonitoringPoint.devices` 用于解析点位状态,没有写进响应;`CockpitMonitoringPointSummary` 没有任何设备字段。 - WS 增量只带 `deviceCode`:`CockpitMonitoringDistributionDeviceStatusDelta`、`CockpitMonitoringOverviewDeviceStatusDelta`、`CockpitMonitoringSituationDeviceStatusDelta`、`CockpitOverviewMonitoringDeviceStatusDelta` 四个 DTO 均无 `monitoringPointCode`;`DeviceStatusWebSocketHandler` 全文无点位字段。 - 事件读模型的行也没有归属点位:`CockpitCurrentEventsResponse.EventItem` 与 `history-analysis` 的 row 都缺 `monitoringPointCode`。 - 现有可用但代价高的替代路径:`GET /monitoring-points/{monitoringPointCode}` 的 `devices[].deviceCode`(逐点 N+1)。 - 后端内部已持有该映射(`SourceMonitoringPoint.devices`;`applyDeviceStatusDelta` 能按 `deviceCode` 解析到点位),因此改动量集中在响应层。 **要做什么**(建议 ①+②,③ 视事件面板需要) 1. `CockpitMonitoringPointSummary` 增加 `deviceCodes`(关联设备编码列表),并顺带补 `industry` 与 `typeCode`。 2. WS 增量帧增加 `monitoringPointCode`(未关联设备为 `null` / 不出现)。 3. 事件读模型行增加 `monitoringPointCode` 与 `monitoringPointName`。 **验收标准** - 点位摘要返回关联设备编码;同一 `snapshotAt` 下与 `/monitoring-points/{code}` 的 `devices[]` 一致,且不产生重复点位。 - WS 增量给出 `monitoringPointCode`;未关联设备显式 `null`,不静默丢失。 - 事件行返回 `monitoringPointCode`,无归属时为 `null`。 - 契约测试覆盖 REST 与 WS 两侧;`docs/cockpit/README.md` 与字段字典同步更新。 **解除阻塞的前端票**:15(WebSocket 状态联动)、08(地图摘要)、19(当前预警 / 历史分析上图联动)。 ### BT-2 全局行业筛选落图:路径裁定 + 落地 → Gogs #60 ✅ 已交付(走路径①完整) **背景与证据** - `CONTEXT.md` 定义行业筛选是作用于整个驾驶舱的全局条件。 - `GET /map-snapshot` 没有 `industry` 入参;`CockpitMonitoringPointSummary` 也没有 `industry`/类型字段,服务端与客户端都无从过滤。 - 但 `GET /monitoring/distribution`(#37)与 `GET /monitoring/overview` 已支持 `industry`/`deviceType`,distribution 还逐点返回 `industry`/`deviceType` 并给 `mapFilter{industry,deviceType,pointStatus,region,pointCodes,deviceCodes}`。 **要做什么**(二选一,并在 `docs/cockpit/README.md` 第 3 节写明结论) 1. 给 `map-snapshot` 增加 `industry`(以及 `deviceType`)入参,并给 `CockpitMonitoringPointSummary` 补 `industry`/`typeCode`;或 2. 正式声明地图筛选以 `/monitoring/distribution` 为准,`map-snapshot` 保持纯分页快照,前端改取数路径。 **验收标准** - 决策结论写入契约手册,前端不需要猜路径。 - 选定路径端到端可用:服务端完成过滤,`mapFilter` 回显实际生效范围,分页与 `snapshotAt` 语义不变。 **解除阻塞的前端票**:18(运行监测面板,含验收项「面板筛选可作用于地图点位」与监测点台账)、08(地图摘要)。 ### BT-3 warning-settings 趋势窗口可声明 → Gogs #61 ✅ 已交付 **背景与证据**:其余切片都已接受时间范围并回显 `Range`,只有 `GET /overview/warning-settings` 仍只有 `mode`;`CockpitOverviewWarningSettingsResponse.Range{type,start,end}` 结构已存在,窗口目前固定。 **要做什么**:给该端点增加 `range` / `startTime` / `endTime` 入参,填充 `Range` 与 `trend[].bucket`,沿用兄弟切片的范围语义。 **验收标准**:非法范围返回 400 `INVALID_REQUEST`;`range` 回显实际生效区间;趋势桶跟随窗口变化;契约测试与手册同步。 **解除阻塞的前端票**:20(态势总览近 7 日趋势)、总体概览的预警设置面板。 ### BT-4 事件行补 coordinateValidation 与报警阈值 → Gogs #62 ✅ 已交付 **背景与证据**:字典已冻结「无效或未验证坐标 `renderable=false`,禁止渲染」,`CockpitMonitoringDistributionResponse`、`CockpitMonitoringSituationResponse` 等都已携带 `CockpitCoordinateValidation`;但 `CockpitCurrentEventsResponse.EventItem` 只有 `longitude`/`latitude`,没有 `coordinateValidation`,事件因此无法判定能否上图。A1 原建议中的 `thresholdMinValue`/`thresholdMaxValue`(仅报警族)同样缺失。 **要做什么**:事件读模型(`events/current` 与 `events/history-analysis`)的行补 `coordinateValidation`;报警族在数据可得时补阈值字段。 **验收标准**:每条事件携带 `coordinateValidation`(`state`/`reason`/`renderable`/`crs`);坐标缺失或未验证时 `renderable=false` 且有 reason;契约测试与手册同步。 **解除阻塞的前端票**:19(当前预警上图、历史分析定位)。 ### BT-5 真实数据接线(程序级) → Gogs #63 **背景与证据**:见上文「二、真实数据接线状态」——23 个适配器接口中 22 个仍为空实现(不计 `/foundation` 自检则 21/22)。 **要做什么**:按切片补真实适配器(复用既有表与服务,遵循 `cockpit-backend-read-contracts` spec 的「先组合既有表与服务,测量后再加投影/索引」)。建议优先级:先地图与监测链路(`map-snapshot`、`monitoring/distribution`、`monitoring/overview`、`monitoring/situation`、`monitoring-points/{code}`),再基础设施三切片,最后预警处置四切片(其中工单链路已接)。 **验收标准**:每个切片存在非空适配器并被 Spring 装配;用真实库跑通 `docs/cockpit/README.md` 第 6 节的联调检查表 1–7;`snapshotAt` 分页稳定、监测点不重复;空结果仍走 200 + `freshness.state=EMPTY`,不用 5xx 表达空。 **解除阻塞**:所有前端票「接真实接口」的环节(mock 阶段不受阻)。 ### BT-6(可选,待确认)situation 支持 monitoringState 过滤 **背景**:H 的原始需求是「跨设备设备状态清单(如离线设备清单)」。`/monitoring/situation` 已给出分页的 `abnormalEquipment[]`,但它按 `industry`/`deviceType`/时间过滤,没有 `monitoringState` 入参。 **要做什么**:若 `operationOverview` 的离线设备清单需要按状态取数,给 `situation` 增加 `monitoringState`(六态字典)入参。 **验收标准**:传 `OFFLINE` 只返回离线设备;`mapFilter` 回显;不改变默认行为。 **备注**:若 `abnormalEquipment` 已满足面板需求,此票不必建。 ## 四、需要业务方口径(不是后端工单) 1. **「故障」是什么?** 字典现状:点位六态 `ALARM/WARNING/WORK_ORDER/NORMAL/OFFLINE/EMPTY`;指标六态 `NORMAL/WARNING/ALARM/EXPIRED/OFFLINE/UNKNOWN`,且明确 `EXPIRED` 不与 `OFFLINE` 合并;`situation.abnormalEquipment.abnormalType` 是异常分类。需业务确认「故障」是否等于这些集合的子集,还是要一个独立桶。 2. **「处置率」口径**:后端已冻结 `basis = CLOSED_WORK_ORDERS_OVER_TOTAL_EVENTS`(已结案工单数 ÷ 事件总数,见 `docs/cockpit/README.md` 第 2 节)。需业务确认这是否即所说的处置率(含已取消事件)。 3. **「管理单位」与 `maintainer`**:`management-information` 以 `organizations` + `ownershipDistribution` + `unmaintained` 建模,与维护单位分开。需业务确认这一区分并回写术语表。 ## 五、给项目经理的决策点 1. ~~G1 的落图路径二选一(BT-2 的两个方案)。~~ **已裁定(2026-09-18)**:走路径①——地图以 `map-snapshot` 为准,且补全 `industry`/`region`/`deviceType` 三入参与 `mapFilter` 回显;结论见 `docs/cockpit/README.md` 第 3 节。 2. ~~G2/G4 的实现取一或全做(BT-1 的 ①②③)。~~ **已全部实现**:BT-1(#59)交付 G4 三件套,BT-2(#60)交付 G1+G2。 3. 真实数据接线的排期与责任人(BT-5 #63)——这是当前**唯一**剩下的后端缺口(BT-1…BT-4 均已交付关闭)。 4. 提醒:后端本地 `#43` 未推送,远端仍是 `#42`;联调前请确认部署来源提交。 5. 提醒:各切片 `*-demo.html` 是 fixtures,不是真实数据;手册第 7/8 节的容器化与性能均为未验证项。