# 城市生命线驾驶舱后端契约:移交与联调手册 本手册面向 UE / 前端对接团队,记录 `/api/cockpit/v1/` 的目标契约、字典、分页、错误与实时增量口径,并给出联调检查表。**当前代码与数据库已于 2026-09-24 发生结构变化,旧冻结字典不能直接当成当前运行时验收结果;第 8 节的“当前重建基线”优先于历史描述。**对应的契约测试仍为 `CockpitContractIntegrationTest` 与 `CockpitContractDictionaryTest`(#69 起新增 `CockpitMonitoringPointDetailSnapshotContractTest` 覆盖跨端点同快照契约);第 3 行早期“工作树编译未通过”仅描述 2026-09-24 前的状态,当前可编译状态以第 8 节为准。 ## 1. 契约总则 - 所有接口均为**只读**:仅 `GET`,不存在任何处置、派发、确认类写入口。**2026-09-28 起驾驶舱 GET 接口免鉴权**:`GET /api/cockpit/v1/**` 匿名可访问,不再要求 `Authorization`;接口安全性由部署环境的网络层内网隔离保障。非 GET 请求、其它业务 API 与管理端接口仍需认证。 - 统一响应信封:`{ "code": 200, "msg": "操作成功", "data": {...} }`;错误为 `{ "code": , "msg": "", "data": { category, message, requestId, serverTime } }`。 - JSON 字段一律 `camelCase`。数据库列名属适配器内部细节,不出现在契约中。 - 设备唯一关联键:对外使用 `deviceCode`(对应 `equipment_base.equipment_code`)。设备主键内部使用 `equipment_base.equipment_id`;`work_order` 当前通过 `device_id` 关联设备,不能读取已删除的 `work_order.device_code`。WebSocket 迁移期同时下发 `device_code` 作为兼容别名。 - 时区:业务时区固定 `Asia/Shanghai`,所有时间戳为带偏移量的 ISO-8601(如 `2026-09-02T10:00:00+08:00`)。 - 可选请求头 `X-Request-Id`;未提供时服务端生成,响应与错误体中都会回传。 ## 2. 字典冻结 | 字典 | 取值 | 说明 | | --- | --- | --- | | 等级颜色 | `1 RED` / `2 YELLOW` / `3 BLUE` / `4 GREEN` / `UNKNOWN` | 1红2黄3蓝4绿 | | 监测点状态 | `ALARM` `WARNING` `WORK_ORDER` `NORMAL` `OFFLINE` `EMPTY` | 优先级即此顺序,后端负责裁决 | | 指标状态 | `NORMAL` `WARNING` `ALARM` `EXPIRED` `OFFLINE` `UNKNOWN` | 运行监测专用,`EXPIRED` 不与 `OFFLINE` 合并 | | 工单状态 | **当前运行时**:0待派单 1待接单 2已接单 3处理中 4待验收 5已结案 6延期中 7已取消 | 以当前 `WorkOrderStatusEnum`/`work_order.order_status` 为准;终态为 5、7,延期中为处理旁路。旧 ADR-0008 的“从 1 开始七态”只保留为历史决策,不得当作当前数据库编码 | | 新鲜度 | `CURRENT` `STALE` `EXPIRED` `EMPTY` `FAILED` | 每次响应携带 `freshness` | | 错误类别 | `UNAUTHORIZED` `SERVER_ERROR` `INVALID_REQUEST` `SNAPSHOT_EXPIRED` `NOT_FOUND` | 401/500/400/400/404 | 效率口径固定为 `basis = CLOSED_WORK_ORDERS_OVER_ELIGIBLE_WORK_ORDERS`:分子=状态 5(已结案)工单数,分母=状态 0–6 工单数之和(状态 7 已取消排除),工单范围=当前筛选内**全部工单**(按 `work_order.create_time` 界定时间窗口,不要求关联报警/事件);分母为 0 时回 `state=EMPTY` + `reason=NO_ELIGIBLE_WORK_ORDERS`,前端显示「不适用」而非 0%。同一个工单范围口径同时用于 `events/handling-efficiency`、`events/history-analysis`(汇总)与 `overview/warning-settings`(两个 family 共用一份范围读数);历史分析的小时桶与预警设置的日趋势仍是**事件**时间桶,与汇总处置率口径不同。旧 `CLOSED_WORK_ORDERS_OVER_TOTAL_EVENTS`(已结案 ÷ 事件总数)与「状态 6 / 事件总数」口径已废止。系统不判断预警真伪,契约中不存在任何准确率、误报率字段。 ## 3. 端点清单 四大业务模式: | 模式 | 端点 | 主要参数 | | --- | --- | --- | | 总体概览 | `GET /api/cockpit/v1/overview/infrastructure` | — | | 总体概览 | `GET /api/cockpit/v1/overview/monitoring` | `industry` | | 总体概览 | `GET /api/cockpit/v1/overview/warning-settings` | `mode`(WARNING\|ALARM) `range` `startTime` `endTime` | | 基础设施 | `GET /api/cockpit/v1/infrastructure/base-archives` | `industry` `facilityType` `ageBucket` `district` | | 基础设施 | `GET /api/cockpit/v1/infrastructure/operating-information` | `industry` `range` `from` `to` | | 基础设施 | `GET /api/cockpit/v1/infrastructure/management-information` | `industry` `district` | | 基础设施 | `GET /api/cockpit/v1/infrastructure/emergency-support` | `category` `industry` `area` | | 运行监测 | `GET /api/cockpit/v1/monitoring/overview` | `industry` `deviceType` | | 运行监测 | `GET /api/cockpit/v1/monitoring/distribution` | `industry` `deviceType` `pointStatus` `district` `page` `pageSize` `snapshotAt` | | 运行监测 | `GET /api/cockpit/v1/monitoring/situation` | `industry` `deviceType` `startTime` `endTime` `page` `pageSize` | | 预警处置 | `GET /api/cockpit/v1/events/current` | `mode`(必填) `level` `industry` `status` `page` `pageSize` | | 预警处置 | `GET /api/cockpit/v1/events/history-analysis` | `eventFamily`(必填) `level` `industry` `startTime` `endTime` | | 预警处置 | `GET /api/cockpit/v1/events/handling-efficiency` | `eventFamily`(必填) `industry` `level` `workOrderState` `startTime` `endTime` `page` `pageSize` | | 预警处置 | `GET /api/cockpit/v1/events/multidimensional-analysis` | `eventFamily`(必填) `industry` `level` `eventType` `cause` `deviceType` `district` `startTime` `endTime` | 一张图与详情: | 用途 | 端点 | | --- | --- | | 地图分页快照(**地图取数路径**) | `GET /api/cockpit/v1/map-snapshot?page&pageSize&snapshotAt&industry&district&deviceType` | | 监测点详情 | `GET /api/cockpit/v1/monitoring-points/{monitoringPointCode}?snapshotAt` | | 设备档案(含最新图片) | `GET /api/cockpit/v1/equipments/{deviceCode}/archive` | | 类型指标 | `GET /api/cockpit/v1/equipments/{deviceCode}/metrics/current`、`.../metrics/history` | | 事件 | `GET /api/cockpit/v1/equipments/{deviceCode}/events/current`、`.../events/history` | | 工单 | `GET /api/cockpit/v1/equipments/{deviceCode}/work-orders`、`/events/{eventSource}/{eventCode}/work-orders` | | 工单时间线 | `GET /api/cockpit/v1/work-orders/{workOrderCode}/timeline` | | 设备详情聚合 | `GET /api/cockpit/v1/equipments/{deviceCode}/detail-aggregate` | | 新鲜度 | `GET /api/cockpit/v1/equipments/{deviceCode}/freshness` | | 契约自检 | `GET /api/cockpit/v1/foundation`、`GET /api/cockpit/v1/device-boundary` | ### 地图筛选路径(冻结结论) **全局行业/范围筛选落到地图,以 `map-snapshot` 为准**(本结论替代「以 `/monitoring/distribution` 为准」的候选路径): - 地图(跨四个模式常驻的中央一张图)只从 `map-snapshot` 取数;`/monitoring/distribution` 是运行监测模式「监测分布」面板的载荷,不作为地图取数路径。 - `map-snapshot` 的目标契约接受 `industry`、`district`、`deviceType` 三个筛选入参;分页与 `snapshotAt` 语义不因筛选改变。**2026-09-24 人工裁定**:正式行业扩为 `GAS` / `WATER_SUPPLY` / `DRAINAGE` / `MANHOLE`(井盖为独立根类型);对外 `typeCode` 使用 `equipment_type.id` 的字符串形式,`type_name` 仅用于展示。`monitoring/overview`、`monitoring/situation`、`map-snapshot`、`monitoring/distribution`、事件和基础设施服务均按该四行业口径校验;对外 `typeCode` 使用 `equipment_type.id` 的字符串形式,`type_name` 仅用于展示。旧 `type_id/parent_type_id` 不是当前 schema 字段。 - 服务端完成过滤,并在响应 `mapFilter{industry,district,districtName,districtFilter,deviceType,pointCodes,deviceCodes}` 回显**实际生效范围**(编码为过滤后全量、分页前,升序)。 - `coordinateValidation` 汇总是**当前筛选范围内的全量口径**(再切片分页);逐点/逐设备保留 `renderable=false` 的对象。 - 逐点 `industry` 由类型推导(口径同 distribution:类型可解析、`objectKind = SMART_DEVICE`、行业属正式行业);不可推导时为 `null`,**默认不排除对象**,仅在请求了 `industry`/`deviceType` 过滤时按推导结果筛选。 ### 片区(district)契约(执行票 12,2026-10-08) - **权威来源**=`equipment_base.district`(`0`城南 / `1`城北 / `2`太常,见 `DistrictEnum`)。**点位没有自有片区列**,按「经其上挂设备归纳」取得:多设备片区不一致、或没有任何设备、或有设备但片区不可信 → **未分区**。管网设施无片区来源,一律未分区。 - **响应形态=编码 + 中文名**:`district`(Integer,未分区为 `null`)+ `districtName`(String,未分区回字面量「未分区」)。统计保留数字、展示层映射中文。 - **筛选入参**:`district=0|1|2` 按片区、`district=UNASSIGNED` 只看未分区、不传=不筛;**其它值一律 400**(`district must be 0, 1, 2 or UNASSIGNED`),脏值不参与筛选。 - **`mapFilter.districtFilter`** 取值 `NONE`(未筛)/ `ASSIGNED`(按片区)/ `UNASSIGNED`(只看未分区)—— 「未筛」与「只看未分区」的编码都是 `null`,必须靠该字段区分。 - **旧自由串 `region` 已废止**:入参不再接受(被忽略),响应中 `region` / `regionDistribution` 已更名为 `district` / `districtDistribution`。前端 `map.filters.regionMap` 配置映射随之失效。 - **管理信息已删字段**(决策票 06):`organizations`、`ownershipDistribution`、`totals.unmaintainedCount`;改回 `districtIndustry[]`(片区×行业的设施/设备计数)。 在线试用每个切片的样例响应:打开 `docs/cockpit/` 下的同名 `*-demo.html`(离线自包含,无需后端)。 ## 4. 分页、快照与错误口径 - `page` 默认 1;`pageSize` 默认 100(地图快照默认 500),上限 1000;越界返回 `INVALID_REQUEST`。 - `map-snapshot` 的 `page > 1` 必须携带**首屏无 token 请求签发**的同一 `snapshotAt`,否则 `SNAPSHOT_EXPIRED`;显式 token 仅复用已签发快照,缓存未命中不得按该时间重读当前库。同一 `snapshotAt` 下分页结果稳定,监测点优先、已关联设备不重复出点。 - 坐标不可上图的对象(结构非法,或落在主场景区外)保留在列表与详情中,但 `coordinateValidation.renderable = false`,禁止渲染。 - **坐标准入(2026-10-12 维护者裁定,取代此前的「人工校核前置」)**:入库坐标即视为可信来源,判据为「结构合法 + 落在主场景区范围内」。判定顺序:缺经度/缺纬度/经度越界/纬度越界/零坐标 → 各自的 `INVALID` 原因;数值合法但落在主场景区外 → `INVALID` / `OUTSIDE_PRIMARY_AREA`;其余 → `VALID` / `renderable=true`。 - 主场景区闭区间(与前端部署配置 `map.primaryArea.bounds` 一致):`west=110.328749941417, south=28.3917230659234, east=110.465779226663, north=28.4913038992907`,常量与 `insidePrimaryArea()` 收在 `CockpitCoordinateValidator` 一处。 - **`coordinateVerified` 入参保留但不再影响结论**:现网既无可信校核字段也无校核入口,继续把它当前置门槛会让全部真实对象恒不可上图(实测修复前 map-snapshot 15/15、`infrastructure/geometry` 5272/5272 全不可渲染)。 - 因此新流程**不再产生 `UNVERIFIED`**;`UNVERIFIED_COORDINATE` 仅保留给历史快照与「调用方未提供校验段」的防御路径。 - 成功但无数据返回 200(例如 `freshness.state = EMPTY`),不得用 5xx 表达空;仅上游读取失败才 `SERVER_ERROR`。 - 时间范围口径:预设 `range` 取值 `LAST_24_HOURS` / `LAST_7_DAYS` / `LAST_30_DAYS`(`infrastructure/operating-information` 与 `overview/warning-settings` 同款);显式区间用 `startTime`/`endTime`(ISO-8601 带偏移,必须成对出现且 `startTime ≤ endTime`,回显 `range.type = CUSTOM`)。`overview/warning-settings` 不声明窗口时维持 `CURRENT_BASELINE`(`start`/`end` 为 `null`,趋势桶不筛选)。 - `overview/warning-settings` 的趋势桶是**业务时区日期**(`yyyy-MM-dd`),声明窗口时按「桶日期落在窗口起止日期之间(含端点)」筛选,**桶顺序沿用适配器顺序**;桶标签无法解析时保留该桶,不静默丢数据。 - 未知类型、非智能设备、非正式行业在**按行业/类型筛选时**显式排除,不做静默归类;`map-snapshot` 不带筛选时仍返回全部对象(`industry`/`typeName` 为 `null`),保证「全城底图」不因类型数据缺失而丢对象。 - 事件行(`overview`/`warningResponse` 的 `events/current` 的 `EventItem`)携带 `coordinateValidation`,与地图/监测切片**同一校验实现**(`CockpitCoordinateValidator`);坐标结构非法、越界或落在主场景区外时 `renderable = false` 且给出 `reason`。 - 事件坐标按同一自动准入判定(不再依赖 `coordinateVerified`):区内且数值合法 → `VALID` / `renderable=true`。报警族在数据可得时另带 `thresholdMinValue`/`thresholdMaxValue`(预警族为 `null`)。 - `events/history-analysis` 的 `rows[]` 是**小时桶聚合行**,不存在逐事件行,因此不携带 `coordinateValidation` 与阈值字段(逐事件坐标只在 `events/current` 提供)。 ### 监测点详情设备坐标 `GET /api/cockpit/v1/monitoring-points/{monitoringPointCode}` 的 `data.devices[]` 保留点位下的全部关联设备(包括离线设备),以 `deviceCode` 作为唯一关联键,并返回设备自身坐标与状态: | 字段 | 语义 | | --- | --- | | `longitude` / `latitude` | 来自 `equipment_base` 的设备坐标;不会复制所属监测点坐标,也不会人工偏移。缺失时字段为 `null`。 | | `coordinateValidation.state` | `VALID`(可上图)或 `INVALID`(不可上图)。新流程不再产生 `UNVERIFIED`。 | | `coordinateValidation.reason` | 不可上图时的非空原因:`MISSING_LONGITUDE`、`MISSING_LATITUDE`、`LONGITUDE_OUT_OF_RANGE`、`LATITUDE_OUT_OF_RANGE`、`ZERO_COORDINATE` 或 `OUTSIDE_PRIMARY_AREA`。 | | `coordinateValidation.renderable` | 结构合法**且**落在主场景区内时为 `true`;前端仅在此为 `true` 时绘制设备点位。 | | `coordinateValidation.crs` | 当前统一为 `WGS84`。 | 当前 `equipment_base` 没有可信坐标校核字段,但按 2026-10-12 裁定**不再需要**它:真实适配器透传设备坐标,由 `CockpitCoordinateValidator` 按「结构合法 + 主场景区内」自动准入,因此区内设备 `renderable=true` 可正常上图;区外设备保留在详情清单中并给出 `OUTSIDE_PRIMARY_AREA`。 **跨端点同快照(#69)**: - 监测点详情接受可选查询参数 `snapshotAt`(ISO-8601、必须带 `+08:00`,语义与 `map-snapshot` 一致)。提供 `snapshotAt` 时,详情与地图按时间戳复用首次读取的地图快照;相同时间戳不会因两次请求之间的点位/设备关联变化而重新读取,详情 `devices[]` 与 `map-snapshot` 对应点位的 `deviceCodes` 集合一致(含离线设备、不重复、不静默丢失)。快照存于 Redis,保留至 `snapshotAt` 后 10 分钟的有效窗口结束,应用节点共享;单节点本地最多缓存 256 份以减少 Redis 读取。过期时返回 `SNAPSHOT_EXPIRED`;Redis/缓存不可用返回 `SERVER_ERROR`,调用方应分别刷新快照或提示上游暂不可用。 - 未提供 `snapshotAt` 时走详情适配器路径(尽力模式):两个请求之间点位-设备关系变化时,详情与地图集合可能不一致,前端按决策票 05「跨端点尽力展示并提示可能不一致」处理。 - **坐标准入口径(2026-10-12 起)**:不再要求人工校核来源,改按「结构合法 + 落在主场景区内」自动判定。现网真实监测点/设备/管线坐标基本都落在主场景区内(实测 `map-snapshot` 12/15、`infrastructure/geometry` 5269/5272 可上图),因此**关联设备位置可正常绘制**。区外对象(含 `(0,0)` 零坐标、测试占位值)仍不可上图,但保留在清单与统计中并给出具体原因。 ## 5. WebSocket 实时增量 端点:`/ws/deviceStatus`(**免鉴权**,与驾驶舱 REST 一致;安全性由网络层内网隔离保障)。 ``` // 订阅全量驾驶舱状态:连接后直接发送,无需 authenticate 帧(2026-09-28 起) → {"type":"cockpitSubscribe","scope":"all"} ← {"type":"cockpitSubscribed","scope":"all","serverUpdatedAt":"2026-09-02T10:00:00+08:00"} // 设备状态增量推送(迁移期同时下发 device_code 别名;monitoringPointCode 关联监测点, // 未关联设备为 null 且不静默丢失;eventId 为报警标识透传,发布方未携带时显式 null) ← {"type":"cockpitDeviceStatusDelta","deviceCode":"TC-PS-WS-202609020012", "device_code":"TC-PS-WS-202609020012", "monitoringPointCode":"MP-001", "eventId":null, "data":{"status":"ALARM","statusTime":"2026-09-02T09:59:50+08:00", "serverUpdatedAt":"2026-09-02T10:00:00+08:00"}} // 工单状态增量推送(执行票 13,2026-10-09 起):扫描检测到 orderStatus 真实变化时 // 批量推给全量订阅会话;首扫只建基线不推送(REST 才是初始快照) ← {"type":"cockpitWorkOrderStateDelta","scanIntervalMs":60000, "serverUpdatedAt":"2026-10-09T10:00:00+08:00", "data":{"items":[{"workOrderCode":"WO202609291245022597", "deviceCode":"TC-PS-WS-202609020012","stateCode":5,"stateName":"已结案"}], "total":1}} ``` `authenticate` 帧仅服务管理端工单推送(`workOrderReminder` 需要用户身份),驾驶舱链路不使用、不要求。 客户端以 `serverUpdatedAt` 判新旧(新者胜),REST 提供首帧权威快照,WebSocket 只推变化设备;断线后重新订阅即可。设备状态校准周期默认 60 秒,可配置延长。 增量帧字段口径:`monitoringPointCode` 为设备关联监测点的编码(`equipment_base.equipment_code` → `equipment_point_rel` → `monitor_point.point_code`);未关联设备该字段显式 `null`,不静默丢失。`data.reason` 无异常时显式 `null`。 **工单状态增量口径(执行票 13)**:`cockpitWorkOrderStateDelta` 由后端定时扫描 `work_order.order_status` 逐单比对产生(工单状态流转不写 `update_time`,不能靠时间过滤),只有真实变化才推送;`scanIntervalMs` 是诚实标注的更新延迟上限(默认 60 秒,`websocket.cockpit-work-order-delta.scan-interval-ms` 可配),消费方据此标注「状态变化最迟 N 秒内可见」。帧内**不携带工单 updateTime**(该列在状态流转时不更新,携带会误导),变化时刻以帧级 `serverUpdatedAt`(扫描时间)为准。`stateCode`/`stateName` 出自工单状态字典单源(0–7,与 REST 读模型一致);字典外的脏码原样上报、`stateName` 显式 `null`;工单对外标识是 `workOrderCode`(order_no),**不泄漏数据库主键 orderId**(与 REST 读模型同口径)。**该帧与 `cockpitDeviceStatusDelta` 语义不同**:后者是设备在线/报警状态,不得当作工单状态消费(决策票 01)。工单被删除(现网无此操作)不产生增量,由消费方 REST 重取兜底。 ## 6. 启动与联调 后端启动(Java 11+,Maven 3.9): ```bash cd pipe-network-service mvn -DskipTests package java -jar zksy-admin/target/zksy-admin.jar --spring.profiles.active=dev ``` 或使用自带脚本 `./ry.sh start|stop|restart|status`。`ry.sh` 已固定 `-Duser.timezone=Asia/Shanghai`。 契约回归: ```bash mvn -pl zksy-admin -am test -Dtest='Cockpit*Test' ``` 联调检查表: 1. **无凭据** `GET` 任一驾驶舱端点,返回 200 且 `data.readOnly = true`(2026-09-28 起免鉴权;接口安全由网络层内网隔离保障)。 2. 对每个端点构造一次非法参数,确认 400 `INVALID_REQUEST` 且不产生业务写入。 3. 用 `snapshotAt` 连续请求 `page=1..n`,确认 `total` 一致、监测点不重复。 4. 用同一 `deviceCode` 依次请求 archive / metrics / events / work-orders / detail-aggregate,确认关联一致。 5. `detail-aggregate` 中任一分区失败时,其余分区仍返回数据。 6. 建立 WebSocket,发送 `cockpitSubscribe(scope=all)`,确认收到 `cockpitSubscribed` 与后续增量。 7. 校验所有时间戳均为 `+08:00`,`freshness` 与实际数据新鲜度一致。 8. 对任一驾驶舱端点发非 GET 请求(如 POST),确认仍被拒绝(405 由映射决定,其余非 GET 仍需认证)。 ## 7. 国产化与容器化可行性 本仓库**当前没有** Dockerfile 或容器编排文件,容器化属于后续工作,此处只记录评估结论: - 运行面:标准 JVM 应用(Java 11 字节码)+ **当前 KingbaseES** / Redis / Nacos;旧文档中的 MySQL 是历史评估假设,不是当前真实数据源。迁移到 aarch64/loongarch64 信创环境仍需对应架构的 JDK、KingbaseES 驱动与实机验证,不应仅凭代码推断无需修改。 - 银河麒麟:主要风险在中文字体、时区与 TLS 库,而非业务代码;`Asia/Shanghai` 已由 `ry.sh` 与各切片 `Clock` 统一约束。 - Docker:可行。建议以 `eclipse-temurin:11-jre`(或信创基础镜像)为基座,外置 `application-prod.yml` 与密钥,数据库走独立容器或既有实例。若目标环境禁止容器,直接以 systemd + `ry.sh` 部署同样可行。 - 内存基线:`ry.sh` 默认 `-Xms512m -Xmx1024m`,如需在驾驶舱工作站与渲染任务共存,建议按实际并发上调堆上限。 - 性能测量:本轮未做生产规模压测,属未验证项;建议在取得真实设备规模后,用同一 `snapshotAt` 对 `map-snapshot` 与 `monitoring/distribution` 做分页吞吐与前端渲染测量,再决定是否加投影或索引。 ## 8. 当前重建基线(2026-09-28) 本节记录本轮读取到的当前代码、KingbaseES schema 事实和真实 HTTP 验收结果;它覆盖并取代 2026-09-18 以前的真实库数量与旧字段假设。认证验收使用本机 IntelliJ 启动的 `127.0.0.1:8301`,该实例通过 Nacos 连接当前 KingbaseES;`192.168.110.30:8301` 部署端口仍不可达。 ### 当前数据库模型 - `equipment_type` 当前列为 `id`、`type_name`、`parent_id`;旧 `type_id`、`parent_type_id` 不存在。对外 `typeCode = String(equipment_type.id)`;行业沿类型树上溯到根,正式行业为 `GAS`、`WATER_SUPPLY`、`DRAINAGE`、`MANHOLE`。 - `monitor_point` 当前实际列为 `point_id`、`point_code`、`point_name`、`location`、`longitude`、`latitude`、`remark`、`create_by`、`create_time`、`update_by`、`update_time`、`del_flag`;`network_id`、`point_type`、`installation_date`、`status` 不存在。Java 实体保留这些兼容字段但以 `@TableField(exist = false)` 标记,驾驶舱不臆造这些值。 - `equipment_point_rel` 当前实际列为 `rel_id`、`equipment_id`、`point_id`、`create_time`,没有 `del_flag`;Java 兼容字段不参与持久化映射,关联查询按当前表列执行。 - `equipment_base.equipment_type_id` 指向 `equipment_type.id`;`equipment_type_name` 是查询补充字段,不是持久化列。 - `work_order` 当前以 `device_id` 关联 `equipment_base.equipment_id`,不再有 `device_code`、`alarm_id`、`case_id`、`hazard_id` 列;报警转工单使用 `alarm_data.work_order_id → work_order.order_id`,案例和隐患分别通过各自的 `work_order_id` 关系读取。 - `alarm_data` 持久化 `device_code`、`work_order_id`、`warning_code`、`alarm_level`、`alarm_status`、`create_time`、`audit_status` 等;设备名称、设备类型、坐标、工单补充字段属于查询投影,不是表列。 - 工单运行时状态为 `0..7`:0待派单、1待接单、2已接单、3处理中、4待验收、5已结案、6延期中、7已取消;终态为 5/7,6 为处理旁路。 ### 当前真实库只读观测 - 既有只读探查记录:`work_order=1`、`alarm_data=3`、`early_warning=35`、`alarm_warning_rel=3`、`equipment_base=2`、`equipment_status=2`、`monitor_point=7`、`equipment_point_rel=20`、`case_info=2`、`hazard_hidden_account=12`;这些数量是观测时点事实,不代表生产规模。 - 点位仍存在空坐标与 `(12,12)` 等异常坐标;当前 schema 没有可信坐标校核字段。2026-10-12 起不再依赖该字段:数值合法且落在主场景区内即 `renderable=true`(不再产生 `UNVERIFIED`),区外归 `OUTSIDE_PRIMARY_AREA`。**这仍是呈现层准入,不等于业务坐标已校核**——库里出现明显错误但落在区内的坐标依然会被画出来,人工核查该列数据的责任仍在业务侧。 - 真实 `map-snapshot` HTTP 响应在本轮样例中返回 `total=15`,分页样例包含 9 个点位对象和 7 个设备编码;设备关系与样本数据会随数据库内容变化,响应的 `snapshotAt` 是唯一分页依据。 ### 当前代码可验收性 - `mvn -pl zksy-admin -am compile -q` 通过;`mvn -pl zksy-admin -am test "-DfailIfNoTests=false" -q` 全量回归通过。 - 地图、分布、事件、基础设施及概览服务当前均接受四个正式行业;地图快照通过 Redis 共享同一 `snapshotAt` 内容,带 10 分钟有效窗口、过期重校验和单节点 256 条本地缓存上限。 - 本轮 `11e5d9a` 进一步修正深层 `equipment_type.parent_id` 行业上溯、`RELEASED` 当前预警状态、未知行业不计入正式总量并进入 excluded,以及 `work_order_log.oper_type` 0–10 操作码到运行时 0–7 工单状态的时间线映射。 - 本轮 `3e9289d` 为点位详情响应补充统一 `freshness` 和 `staleReason`:同 `snapshotAt` 快照返回 `CURRENT`,未提供快照的尽力路径显式标记 `BEST_EFFORT_SOURCE`,过期仍返回 `SNAPSHOT_EXPIRED`。 - 本轮 `7e0d2c8` 将基础档案、运行信息和总体概览的共用泵站读取统一为显式 `station_type IN (water_supply, drainage)`,避免供水/排水数据串读。 - 本机真实登录态 HTTP 验收通过:登录成功;未认证请求返回 401 `UNAUTHORIZED`;4 个非法参数样例返回 400 `INVALID_REQUEST`;同一 `snapshotAt` 的 5 页地图请求总数稳定且点位不重复;点位详情和同一设备的 archive / metrics / events / work-orders / detail-aggregate / freshness 均返回 200 且 `readOnly=true`;列出的概览、基础设施、监测、事件和契约自检端点均返回 200 且只读。 - 本轮真实登录态补充验收:16 个端点非法参数样例全部返回 400 `INVALID_REQUEST`;以真实 `deviceCode` `860347065467627` 依次请求 archive、metrics、events、work-orders、detail-aggregate、freshness,均返回 200、`readOnly=true` 并回显同一 canonical `deviceCode`。 - 第 4 轮 `detail-aggregate` 的 MockMvc 故障注入证明:单条时间线失败保留其余成功时间线和档案/指标;返回其他工单的顶层或内层日志编码会被拒绝,聚合仍以 200 `PARTIAL` 返回未受影响分区。这是契约测试证据,未在真实服务上制造业务故障。 - 第 4 轮真实 HTTP 复核(重启加载 `f33b9bf`):首屏无 token 返回 200 并签发 `snapshotAt=+08:00`、`total=15`;使用该 token 请求第 2 页返回 200、同 `snapshotAt`、同 `total`;第 2 页缺 token 和使用旧未签发 token 均返回 400(契约类别由 MockMvc 固化为 `SNAPSHOT_EXPIRED`)。 - 第 7 轮补充 Redis GET/SET 运行时异常测试:适配器将缓存连接故障包装为 `CockpitReadException`,控制器契约映射为 `500 SERVER_ERROR`,不误报为 `SNAPSHOT_EXPIRED`;定向与全量回归均通过。 - 第 8 轮本机受控性能烟测:同一真实 `snapshotAt` 连续认证请求 30 次,30/30 成功,平均 24.10ms、P95 30.60ms、最大 34.35ms;本次 live 数据样例 `total=7`。该结果仅代表本机进程和当前数据量,不替代生产规模压测。 - 第 9 轮改动前逐端点扫描:16 个主要 endpoint 全部 HTTP/app code 200;扫描到的全部 ISO 时间戳均为 `+08:00`。当时其中 11 个 endpoint 显式提供 freshness;`events/current`、`events/history-analysis`、`events/handling-efficiency`、`events/multidimensional-analysis` 和 `device-boundary` 尚无统一 freshness 字段。 - 第 10 轮重启后的本机真实登录态复验:上述 5 个端点均返回 HTTP/app code 200、`readOnly=true` 和 `freshness=CURRENT`。该结果仅确认当前非空样本的字段与状态;尚未证明数据的实际时效或空数据、故障场景下的状态准确性。 - **验收边界**:上述 200/readOnly 证明当前本机实例的认证与响应契约,不等于 #63 全部切片的代表性真实数据、空/脏数据及故障场景均已验收。静态装配盘点显示 23 个 `Empty*Adapter` 均有对应的 `@Primary Business*Adapter`(另有 1 个共享事件事实适配器);`Empty*Adapter` 作为 fallback 保留,不能仅凭类仍存在判断运行时未接线。目标部署实例仍需验收,issue 保持开启。 - WebSocket `/ws/deviceStatus` 真实浏览器验收通过:发送 `cockpitSubscribe(scope=all)` 后收到 `cockpitSubscribed`,响应带 `serverUpdatedAt`;所有抽查时间戳为 `+08:00`。 - 目标部署地址 `192.168.110.30:8301` TCP 不可达,因此没有把它当作本轮 HTTP 证据;生产部署实例、性能压测、银河麒麟与 Docker 实机验证仍未执行。 ## 9. 已知边界与未验证项 - 当前工单运行时状态以 ADR-0010 的 0–7 八值枚举为权威;旧 cockpit 七态目录仍存在于部分响应模型/测试中,需继续确认映射方案后才可宣称所有工单详情状态已完全对齐。 - 本轮已完成本机 8301 真实登录态和当前 KingbaseES 的第 6 节检查表 1–7 主要路径验收,但目标部署端口不可达;生产规模性能、银河麒麟与 Docker 的实机验证仍为未执行项。 - 认证凭据未写入仓库、文档或记忆库。