## 1. 修复购买时实名状态检查（order/service.go）

- [x] 1.1 在 `activateMainPackage` 的 REALNAME-02 决策块中，扩展卡信息查询：将 `tx.Select("card_category")` 改为 `tx.Select("card_category", "real_name_status")`，并从结果读取 `currentlyRealnamed` 标志
- [x] 1.2 在 REALNAME-02 决策块中，新增 `device` 载体的实名状态检查：当 `carrierType == "device"` 时，通过 GORM 子查询统计绑定卡（`bind_status=1`）中 `real_name_status=1` 的数量，`count > 0` 则 `currentlyRealnamed=true`；注意：使用 GORM 查询时软删除过滤（`deleted_at IS NULL`）由 GORM 自动注入，**不需要**手动添加 `.Where("deleted_at IS NULL")`
- [x] 1.3 修改 `expiry_base != "from_purchase"` 分支的决策逻辑：若 `currentlyRealnamed=true` 则保持 `status=Active`（不切换为 pending），记录 Info 日志"购买时载体已实名，直接激活套餐"；若 `currentlyRealnamed=false` 则保持原有 `pending_realname_activation=true` 逻辑；**边界情况**：若 1.1 的卡查询失败（`err != nil`）或 1.2 的设备子查询出错，`currentlyRealnamed` 应保守默认为 `false`（走 pending 路径），不应阻断整个购买流程
- [x] 1.4 运行 `lsp_diagnostics` 确认 `internal/service/order/service.go` 无编译错误

## 2. 扩展 PollingRealnameHandler（polling_realname_handler.go）

- [x] 2.1 在 `PollingRealnameHandler` 结构体中新增字段 `deviceSimBindingStore *postgres.DeviceSimBindingStore`
- [x] 2.2 更新 `NewPollingRealnameHandler` 构造函数签名，在参数列表末尾新增 `deviceSimBindingStore *postgres.DeviceSimBindingStore`，并在函数体中赋值到结构体字段
- [x] 2.3 新增 `triggerDeviceRealnameActivation(ctx context.Context, cardID uint)` 函数：调用 `h.deviceSimBindingStore.GetActiveBindingByCardID` 获取设备绑定；判断无绑定使用同包内已有的 `isNotFound(err)` 工具函数（定义于 `internal/task/polling_utils.go`），命中则静默返回；若有绑定则提交 `carrier_type="device", carrier_id=binding.DeviceID` 的 `TaskTypePackageFirstActivation` Asynq 任务（与卡级任务相同的 MaxRetry/Timeout/Queue 配置，参照 `triggerFirstRealnameActivation` 实现）；任务提交失败记录 Warn 日志，日志字段需同时包含 `card_id` 和 `device_id` 以便关联排查，不中断流程
- [x] 2.4 在 `isFirstRealname` 分支中，在调用 `triggerFirstRealnameActivation` 之后追加调用 `triggerDeviceRealnameActivation(ctx, cardID)`
- [x] 2.5 运行 `lsp_diagnostics` 确认 `internal/task/polling_realname_handler.go` 无编译错误

## 3. 更新 Worker 构造调用（pkg/queue/handler.go）

- [x] 3.1 在 `registerPollingHandlers` 中，将 `task.NewPollingRealnameHandler(...)` 调用末尾追加参数 `h.workerResult.Stores.DeviceSimBinding`
- [x] 3.2 运行 `lsp_diagnostics` 确认 `pkg/queue/handler.go` 无编译错误

## 4. 整体编译验证与存量修复

- [x] 4.1 执行 `go build ./...` 确认整个项目编译通过，零错误零警告
- [x] 4.2 通过 psql 或任意数据库客户端手动执行存量修复，分三步：

  **步骤 0 — 确认受影响范围（只读，先跑）**
  ```sql
  SELECT pu.id, pu.device_id, pu.iot_card_id,
         p.calendar_type, p.duration_months, p.duration_days, p.data_reset_cycle
  FROM tb_package_usage pu
  JOIN tb_package p ON p.id = pu.package_id
  WHERE pu.status = 0 AND pu.pending_realname_activation = true;
  ```
  预期：仅返回 `id=1`（device_id=2，natural_month，12 个月，monthly 重置）。若有其他记录，核实后再执行步骤 1。

  **步骤 1 — 批量修复（写操作，建议在事务中执行）**
  ```sql
  BEGIN;

  UPDATE tb_package_usage pu
  SET
      status                     = 1,
      pending_realname_activation = false,
      activated_at               = NOW(),
      expires_at = CASE p.calendar_type
          WHEN 'natural_month' THEN
              DATE_TRUNC('month', NOW())
                  + ((p.duration_months + 1)::text || ' months')::interval
                  - INTERVAL '1 second'
          ELSE
              DATE_TRUNC('day', NOW())
                  + (p.duration_days::text || ' days')::interval
                  + INTERVAL '86399 seconds'
      END,
      next_reset_at = CASE p.data_reset_cycle
          WHEN 'monthly' THEN
              CASE p.calendar_type
                  WHEN 'natural_month' THEN DATE_TRUNC('month', NOW()) + INTERVAL '1 month'
                  ELSE DATE_TRUNC('day', NOW()) + INTERVAL '30 days'
              END
          WHEN 'daily'  THEN DATE_TRUNC('day', NOW()) + INTERVAL '1 day'
          WHEN 'yearly' THEN DATE_TRUNC('year', NOW() + INTERVAL '1 year')
          ELSE NULL
      END,
      updated_at = NOW()
  FROM tb_package p
  WHERE pu.package_id = p.id
    AND pu.status = 0
    AND pu.pending_realname_activation = true
    AND pu.device_id > 0
    AND pu.device_id IN (
        SELECT DISTINCT dsb.device_id
        FROM tb_device_sim_binding dsb
        JOIN tb_iot_card ic ON ic.id = dsb.iot_card_id
        WHERE dsb.bind_status = 1 AND dsb.deleted_at IS NULL
          AND ic.real_name_status = 1 AND ic.deleted_at IS NULL
    );

  -- 确认影响行数为预期值后再 COMMIT，否则 ROLLBACK
  COMMIT;
  ```

  **步骤 2 — 验证结果**
  ```sql
  SELECT id, status, pending_realname_activation, activated_at, expires_at, next_reset_at
  FROM tb_package_usage
  WHERE id = 1;
  ```
  预期：`status=1`，`pending_realname_activation=false`，`expires_at` 为当月 +12 个月月末 23:59:59，`next_reset_at` 为下月 1 日 00:00:00。
