## 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 消费者不感知。
- **设备实名时间仅限当前绑定卡**：历史上曾绑定过的卡不计入。→ 与业务定义一致（设备换卡后旧卡脱离关系）。
