# IoT SIM 管理系统 - 数据模型总结

## 概述

本文档总结了 IoT SIM 管理系统的数据模型层实现,包括 26 张数据库表和对应的 GORM 模型定义。

## 实现范围

- ✅ 数据库迁���脚本 (migrations/000005_create_iot_sim_management_tables.up/down.sql)
- ✅ GORM 模型定义 (internal/iot/model/*.go)
- ✅ 业务常量定义 (pkg/constants/iot.go)
- ❌ API Handler 层 (不在本阶段范围)
- ❌ Service 业务逻辑层 (不在本阶段范围)
- ❌ Store 数据访问层 (不在本阶段范围)

## 核心业务实体

### 1. 运营商管理 (Carrier)

**表名**: `carriers`

**核心字段**:
- `carrier_code`: 运营商编码 (CMCC/CUCC/CTCC)
- `carrier_name`: 运营商名称 (中国移动/中国联通/中国电信)
- `api_endpoint`: API 接口地址
- `api_credentials`: API 凭证 (JSONB)

**预置数据**: 初始化三大运营商数据

**文件位置**: `internal/iot/model/carrier.go:5`

---

### 2. IoT 卡管理 (IotCard)

**表名**: `iot_cards`

**核心字段**:
- `iccid`: IoT 卡唯一标识 (20 位数字)
- `card_category`: 卡业务类型 (normal-普通卡, industry-行业卡)
- `carrier_id`: 所属运营商 ID
- `owner_type`: 所有者类型 (platform/agent/user/device)
- `owner_id`: 所有者 ID
- `activation_status`: 激活状态 (0-未激活, 1-已激活)
- `real_name_status`: 实名状态 (0-未实名, 1-已实名)
- `network_status`: 网络状态 (0-停机, 1-开机)
- `enable_polling`: 是否参与轮询

**特殊机制**:
- 支持行业卡(无需实名)和普通卡(需实名)
- 多所有者模式 (owner_type + owner_id)
- 轮询开关控制 (enable_polling)
- 流量使用累计 (data_usage_mb)
- Gateway 同步时间戳 (last_sync_time)

**文件位置**: `internal/iot/model/iot_card.go:8`

---

### 3. 设备管理 (Device)

**表名**: `devices`

**核心字段**:
- `device_code`: 设备唯一编码
- `device_name`: 设备名称
- `device_type`: 设备类型
- `sim_slots`: SIM 卡槽数量 (1-4)
- `owner_type`: 所有者类型 (platform/agent/user)
- `owner_id`: 所有者 ID

**关联关系**:
- 通过 `device_sim_bindings` 表关联 1-4 张 IoT 卡

**文件位置**: `internal/iot/model/device.go:5`

---

### 4. 号卡管理 (NumberCard)

**表名**: `number_cards`

**核心字段**:
- `virtual_product_code`: 虚拟商品编码 (用于对应运营商订单)
- `card_name`: 号卡名称
- `carrier`: 运营商
- `data_amount_mb`: 流量额度 (MB)
- `price`: 价格 (元)

**业务说明**: 号卡是完全独立的业务线,从上游平台下单,使用虚拟商品编码映射运营商订单。

**文件位置**: `internal/iot/model/number_card.go:8`

---

## 套餐与流量管理

### 5. 套餐系列 (PackageSeries)

**表名**: `package_series`

**核心字段**:
- `series_code`: 系列编码
- `series_name`: 系列名称
- `description`: 描述

**用途**: 套餐分组,用于一次性分佣规则配置。

**文件位置**: `internal/iot/model/package.go:7`

---

### 6. 套餐 (Package)

**表名**: `packages`

**核心字段**:
- `package_code`: 套餐编码
- `package_name`: 套餐名称
- `series_id`: 所属套餐系列 ID
- `package_type`: 套餐类型 (formal-正式套餐, addon-附加套餐)
- `duration_months`: 套餐时长 (月数)
- `data_type`: 流量类型 (real-真流量, virtual-虚流量)
- `real_data_mb`: 真流量额度 (MB)
- `virtual_data_mb`: 虚流量额度 (MB)
- `data_amount_mb`: 总流量额度 (MB)
- `price`: 套餐价格 (元)

**特殊机制**:
- 支持真流量/虚流量共存
- 停机判断基于虚流量
- 支持正式套餐和附加套餐

**文件位置**: `internal/iot/model/package.go:23`

---

### 7. 代理套餐分配 (AgentPackageAllocation)

**表名**: `agent_package_allocations`

**核心字段**:
- `agent_id`: 代理用户 ID
- `package_id`: 套餐 ID
- `cost_price`: 成本价 (元)
- `retail_price`: 零售价 (元)

**用途**: 为直属下级代理分配套餐,设置佣金模式。

**文件位置**: `internal/iot/model/package.go:48`

---

### 8. 设备-IoT 卡绑定 (DeviceSimBinding)

**表名**: `device_sim_bindings`

**核心字段**:
- `device_id`: 设备 ID
- `iot_card_id`: IoT 卡 ID
- `slot_position`: 插槽位置 (1, 2, 3, 4)
- `bind_status`: 绑定状态 (1-已绑定, 2-已解绑)
- `bind_time`: 绑定时间
- `unbind_time`: 解绑时间

**用途**: 管理设备与 IoT 卡的多对多绑定关系 (1 设备绑定 1-4 张 IoT 卡)。

**文件位置**: `internal/iot/model/package.go:66`

---

### 9. 套餐使用情况 (PackageUsage)

**表名**: `package_usages`

**核心字段**:
- `order_id`: 订单 ID
- `package_id`: 套餐 ID
- `usage_type`: 使用类型 (single_card-单卡套餐, device-设备级套餐)
- `iot_card_id`: IoT 卡 ID (单卡套餐时有值)
- `device_id`: 设备 ID (设备级套餐时有值)
- `data_limit_mb`: 流量限额 (MB)
- `data_usage_mb`: 已使用流量 (MB)
- `real_data_usage_mb`: 真流量使用 (MB)
- `virtual_data_usage_mb`: 虚流量使用 (MB)
- `activated_at`: 套餐生效时间
- `expires_at`: 套餐过期时间
- `status`: 状态 (1-生效中, 2-已用完, 3-已过期)
- `last_package_check_at`: 最后一次套餐流量检查时间

**用途**: 跟踪单卡套餐和设备级套餐的流量使用。

**文件位置**: `internal/iot/model/package.go:85`

---

### 10. 轮询配置 (PollingConfig)

**表名**: `polling_configs`

**核心字段**:
- `config_name`: 配置名称 (如 未实名卡、实名卡)
- `card_condition`: 卡状态条件 (not_real_name/real_name/activated/suspended)
- `carrier_id`: 运营商 ID (NULL 表示所有运营商)
- `real_name_check_enabled`: 是否启用实名检查
- `real_name_check_interval`: 实名检查间隔 (秒)
- `card_data_check_enabled`: 是否启用卡流量检查
- `card_data_check_interval`: 卡流量检查间隔 (秒)
- `package_check_enabled`: 是否启用套餐流量检查
- `package_check_interval`: 套餐流量检查间隔 (秒)
- `priority`: 优先级 (数字越小优先级越高)

**特殊机制**: 支持梯度轮询策略 (实名检查、卡流量检查、套餐流量检查)。

**文件位置**: `internal/iot/model/polling.go:7`

---

### 11. 流量使用记录 (DataUsageRecord)

**表名**: `data_usage_records`

**核心字段**:
- `iot_card_id`: IoT 卡 ID
- `usage_date`: 使用日期
- `data_usage_mb`: 流量使用 (MB)
- `carrier_sync_data`: 运营商同步数据 (JSONB)
- `synced_at`: 同步时间

**用途**: 记录 IoT 卡每日流量使用情况 (历史数据)。

**文件位置**: `internal/iot/model/data_usage.go:5`

---

## 订单管理

### 12. 订单 (Order)

**表名**: `orders`

**核心字段**:
- `order_no`: 订单号 (唯一标识)
- `order_type`: 订单类型 (1-套餐订单, 2-号卡订单)
- `iot_card_id`: IoT 卡 ID (单卡套餐订单时有值)
- `device_id`: 设备 ID (设备级套餐订单时有值)
- `number_card_id`: 号卡 ID (号卡订单时有值)
- `package_id`: 套餐 ID (套餐订单时有值)
- `user_id`: 用户 ID
- `agent_id`: 代理用户 ID
- `amount`: 订单金额 (元)
- `payment_method`: 支付方式 (wallet/online/carrier)
- `status`: 状态 (1-待支付, 2-已支付, 3-已完成, 4-已取消, 5-已退款)
- `carrier_order_id`: 运营商订单 ID
- `carrier_order_data`: 运营商订单原始数据 (JSONB)

**支持场景**:
- 套餐订单 (单卡套餐 / 设备级套餐)
- 号卡订单

**文件位置**: `internal/iot/model/order.go:11`

---

## 分佣系统

### 13. 代理层级关系 (AgentHierarchy)

**表名**: `agent_hierarchies`

**核心字段**:
- `agent_id`: 代理用户 ID
- `parent_agent_id`: 上级代理用户 ID
- `agent_level`: 代理层级 (1-一级代理, 2-二级代理, ...)
- `agent_path`: 代理路径 (如 /1/2/3/)

**用途**: 管理代理的树形层级关系。

**文件位置**: `internal/iot/model/commission.go:8`

---

### 14. 分佣规则 (CommissionRule)

**表名**: `commission_rules`

**核心字段**:
- `rule_name`: 规则名称
- `rule_type`: 规则类型 (one_time-一次性分佣, long_term-长期分佣, combined-组合分佣)
- `package_series_id`: 套餐系列 ID
- `commission_type`: 分佣方式 (fixed-固定金额, percentage-百分比)
- `commission_value`: 分佣值
- `target_level`: 目标层级 (NULL 表示所有层级)
- `enable_ladder`: 是否启用阶梯
- `freeze_days`: 冻结天数 (长期分佣)
- `freeze_data_mb`: 冻结流量 (MB, 长期分佣)
- `unfreeze_mode`: 解冻模式 (auto-自动, manual-手动)

**分佣类型说明**:
- **一次性分佣**: 订单完成后立即发放
- **长期分佣**: 订单完成后冻结,满足解冻条件后发放
- **组合分佣**: 同时包含一次性和长期分佣

**文件位置**: `internal/iot/model/commission.go:24`

---

### 15. 分佣阶梯 (CommissionLadder)

**表名**: `commission_ladder`

**核心字段**:
- `rule_id`: 分佣规则 ID
- `min_quantity`: 最小数量
- `max_quantity`: 最大数量
- `commission_type`: 分佣方式 (fixed/percentage)
- `commission_value`: 分佣值

**用途**: 为分佣规则配置阶梯奖励 (订单数量越多,分佣越高)。

**文件位置**: `internal/iot/model/commission.go:47`

---

### 16. 组合分佣条件 (CommissionCombinedCondition)

**表名**: `commission_combined_conditions`

**核心字段**:
- `rule_id`: 分佣规则 ID
- `condition_type`: 条件类型 (one_time-一次性, long_term-长期)
- `commission_type`: 分佣方式 (fixed/percentage)
- `commission_value`: 分佣值
- `freeze_days`: 冻结天数 (长期分佣)
- `freeze_data_mb`: 冻结流量 (MB, 长期分佣)

**用途**: 定义组合分佣规则的具体条件 (一次性部分 + 长期部分)。

**文件位置**: `internal/iot/model/commission.go:68`

---

### 17. 分佣记录 (CommissionRecord)

**表名**: `commission_records`

**核心字段**:
- `order_id`: 订单 ID
- `agent_id`: 代理用户 ID
- `rule_id`: 分佣规则 ID
- `commission_type`: 分佣类型 (one_time/long_term/combined)
- `commission_amount`: 分佣金额 (元)
- `status`: 状态 (1-待发放, 2-已发放, 3-已冻结, 4-已取消)
- `freeze_days`: 冻结天数
- `freeze_data_mb`: 冻结流量 (MB)
- `unfreeze_conditions`: 解冻条件 (JSONB)
- `unfrozen_at`: 解冻时间
- `distributed_at`: 发放时间

**特殊机制**: 支持 OR 条件解冻 (时间到期 OR 流量达标,满足其一即可解冻)。

**文件位置**: `internal/iot/model/commission.go:88`

---

### 18. 分佣审批 (CommissionApproval)

**表名**: `commission_approvals`

**核心字段**:
- `commission_record_id`: 分佣记录 ID
- `agent_id`: 代理用户 ID
- `approval_status`: 审批状态 (1-待审批, 2-已通过, 3-已拒绝)
- `approver_id`: 审批人 ID
- `approval_reason`: 审批原因
- `approved_at`: 审批时间

**用途**: 管理需要手动审批的分佣记录。

**文件位置**: `internal/iot/model/commission.go:116`

---

### 19. 分佣模板 (CommissionTemplate)

**表名**: `commission_templates`

**核心字段**:
- `template_name`: 模板名称
- `template_data`: 模板数据 (JSONB)
- `description`: 描述

**用途**: 快速创建分佣规则的预设模板。

**文件位置**: `internal/iot/model/commission.go:137`

---

### 20. 运营商结算 (CarrierSettlement)

**表名**: `carrier_settlements`

**核心字段**:
- `carrier_id`: 运营商 ID
- `settlement_month`: 结算月份 (YYYY-MM)
- `total_orders`: 总订单数
- `total_amount`: 总金额 (元)
- `settlement_status`: 结算状态 (1-待结算, 2-已结算, 3-已支付)
- `settled_at`: 结算时间
- `paid_at`: 支付时间

**用途**: 记录与运营商的月度结算情况。

**文件位置**: `internal/iot/model/commission.go:155`

---

## 财务管理

### 21. 提现申请 (CommissionWithdrawalRequest)

**表名**: `commission_withdrawal_requests`

**核心字段**:
- `agent_id`: 代理用户 ID
- `withdrawal_amount`: 提现金额 (元)
- `withdrawal_method`: 提现方式 (bank_card/alipay/wechat)
- `account_info`: 账户信息 (JSONB)
- `status`: 状态 (1-待审核, 2-已通过, 3-已拒绝, 4-已打款, 5-已取消)
- `reviewer_id`: 审核人 ID
- `review_reason`: 审核原因
- `reviewed_at`: 审核时间
- `paid_at`: 打款时间

**用途**: 管理代理用户的佣金提现申请。

**文件位置**: `internal/iot/model/financial.go:8`

---

### 22. 提现设置 (CommissionWithdrawalSetting)

**表名**: `commission_withdrawal_settings`

**核心字段**:
- `agent_id`: 代理用户 ID
- `min_withdrawal_amount`: 最小提现金额 (元)
- `max_withdrawal_amount`: 最大提现金额 (元)
- `withdrawal_fee_rate`: 提现手续费率 (小数)
- `auto_approval_enabled`: 是否启用自动审批

**用途**: 配置代理用户的提现规则。

**文件位置**: `internal/iot/model/financial.go:31`

---

### 23. 收款商户设置 (PaymentMerchantSetting)

**表名**: `payment_merchant_settings`

**核心字段**:
- `merchant_name`: 商户名称
- `merchant_type`: 商户类型 (alipay/wechat/bank)
- `merchant_config`: 商户配置 (JSONB)
- `is_default`: 是否默认商户

**用途**: 配置收款商户信息 (支付宝、微信、银行)。

**文件位置**: `internal/iot/model/financial.go:51`

---

## 系统管理

### 24. 开发能力配置 (DevCapabilityConfig)

**表名**: `dev_capability_configs`

**核心字段**:
- `capability_name`: 能力名称
- `capability_code`: 能力编码
- `capability_config`: 能力配置 (JSONB)
- `description`: 描述

**用途**: 管理系统开发能力配置 (如 API 开关、功能权限等)。

**文件位置**: `internal/iot/model/system.go:5`

---

### 25. 换卡申请 (CardReplacementRequest)

**表名**: `card_replacement_requests`

**核心字段**:
- `old_iot_card_id`: 旧卡 ID
- `new_iot_card_id`: 新卡 ID
- `user_id`: 用户 ID
- `replacement_reason`: 换卡原因
- `status`: 状态 (1-待审核, 2-已通过, 3-已拒绝, 4-已完成)
- `reviewer_id`: 审核人 ID
- `reviewed_at`: 审核时间
- `completed_at`: 完成时间

**用途**: 管理 IoT 卡的换卡申请流程。

**文件位置**: `internal/iot/model/system.go:25`

---

## 数据库设计原则

### 1. 无外键约束

- 数据库表之间**禁止建立外键约束** (Foreign Key Constraints)
- 关联关系通过存储关联 ID 字段手动维护
- 关联数据查询在代码层面显式执行

**设计理由**:
- 灵活性：业务逻辑完全在代码中控制
- 性能：无数据库层面的引用完整性检查开销
- 可控性：开发者完全掌控何时查询关联数据
- 分布式友好：在微服务场景下更容易扩展

---

### 2. GORM 模型规范

- 所有字段必须显式指定 `column:` 标签
- 禁止使用 ORM 关联关系 (`foreignKey`, `references`, `hasMany`, `belongsTo`)
- 所有字段必须添加中文注释
- 字符串字段长度必须明确定义 (VARCHAR(100)/VARCHAR(255)/TEXT)
- 数值字段精度必须明确定义 (DECIMAL(10,2)/BIGINT)
- 时间字段使用 GORM 自动管理 (`autoCreateTime`, `autoUpdateTime`)

---

### 3. 命名规范

- 数据库字段名：下划线命名法 (snake_case)，如 `user_id`, `created_at`
- Go 结构体字段名：驼峰命名法 (PascalCase)，如 `UserID`, `CreatedAt`
- 表名：复数形式，如 `iot_cards`, `orders`, `commission_rules`
- 常量名：大写驼峰 + 前缀，如 `IotOrderStatusPending`, `CarrierCodeCMCC`

---

## 常量定义

所有业务常量统一定义在 `pkg/constants/iot.go` 文件中,包括:

- 卡类型、卡业务类型、激活状态、实名状态、网络状态
- 所有者类型、卡状态、设备状态
- 套餐类型、流量类型、套餐使用状态
- 订单类型、订单状态、支付方式
- 轮询卡状态条件
- 分佣规则类型、分佣方式、分佣状态、解冻模式
- 提现状态、提现方式、商户类型
- 换卡申请状态、审批状态

**文件位置**: `pkg/constants/iot.go:1`

---

## 数据库迁移

### 迁移脚本

- **UP 脚本**: `migrations/000005_create_iot_sim_management_tables.up.sql`
  - 创建 26 张表
  - 创建所有必需的索引
  - 添加完整的中文注释
  - 初始化三大运营商数据

- **DOWN 脚本**: `migrations/000005_create_iot_sim_management_tables.down.sql`
  - 按反向依赖顺序删除所有表

### 迁移测试

```bash
# 应用迁移
source .env && migrate -database "postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=${DB_SSLMODE}" -path migrations up

# 回滚迁移
source .env && migrate -database "postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=${DB_SSLMODE}" -path migrations down 1

# 查看版本
source .env && migrate -database "postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=${DB_SSLMODE}" -path migrations version
```

### 测试结果

- ✅ UP 迁移成功 (耗时 616ms)
- ✅ DOWN 迁移成功 (耗时 602ms)
- ✅ 数据库版本正确切换 (4 → 5 → 4 → 5)

---

## 文件清单

### 数据库迁移脚本
- `migrations/000005_create_iot_sim_management_tables.up.sql` (1102 行)
- `migrations/000005_create_iot_sim_management_tables.down.sql` (27 行)

### GORM 模型定义
- `internal/iot/model/carrier.go` (17 行)
- `internal/iot/model/iot_card.go` (40 行)
- `internal/iot/model/device.go` (27 行)
- `internal/iot/model/number_card.go` (26 行)
- `internal/iot/model/package.go` (108 行)
- `internal/iot/model/order.go` (36 行)
- `internal/iot/model/polling.go` (29 行)
- `internal/iot/model/data_usage.go` (20 行)
- `internal/iot/model/commission.go` (175 行)
- `internal/iot/model/financial.go` (70 行)
- `internal/iot/model/system.go` (46 行)

### 常量定义
- `pkg/constants/iot.go` (164 行)

---

## 代码质量

- ✅ `go fmt` 格式化通过
- ✅ `goimports` 导入整理通过
- ✅ `golangci-lint` 质量检查通过 (0 issues)
- ✅ `go build` 编译通过
- ✅ `go mod tidy` 依赖管理通过

---

## 下一步工作

根据 OpenSpec 规范,本阶段只实现数据模型层,以下工作不在本阶段范围:

- ❌ API Handler 层
- ❌ Service 业务逻辑层
- ❌ Store 数据访问层
- ❌ 单元测试
- ❌ 集成测试
- ❌ API 文档生成

这些工作将在后续阶段按照 OpenSpec 流程逐步实现。

---

## 参考文档

- [表结构详细说明](./表结构详细说明.md)
- [轮询机制说明](./轮询机制说明.md)
- [分佣系统说明](./分佣系统说明.md)

---

**文档版本**: v1.0
**最后更新**: 2026-01-12
**维护人员**: Claude Sonnet 4.5
