All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m5s
- AssetResolveResponse 新增 real_name_at 字段:card 类型取 first_realname_at,device 类型取绑定卡中最小的实名时间 - BoundCardInfo 新增 real_name_at 字段:各卡自己的 first_realname_at - RefreshCardDataFromGateway 手动刷新路径补写实名时间:检测到 0→1 变化时同步写入 first_realname_at - 同步更新 asset-resolve 规格文档 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
46 lines
2.5 KiB
Markdown
46 lines
2.5 KiB
Markdown
## Context
|
||
|
||
`IotCard` 表已有 `first_realname_at` 字段,记录卡每次从未实名(0)变为已实名(1)的时间戳(轮询路径在每次 `0→1` 时覆盖写入,字段名为"首次"但实际是"最近一次")。该字段目前仅用于内部业务触发(首次实名激活任务),未对外暴露。
|
||
|
||
**当前问题**:
|
||
1. `AssetResolveResponse` 和 `BoundCardInfo` DTO 没有 `real_name_at` 字段
|
||
2. 手动刷新路径(`RefreshCardDataFromGateway`)在更新 `real_name_status` 时漏写 `first_realname_at`
|
||
3. `Device` model 无实名时间,设备视角需从绑定卡聚合
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
- 在 `GET /api/admin/assets/resolve/:identifier` 响应中暴露实名时间
|
||
- 卡视角直接返回 `IotCard.first_realname_at`
|
||
- 设备视角返回当前绑定卡 `first_realname_at` 的最小值
|
||
- `BoundCardInfo` 列表中每张卡返回各自的实名时间
|
||
- 修复手动刷新路径漏写 `first_realname_at` 的 bug
|
||
|
||
**Non-Goals:**
|
||
- 不新增数据库字段(`first_realname_at` 已存在)
|
||
- 不修改实名检查轮询逻辑
|
||
- 不对设备 model 新增字段(运行时聚合,不持久化)
|
||
- 不改变 `triggerFirstRealnameActivation` 的触发条件
|
||
|
||
## Decisions
|
||
|
||
### 决策1:复用 `first_realname_at` 而非新增字段
|
||
|
||
`first_realname_at` 在每次 `0→1` 时覆盖写入,语义上等同于"最近一次实名时间"。新增字段需要迁移,收益不成比例。
|
||
|
||
**替代方案**:新增 `realname_at` 字段,明确"最近一次"语义。
|
||
**放弃原因**:需要数据库迁移,且历史卡数据无法回填,反而不如 `first_realname_at` 完整。
|
||
|
||
### 决策2:设备实名时间运行时聚合,不持久化
|
||
|
||
设备无实名时间字段,从绑定卡内存聚合(`buildDeviceResolveResponse` 已查询全部绑定卡),只需遍历取 `MIN(first_realname_at)` 即可,无需额外查询。
|
||
|
||
### 决策3:手动刷新路径与轮询路径对齐
|
||
|
||
`RefreshCardDataFromGateway` 在 `real_name_status` 由非已实名变为已实名时,同步写入 `first_realname_at`,逻辑与 `polling_realname_handler.go` 的 `isFirstRealname` 条件完全一致。
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- **字段名语义不对齐**:`first_realname_at` 叫"首次"但实为"最近一次"。→ 通过 DTO 字段命名为 `real_name_at` 对外屏蔽内部字段名,API 消费者不感知。
|
||
- **设备实名时间仅限当前绑定卡**:历史上曾绑定过的卡不计入。→ 与业务定义一致(设备换卡后旧卡脱离关系)。
|