## Context

Carrier（运营商）模块当前状态：
- Model 已定义于 `internal/model/carrier.go`，表名 `tb_carrier`
- 被 IotCard、IotCardImportTask、PollingConfig 通过 `carrier_id` 引用
- 缺少管理接口，数据通过其他方式手动管理
- `channel_name`、`channel_code` 字段未被任何地方使用
- 查询 IotCard 时需要 JOIN Carrier 表获取 carrier_name

CarrierType 固定为 4 种：CMCC（中国移动）、CUCC（中国联通）、CTCC（中国电信）、CBN（中国广电）

## Goals / Non-Goals

**Goals:**
- 提供完整的 Carrier 管理 API（CRUD + 状态管理）
- 简化 Carrier Model，移除冗余字段
- IotCard/ImportTask 存储冗余快照，实现数据自包含
- 优化查询性能，减少不必要的 JOIN

**Non-Goals:**
- PollingConfig 保持 carrier_id 引用方式（配置语义，NULL 表示所有运营商）
- 不修改 Carrier 的业务逻辑（仅提供管理接口）
- 不支持 CarrierType 动态扩展（固定 4 种）

## Decisions

### D1: 冗余快照 vs 保持引用

**决策**: IotCard/ImportTask 采用冗余快照存储 carrier_type、carrier_name

**理由**:
- 查询时无需 JOIN，性能更好
- Carrier 软删除后历史数据完整
- 符合"赋予时刻快照"的业务语义——卡分配后运营商信息不应变化

**备选方案**:
- 保持纯引用：需要限制 Carrier 删除，查询需要 JOIN
- 软引用 + 视图：复杂度高，维护成本大

### D2: PollingConfig 不添加冗余字段

**决策**: PollingConfig 保持 carrier_id 引用

**理由**:
- PollingConfig 是配置表，`carrier_id = NULL` 有特殊含义（所有运营商）
- 配置应该跟随 Carrier 变化，不需要历史快照
- 场景不同于数据记录

### D3: CarrierType 枚举校验

**决策**: 创建时 carrier_type 必须是 CMCC/CUCC/CTCC/CBN 之一，使用 validator 枚举校验

**理由**:
- 运营商类型固定，不会动态扩展
- 前端下拉选择，后端强校验
- 避免脏数据

### D4: 删除策略

**决策**: Carrier 可以软删除，不检查关联数据

**理由**:
- IotCard 已有冗余字段，不依赖 Carrier 表
- ImportTask 同理
- PollingConfig 的 carrier_id 可能变成悬空引用，但配置场景可接受（管理员负责）

### D5: API 路由设计

**决策**: 遵循项目现有 RESTful 风格

```
POST   /api/admin/carriers           创建
GET    /api/admin/carriers           列表（分页+筛选）
GET    /api/admin/carriers/:id       详情
PUT    /api/admin/carriers/:id       更新
DELETE /api/admin/carriers/:id       软删除
PUT    /api/admin/carriers/:id/status 启用/禁用
```

## Risks / Trade-offs

### R1: 数据冗余导致存储增加
- **风险**: 每条 IotCard 多存 carrier_type(20B) + carrier_name(100B)
- **缓解**: 可接受的存储开销，换取查询性能和数据独立性

### R2: 迁移时需要填充历史数据
- **风险**: 现有 IotCard/ImportTask 记录需要通过 UPDATE 填充冗余字段
- **缓解**: 迁移脚本从 Carrier 表 JOIN 填充，一次性操作

### R3: carrier_code/carrier_type 创建后不可修改
- **风险**: 如果创建错误，只能删除重建
- **缓解**: 前端选择 + 后端校验，降低出错概率；错误情况下软删除后重建

### R4: 移除 channel 字段是 BREAKING CHANGE
- **风险**: 如果有外部系统依赖这些字段
- **缓解**: 已确认这些字段未被使用，可安全移除
