Files
junhong_cmp_fiber/.planning/phases/03.1-sync-info-phase-3-dto/03.1-CONTEXT.md

10 KiB
Raw Blame History

Phase 03.1: 设备 sync-info 读取链路修复 - Context

Gathered: 2026-03-28 Status: Ready for planning

## Phase Boundary

Phase 3 完成了设备数据的写入侧sync-info 调用 + DB 字段写入 + is_current 更新),但遗漏了读取侧的 DTO 映射和设备实时数据的架构对齐。

本 Phase 修复两类缺口:

  1. 静态 DTO 映射缺口DB 字段已存储但未通过 API 返回)

    • toDeviceResponse 5 个字段未映射 → 影响设备管理列表/详情
    • ListBindings IsCurrent 未映射 → 影响设备绑卡列表接口
    • BoundCardInfo IsCurrent 未映射2 处)→ 影响资产 Resolve/Refresh 响应
    • AssetResolveResponse 缺 5 个 DB 缓存字段 → 影响 admin 资产解析接口
  2. 设备实时数据架构对齐(统一视图的上游属性必须实时查询)

    • 设备上游属性(在线状态/信号/电量/WiFi/当前卡)具有实时特性,存 DB 无意义,必须实时从 Gateway 拉取
    • GetRealtimeStatus 对 device 类型实时调用 Gateway sync-info
    • C 端 GetAssetDeviceRealtimeInfo stub 替换为真实 Gateway 数据

不在本 Phase 范围:

  • 卡资产的上游属性(走轮询系统,已由 DB 存储,无需改动)
  • 设备管理列表(展示 DB 缓存字段即可,不需要实时 Gateway 调用)
  • 设备 Refresh 流程(已有 updateDeviceFromSyncInfo保持现状
## Implementation Decisions

Plan 分组

  • D-01: 全部修复合并为 1 个 Plan。所有变更同属"DTO 映射缺口 + 实时数据架构对齐",无依赖关系需拆分。

静态 DTO 缺口修复

  • D-02: device/service.go:toDeviceResponse() 补全 5 个 DB 缓存字段:

    • OnlineStatusLastOnlineTimeSoftwareVersionSwitchModeLastGatewaySyncAt
    • 这些字段对设备管理列表List仍有意义展示 DB 缓存值),保留此映射
  • D-03: device/binding.go:ListBindings() 补全 IsCurrent 字段映射

    • DeviceCardBindingResponse.IsCurrent 直接从 binding.IsCurrent 取值
  • D-04: asset/service.go 中 2 处 BoundCardInfo 构建Resolve path + Refresh path补全 IsCurrent

    • 实现方式:在 bindings 遍历中同时构建 isCurrentMap[b.IotCardID] = b.IsCurrent(与 slotMap 同构)
    • 构建 BoundCardInfo 时追加 IsCurrent: isCurrentMap[c.ID]
  • D-12: asset_dto.go:AssetResolveResponse 新增 5 个 DB 缓存字段,同步更新 asset/service.go:buildDeviceResolveResponse() 映射

    • 新增字段:OnlineStatus intLastOnlineTime *time.TimeSoftwareVersion stringSwitchMode stringLastGatewaySyncAt *time.Time
    • 这些是 DB 存储值Phase 3 写入,上次 sync-info 的快照),不触发 Gateway 调用
    • 适用场景admin 资产 Resolve 接口(/api/admin/assets/resolve/:identifier)快速展示设备上次已知状态
    • 与 D-07GetRealtimeStatus 实时 Gateway 调用互补Resolve = 快速快照Realtime = 精确实时

设备实时数据架构原则

  • D-05: 设备上游属性(在线/信号/电量/WiFi/当前卡)不缓存,必须实时查询 Gateway。原因:设备具有在线/离线实时特性,存 DB 的值在设备离线后立即过时,无法代表真实状态。

    • 对比:卡资产的上游属性通过轮询系统有规律地同步到 DB查询 DB 有意义。
  • D-06: Gateway 调用失败时(设备离线/超时/IMEI 为空)返回部分数据DeviceRealtime 字段为 null资产基础信息正常返回。不抛错误与卡资产处理保持一致。

GetRealtimeStatus 改造

  • D-07: asset/service.go:GetRealtimeStatus() 对 device 类型新增 Gateway 实时调用:
    • 调用 s.gatewayClient.SyncDeviceInfo(ctx, &gateway.SyncDeviceInfoReq{IMEI: device.IMEI})gatewayClient 已注入)
    • 成功:将响应映射到新增的 AssetRealtimeStatusResponse.DeviceRealtime *DeviceGatewayInfo 字段
    • 失败:仅记录 Warn 日志,DeviceRealtime 返回 null

DTO 结构

  • D-08: B 端和 C 端使用独立结构体,不共用。原因:未来管理端可能展示 C 端不展示的字段(如 IMSI、DL/UL stats、LAN/WAN IP 等技术字段)。

    • B 端:新建 DeviceGatewayInfo struct位于 internal/model/dto/asset_dto.go
    • C 端:保留现有 DeviceRealtimeInfo struct位于 internal/model/dto/client_asset_dto.go
    • AssetRealtimeStatusResponse 新增 DeviceRealtime *DeviceGatewayInfo 字段
  • D-09: DeviceGatewayInfoB 端)至少包含以下字段(参考 Gateway sync-info 文档完整映射):

    • 关键:OnlineStatusBatteryLevelRsrp/Rsrq/Rssi/Sinr(信号)、MaxClients(连接数)
    • WiFiSSIDWifiPassword
    • 当前卡:CurrentIccid
    • 附加:SoftwareVersionSwitchModeRunTimeDailyUsageLastOnlineTime
  • D-10: gateway.SyncDeviceInfoResp 当前缺少字段,需补全:

    • 补充:Rsrp intRsrq intSinr intWifiPassword stringIPAddress string
    • 补充:WANIP stringLANIP stringMaxClients intConnectTime string
    • 补充:Status int(设备状态)、IMSI stringULStats stringDLStats string
    • 补充:LimitSpeed intSyncInterval intMACAddress string

C 端 DeviceRealtime stub 替换

  • D-11: C 端 client_asset.go:GetAsset() 中对 device 类型的处理:
    • 删除 buildMockDeviceRealtime() 调用
    • 改为调用 h.assetService.GetRealtimeStatus("device", deviceID) 获取实时数据
    • 将返回的 AssetRealtimeStatusResponse.DeviceRealtime (*DeviceGatewayInfo) 映射到 ClientAssetResponse.DeviceRealtime (*DeviceRealtimeInfo)
    • Gateway 失败时 resp.DeviceRealtime = nil(已处理,不额外报错)

Agent's Discretion

  • DeviceGatewayInfo B 端结构体的字段是否包含所有 Gateway 字段或只包含关键字段agent 可参考 DeviceRealtimeInfoC 端)的完整字段集合决定
  • toDeviceResponseGetRealtimeStatus 调用的冷却 Key 策略(是否需要防止高频调用)由 agent 参考现有 Refresh 冷却 Key 逻辑自行决定

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Gateway 接口文档

  • docs/第三方文档/gateway设备详情同步接口.md — sync-info 完整字段说明data 字段映射表,包含 rsrp/rsrq/sinr/wifi_password 等当前 SyncDeviceInfoResp 缺失的字段)

Phase 3 上下文(继承决策)

  • .planning/phases/03-device-system/03-CONTEXT.md — Phase 3 所有决策D-06结构体位置D-13/14/15updateDeviceFromSyncInfo 实现细节D-08/09存储字段范围

核心修改文件

  • internal/service/device/service.gotoDeviceResponse():补全 5 个字段
  • internal/service/device/binding.goListBindings():补全 IsCurrent
  • internal/service/asset/service.goGetRealtimeStatus():新增 Gateway 调用Resolve/Refresh 两处 BoundCardInfo补全 IsCurrent
  • internal/model/dto/asset_dto.go — 新增 DeviceGatewayInfoAssetRealtimeStatusResponse 新增 DeviceRealtime 字段;AssetResolveResponse 新增 5 个 DB 缓存字段D-12
  • internal/model/dto/device_dto.go — 已有字段,无需新增(确认映射即可)
  • internal/gateway/models.goSyncDeviceInfoResp 补全缺失字段
  • internal/handler/app/client_asset.go — 删除 buildMockDeviceRealtime() stub改为调用服务 + 映射

当前 SyncDeviceInfoResp 位置

  • internal/gateway/models.go:147 — 当前结构(缺 Rsrp/Rsrq/Sinr/WifiPassword/LANIP/MaxClients 等)

</canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • internal/service/asset/service.go:gatewayClient — 已注入,GetRealtimeStatus 可直接使用
  • internal/service/asset/service.go:updateDeviceFromSyncInfo() — Phase 3 已实现,展示了 SyncDeviceInfoResp → DB 的映射模式,可参考作为 Gateway 响应 → DTO 映射的参考
  • internal/gateway/device.go:SyncDeviceInfo() — 已实现Phase 3直接复用
  • internal/model/dto/client_asset_dto.go:DeviceRealtimeInfo — 完整的 C 端实时信息结构46 字段),对应所有 Gateway 字段,作为 DeviceGatewayInfo 的参考

Established Patterns

  • isCurrentMap 模式:参考 slotMapasset/service.go 的构建方式,isCurrentMap[b.IotCardID] = b.IsCurrent
  • Gateway 失败不阻断主流程:logger.Warn("..."),继续返回部分数据
  • B 端 DTO 字段均需 description tag参考 asset_dto.go 现有字段)

Integration Points

  • asset/service.go:GetRealtimeStatus() — device case 追加 Gateway 调用入口(现只有 getDeviceProtectStatus 和 bindings 查询)
  • handler/app/client_asset.go:GetAsset() — 约第 187-191 行device 类型的 resp.DeviceRealtime = buildMockDeviceRealtime() 替换入口
  • internal/model/dto/asset_dto.go:AssetRealtimeStatusResponse — 新增 DeviceRealtime *DeviceGatewayInfo 字段位置

</code_context>

## Specific Ideas
  • 用户明确:设备上游属性(在线/信号/电量/WiFi/当前卡)不应存 DB,必须实时查询。现有的 online_status 等 DB 字段对于设备管理列表展示仍有价值(缓存上次同步值)。
  • 用户明确:关键实时字段优先级 — 在线状态 > 信号强度 > 连接数 > 电量 > WiFi 名称 + WiFi 密码 > 当前使用卡 ICCID
  • DeviceGatewayInfoB 端)与 DeviceRealtimeInfoC 端结构独立为未来管理端展示更多技术字段IMSI、LAN/WAN IP、DL/UL stats 等)预留空间
## Deferred Ideas
  • 设备 Refresh 接口的语义重新评估(用户提到"刷新接口对设备而言意义不大")——当前 Refresh 仍保留(写回 DB 供管理列表使用),但未来可能弃用 —— Phase 4+ 评估
  • GetRealtimeStatus 的防高频调用冷却 Key若 C 端每次进入详情页都触发 Gateway 调用,需评估频率)—— 留待 Phase 4 运营优化

Phase: 03.1-sync-info-phase-3-dto Context gathered: 2026-03-28 (updated: 2026-03-28, added D-12)