## ADDED Requirements

### Requirement: 流量增量写入 Redis 缓冲
轮询检测到流量增量 > 0 时，系统 SHALL 使用 `INCRBYFLOAT` 将增量写入 Redis key（格式 `traffic:daily:{card_id}:{YYYY-MM-DD}`），TTL 48 小时。增量 <= 0 时 SHALL NOT 写入。**直接替换旧的 `insertDataUsageRecord()` 写 DB 路径，不双写。**

#### Scenario: 有流量增量时写 Redis
- **WHEN** 轮询检测到卡 ID=100 今日流量增量为 5.2 MB
- **THEN** 系统 SHALL 执行 `INCRBYFLOAT traffic:daily:100:2026-03-28 5.2`，并设置 48h TTL

#### Scenario: 无流量增量时跳过
- **WHEN** 轮询检测到流量增量 <= 0
- **THEN** 系统 SHALL NOT 执行任何 Redis 或 DB 写入

### Requirement: 每日落盘定时任务
系统 SHALL 每天凌晨 2 点（Asia/Shanghai）通过 Asynq Scheduler 触发落盘任务。

#### Scenario: 正常落盘（分批处理）
- **WHEN** 凌晨 2 点落盘任务执行
- **THEN** 系统 SHALL 分批 SCAN 所有 `traffic:daily:*:{昨日}` key（每批 COUNT 500）
- **AND** 分批 UPSERT 到 `tb_card_daily_usage`（每批 200 条，**覆盖语义**保证幂等：`ON CONFLICT DO UPDATE SET usage_mb = EXCLUDED.usage_mb`）
- **AND** 分批 Pipeline 删除已落盘的 Redis key
- **AND** 记录日志：落盘条数、耗时

#### Scenario: 落盘失败重试
- **WHEN** 落盘任务执行失败
- **THEN** Asynq SHALL 自动重试（MaxRetry=3，超时 5 分钟），Redis key 因 48h TTL 仍可用
- **AND** 因 UPSERT 使用覆盖语义，重试时不会导致数据翻倍

### Requirement: tb_card_daily_usage 表结构
`usage_mb` 字段 SHALL 使用 `NUMERIC(12,2)` 类型（匹配 Redis `INCRBYFLOAT` 的浮点精度和现有 `current_month_usage_mb` 的 `decimal(10,2)` 类型），不使用 BIGINT。
