- 添加 IoT 核心业务表:运营商、IoT 卡、设备、号卡、套餐、订单等 - 添加分佣系统表:分佣规则、分佣记录、运营商结算等 - 添加轮询和流量管理表:轮询配置、流量使用记录等 - 添加财务和系统管理表:佣金提现、换卡申请等 - 实现完整的 GORM 模型和常量定义 - 添加数据库迁移脚本和详细文档 - 集成 OpenSpec 工作流工具(opsx 命令和 skills) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
442 lines
23 KiB
Markdown
442 lines
23 KiB
Markdown
# IoT SIM 管理 - 数据模型与数据库表结构实现任务
|
||
|
||
本任务清单聚焦于 IoT SIM 管理模块的数据模型定义和数据库表结构实现,不包含业务逻辑代码。
|
||
|
||
---
|
||
|
||
## 1. 数据库迁移脚本
|
||
|
||
### 1.1 核心业务表
|
||
- [x] 1.1.1 创建迁移脚本文件:`migrations/YYYYMMDDHHMMSS_create_iot_sim_management_tables.up.sql` 和 `*.down.sql`
|
||
- [x] 1.1.2 创建运营商表(carriers)及其索引
|
||
- 主键索引
|
||
- `carrier_code` 唯一索引
|
||
- 初始数据:中国移动(CMCC)、中国联通(CUCC)、中国电信(CTCC)
|
||
- [x] 1.1.3 创建 IoT 卡表(iot_cards)及其索引
|
||
- 主键索引
|
||
- `iccid` 唯一索引
|
||
- `card_category` 字段:枚举值 "normal"(普通卡) | "industry"(行业卡),默认 "normal"
|
||
- `carrier_id` 索引(关联运营商表)
|
||
- `owner_type` + `owner_id` + `status` 组合索引
|
||
- `batch_no` 索引
|
||
- `activated_at` 索引
|
||
- `card_category` 索引(用于区分普通卡和行业卡)
|
||
- `enable_polling` + `activation_status` + `last_data_check_at` 组合索引(卡流量轮询查询优化)
|
||
- `enable_polling` + `real_name_status` + `last_real_name_check_at` 组合索引(实名轮询查询优化)
|
||
- [x] 1.1.4 创建设备表(devices)及其索引
|
||
- 主键索引
|
||
- `device_no` 唯一索引
|
||
- `owner_type` + `owner_id` + `status` 组合索引
|
||
- [x] 1.1.5 创建号卡表(number_cards)及其索引
|
||
- 主键索引
|
||
- `virtual_product_code` 唯一索引
|
||
- `agent_id` + `status` 组合索引
|
||
- [x] 1.1.6 创建套餐系列表(package_series)及其索引
|
||
- 主键索引
|
||
- `series_code` 唯一索引
|
||
- [x] 1.1.7 创建套餐表(packages)及其索引
|
||
- 主键索引
|
||
- `package_code` 唯一索引
|
||
- `series_id` + `status` 组合索引
|
||
- [x] 1.1.8 创建代理套餐分配表(agent_package_allocations)及其索引
|
||
- 主键索引
|
||
- `agent_id` + `package_id` 唯一组合索引
|
||
- [x] 1.1.9 创建设备-IoT卡绑定关系表(device_sim_bindings)及其索引
|
||
- 主键索引
|
||
- `device_id` + `bind_status` 组合索引
|
||
- `iot_card_id` + `bind_status` 组合索引
|
||
- `iot_card_id` 部分唯一索引(WHERE bind_status = 1)
|
||
- [x] 1.1.10 创建订单表(orders)及其索引
|
||
- 主键索引
|
||
- `order_no` 唯一索引
|
||
- `user_id` + `status` 组合索引
|
||
- `agent_id` + `status` 组合索引
|
||
- `iot_card_id` 索引
|
||
- `device_id` 索引
|
||
- `number_card_id` 索引
|
||
|
||
### 1.2 套餐和轮询相关表
|
||
- [x] 1.2.1 创建套餐使用情况表(package_usages)及其索引
|
||
- 主键索引
|
||
- `order_id` 索引
|
||
- `package_id` 索引
|
||
- `iot_card_id` 索引
|
||
- `device_id` 索引
|
||
- `status` + `expires_at` + `last_package_check_at` 组合索引(套餐流量检查优化)
|
||
- [x] 1.2.2 创建轮询配置表(polling_configs)及其索引
|
||
- 主键索引
|
||
- `config_name` 唯一索引
|
||
- `status` + `card_condition` + `carrier_id` + `priority` 组合索引(配置匹配优化)
|
||
- [x] 1.2.3 创建流量使用记录表(data_usage_records)及其索引
|
||
- 主键索引
|
||
- `iot_card_id` + `check_time` 组合索引(按卡和时间查询)
|
||
- `check_time` 索引(按时间范围查询)
|
||
- 注意:此表数据量会快速增长,建议定期清理 90 天前的记录或使用分区表
|
||
|
||
### 1.3 分佣相关表
|
||
- [x] 1.3.1 创建代理层级关系表(agent_hierarchies)及其索引
|
||
- 主键索引
|
||
- `agent_id` 唯一索引
|
||
- `parent_agent_id` 索引
|
||
- [x] 1.3.2 创建分佣规则表(commission_rules)及其索引
|
||
- 主键索引
|
||
- `agent_id` + `business_type` + `card_type` 组合索引
|
||
- [x] 1.3.3 创建阶梯分佣配置表(commission_ladder)及其索引
|
||
- 主键索引
|
||
- `rule_id` 索引
|
||
- [x] 1.3.4 创建组合分佣条件表(commission_combined_conditions)及其索引
|
||
- 主键索引
|
||
- `rule_id` 唯一索引
|
||
- [x] 1.3.5 创建分佣记录表(commission_records)及其索引
|
||
- 主键索引
|
||
- `agent_id` + `status` 组合索引
|
||
- `order_id` 索引
|
||
- `rule_id` 索引
|
||
- [x] 1.3.6 创建分佣审批表(commission_approvals)及其索引
|
||
- 主键索引
|
||
- `commission_record_id` 索引
|
||
- `status` 索引
|
||
- [x] 1.3.7 创建分佣模板表(commission_templates)及其索引
|
||
- 主键索引
|
||
- `template_name` 唯一索引
|
||
- [x] 1.3.8 创建号卡运营商结算表(carrier_settlements)及其索引
|
||
- 主键索引
|
||
- `commission_record_id` 唯一索引
|
||
- `agent_id` + `status` 组合索引
|
||
|
||
### 1.4 财务管理表
|
||
- [x] 1.4.1 创建佣金提现申请表(commission_withdrawal_requests)及其索引
|
||
- 主键索引
|
||
- `agent_id` + `status` 组合索引
|
||
- `created_at` 索引
|
||
- [x] 1.4.2 创建佣金提现设置表(commission_withdrawal_settings)及其索引
|
||
- 主键索引
|
||
- `status` 索引
|
||
- [x] 1.4.3 创建收款商户设置表(payment_merchant_settings)及其索引
|
||
- 主键索引
|
||
- `user_id` + `is_default` 组合索引
|
||
- `merchant_type` + `status` 组合索引
|
||
|
||
### 1.5 系统管理表
|
||
- [x] 1.5.1 创建开发能力配置表(dev_capability_configs)及其索引
|
||
- 主键索引
|
||
- `app_id` 唯一索引
|
||
- `user_id` + `status` 组合索引
|
||
- [x] 1.5.2 创建换卡申请表(card_replacement_requests)及其索引
|
||
- 主键索引
|
||
- `user_id` + `status` 组合索引
|
||
- `old_iccid` 索引
|
||
- `new_iccid` 索引
|
||
|
||
### 1.6 迁移脚本验证
|
||
- [x] 1.6.1 编写迁移脚本的 down 部分(删除所有表)
|
||
- [x] 1.6.2 在本地测试数据库执行 up 迁移
|
||
- [x] 1.6.3 验证所有表和索引创建成功
|
||
- [x] 1.6.4 执行 down 迁移验证回滚成功
|
||
- [x] 1.6.5 编写迁移脚本的 README 说明(执行步骤、注意事项)
|
||
|
||
---
|
||
|
||
## 2. GORM 模型定义
|
||
|
||
### 2.1 目录结构
|
||
- [x] 2.1.1 创建 `internal/iot/model` 目录
|
||
- [x] 2.1.2 创建模型文件结构:
|
||
- `carrier.go` - 运营商模型
|
||
- `iot_card.go` - IoT 卡模型
|
||
- `device.go` - 设备模型
|
||
- `number_card.go` - 号卡模型
|
||
- `package.go` - 套餐、套餐系列、套餐使用情况模型
|
||
- `order.go` - 订单模型
|
||
- `polling.go` - 轮询配置模型
|
||
- `data_usage.go` - 流量使用记录模型
|
||
- `commission.go` - 分佣相关模型
|
||
- `financial.go` - 财务管理模型
|
||
- `system.go` - 系统管理模型
|
||
|
||
### 2.2 核心业务模型
|
||
- [x] 2.2.1 定义运营商(Carrier)模型
|
||
- 字段包括:id, carrier_code, carrier_name, description, status, created_at, updated_at
|
||
- 初始数据:中国移动(CMCC)、中国联通(CUCC)、中国电信(CTCC)
|
||
- [x] 2.2.2 定义 IoT 卡(IotCard)模型
|
||
- 所有字段必须显式指定 `gorm:"column:字段名"`
|
||
- 添加中文字段注释(comment 标签)
|
||
- 字段包括:id, iccid, card_type, card_category, carrier_id, imsi, msisdn, batch_no, supplier, cost_price, distribute_price, status, owner_type, owner_id, activated_at, activation_status, real_name_status, network_status, data_usage_mb, enable_polling, last_data_check_at, last_real_name_check_at, last_sync_time, created_at, updated_at
|
||
- **关键调整**:
|
||
- `card_category` 字段:枚举值 "normal"(普通卡) | "industry"(行业卡),默认 "normal"
|
||
- `carrier_id` 关联运营商表(替代原来的 carrier 字符串字段)
|
||
- `enable_polling` 控制是否参与轮询(默认 true)
|
||
- `last_data_check_at` 卡流量检查时间
|
||
- `last_real_name_check_at` 实名检查时间
|
||
- 行业卡可以在 `real_name_status` 为 0 的情况下激活使用
|
||
- [x] 2.2.3 定义设备(Device)模型
|
||
- 字段包括:id, device_no, device_name, device_model, device_type, max_sim_slots, manufacturer, batch_no, owner_type, owner_id, status, activated_at, device_username, device_password_encrypted, device_api_endpoint, created_at, updated_at
|
||
- [x] 2.2.4 定义号卡(NumberCard)模型
|
||
- 字段包括:id, virtual_product_code, card_name, card_type, carrier, data_amount_mb, price, agent_id, status, created_at, updated_at
|
||
- [x] 2.2.5 定义套餐系列(PackageSeries)模型
|
||
- 字段包括:id, series_code, series_name, description, status, created_at, updated_at
|
||
- [x] 2.2.6 定义套餐(Package)模型
|
||
- 字段包括:id, package_code, package_name, series_id, package_type, duration_months, data_type, real_data_mb, virtual_data_mb, data_amount_mb, price, status, created_at, updated_at
|
||
- [x] 2.2.7 定义代理套餐分配(AgentPackageAllocation)模型
|
||
- 字段包括:id, agent_id, package_id, cost_price, retail_price, status, created_at, updated_at
|
||
- [x] 2.2.8 定义设备-IoT卡绑定关系(DeviceSimBinding)模型
|
||
- 字段包括:id, device_id, iot_card_id, slot_number, bind_status, bound_at, unbound_at, created_at, updated_at
|
||
- [x] 2.2.9 定义订单(Order)模型
|
||
- 字段包括:id, order_no, order_type, iot_card_id, device_id, number_card_id, package_id, user_id, agent_id, amount, payment_method, status, carrier_order_id, carrier_order_data, paid_at, completed_at, created_at, updated_at
|
||
|
||
### 2.3 套餐和轮询相关模型
|
||
- [x] 2.3.1 定义套餐使用情况(PackageUsage)模型
|
||
- 字段包括:id, order_id, package_id, usage_type, iot_card_id, device_id, data_limit_mb, data_usage_mb, real_data_usage_mb, virtual_data_usage_mb, activated_at, expires_at, status, last_package_check_at, created_at, updated_at
|
||
- **业务逻辑**:
|
||
- `usage_type` = "single_card" 时,`iot_card_id` 有值,`device_id` 为 NULL
|
||
- `usage_type` = "device" 时,`device_id` 有值,`iot_card_id` 为 NULL
|
||
- `data_usage_mb` 通过汇总卡的流量计算(单卡套餐直接读卡流量,设备级套餐汇总所有卡流量)
|
||
- [x] 2.3.2 定义轮询配置(PollingConfig)模型
|
||
- 字段包括:id, config_name, description, card_condition, carrier_id, real_name_check_enabled, real_name_check_interval, card_data_check_enabled, card_data_check_interval, package_check_enabled, package_check_interval, priority, status, created_at, updated_at
|
||
- **配置说明**:
|
||
- `carrier_id` 为 NULL 表示匹配所有运营商
|
||
- `priority` 数字越小优先级越高
|
||
- 支持独立配置实名检查、卡流量检查、套餐流量检查
|
||
- [x] 2.3.3 定义流量使用记录(DataUsageRecord)模型
|
||
- 字段包括:id, iot_card_id, data_usage_mb, data_increase_mb, check_time, source, created_at
|
||
- **业务逻辑**:
|
||
- Worker 每次轮询卡流量后插入一条记录
|
||
- `data_increase_mb` = 本次流量 - 上次流量
|
||
- `source` 数据来源(polling-轮询 manual-手动 gateway-回调)
|
||
|
||
### 2.4 分佣相关模型
|
||
- [x] 2.4.1 定义代理层级关系(AgentHierarchy)模型
|
||
- 字段包括:id, agent_id, parent_agent_id, agent_path, level, created_at, updated_at
|
||
- [x] 2.4.2 定义分佣规则(CommissionRule)模型
|
||
- 字段包括:id, agent_id, business_type, card_type, commission_type, commission_mode, commission_value, unfreeze_days, min_activation_for_unfreeze, approval_type, status, created_at, updated_at
|
||
- [x] 2.4.3 定义阶梯分佣配置(CommissionLadder)模型
|
||
- 字段包括:id, rule_id, ladder_type, threshold_value, commission_mode, commission_value, created_at, updated_at
|
||
- [x] 2.4.4 定义组合分佣条件(CommissionCombinedCondition)模型
|
||
- 字段包括:id, rule_id, one_time_commission_mode, one_time_commission_value, long_term_commission_mode, long_term_commission_value, long_term_unfreeze_days, long_term_min_activation, created_at, updated_at
|
||
- [x] 2.4.5 定义分佣记录(CommissionRecord)模型
|
||
- 字段包括:id, agent_id, order_id, rule_id, commission_type, amount, status, unfrozen_at, released_at, created_at, updated_at
|
||
- [x] 2.4.6 定义分佣审批(CommissionApproval)模型
|
||
- 字段包括:id, commission_record_id, approver_id, status, reason, created_at, updated_at
|
||
- [x] 2.4.7 定义分佣模板(CommissionTemplate)模型
|
||
- 字段包括:id, template_name, business_type, card_type, commission_type, commission_mode, commission_value, unfreeze_days, min_activation_for_unfreeze, approval_type, created_at, updated_at
|
||
- [x] 2.4.8 定义号卡运营商结算(CarrierSettlement)模型
|
||
- 字段包括:id, commission_record_id, agent_id, settlement_month, settlement_amount, status, created_at, updated_at
|
||
|
||
### 2.5 财务管理模型
|
||
- [x] 2.5.1 定义佣金提现申请(CommissionWithdrawalRequest)模型
|
||
- 字段包括:id, agent_id, amount, withdrawal_method, merchant_id, account_info, status, approved_by, approved_at, rejected_reason, paid_at, created_at, updated_at
|
||
- [x] 2.5.2 定义佣金提现设置(CommissionWithdrawalSetting)模型
|
||
- 字段包括:id, min_withdrawal_amount, max_withdrawal_amount, daily_withdrawal_limit, fee_rate, status, created_at, updated_at
|
||
- [x] 2.5.3 定义收款商户设置(PaymentMerchantSetting)模型
|
||
- 字段包括:id, user_id, merchant_type, account_name, account_number, bank_name, is_verified, is_default, status, created_at, updated_at
|
||
|
||
### 2.6 系统管理模型
|
||
- [x] 2.6.1 定义开发能力配置(DevCapabilityConfig)模型
|
||
- 字段包括:id, user_id, app_id, app_secret, callback_url, status, created_at, updated_at
|
||
- [x] 2.6.2 定义换卡申请(CardReplacementRequest)模型
|
||
- 字段包括:id, user_id, old_iccid, new_iccid, reason, status, processed_by, processed_at, created_at, updated_at
|
||
|
||
---
|
||
|
||
## 3. 常量定义
|
||
|
||
### 3.1 核心业务常量
|
||
- [x] 3.1.1 在 `pkg/constants/iot.go` 中定义以下常量:
|
||
- IoT 卡状态:IotCardStatusInStock(1), IotCardStatusDistributed(2), IotCardStatusActivated(3), IotCardStatusSuspended(4)
|
||
- 设备状态:DeviceStatusInStock(1), DeviceStatusDistributed(2), DeviceStatusActivated(3), DeviceStatusSuspended(4)
|
||
- 号卡状态:NumberCardStatusOnSale(1), NumberCardStatusOffSale(2)
|
||
- IoT 卡激活状态:ActivationStatusInactive(0), ActivationStatusActive(1)
|
||
- IoT 卡实名状态:RealNameStatusNotVerified(0), RealNameStatusVerified(1)
|
||
- IoT 卡网络状态:NetworkStatusOffline(0), NetworkStatusOnline(1)
|
||
- 套餐流量类型:DataTypeReal("real"), DataTypeVirtual("virtual")
|
||
- 套餐类型:PackageTypeFormal("formal"), PackageTypeAddon("addon")
|
||
- 订单类型:OrderTypePackage(1), OrderTypeNumberCard(2)
|
||
- 订单状态:OrderStatusPending(1), OrderStatusPaid(2), OrderStatusCompleted(3), OrderStatusCancelled(4), OrderStatusRefunded(5)
|
||
- 支付方式:PaymentMethodWallet("wallet"), PaymentMethodOnline("online"), PaymentMethodCarrier("carrier")
|
||
- 所有者类型:OwnerTypePlatform("platform"), OwnerTypeAgent("agent"), OwnerTypeUser("user"), OwnerTypeDevice("device")
|
||
- 绑定状态:BindStatusBound(1), BindStatusUnbound(2)
|
||
|
||
### 3.2 套餐和轮询相关常量
|
||
- [x] 3.2.1 定义套餐使用类型常量:
|
||
- PackageUsageTypeSingleCard("single_card") - 单卡套餐
|
||
- PackageUsageTypeDevice("device") - 设备级套餐
|
||
- [x] 3.2.2 定义套餐使用状态常量:
|
||
- PackageUsageStatusActive(1) - 生效中
|
||
- PackageUsageStatusExhausted(2) - 已用完
|
||
- PackageUsageStatusExpired(3) - 已过期
|
||
- [x] 3.2.3 定义轮询配置卡条件常量:
|
||
- CardConditionNotRealName("not_real_name") - 未实名
|
||
- CardConditionRealName("real_name") - 已实名
|
||
- CardConditionActivated("activated") - 已激活
|
||
- CardConditionSuspended("suspended") - 已停用
|
||
- [x] 3.2.4 定义流量使用记录来源常量:
|
||
- DataUsageSourcePolling("polling") - 轮询
|
||
- DataUsageSourceManual("manual") - 手动
|
||
- DataUsageSourceGateway("gateway") - Gateway 回调
|
||
|
||
### 3.3 分佣相关常量
|
||
- [x] 3.3.1 定义分佣相关常量:
|
||
- 分佣类型:CommissionTypeOneTime("one_time"), CommissionTypeLongTerm("long_term"), CommissionTypeCombined("combined")
|
||
- 分佣模式:CommissionModeFixed("fixed"), CommissionModePercent("percent")
|
||
- 分佣状态:CommissionStatusFrozen(1), CommissionStatusUnfreezing(2), CommissionStatusReleased(3), CommissionStatusInvalid(4)
|
||
- 阶梯类型:LadderTypeActivation("activation"), LadderTypePickup("pickup"), LadderTypeDeposit("deposit")
|
||
- 卡类型:CardTypeNumberCard("number_card"), CardTypeIotCard("iot_card")
|
||
- 审批类型:ApprovalTypeAuto("auto"), ApprovalTypeManual("manual")
|
||
- 审批状态:ApprovalStatusPending(1), ApprovalStatusApproved(2), ApprovalStatusRejected(3)
|
||
|
||
### 3.4 财务管理常量
|
||
- [x] 3.4.1 定义财务相关常量:
|
||
- 提现状态:WithdrawalStatusPending(1), WithdrawalStatusApproved(2), WithdrawalStatusRejected(3), WithdrawalStatusPaid(4)
|
||
- 提现方式:WithdrawalMethodAlipay("alipay"), WithdrawalMethodWechat("wechat"), WithdrawalMethodBank("bank")
|
||
- 商户类型:MerchantTypeAlipay("alipay"), MerchantTypeWechat("wechat"), MerchantTypeBank("bank")
|
||
|
||
### 3.5 系统管理常量
|
||
- [x] 3.5.1 定义系统管理常量:
|
||
- 换卡申请状态:ReplacementStatusPending(1), ReplacementStatusApproved(2), ReplacementStatusRejected(3), ReplacementStatusCompleted(4)
|
||
- 开发能力配置状态:DevCapabilityStatusEnabled(1), DevCapabilityStatusDisabled(2)
|
||
|
||
---
|
||
|
||
## 4. 模型和表结构文档
|
||
|
||
### 4.1 代码注释
|
||
- [x] 4.1.1 为所有 GORM 模型添加中文结构体注释(描述表的业务用途)
|
||
- [x] 4.1.2 为所有模型字段添加清晰的中文注释
|
||
- [x] 4.1.3 为所有常量添加中文注释(说明枚举值含义)
|
||
- [x] 4.1.4 在迁移脚本中为所有表和字段添加 SQL COMMENT
|
||
|
||
### 4.2 数据库设计文档
|
||
- [x] 4.2.1 在 `docs/iot-sim-management/` 目录下创建 `数据库设计.md`
|
||
- [x] 4.2.2 使用 Markdown 表格描述所有表结构(字段名、类型、约束、说明)
|
||
- [x] 4.2.3 使用 dbdiagram.io 或 draw.io 创建数据库 ERD 图
|
||
- [x] 4.2.4 导出 ERD 图并保存到 `docs/iot-sim-management/erd.png`
|
||
- [x] 4.2.5 在 `数据库设计.md` 中嵌入 ERD 图
|
||
|
||
### 4.3 模型使用说明
|
||
- [x] 4.3.1 创建 `docs/iot-sim-management/模型说明.md`
|
||
- [x] 4.3.2 说明每个模型的用途和关键字段含义
|
||
- [x] 4.3.3 说明表之间的关联关系(虽然没有外键,但逻辑关联需要说明)
|
||
- [x] 4.3.4 说明关键枚举字段的取值和含义
|
||
- [x] 4.3.5 说明特殊设计决策(如无外键约束、owner_type/owner_id 模式等)
|
||
|
||
### 4.4 轮询机制说明文档
|
||
- [x] 4.4.1 创建 `docs/iot-sim-management/轮询机制说明.md`
|
||
- [x] 4.4.2 说明三个独立轮询流程:实名状态轮询、卡流量轮询、套餐流量检查
|
||
- [x] 4.4.3 说明轮询配置的匹配规则和优先级
|
||
- [x] 4.4.4 说明 `enable_polling` 字段的使用场景
|
||
- [x] 4.4.5 说明流量使用记录表的数据保留策略
|
||
|
||
### 4.5 项目文档更新
|
||
- [x] 4.5.1 更新 `README.md`,添加 IoT SIM 管理模块描述
|
||
- [x] 4.5.2 在 README 中添加数据库设计文档链接
|
||
- [x] 4.5.3 在 README 中添加模型说明文档链接
|
||
- [x] 4.5.4 在 README 中添加轮询机制说明文档链接
|
||
|
||
---
|
||
|
||
## 5. 数据迁移验证
|
||
|
||
### 5.1 本地验证
|
||
- [x] 5.1.1 在本地 PostgreSQL 测试数据库执行迁移脚本 up
|
||
- [x] 5.1.2 使用 `\dt` 和 `\d table_name` 验证所有表创建成功
|
||
- [x] 5.1.3 验证所有字段类型、默认值、NOT NULL 约束正确
|
||
- [x] 5.1.4 使用 `\di` 验证所有索引创建成功
|
||
- [x] 5.1.5 验证唯一索引和组合索引的正确性
|
||
|
||
### 5.2 数据完整性验证
|
||
- [x] 5.2.1 插入测试数据验证唯一索引生效(尝试插入重复 ICCID 应失败)
|
||
- [x] 5.2.2 插入测试数据验证 NOT NULL 约束生效
|
||
- [x] 5.2.3 插入测试数据验证 CHECK 约束生效(如金额 >= 0)
|
||
- [x] 5.2.4 查询测试数据验证组合索引生效(使用 EXPLAIN ANALYZE)
|
||
- [x] 5.2.5 验证运营商初始数据插入成功
|
||
|
||
### 5.3 回滚验证
|
||
- [x] 5.3.1 执行迁移脚本 down
|
||
- [x] 5.3.2 验证所有表和索引删除成功
|
||
- [x] 5.3.3 重新执行 up 验证迁移脚本可重复执行
|
||
|
||
---
|
||
|
||
## 6. 代码质量检查
|
||
|
||
### 6.1 代码格式化
|
||
- [x] 6.1.1 使用 `go fmt` 格式化所有模型代码
|
||
- [x] 6.1.2 使用 `goimports` 整理导入语句
|
||
- [x] 6.1.3 使用 `golangci-lint` 检查代码质量
|
||
|
||
### 6.2 命名规范检查
|
||
- [x] 6.2.1 验证所有 Go 字段名遵循驼峰命名法(PascalCase)
|
||
- [x] 6.2.2 验证所有数据库字段名遵循下划线命名法(snake_case)
|
||
- [x] 6.2.3 验证所有常量命名遵循 Go 规范(如 IotCardStatusInStock)
|
||
- [x] 6.2.4 验证所有模型文件名遵循 Go 规范(snake_case,如 iot_card.go)
|
||
|
||
### 6.3 GORM 标签检查
|
||
- [x] 6.3.1 验证所有字段都有 `gorm:"column:字段名"` 标签
|
||
- [x] 6.3.2 验证所有字段都有 `json:"字段名"` 标签
|
||
- [x] 6.3.3 验证所有字段的 `comment` 标签包含中文说明
|
||
- [x] 6.3.4 验证字符串字段的 `type` 标签指定了长度(如 `type:varchar(100)`)
|
||
- [x] 6.3.5 验证数值字段的 `type` 标签指定了精度(如 `type:decimal(10,2)`)
|
||
|
||
---
|
||
|
||
## 完成标准
|
||
|
||
本阶段任务完成后,应该具备:
|
||
|
||
1. ✅ 完整的数据库迁移脚本(up 和 down)
|
||
2. ✅ 完整的 GORM 模型定义(所有表对应的 Go 结构体)
|
||
3. ✅ 完整的常量定义(所有枚举值)
|
||
4. ✅ 完整的数据库设计文档(ERD 图 + 表结构说明)
|
||
5. ✅ 完整的模型使用说明文档
|
||
6. ✅ 完整的轮询机制说明文档
|
||
7. ✅ 数据库迁移在本地测试通过
|
||
8. ✅ 所有代码遵循项目开发规范(命名、注释、格式)
|
||
|
||
**不包含**:业务逻辑实现、API 接口、Service 层、Store 层、DTO、错误码、Redis Key 等。
|
||
|
||
---
|
||
|
||
## 关键设计说明
|
||
|
||
### 运营商表 (carriers)
|
||
- 存储运营商基础信息(中国移动、中国联通、中国电信)
|
||
- IoT 卡表通过 `carrier_id` 关联运营商表
|
||
|
||
### IoT 卡表 (iot_cards)
|
||
- `card_category` 字段:枚举值 "normal"(普通卡) | "industry"(行业卡),默认 "normal"
|
||
- **普通卡**: 需要实名认证才能激活使用
|
||
- **行业卡**: 不需要实名认证,可以在 `real_name_status` 为 0 的情况下激活使用
|
||
- `carrier_id` 关联运营商表(替代原来的 carrier 字符串字段)
|
||
- `enable_polling` 控制是否参与轮询(默认 true,可手动禁用)
|
||
- `last_data_check_at` 记录卡流量检查时间
|
||
- `last_real_name_check_at` 记录实名检查时间
|
||
|
||
### 套餐使用情况表 (package_usages)
|
||
- 核心业务表,跟踪套餐的激活、使用、过期情况
|
||
- 单卡套餐:`usage_type` = "single_card",`iot_card_id` 有值
|
||
- 设备级套餐:`usage_type` = "device",`device_id` 有值
|
||
- `data_usage_mb` 通过汇总卡的流量计算(不是实时轮询,而是定期统计)
|
||
|
||
### 轮询配置表 (polling_configs)
|
||
- 支持梯度配置(未实名卡、实名卡使用不同的轮询策略)
|
||
- 支持按运营商配置不同的轮询频率
|
||
- 独立配置三种轮询:实名检查、卡流量检查、套餐流量检查
|
||
- `priority` 数字越小优先级越高
|
||
|
||
### 流量使用记录表 (data_usage_records)
|
||
- 记录每次卡流量检查的结果
|
||
- 支持按卡、按时间范围查询流量历史
|
||
- 数据量会快速增长,建议定期清理 90 天前的记录或使用分区表
|
||
|
||
### 轮询逻辑(概念说明)
|
||
1. **卡流量轮询**:只轮询有生效套餐的卡,`enable_polling = true`
|
||
2. **套餐流量检查**:定期汇总卡的流量,判断套餐是否超额
|
||
3. **实名状态轮询**:定期检查卡的实名状态,实名后降低轮询频率
|
||
- **行业卡特殊处理**: 行业卡的实名状态检查应该被禁用或设置为低优先级
|
||
4. **三个流程独立运行**:互不干扰,通过轮询配置表动态控制
|
||
|
||
### 分佣解冻逻辑(概念说明)
|
||
1. **一次性分佣**: 普通卡需要实名认证后才能解冻;行业卡无需实名认证,只需满足激活和充值条件
|
||
2. **长期分佣**: 普通卡需要实名认证后才能开始长期分佣;行业卡无需实名认证,满足其他条件即可
|
||
3. **组合分佣**: 行业卡的时间点条件从激活时开始计算(不是实名时)
|