城市生命线驾驶舱系统:后端只读接口与实时状态契约
Status: ready-for-agent
2026-09-24 需求裁定完成,后端 BT-5 已从 needs-triage 转回 ready-for-agent,但当前工作树仍未编译通过、接线验收进度为 0%。本文件的当前实现基线优先于历史目标条目。
Problem Statement
城市生命线驾驶舱系统面向指挥中心领导和值班人员,是一个只读展示大屏。UE 需要在进入程序后加载“一张图”,以监测点为首要地图对象,查看关联智能设备的基础档案、当前监测数据、预警、报警和工单处置状态。现有后端主要提供管理型接口,字段、分页和写入能力与驾驶舱展示边界不一致;预警接口仍处于向统一工单模型迁移的阶段,设备状态 WebSocket 也使用旧的驼峰设备字段。
如果 UE 直接拼接管理接口,客户端将不得不推断监测点综合状态、复制事件关系和承担迁移兼容,导致状态口径不一致、地图分页重复、局部详情失败被空数据掩盖以及只读大屏误用业务写接口。因此后端需要提供稳定、版本化、只读的驾驶舱专用契约,并在内部复用现有表和服务。
Solution
新增驾驶舱只读聚合服务和 DTO,统一挂载于 /api/cockpit/v1/。服务端负责从现有监测点、智能设备、设备类型、预警、报警、alarm_warning_rel、工单和指标数据中组合稳定响应;UE 不直接访问管理接口或数据库。当前数据接线必须遵循 2026-09-24 之后的领域模型:设备类型由 equipment_type.id/type_name/parent_id 表示,设备由 equipment_base.equipment_type_id 关联;工单由 work_order.device_id 关联设备,报警转工单由 alarm_data.work_order_id 关联工单,不能再依赖已删除的 work_order.device_code 或旧的直接报警字段。
地图摘要使用一个共享 snapshotAt 的分页快照,分别返回监测点摘要和未关联智能设备摘要。后端返回已解析的 pointStatus、状态原因、统计和坐标校验结果。监测点优先渲染;已关联设备不重复生成独立点位;未关联且坐标有效的设备才作为直接设备点位;无效坐标对象保留在列表和详情中但禁止地图渲染。
设备详情采用基础档案、当前指标、预警、报警、工单、工单时间线和图片等独立只读分区。REST 首次提供权威快照,WebSocket 仅推送状态增量。现有 /ws/deviceStatus 增加 cockpitSubscribe 范围订阅,规范字段使用 deviceCode,迁移期可额外返回旧 device_code;UE 以 serverUpdatedAt 判断新旧消息,断线后自动重连和恢复订阅。
Current-source precedence (2026-09-24): The user stories and decisions below have been brought up to date for the current type IDs, 0–7 work-order states, and four formal industries. The earlier nine-state, old type_id/parent_type_id, and three-industry/manhole-exclusion proposals are historical only. Current runtime facts and implementation gaps are recorded in “Current Implementation Baseline” below; do not infer integration readiness from the target contract.
User Stories
- As a 指挥中心领导, I want the cockpit to load the map frame before data completes, so that the display never appears frozen during startup.
- As a 值班人员, I want paginated monitoring-point summaries, so that a large city dataset can load progressively.
- As a 地图使用者, I want one consistent snapshot across all map pages, so that points are not duplicated or omitted while data changes.
- As a 值班人员, I want unassociated intelligent equipment with valid coordinates to appear directly on the map, so that equipment is not lost when an association is absent.
- As a 数据负责人, I want invalid or unverified coordinates returned with a reason, so that the cockpit never guesses a spatial transform.
- As a 地图使用者, I want the server to return the resolved monitoring-point status, so that UE does not recompute status from a partial page.
- As a 值班人员, I want to click a monitoring point and see its summary and backend-ordered equipment cards, so that I can choose the relevant equipment.
- As a 值班人员, I want to open equipment details by stable equipment code, so that detail navigation does not depend on database primary IDs.
- As a 值班人员, I want equipment archive fields and the latest image, so that I can identify the physical equipment.
- As a 值班人员, I want type-specific current metrics, including sewage environmental metrics when supplied, so that the display reflects the equipment schema.
- As a 值班人员, I want warning and alarm events in separate sections, so that their distinct event families remain clear.
- As a 值班人员, I want current and historical event results with explicit empty and unavailable states, so that missing data is not mistaken for no events.
- As a 值班人员, I want every related work order and its complete current 0–7 runtime-state timeline, so that handling progress is visible without merging records.
- As a 系统集成负责人, I want event and work-order relationships resolved by the backend, so that the cockpit does not infer relationships from names, coordinates or timestamps.
- As a 驾驶舱维护者, I want independent detail sections, so that one failed query does not erase successful sibling sections.
- As a 值班人员, I want a short-lived cached detail with an explicit stale marker, so that I retain context without being misled about freshness.
- As a 值班人员, I want scheduled summary refresh between three and ten minutes and a manual refresh, so that display freshness can match deployment needs.
- As a 系统运维人员, I want device-state calibration to start at sixty seconds and be extendable, so that device population does not overload the service.
- As a 值班人员, I want incremental WebSocket updates to identify the affected device, so that the map and open detail update promptly.
- As a 网络异常场景下的值班人员, I want automatic reconnect and subscription recovery, so that temporary disconnections do not permanently stop updates.
- As a 安全负责人, I want fixed display identity supplied outside UE assets, so that credentials are not exposed in packaged content.
- As a 安全负责人, I want all cockpit endpoints to be read-only, so that display interactions cannot mutate business records.
- As a 后端协作者, I want dedicated JSON fields to use camelCase, so that the contract is consistent with the existing Java stack while keeping database names internal.
- As a 后端协作者, I want
deviceCode to be canonical and device_code to be a migration alias, so that old WebSocket clients remain compatible.
- As a 统计使用者, I want facility counts and intelligent-equipment counts separated, so that water plants and pump stations are not mixed with sensor equipment.
- As a 业务负责人, I want the formal cockpit industry scope to include gas, supply water, drainage and manhole, so that a known manhole type is not silently dropped or folded into drainage and unknown types are not silently counted.
- As a 业务负责人, I want sensor-equipped manholes represented as intelligent equipment under the formal MANHOLE industry, so that the device and facility boundaries remain distinct.
- As a 统计使用者, I want overview, infrastructure, monitoring and warning-disposal metrics to use one timezone and freshness vocabulary, so that dashboards are comparable.
- As a 后端协作者, I want contract handoff material before warning migration replacement, so that the adapter changes from evidence rather than guessed fields.
- As a 测试人员, I want the aggregate behavior observable through one public read model seam, so that contract tests verify user-visible behavior without coupling to database joins.
Implementation Decisions
- Add a versioned read-only cockpit API surface under
/api/cockpit/v1/; keep management endpoints as internal composition sources only.
- Preserve the existing response envelope convention, while placing dedicated camelCase DTOs in the data payload.
- Provide map-summary, monitoring-point-detail and equipment-detail contracts, plus read-only metric, warning, alarm, work-order, timeline and image sections.
- Map summaries use
page, pageSize and snapshotAt; default page size is 500 and maximum is 1000. The response includes total, batch update time and completion metadata.
- Return monitoring points and unassociated equipment as separate collections. A valid published map coordinate is WGS84; missing, zero, out-of-range or unvalidated coordinates fail the render gate and include a reason.
- Return
pointStatus and a status reason from the backend. Fixed codes are ALARM, WARNING, WORK_ORDER, NORMAL, OFFLINE and EMPTY, each with a display label. The backend owns precedence.
- Keep facility and intelligent-equipment statistics separate. Facilities include water plants, pump stations and pipelines; sensor-equipped manholes belong to intelligent equipment under the MANHOLE industry, not to a facility count.
- Use the database
equipment_base.equipment_code as the preferred shared association key. Dedicated cockpit JSON exposes it as deviceCode; legacy data may retain device_code or other aliases inside the adapter boundary.
- Keep warning and alarm event families distinct. Reuse backend authority for
alarm_warning_rel, event cardinality and work-order uniqueness; the cockpit never creates or deduplicates work orders.
- Resolve work-order relationships through current foreign-key paths: device lookup uses
work_order.device_id → equipment_base.equipment_id; alarm lookup uses alarm_data.work_order_id → work_order.order_id; warning lookup uses alarm_warning_rel.warning_id/alarm_id followed by alarm_data.work_order_id. The cockpit must expose deviceCode only after resolving the device record.
- Preserve the current runtime work-order states from
WorkOrderStatusEnum: 0 pending dispatch, 1 pending acceptance, 2 accepted, 3 processing, 4 pending verification, 5 closed, 6 delayed, 7 cancelled. Terminal states are 5 and 7; delayed is a processing side path. The older ADR-0008 target encoding must not be used as a runtime database assumption.
- Use
Asia/Shanghai for business date and statistic boundaries. Emit ISO-8601 timestamps with timezone information and return selected range, timezone and update time.
- Extend
/ws/deviceStatus with cockpitSubscribe and scope=all, while retaining existing device-code subscription compatibility. REST provides initial snapshots; WebSocket sends changed-device deltas only.
- WebSocket payloads use canonical
deviceCode, may include legacy device_code, and include current status, statusTime and serverUpdatedAt. No sequence field is added; newest serverUpdatedAt wins.
- On reconnect, the client may resubscribe automatically. The service must not treat subscription, refresh or detail queries as business writes.
- Enforce service identity at the deployment or gateway layer. Do not embed credentials in UE, DTOs or packaged assets. Use standard HTTP errors to distinguish empty data, invalid input, missing resources, authentication failure and server failure.
- Implement the read model by composing existing tables and services first. Add indexes or a projection only after query and representative-scale measurements demonstrate the need.
- Do not publish unverified CAD coordinates. Conversion from CGCS2000, Xi'an 80, Beijing 54 and elevation references happens before publication and requires later control-point validation.
Testing Decisions
- Use one highest-level public seam: a fake read-only cockpit adapter feeds the aggregate presentation contract with deterministic map pages, details and WebSocket updates; assert only public DTO behavior, freshness, selection identity and update results.
- Add controller/service contract tests for response envelopes, camelCase fields, status dictionaries, HTTP error categories, pagination snapshot consistency and facility/equipment count separation.
- Add integration tests against representative database fixtures for monitoring-point association, unassociated equipment, invalid coordinates, event-family separation,
alarm_warning_rel relationships and the current 0–7 work-order states (including delayed as a non-terminal state).
- Add WebSocket tests for canonical and legacy device-code fields, delta-only pushes,
serverUpdatedAt ordering, missing point status fallback, scope subscription, reconnect subscription and heartbeat behavior.
- Add read-only safety tests using an adapter/request spy; all map loading, detail loading, refresh, retry and subscription operations must produce no business mutation request.
- Add freshness tests for successful empty results, one missed cycle, two missed cycles, stale retention and independent section failure.
- Add statistics tests for timezone boundaries, selected ranges, formal industry filtering, unknown-type exclusion and separate facility/equipment totals.
- Reuse existing Spring controller/service test conventions and add dedicated contract fixtures rather than testing private SQL helpers or requiring a particular join implementation.
Current Implementation Baseline (2026-09-24)
This section records the current repository and database facts discovered during the requirements resynchronization. It is not an acceptance claim and does not authorize implementation changes.
- The repository
HEAD has moved through alarm and work-order structural refactors after the original cockpit contract work. The current worktree also contains uncommitted cockpit adapter changes from the previous connection attempt.
equipment_type currently exposes id, type_name, and parent_id; the former type_id/parent_type_id vocabulary is obsolete for the current schema. Human ruling: the cockpit public typeCode uses equipment_type.id (serialized as a string at the JSON boundary); adapters must not call removed accessors or reuse old slug codes. Type names remain display labels.
work_order currently contains order_id, order_no, device_id, status and lifecycle fields, but no device_code, alarm_id, case_id, or hazard_id. alarm_data.work_order_id is the current alarm-to-order link. The shared device-fact resolver now queries device_id and treats statuses 0–4 and 6 as open. The public work-order dictionary is still the older 1–7 model and is not yet aligned.
- Current KingbaseES
app_user observation is a sparse snapshot of the real-device database: 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. Treat these rows as real data; the observed counts are time-specific evidence, not production-size guarantees or permission to synthesize more business rows.
- Current data quality is not the prior 2026-09-18 snapshot: only one alarm row is linked to a work order; only six of 35 warnings resolve to an equipment/type record; the current equipment table has two rows while point relations reference many historical/test IDs. Point coordinates include null and outlier values.
- Human ruling: add
MANHOLE as the fourth formal cockpit industry, aligned with the independent manhole type root and frontend filter. monitoring/overview and monitoring/situation now accept it and resolve industry by walking the type tree to its root. Map, distribution, event, and infrastructure validators still reject it; those endpoints are not done.
- Human ruling: use the current real KingbaseES data as the integration baseline, including its sparse relationships; do not synthesize business rows to make counts non-empty. Verify schema and legitimate empty responses, and record which scenarios current data cannot exercise.
- Coordinate choice under the minimal-change constraint: retain the existing
CockpitCoordinateValidator gate. With no trusted verification source in the current schema, coordinateVerified=false and renderable=false; the generic WGS84 range check alone would wrongly pass outliers such as (12,12). A future regional boundary validator requires a separately approved boundary/CRS source and is not part of this round.
- Human clarification: the authoritative work-order "dictionary" means the code enum
WorkOrderStatusEnum, not a separate database table. Runtime states are 0–7 per that enum and ADR-0010; a read-only check found no work-order-status entry in app_user.sys_dict_type/sys_dict_data. There is no additional database-dictionary parity prerequisite.
- The previous “4/22 adapters connected” record is historical progress, not current acceptance. As of 2026-09-24 the worktree compiles (
mvn -pl zksy-admin -am compile -q) and the overview/situation targeted tests pass (34 tests, 0 failures). BT-5 remains open until the remaining slices and the authenticated current-database checklist pass.
Out of Scope
- No UE implementation, UMG changes, Actor implementation, Three.js migration or Pixel Streaming work.
- No login page, role management, threshold configuration, publishing, upgrading, resolving, dispatching, accepting, processing, verifying, approving or other business write operation in the cockpit API.
- No replacement of the existing management APIs or removal of their compatibility behavior.
- No local UE aggregation of monitoring-point state, event relationships, coordinate transforms or work-order uniqueness.
- No Flowable introduction or redesign of the existing work-order state machine.
- No judgment of warning truthfulness or false positives.
- No final GIS accuracy threshold, production-scale performance threshold or Galaxy Kylin certification; these remain later validation gates.
Further Notes
- The backend working tree contains pre-existing uncommitted changes. This spec does not authorize reverting or mixing those changes into the cockpit implementation.
- The warning lifecycle is expected to migrate to the same work-order model as alarms. The dedicated adapter must remain stable while the backend absorbs that migration.
- Before replacing transitional warning mappings, backend handoff must include endpoint paths, request parameters, response examples, field and status dictionaries, relationship/cardinality rules, pagination and freshness semantics, and WebSocket samples.
- Historical note: when this spec was first drafted,
/api/cockpit/v1 was not yet implemented. The current repository now contains cockpit controllers and DTOs, but the real-data adapters in the worktree are not compile-clean under the current domain model; endpoint presence is not evidence of current integration readiness.
- Apply the
ready-for-agent triage label when publishing this spec to Gogs Issues.