codex f33ef5708c fix(cockpit): admit coordinates by primary-area rule instead of manual verification 1 vecka sedan
..
README.md f33ef5708c fix(cockpit): admit coordinates by primary-area rule instead of manual verification 1 vecka sedan
current-warnings-demo.html 903d44d1c1 feat(cockpit): BT-5 真实数据接线收尾 - 四行业与工单字典 0-7 对齐 3 veckor sedan
device-boundary-demo.html b5d7e8678c feat(cockpit): define device identity and domain boundary (#19) 1 månad sedan
equipment-archive-demo.html d6fd256090 feat(cockpit): add equipment archive and latest image (#22) 1 månad sedan
equipment-detail-aggregate-demo.html 2a27481f07 feat(cockpit): add equipment detail aggregation (#26) 1 månad sedan
event-read-demo.html 45b4d35537 feat(cockpit): add warning and alarm read models (#24) 1 månad sedan
foundation-demo.html 06496ecb20 feat(cockpit): add read-only foundation API (#18) 1 månad sedan
freshness-semantics-demo.html a15a5adab2 feat(cockpit): add freshness expiry semantics (#27) 1 månad sedan
handling-efficiency-demo.html 2c8fb911ce feat(cockpit): add warning handling efficiency (#41) 1 månad sedan
history-analysis-demo.html ed9bdafc08 feat(cockpit): add warning history analysis (#40) 1 månad sedan
infrastructure-base-archives-demo.html c9b9647407 feat(cockpit): add infrastructure base archives (#32) 1 månad sedan
infrastructure-emergency-support-demo.html 68c7875b40 feat(cockpit): add infrastructure emergency support (#35) 1 månad sedan
infrastructure-management-information-demo.html 520f4678e7 feat(cockpit): add infrastructure management information (#34) 1 månad sedan
infrastructure-operating-information-demo.html fcfe0378b2 feat(cockpit): add infrastructure operating information (#33) 1 månad sedan
map-snapshot-demo.html 903d44d1c1 feat(cockpit): BT-5 真实数据接线收尾 - 四行业与工单字典 0-7 对齐 3 veckor sedan
monitoring-distribution-demo.html 5642023ae8 feat(cockpit): add monitoring distribution (#37) 1 månad sedan
monitoring-operating-situation-demo.html 3cddd0f74a feat(cockpit): add monitoring operating situation (#38) 1 månad sedan
monitoring-overview-demo.html eb8a3dbd3d feat(cockpit): add monitoring overview (#36) 1 månad sedan
monitoring-point-detail-demo.html a1d0e62488 feat(cockpit): resolve monitoring point status and detail (#21) 1 månad sedan
multidimensional-analysis-demo.html e2b4e45eb0 feat(cockpit): add warning multidimensional analysis (#42) 1 månad sedan
overview-infrastructure-demo.html 3df5d483c7 feat(cockpit): add overview infrastructure summary (#29) 1 månad sedan
overview-monitoring-demo.html e1030643a2 feat(cockpit): add overview monitoring capability (#30) 1 månad sedan
overview-warning-settings-demo.html 078674d33e fix(cockpit): align warning settings efficiency contract (#31) 1 månad sedan
type-metrics-demo.html 74e9963277 feat(cockpit): add type-specific current and historical metrics (#23) 1 månad sedan
websocket-scope-delta-demo.html 903d44d1c1 feat(cockpit): BT-5 真实数据接线收尾 - 四行业与工单字典 0-7 对齐 3 veckor sedan
work-order-seven-states-demo.html 0ec06fbe31 refactor(cockpit): use authoritative seven-state work order dictionary (#25) 1 månad sedan

README.md

城市生命线驾驶舱后端契约:移交与联调手册

本手册面向 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": <httpStatus>, "msg": "<message>", "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):

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。

契约回归:

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 的实机验证仍为未执行项。
  • 认证凭据未写入仓库、文档或记忆库。