## ADDED Requirements

### Requirement: 卡流量查询

系统 SHALL 调用 Gateway API 查询卡的流量使用情况，并处理跨月流量计算。

#### Scenario: 查询卡流量

- **WHEN** 流量检查任务执行，卡A的 ICCID 为 "89860123456789012345"
- **THEN** 系统调用 Gateway.QueryFlow(ICCID)，获取流量响应（包含月总流量 MB）

#### Scenario: Gateway 返回月总流量

- **WHEN** Gateway 返回流量数据，total_usage_mb=500（本自然月累计）
- **THEN** 系统获取到月总流量数据，准备计算增量

#### Scenario: Gateway API 超时

- **WHEN** 调用 Gateway API 超时（>30秒）
- **THEN** 系统记录错误日志，任务失败，不重试，卡重新入队（按原计划下次检查）

#### Scenario: Gateway API 返回错误

- **WHEN** Gateway API 返回业务错误（如卡号不存在）
- **THEN** 系统记录错误日志，不更新数据库，任务失败，卡重新入队

### Requirement: 跨月流量计算

系统 SHALL 正确处理跨月流量计算，识别月份切换并重置月度统计。

#### Scenario: 首次查询流量（冷启动）

- **WHEN** 卡A从未查询过流量，current_month_start_date 为 NULL
- **THEN** 系统初始化 current_month_start_date=当前月1日，current_month_usage_mb=Gateway返回值，last_month_total_mb=0

#### Scenario: 同月内流量增长

- **WHEN** 卡A上次查询在本月（current_month_start_date=2024-01-01），Gateway 返回 total_usage_mb=500，数据库当前 current_month_usage_mb=400
- **THEN** 系统计算增量 100 MB，更新 current_month_usage_mb=500

#### Scenario: 跨月流量重置

- **WHEN** 卡A上次查询在上月（current_month_start_date=2024-01-01），当前时间为 2024-02-05，Gateway 返回 total_usage_mb=50（新月重置后）
- **THEN** 系统检测到跨月，保存 last_month_total_mb=400（上月结束值），重置 current_month_start_date=2024-02-01，current_month_usage_mb=50

#### Scenario: Gateway 返回值回退（异常）

- **WHEN** Gateway 返回 total_usage_mb=300，小于数据库当前值 current_month_usage_mb=400（同月内）
- **THEN** 系统记录警告日志，怀疑数据异常，但仍更新为 Gateway 值（信任 Gateway 数据源）

### Requirement: 数据库更新

系统 SHALL 更新卡的流量字段到数据库。

#### Scenario: 更新流量字段

- **WHEN** 计算出增量流量 100 MB
- **THEN** 系统执行 `UPDATE iot_cards SET current_month_usage_mb=500, current_month_start_date='2024-01-01', last_realname_check_at=NOW() WHERE id=?`

#### Scenario: 数据库更新失败

- **WHEN** 数据库更新失败（如连接断开）
- **THEN** 系统记录错误日志，任务失败，卡重新入队

### Requirement: Redis 缓存更新

系统 SHALL 同步更新 Redis 缓存中的卡流量信息。

#### Scenario: 更新缓存流量字段

- **WHEN** 数据库更新成功
- **THEN** 系统使用 HSET 更新 Redis 缓存（polling:card:{card_id}）的 current_month_usage_mb、current_month_start_date、last_month_total_mb 字段

#### Scenario: 缓存更新失败不影响主流程

- **WHEN** Redis 更新失败
- **THEN** 系统记录警告日志，但任务仍视为成功（缓存可以通过定时同步或懒加载恢复）

### Requirement: 流量历史记录

系统 SHALL 记录流量变化历史到 data_usage_records 表。

#### Scenario: 记录流量增量

- **WHEN** 计算出增量流量 100 MB
- **THEN** 系统插入记录到 data_usage_records 表（card_id、usage_mb=100、usage_type='data'、recorded_at=NOW()）

#### Scenario: 跨月时记录上月总量

- **WHEN** 检测到跨月，上月总流量为 400 MB
- **THEN** 系统插入一条月度汇总记录（card_id、usage_mb=400、usage_type='monthly_summary'、recorded_at=上月最后一天）

#### Scenario: 历史记录插入失败

- **WHEN** 历史记录插入失败
- **THEN** 系统记录警告日志，但任务仍视为成功（历史记录非关键路径）

### Requirement: 触发套餐检查

系统 SHALL 在流量更新后触发关联套餐的流量检查。

#### Scenario: 卡有关联套餐

- **WHEN** 卡A更新流量后，card_package_id 不为空
- **THEN** 系统将该套餐加入 polling:manual:package 手动触发队列，优先检查套餐流量

#### Scenario: 卡无关联套餐

- **WHEN** 卡A更新流量后，card_package_id 为空
- **THEN** 系统不触发套餐检查

#### Scenario: 卡关联设备级套餐

- **WHEN** 卡A属于设备D，设备D有套餐
- **THEN** 系统将设备的套餐加入手动触发队列

### Requirement: 并发控制

系统 SHALL 使用 Redis 信号量控制流量检查的并发数。

#### Scenario: 获取并发信号量成功

- **WHEN** 流量检查任务开始执行，当前并发数为 30，配置的最大并发数为 50
- **THEN** 系统使用 INCR 增加计数，获取信号量成功，执行任务

#### Scenario: 并发已满

- **WHEN** 流量检查任务开始执行，当前并发数为 50，配置的最大并发数为 50
- **THEN** 系统 INCR 后发现超过限制，DECR 归还，任务返回 SkipRetry（不执行，等待下次调度）

#### Scenario: 任务完成释放信号量

- **WHEN** 流量检查任务完成（成功或失败）
- **THEN** 系统使用 DECR 释放信号量

### Requirement: 重新入队

系统 SHALL 在检查完成后，将卡重新加入轮询队列。

#### Scenario: 计算下次检查时间

- **WHEN** 流量检查完成，当前配置的检查间隔为 1800 秒
- **THEN** 系统计算 next_check_time = NOW() + 1800秒

#### Scenario: 加回队列

- **WHEN** 计算出下次检查时间
- **THEN** 系统使用 ZADD 将卡ID和时间戳加入 polling:queue:carddata

#### Scenario: 任务失败也重新入队

- **WHEN** 任务因 Gateway 超时失败
- **THEN** 系统仍然将卡重新入队（按原计划下次检查），不阻塞后续检查

### Requirement: 监控统计

系统 SHALL 记录流量检查的成功率和耗时。

#### Scenario: 记录成功统计

- **WHEN** 流量检查成功完成，耗时 234 毫秒
- **THEN** 系统更新 Redis Hash（polling:stats:carddata），增加 success_count_1h，累加 total_duration_1h

#### Scenario: 记录失败统计

- **WHEN** 流量检查失败（Gateway 超时）
- **THEN** 系统更新 Redis Hash，增加 failure_count_1h

#### Scenario: 每小时重置计数器

- **WHEN** 每小时整点（如 10:00:00）
- **THEN** 系统重置计数器（success_count_1h、failure_count_1h、total_duration_1h），保持时间窗口滚动

### Requirement: 日志记录

系统 SHALL 记录详细的流量检查日志，便于排查问题。

#### Scenario: 记录开始日志

- **WHEN** 流量检查任务开始执行
- **THEN** 系统记录 Info 日志，包含 card_id、iccid、config_id

#### Scenario: 记录成功日志

- **WHEN** 流量检查成功完成
- **THEN** 系统记录 Info 日志，包含 card_id、iccid、old_usage_mb、new_usage_mb、increment_mb、duration_ms

#### Scenario: 记录失败日志

- **WHEN** 流量检查失败
- **THEN** 系统记录 Error 日志，包含 card_id、iccid、error 详情

#### Scenario: 记录跨月日志

- **WHEN** 检测到跨月
- **THEN** 系统记录 Info 日志，包含 card_id、old_month、new_month、last_month_total_mb
