From ce6aa62fd679de4f2331ad0be4dc96820c8fab7b Mon Sep 17 00:00:00 2001 From: huang Date: Sat, 28 Mar 2026 11:16:02 +0800 Subject: [PATCH] docs(03): capture phase context --- .../phases/03-device-system/03-CONTEXT.md | 132 ++++++++++++++++++ .../03-device-system/03-DISCUSSION-LOG.md | 70 ++++++++++ 2 files changed, 202 insertions(+) create mode 100644 .planning/phases/03-device-system/03-CONTEXT.md create mode 100644 .planning/phases/03-device-system/03-DISCUSSION-LOG.md diff --git a/.planning/phases/03-device-system/03-CONTEXT.md b/.planning/phases/03-device-system/03-CONTEXT.md new file mode 100644 index 0000000..16a41ff --- /dev/null +++ b/.planning/phases/03-device-system/03-CONTEXT.md @@ -0,0 +1,132 @@ +# Phase 3: 设备体系完善 - Context + +**Gathered:** 2026-03-28 +**Status:** Ready for planning + + +## Phase Boundary + +扩展设备数据模型(D-0)、对接 Gateway sync-info 同步接口(D-1)、建立"当前使用卡"标识(D-2)、将刷新接口接入 sync-info 完成端到端数据更新(D-3)。 + +全部为修复性/完善性变更,无新业务模块。仅影响设备相关模型、Gateway 客户端、资产刷新服务。 + + + + +## Implementation Decisions + +### Plan 分组策略 + +- **D-01:** 拆分为 **2 个 Plan**: + - **Plan 1(基础层)**:D-0(迁移+模型+DTO)+ D-1(Gateway SyncDeviceInfo 方法)+ D-2(is_current 字段) + - **Plan 2(功能层)**:D-3(Refresh 接入 sync-info + updateDeviceFromSyncInfo) +- **D-02:** Plan 1 内部执行顺序:D-0 先行(DB 迁移、Device Model、DeviceSimBinding Model、DTO 全部到位)→ D-1 + D-2 并行(都依赖 D-0,互不依赖) +- **D-03:** 每个子任务独立一个 commit(延续 Phase 1/2 粒度规范) + +### DB 迁移 + +- **D-04:** 迁移编号从 `000090` 起,拆为 2 个迁移文件: + - `000090_device_fields_extension`:tb_device 新增 5 个字段 + - `000091_device_sim_binding_is_current`:tb_device_sim_binding 新增 is_current 字段 +- **D-05:** 使用 `.up.sql` / `.down.sql` 双文件形式(与现有迁移规范一致) + +### Gateway 类型定义位置 + +- **D-06:** `SyncDeviceInfoReq` / `SyncDeviceInfoResp` 放在 **`internal/gateway/models.go`**(与现有 DeviceInfoReq / SlotInfoResp 等结构保持风格一致) +- **D-07:** `SyncDeviceInfo()` 方法放在 `internal/gateway/device.go`(与现有 GetDeviceInfo / GetSlotInfo 等方法一起) +- 修正文档中将类型嵌入 device.go 代码片段属于示意,不代表最终位置 + +### 实时字段暴露范围 + +- **D-08:** Refresh 响应中**不暴露**非存储实时字段(rssi / battery_level / ssid / wifi_enabled 等) +- **D-09:** 实时字段仅在调用 sync-info 时**写入 DB 存储字段**(online_status / last_online_time / software_version / switch_mode / last_gateway_sync_at) +- **D-10:** 这满足所有成功标准(标准 2、4 只要求存储字段同步) + +### is_current 字段的 DTO 同步范围 + +- **D-11:** `is_current` 同步到**两处 DTO**: + - `BoundCardInfo`(`internal/model/dto/asset_dto.go`)—— 资产实时状态 Refresh 响应中的绑定卡列表 + - `DeviceCardBindingResponse`(`internal/model/dto/device_dto.go`)—— 设备管理页 ListDeviceCards 接口 +- **D-12:** 两处同步,保持前端两个场景下的数据一致 + +### updateDeviceFromSyncInfo 实现细节 + +- **D-13:** `updateDeviceFromSyncInfo` 为私有函数,位于 `internal/service/asset/service.go` +- **D-14:** is_current 更新使用**事务**:先全部设为 false,再把 current_iccid 对应行设为 true(原子操作,防止中间状态) +- **D-15:** sync-info 调用失败时**不阻断刷新流程**,仅记录 Warn 日志(`sync-info 调用失败`) + +### Agent's Discretion + +- `last_online_time` / `last_gateway_sync_at` 字段 parsing(sync-info 返回字符串,需转换为 time.Time)的具体格式,agent 参考 Gateway 文档中的 `last_update_time` 示例格式 +- `DeviceRealtimeInfo` 独立 DTO 结构**不创建**(不暴露实时字段,无需此结构) +- `updateDeviceFromSyncInfo` 的 DB 更新使用 GORM `Updates(map[string]any{...})`,不用 `Save()`(避免全字段覆写) + + + + +## Canonical References + +**Downstream agents MUST read these before planning or implementing.** + +### 修复规格(核心参考) +- `.sisyphus/plans/修正业务-完整方案.md` — 完整修复规格书,含每个需求的代码片段和人工验收清单: + - 方案 D(DEVICE-01~04):约第 955-1130 行(D-0 字段策略 + D-1 Gateway 接口 + D-2 is_current + D-3 Refresh 接入) + +### Gateway 接口文档 +- `docs/第三方文档/gateway设备详情同步接口.md` — sync-info 接口完整字段说明(data 字段映射表、cardNo 规则、认证方式) + +### 需要修改的核心文件 +- `internal/model/device.go` — D-0:新增 5 个 DB 字段 +- `internal/model/device_sim_binding.go` — D-2:新增 is_current 字段 +- `internal/model/dto/asset_dto.go` — D-2:BoundCardInfo 新增 is_current +- `internal/model/dto/device_dto.go` — D-0:DeviceResponse 新增 5 个字段;D-2:DeviceCardBindingResponse 新增 is_current +- `internal/gateway/models.go` — D-1:新增 SyncDeviceInfoReq / SyncDeviceInfoResp +- `internal/gateway/device.go` — D-1:新增 SyncDeviceInfo() 方法 +- `internal/service/asset/service.go` — D-3:Refresh device 分支追加 sync-info 调用;新增 updateDeviceFromSyncInfo() +- `migrations/` — D-0:000090_device_fields_extension;D-2:000091_device_sim_binding_is_current + +### 现有参考实现 +- `internal/service/asset/service.go:Refresh()` — 约第 295 行,现有 device 刷新分支(追加 sync-info 调用入口) + + + + +## Existing Code Insights + +### Reusable Assets +- `internal/gateway/client.go:doRequestWithResponse[T]()` — 泛型请求方法,SyncDeviceInfo 直接复用(与 GetDeviceInfo 相同调用模式) +- `internal/service/asset/service.go:Refresh()` — 已有 device 冷却 Key + 绑定卡遍历框架,D-3 在此追加 sync-info 调用 +- `internal/service/asset/service.go:deviceSimBindingStore` — 已注入,D-3 的 updateDeviceFromSyncInfo 可直接使用 + +### Established Patterns +- Gateway 类型分离:结构体在 `models.go`,方法在对应领域文件(device.go / flow_card.go 等) +- DB 更新:使用 `Updates(map[string]any{...})` + `Model(&T{})` + `Where`,不用 `Save()` +- 错误处理:非关键步骤失败用 `logger.Warn`,关键步骤用 `errors.Wrap` + +### Integration Points +- `internal/gateway/device.go` — 新增 SyncDeviceInfo 方法 +- `internal/service/asset/service.go:Refresh()` device 分支 —— sync-info 调用入口(冷却 Key 设置之前,已遍历完绑定卡之后) +- `BoundCardInfo` 在 `asset_dto.go`(被 AssetRealtimeStatusResponse 引用,多个 C 端和 B 端接口共用) + + + + +## Specific Ideas + +- 修正文档中 D-3 的代码片段提供了 `updateDeviceFromSyncInfo` 的函数骨架,agent 应直接参考(文件:`.sisyphus/plans/修正业务-完整方案.md` 方案 D-3 段落) +- `SyncDeviceInfoResp.LastOnlineTime` 字段类型用 `string`(Gateway 返回字符串),在 updateDeviceFromSyncInfo 内按需 Parse + + + + +## Deferred Ideas + +- 设备实时字段(rssi / battery_level / ssid 等)暴露到 Refresh 响应 —— 超出当前成功标准,考虑 Phase 4+ 或按需补充 +- DeviceRealtimeInfo 独立 DTO 结构 —— 若未来暴露实时字段时再创建 + + + +--- + +*Phase: 03-device-system* +*Context gathered: 2026-03-28* diff --git a/.planning/phases/03-device-system/03-DISCUSSION-LOG.md b/.planning/phases/03-device-system/03-DISCUSSION-LOG.md new file mode 100644 index 0000000..db4f829 --- /dev/null +++ b/.planning/phases/03-device-system/03-DISCUSSION-LOG.md @@ -0,0 +1,70 @@ +# Phase 3: 设备体系完善 - Discussion Log + +> **Audit trail only.** Do not use as input to planning, research, or execution agents. +> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered. + +**Date:** 2026-03-28 +**Phase:** 03-device-system +**Areas discussed:** Plan 分组策略, 实时字段暴露范围, is_current DTO 同步范围, Gateway 类型定义位置 + +--- + +## Plan 分组策略 + +| Option | Description | Selected | +|--------|-------------|----------| +| 2 个 Plan(推荐) | Plan 1: D-0+D-1+D-2(基础层),Plan 2: D-3(功能层)—— 与 Phase 2 分法类似 | ✓ | +| 1 个 Plan | D-0~D-3 全在一个 Plan 里,顶序执行,简单直接但回滚粒度较粗 | | +| 3 个 Plan | Plan 1: D-0,Plan 2: D-1+D-2(并行),Plan 3: D-3 —— 粒度最细 | | + +**User's choice:** 2 个 Plan(推荐) +**Notes:** 与 Phase 2 的"小修合并 + REALNAME 独立"分法保持风格一致 + +--- + +## 实时字段暴露范围 + +| Option | Description | Selected | +|--------|-------------|----------| +| 不暴露(推荐) | 实时字段仅写入 DB,响应只返回存储字段,满足所有成功标准 | ✓ | +| 暴露实时字段 | 在 AssetRealtimeStatusResponse 新增嵌套 DeviceRealtimeInfo 结构(rssi / battery / ssid 等),需较大 DTO 改动 | | + +**User's choice:** 不暴露(推荐) +**Notes:** 成功标准 2/4 只要求 online_status / software_version 等存储字段同步,不特别要求实时字段。实时字段暴露推迟到后续阶段按需决策。 + +--- + +## is_current DTO 同步范围 + +| Option | Description | Selected | +|--------|-------------|----------| +| 两处都加(推荐) | BoundCardInfo(asset_dto.go)+ DeviceCardBindingResponse(device_dto.go)同时新增 is_current | ✓ | +| 仅 BoundCardInfo | 只改 BoundCardInfo,设备管理页绑定列表看不到当前卡标识 | | + +**User's choice:** 两处都加(推荐) +**Notes:** 保持前端两个场景下的数据一致性 + +--- + +## Gateway 类型定义位置 + +| Option | Description | Selected | +|--------|-------------|----------| +| 放 models.go(推荐) | 与现有 DeviceInfoReq / SlotInfoResp 等结构保持一致,Gateway 类型集中在一个文件 | ✓ | +| 放 device.go | 跟修正文档建议,类型和方法在同一文件,但与其他 Gateway 结构不一致 | | + +**User's choice:** 放 models.go(推荐) +**Notes:** 修正文档将类型嵌入 device.go 代码片段属于示意用法,不代表最终放置位置,遵循现有项目分离风格 + +--- + +## Agent's Discretion + +- `updateDeviceFromSyncInfo` 内 is_current 更新的事务策略(先全 false 再设 true) +- `last_online_time` 字符串 → time.Time 的 Parse 格式 +- GORM Updates 而非 Save 的具体写法 + +## Deferred Ideas + +- 设备实时字段(rssi / battery / ssid 等)暴露到 Refresh 响应 —— 超出当前成功标准 +- DeviceRealtimeInfo 独立 DTO 结构 —— 等实时字段暴露需求时再建