## 一、系统定位

当前项目不是业务库写入服务。它的核心职责是把 GB/T 32960、JT/T 808、JT/T 1078、JSATL12、 MQTT、信达 Push 等不同来源的车辆数据统一转换为 `VehicleEvent` 和全字段 `TelemetrySnapshot`， 再通过 Kafka、原始报文归档、Parquet 明细文件库、Redis 热状态和独立统计模块交给下游业务。

接入方式 Netty TCP、MQTT、HTTP Push、后续可扩展更多 Inbound Adapter。
统一模型 所有协议归一到 `VehicleEvent` 和全字段内部 `TelemetrySnapshot`。
输出方式 Kafka Protobuf Envelope + 原始 bytes 冷存 + Parquet/DuckDB + Redis 热状态。
业务边界 日统计由 `vehicle-stat-service` 消费 Kafka 实现，告警工单、资产业务继续由下游消费。

## 二、模块分层图

    flowchart TB
      subgraph external["外部来源"]
        vehicle["车辆终端
    GB/T 32960 / JT808 / JT1078"]
        mqttSource["车企或平台 MQTT"]
        xindaSource["信达 Push"]
        commandClient["业务系统 / 运维平台
    HTTP 下行命令"]
      end

      subgraph protocolModules["协议模块 modules/protocols"]
        gb["protocol-gb32960
    32960 Netty 接入、鉴权、ACK、解析"]
        jt808["protocol-jt808
    808 Netty 接入、会话、位置/批量位置、媒体、透传、下行"]
        jt1078["protocol-jt1078
    1078 信令 + TCP/UDP RTP 媒体流归档"]
        jsatl12["protocol-jsatl12
    主动安全附件流接入"]
      end

      subgraph inbound["入口适配 modules/inbound"]
        mqtt["inbound-mqtt
    MQTT endpoint 生命周期、PEM TLS"]
        mqttProfile["MqttProfileRegistry
    按 endpoint profile 解析/映射"]
        xinda["inbound-xinda-push
    HTTP Push 适配"]
      end

      subgraph protocolBase["核心与公共能力 modules/core"]
        codec["ingest-codec-common
    BCD / CRC / BCC / bit 工具"]
        session["session-core
    设备会话、命令分发接口、会话存储"]
        identity["vehicle-identity
    跨协议身份解析、外部标识绑定、文件持久化"]
        obs["observability
    metrics / tracing / health"]
        api["ingest-api
    ProtocolId / RawFrame / VehicleEvent / 注解 SPI"]
        registry["HandlerRegistry
    按协议、命令、infoType 路由"]
        dispatcher["Dispatcher
    RawFrame 到 Handler 到 EventBus"]
        bus["DisruptorEventBus
    高吞吐事件发布"]
      end

      subgraph sink["输出与明细存储 modules/sinks"]
        mq["sink-mq
    VehicleEvent 到 Protobuf Envelope 到 Kafka"]
        archive["sink-archive
    RawArchive 到本地/S3/OSS 冷存"]
        fileStore["event-file-store
    VehicleEvent/RawArchive 索引到 Parquet，DuckDB 按日查询"]
      end

      subgraph services["消费服务 modules/services"]
        history["event-history-service
    Kafka 全字段事件到历史查询/导出"]
        state["vehicle-state-service
    Kafka 全字段事件到 Redis 热状态"]
        stat["vehicle-stat-service
    Kafka 全字段事件到可配置日统计"]
      end

      subgraph apps["应用入口 modules/apps"]
        gateway["command-gateway
    HTTP 到设备命令入口"]
        bootall["bootstrap-all
    聚合所有 AutoConfiguration 一体启动"]
      end

      vehicle --> gb
      vehicle --> jt808
      vehicle --> jt1078
      vehicle --> jsatl12
      mqttSource --> mqtt
      mqtt --> mqttProfile
      mqttProfile --> api
      xindaSource --> xinda
      commandClient --> gateway

      gb --> codec
      jt808 --> codec
      jt1078 --> codec
      jsatl12 --> codec

      gb --> api
      jt808 --> api
      xinda --> api
      xinda --> dispatcher
      jsatl12 --> archive
      jsatl12 --> jt808

      api --> registry
      registry --> dispatcher
      dispatcher --> bus
      bus --> mq
      bus --> archive
      bus --> fileStore
      mq --> history
      mq --> state
      mq --> stat

      gateway --> session
      session --> jt808
      session --> gb
      identity --> jt808
      identity --> mqttProfile
      identity --> xinda

      obs -.监控.-> dispatcher
      obs -.监控.-> bus
      obs -.监控.-> mq
      bootall -.装配.-> gb
      bootall -.装配.-> jt808
      bootall -.装配.-> mqtt
      bootall -.装配.-> xinda
      bootall -.装配.-> mq
      bootall -.装配.-> archive
      bootall -.装配.-> fileStore
      bootall -.装配.-> history
      bootall -.装配.-> state
      bootall -.装配.-> stat

      classDef entry fill:#eff6ff,stroke:#2563eb,color:#1e3a8a;
      classDef core fill:#ecfdf3,stroke:#0f766e,color:#134e48;
      classDef sink fill:#fffbeb,stroke:#b45309,color:#7c2d12;
      classDef command fill:#f5f3ff,stroke:#6d28d9,color:#4c1d95;
      classDef support fill:#f8fafc,stroke:#64748b,color:#334155;

      class gb,jt808,jt1078,jsatl12,mqtt,mqttProfile,xinda entry;
      class api,registry,dispatcher,bus,identity core;
      class mq,archive,fileStore sink;
      class gateway,session command;
      class codec,obs,bootall support;

入口/协议模块 核心管线 输出层 下行命令/会话

## 三、上行数据流转

    sequenceDiagram
      autonumber
      participant Device as 车辆/平台
      participant Inbound as Inbound Adapter
    Netty/MQTT/Push
      participant Decoder as FrameDecoder
    MessageDecoder
      participant Dispatcher as Dispatcher
      participant Handler as Protocol Handler
    Mapper
      participant EventBus as DisruptorEventBus
      participant MQ as sink-mq
    Kafka Envelope
      participant Archive as sink-archive
    ArchiveStore
      participant FileStore as event-file-store
    Parquet + DuckDB
      participant Consumer as 下游业务消费者

      Device->>Inbound: 原始报文 bytes / MQTT message / HTTP payload
      Inbound->>Decoder: 粘包拆帧、校验、协议体解析
      Inbound->>Inbound: MQTT 按 endpoint profile 选择厂商解析器
      Decoder->>Dispatcher: RawFrame(protocol, command, infoType, payload, rawBytes)
      Dispatcher->>EventBus: 先发布 RawArchive 事件
      EventBus->>Archive: 保存原始 bytes，生成可回放材料
      Dispatcher->>Handler: 根据 protocol + command + infoType 路由
      Handler->>Handler: 协议字段映射为内部字段
      Dispatcher->>Handler: 绑定 rawArchiveKey / rawArchiveUri
      Handler->>EventBus: VehicleEvent(Realtime / Location / Alarm / Login ...)
      EventBus->>MQ: 投递规整后的业务事件
      EventBus->>FileStore: 写入解析后明细事件
      MQ->>MQ: EnvelopeMapper 转 Protobuf
      MQ->>Consumer: Kafka topic，key=vin，单车有序
      FileStore->>Consumer: 按日期范围正序/倒序查询和导出
      Consumer->>Consumer: 历史明细查询、Redis 热状态、可配置日统计、告警工单

关键边界： 协议字段只在协议模块内解释，出了 Mapper 以后都应该使用内部字段。统计每日里程、每日用电量、每日用氢量、储氢安全和氢泄露告警时，应消费全字段 TelemetrySnapshot，不要直接依赖某个协议的原始字段名。
原始追溯： Dispatcher 为所有带 rawBytes 的 RawFrame 生成统一的 `rawArchiveKey`，业务事件 metadata 使用 `rawArchiveUri=archive://...` 指向同一份原始 bytes。归档文件的真实本地/S3/OSS 地址只属于 ArchiveStore，查询、导出和 Kafka Envelope 使用逻辑 URI 解耦存储实现。

## 四、32960 细化链路

    flowchart LR
      terminal["氢能车 TBOX
    GB/T 32960"] --> netty["Gb32960NettyServer
    TCP / TLS / Idle 检测"]
      netty --> access["Gb32960AccessService
    VIN 白名单 / 平台登录鉴权"]
      netty --> frame["Gb32960FrameDecoder
    拆帧、转义、校验"]
      frame --> decoder["Gb32960MessageDecoder
    Header + Body 解析"]
      decoder --> diag["Gb32960FrameDiagnostics
    首帧、Raw 块、异常诊断"]
      decoder --> handler["Gb32960ChannelHandler
    ACK / NACK / dispatch"]
      handler --> ack["Gb32960AckService
    登录应答、失败断开"]
      handler --> dispatcher["Dispatcher"]
      dispatcher --> rtHandler["Gb32960RealtimeHandler"]
      rtHandler --> mapper["Gb32960EventMapper
    协议字段到内部字段"]
      mapper --> realtime["RealtimePayload
    速度、里程、电量、氢量、压力、温度"]
      mapper --> alarm["AlarmPayload
    安全分类、氢泄露、告警等级"]
      mapper --> login["Login / Logout / Heartbeat"]
      realtime --> bus["DisruptorEventBus"]
      alarm --> bus
      login --> bus
      bus --> kafka["Kafka Envelope"]
      bus --> archive["RawArchive 冷存"]

      classDef safety fill:#fff1f3,stroke:#b42318,color:#7a271a;
      classDef core fill:#ecfdf3,stroke:#0f766e,color:#134e48;
      classDef entry fill:#eff6ff,stroke:#2563eb,color:#1e3a8a;
      classDef sink fill:#fffbeb,stroke:#b45309,color:#7c2d12;

      class terminal,netty,frame,decoder,handler entry;
      class access,diag,ack,dispatcher,rtHandler,mapper,bus core;
      class alarm safety;
      class kafka,archive sink;

## 五、模块职责表

模块 | 职责 | 主要输入 | 主要输出 | 业务开发关注点
--- | --- | --- | --- | ---
modules/core/ingest-api | 定义系统边界：协议 ID、RawFrame、IngestContext、VehicleEvent、Payload、Handler 注解、Sink SPI；ProtocolId 提供 UNKNOWN 隔离桶，供消费侧兼容未来协议或脏数据，不作为正式接入协议使用；consumer 包定义 EnvelopeIngestor、EnvelopeConsumerProcessor 和 EnvelopeDeadLetterSink，统一 Kafka 消费结果与死信边界。 | 无直接外部输入。 | 全项目共享的接口和内部事件模型。 | 内部字段定义新增事件类型字段兼容性
modules/core/ingest-codec-common | 公共编解码工具，承载 BCD、CRC、BCC、bit 操作等协议底层能力。 | 协议模块传入的 byte、bit、校验材料。 | 解析辅助结果。 | 协议基础能力
modules/core/ingest-core | 核心管线。扫描 Handler，按协议和命令路由，执行拦截器，发布 VehicleEvent 到 Disruptor。 | RawFrame。 | VehicleEvent、RawArchive。 | 吞吐路由原始可回放
modules/core/session-core | 设备会话、命令下发抽象、SessionStore、CommandDispatcher 默认实现。SessionStore 支持 `memory` 和 `redis` 两种后端；生产默认使用 Redis 保存 `sessionId`、VIN 和 phone 三索引及 TTL，内存实现作为本地开发/无 Redis 降级，协议模块只依赖 SPI，不感知存储后端。 | 设备连接、命令请求。 | 会话状态、命令分发结果、Redis 会话索引。 | 在线状态下行控制多实例会话索引
modules/core/vehicle-identity | 跨协议车辆身份解析，维护 phone、deviceId、plate 到 VIN 的绑定关系；支持 memory 和 append-only JSONL file 后端，避免重启丢失绑定。 | 协议模块传入的外部标识。 | 稳定 VIN、解析来源、是否已命中绑定。 | 统计主键多协议归一持久化绑定
modules/core/observability | 监控、指标、追踪、健康检查等横切能力。 | 核心管线和 Sink 运行状态。 | Micrometer 指标、健康信息。 | 可用性延迟监控
modules/protocols/protocol-gb32960 | GB/T 32960 接入、鉴权、ACK、报文解析、实时数据和告警映射。 | 32960 TCP 报文。 | Realtime、Location、Alarm、Login、Logout、Heartbeat、RawFrame。 | 氢泄露储罐安全电量/氢量里程
modules/protocols/protocol-jt808 | JT/T 808 接入、注册/鉴权/心跳/注销、位置/位置附加项、批量位置、参数/属性、多媒体、透传、未知上行兜底透传、分帧边界异常和协议解析异常坏帧兜底、下行命令和超长下行分包能力；0x0200 位置附加项 0x01 总里程按 0.1km 解码为内部字段 `total_mileage_km`，后续每日里程统计不依赖 808 原始字段；0x0102 鉴权帧解析会保留完整 token，并尽量提取 IMEI 和软件版本；注册和鉴权会话均使用共享身份解析后的内部 VIN，避免 deviceId/IMEI 污染后续会话和下行边界；终端连接断开时同步解绑 Channel 并清理 `SessionStore` 会话，避免 command-gateway 误判离线车辆仍可下行；正常上行 RawArchive 和业务事件 metadata 均使用共享身份解析后的内部 vin，并保留 phone、identityResolved、identitySource 便于冷存和业务事件按同一车辆查询；无法解析终端身份的坏帧 RawArchive 和 Passthrough 均按 vin=unknown、identityResolved=false、identitySource=UNKNOWN 标记；0x0900 透传事件按原始消息 ID 归类，透传类型写入 passthroughType metadata。 | 808 TCP 报文。 | Location、Login、Logout、Heartbeat、MediaMeta、Passthrough、未知上行 Raw 兜底、坏帧 Passthrough、会话状态、下行响应。 | GPS 位置在线状态媒体证据命令链路
modules/protocols/protocol-jt1078 | JT/T 1078 音视频能力。信令在 JT808 mapper 存在时桥接复用 JT808 连接和包头；0x1005 乘客流量保留原始 body，同时结构化 channelId、startTime、endTime、passengerGetOn、passengerGetOff metadata 便于查询/导出；0x1205 文件列表保留原始 body，同时结构化 responseSerialNo、fileCount 摘要；下行信令编码由本模块提供，覆盖 0x1003 音视频属性查询、0x9101 实时预览、0x9102 实时控制、0x9201 历史回放、0x9202 回放控制、0x9205 资源列表查询、0x9206 文件上传和 0x9207 文件上传控制，命令发送仍由 command-gateway 经 CommandDispatcher 复用 JT808 在线通道；TCP/UDP RTP 媒体流独立端口接入，生产默认端口按旧接收服务对齐为 `11078`，按 VIN/通道/时间分段写 ArchiveStore，Kafka 只发送 MediaMeta 引用，事件 metadata 暴露内部 vin、sim、channelId、dataType、packetType、segment、sequence、segmentSizeBytes、archiveKey 和 archiveRef，MediaMeta.sizeBytes 同步当前片段大小，MediaMeta 按 archiveKey 去重，避免同一 SIM 运行中从 fallback 身份切换到内部 VIN 时漏发新归档引用，便于文件明细库追踪、展示和导出；超长/短包/坏魔数等 RTP 入口异常和媒体归档失败都会兜底产出 Passthrough 错误事件，坏 RTP 统一走 Dispatcher 产出 RawArchive 和 Passthrough，统一标记 parseError 和 parseErrorMessage，并保留内部 vin、原始 bytes、peer、长度、原因、RawArchive 引用、segment 和 archiveKey 便于排障；坏 RTP 头部可读时会提取 SIM 并通过共享身份服务映射 VIN。 | 1078 信令报文、TCP/UDP RTP 媒体流。 | MediaMeta、乘客流量 Passthrough、文件列表 Passthrough、坏 RTP/归档失败 Passthrough、归档媒体分段。 | 视频扩展信令事件化大流冷存
modules/protocols/protocol-jsatl12 | 苏标主动安全报警附件接入。依赖 ArchiveStore 和 JT808 decoder；生产默认端口按旧接收服务对齐为 `7612`；附件 DataPacket 按旧服务真实布局 `01cd + 50B文件名 + offset + length + data` 分帧解析，不再把文件名前 4 字节误判为帧长；附件数据写 ArchiveStore 后通过 Dispatcher 产出 MediaMeta 引用事件，事件 metadata 保留 fileName、fileOffset、declaredChunkSizeBytes、archiveKey 和 archiveRef，便于附件明细查询、导出和补传诊断；内置附件状态机处理 T1210 文件清单、DataPacket 分块区间和 T1212 上传完成消息，数据分块会按 T1210 文件清单中的文件名继承手机号并通过共享身份解析器得到内部 VIN，入口 RawFrame、ArchivedChunk 和 MediaMeta 均保留 phone、vin、identityResolved、identitySource，只有找不到文件归属时才标记 UNKNOWN；按文件名合并无身份数据分块并返回 0x9212 完成/补传应答，补传应答包含缺失 offset/length 区间；附件归档失败会产出 JSATL12 Passthrough 错误事件并保留原始分块；JT_MESSAGE 信令复用 JT808 decoder 后进入 Dispatcher，桥接 RawFrame 使用共享身份解析后的内部 VIN并保留 phone、identityResolved、identitySource，坏 JT 信令入口 RawFrame 同样标记 UNKNOWN 身份；超长/畸形附件帧、未闭合超长 JT 信令和坏 JT 信令都以 JSATL12 Passthrough 兜底，附件帧异常同时标记 frameError 与统一 parseError/parseErrorMessage，保留原始字节、peer、长度和错误元数据，帧长和 worker 线程支持部署配置。 | 主动安全附件流、JT808 信令帧。 | 归档文件、MediaMeta、JT808 统一事件、坏帧/坏信令/归档失败 Passthrough。 | 附件归档报警证据信令复用错误隔离
modules/inbound/inbound-mqtt | MQTT 多 endpoint 生命周期管理，支持 PEM CA、客户端证书/私钥双向 TLS，按 endpoint profile 路由到厂商解析/映射实现，默认提供宇通 profile；生产默认接入口径参考旧接收服务：`ssl://cpxlm.axxc.cn:38883`、topic `/ytforward/shln/+`、QoS 2、cleanSession=false、keepAlive=20s、connectTimeout=10s，用户名和密码仍通过环境变量注入；入站 RawFrame 和事件映射均接入统一车辆身份解析，解析器保留 externalVin、phone、mqttDeviceId、plateNo，优先按设备号/终端 ID/IMEI 绑定解析内部 VIN，未绑定且字段形态为 VIN 时再作为显式 VIN 兜底，冷存和事件 metadata 均保留这些外部标识、identityResolved、identitySource；未知 profile、解析失败、profile 运行时异常、endpoint 初始化/连接/订阅失败均兜底为 Passthrough，解析失败诊断和 profile 异常诊断都会同步写入 RawArchive metadata，并在最终 Passthrough 事件保留 parseErrorMessage 或 operational reason，无法解析设备身份的兜底事件和运行类归档都按 vin=unknown、identityResolved=false、identitySource=UNKNOWN 标记，保留原始 payload 或 operational 错误信息便于排障和归档追溯。 | MQTT topic/message、endpoint profile、TLS PEM 配置。 | 统一 RawFrame、Realtime、Location、Passthrough。 | 车企平台接入 profile 扩展身份映射双向 TLS 错误隔离
modules/inbound/inbound-xinda-push | 信达 Push 接入适配，基于 PushClient 接收真实协议帧并统一转换为 RawFrame；入站 RawFrame 和事件映射均接入统一车辆身份解析，冷存和事件 metadata 均携带内部 vin，并保留 externalVin、phone、deviceId、plateNo、identityResolved、identitySource；0200 映射 Location，并将 totalMileage、mileage 等里程别名归一为内部字段 `total_mileage_km`；0300 映射标准 AlarmPayload，氢气泄漏类报警统一提升为 HYDROGEN_LEAK/CRITICAL 并标记 hydrogenLeakDetected、hydrogenLeakActionRequired，报警元数据保留 alarmType、alarmName、alarmLevel；未知业务 cmd、非法十六进制 cmd、JSON 异常、身份解析/业务处理异常、启动配置缺失、启动异常、登录拒绝和坏登录应答均兜底为 Passthrough，运行类错误按 vin=unknown、identityResolved=false、identitySource=UNKNOWN 归档，非法 cmd 命令码归零并标记 malformedCommand，业务消息 JSON 异常会在 RawArchive metadata 和最终 Passthrough 事件同时保留 parseErrorMessage，业务处理异常会保留原始 payload 并标记 operationalError、phase=message 和 reason，便于归档追溯。 | 信达 Push payload。 | RawFrame、Location、Passthrough、operational error。 | 第三方平台接入统一 Dispatcher 身份映射
modules/sinks/sink-mq | Kafka Sink。把 VehicleEvent 转成 Protobuf Envelope，按 VIN 分区投递；业务事件携带全字段 TelemetrySnapshot 和 rawArchiveUri，显式 RawArchive Envelope 会填充 archive:// 逻辑 URI 与 size，默认 Kafka Sink 仍不发送原始 bytes 本体；同时提供 KafkaEnvelopeConsumerFactory、KafkaEnvelopeConsumerRunner、KafkaEnvelopeConsumerWorker 和 KafkaEnvelopeDeadLetterSink，统一服务侧 Kafka 消费启动、独立 group 绑定、死信发布和 topic 到 EnvelopeConsumerProcessor 的分发。 | VehicleEvent。 | Kafka Protobuf 消息、消费侧 DLQ 记录。 | 单车有序 Schema 演进安全字段下发给消费者
modules/sinks/sink-archive | 原始报文冷存，当前有本地文件系统实现，后续可替换 S3/OSS；写入键与业务事件 metadata 中的 `rawArchiveKey` 保持一致。 | RawArchive 事件、附件流。 | 可回放原始文件、`archive://...` 逻辑引用。 | 问题排查合规留痕
modules/sinks/event-file-store | 文件型明细库，使用 Parquet 存储解析后的事件明细和 RawArchive 可查询索引，使用 DuckDB 按日期范围正序/倒序查询；RawArchive 只存 archive:// 逻辑 URI、命令码、长度和 metadata，不嵌入原始 bytes，原始 bytes 本体仍由 sink-archive 管理；读取历史文件时未知 protocol 会降级为 UNKNOWN，避免查询中断。 | VehicleEvent 或 EventFileRecord。 | protocol/date 分区的 Parquet 文件和查询结果。 | 按日查询导出字段配置
modules/services/event-history-service | 消费 Kafka 全字段事件，写入文件型明细库，并提供历史查询和 CSV 导出边界；导出支持通过 `fields` 参数选择内部字段并平铺为 CSV 列，也支持 `metadata.xxx` 导出协议侧诊断、媒体归档、报警类型等 metadata 字段；未知 Envelope source 会进入 UNKNOWN 协议分区，并在 metadata 保留 `originalSource` 便于回溯；生产消费可使用 `tryIngest` 和自动装配的 `EnvelopeConsumerProcessor` 将坏 protobuf、缺快照和存储异常收敛为结构化结果，并通过 `EnvelopeDeadLetterSink` 发布死信，避免阻塞 Kafka 分区。 | Kafka Protobuf Envelope。 | EventFileRecord、查询结果、可配置字段 CSV。 | 历史明细多日导出字段配置
modules/services/vehicle-state-service | 消费 Kafka 全字段事件，更新车辆最新状态、位置、安全和最后事件到 Redis；生产消费可使用 `tryIngest` 和自动装配的 `EnvelopeConsumerProcessor` 隔离坏 protobuf 和缺快照 Envelope，并把失败记录交给死信出口。 | Kafka Protobuf Envelope。 | `vehicle:state:{vin}`、`vehicle:location:{vin}`、`vehicle:safety:{vin}`。 | 毫秒级热查询氢泄露安全
modules/services/vehicle-stat-service | 消费 Kafka 全字段事件，抽取统计源点，按车辆规则计算每日里程等日统计；生产消费可使用 `tryIngest` 和自动装配的 `EnvelopeConsumerProcessor` 隔离坏 protobuf，缺少 telemetry_snapshot 的消息会标记为 SKIPPED 并进入死信出口。 | Kafka Protobuf Envelope、车辆统计规则。 | 按 `vin + stat_date` 保存的日统计结果。 | 每日里程规则配置
modules/apps/command-gateway | HTTP 到设备下行命令入口。支持会话查询、808 位置查询、参数查询/设置、终端控制、平台通用应答、终端属性查询 0x8107、区域删除 0x8601、人工报警确认 0x8203，以及 1078 音视频属性查询、实时预览/控制、历史回放/控制、资源列表查询、文件上传/控制；通过 CommandDispatcher 复用 protocol-jt808 的在线通道、流水号和同步应答等待能力。 | 业务系统命令请求。 | CommandDispatcher 调用、设备应答摘要。 | 远程控制参数设置属性查询区域删除报警确认视频控制
modules/apps/bootstrap-all | 一体化启动模块，聚合各模块 AutoConfiguration 和运行配置。 | application.yml、Spring Boot 启动。 | 完整接入服务实例。 | 部署开关配置

## 六、氢能业务开发落点

业务主题 | 当前建议落点 | 说明
--- | --- | ---
车辆状态、速度、位置 | `RealtimePayload`、`LocationPayload` | 32960 和 808 都可能提供位置。统计侧需要明确优先级，例如优先 32960，缺失时用 808 补点。
每日里程 | Kafka 下游统计服务 | 接入层只投递总里程和实时点位；日增里程建议下游按 VIN、自然日、事件时间聚合，处理回补和乱序。
每日用电量 | 内部电池字段 + 下游统计 | 接入层保留 SOC、电压、电流等瞬时字段；若有累计电耗字段，可加入内部字段模型后统一投递。
每日用氢量 | `hydrogenRemainingKg` + 下游统计 | 优先使用累计氢耗字段；没有累计值时用氢余量差值估算，并在统计结果里标记估算口径。
储氢安全 | `RealtimePayload` 压力/温度 + `AlarmPayload.safetyCategory` | 高压、低压、温度、异常 bit 都应统一归入储罐安全域，下游可做趋势、阈值和连续异常判断。
氢气泄露 | `AlarmPayload.hydrogenLeakDetected` | 当前已作为高优先级安全事件。32960 中出现 `HYDROGEN_LEAK` 时强制映射为 `CRITICAL`。
原始报文追溯 | `RawArchive` + `rawArchiveUri` + `sink-archive` | 业务统计出现争议时，用事件 metadata 中的 `archive://...` 逻辑 URI 回查原始 bytes，结合 eventId、traceId、VIN、时间复现解析链路。
明细展示和导出 | `event-file-store` | 解析后的事件明细和 RawArchive 索引按 protocol/date 写 Parquet。DuckDB 查询时按日期范围读取，并按 event_time 正序或倒序返回。

后续开发建议： 当前 Kafka Protobuf 已加入全字段 `TelemetrySnapshot`。后续业务统计服务继续只依赖内部字段，不依赖 32960 原始字段名，这样接入 808、MQTT、车企私有协议时不会重写统计口径。