- 添加 IoT 核心业务表:运营商、IoT 卡、设备、号卡、套餐、订单等 - 添加分佣系统表:分佣规则、分佣记录、运营商结算等 - 添加轮询和流量管理表:轮询配置、流量使用记录等 - 添加财务和系统管理表:佣金提现、换卡申请等 - 实现完整的 GORM 模型和常量定义 - 添加数据库迁移脚本和详细文档 - 集成 OpenSpec 工作流工具(opsx 命令和 skills) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
23 KiB
23 KiB
IoT SIM 管理 - 数据模型与数据库表结构实现任务
本任务清单聚焦于 IoT SIM 管理模块的数据模型定义和数据库表结构实现,不包含业务逻辑代码。
1. 数据库迁移脚本
1.1 核心业务表
- 1.1.1 创建迁移脚本文件:
migrations/YYYYMMDDHHMMSS_create_iot_sim_management_tables.up.sql和*.down.sql - 1.1.2 创建运营商表(carriers)及其索引
- 主键索引
carrier_code唯一索引- 初始数据:中国移动(CMCC)、中国联通(CUCC)、中国电信(CTCC)
- 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组合索引(实名轮询查询优化)
- 1.1.4 创建设备表(devices)及其索引
- 主键索引
device_no唯一索引owner_type+owner_id+status组合索引
- 1.1.5 创建号卡表(number_cards)及其索引
- 主键索引
virtual_product_code唯一索引agent_id+status组合索引
- 1.1.6 创建套餐系列表(package_series)及其索引
- 主键索引
series_code唯一索引
- 1.1.7 创建套餐表(packages)及其索引
- 主键索引
package_code唯一索引series_id+status组合索引
- 1.1.8 创建代理套餐分配表(agent_package_allocations)及其索引
- 主键索引
agent_id+package_id唯一组合索引
- 1.1.9 创建设备-IoT卡绑定关系表(device_sim_bindings)及其索引
- 主键索引
device_id+bind_status组合索引iot_card_id+bind_status组合索引iot_card_id部分唯一索引(WHERE bind_status = 1)
- 1.1.10 创建订单表(orders)及其索引
- 主键索引
order_no唯一索引user_id+status组合索引agent_id+status组合索引iot_card_id索引device_id索引number_card_id索引
1.2 套餐和轮询相关表
- 1.2.1 创建套餐使用情况表(package_usages)及其索引
- 主键索引
order_id索引package_id索引iot_card_id索引device_id索引status+expires_at+last_package_check_at组合索引(套餐流量检查优化)
- 1.2.2 创建轮询配置表(polling_configs)及其索引
- 主键索引
config_name唯一索引status+card_condition+carrier_id+priority组合索引(配置匹配优化)
- 1.2.3 创建流量使用记录表(data_usage_records)及其索引
- 主键索引
iot_card_id+check_time组合索引(按卡和时间查询)check_time索引(按时间范围查询)- 注意:此表数据量会快速增长,建议定期清理 90 天前的记录或使用分区表
1.3 分佣相关表
- 1.3.1 创建代理层级关系表(agent_hierarchies)及其索引
- 主键索引
agent_id唯一索引parent_agent_id索引
- 1.3.2 创建分佣规则表(commission_rules)及其索引
- 主键索引
agent_id+business_type+card_type组合索引
- 1.3.3 创建阶梯分佣配置表(commission_ladder)及其索引
- 主键索引
rule_id索引
- 1.3.4 创建组合分佣条件表(commission_combined_conditions)及其索引
- 主键索引
rule_id唯一索引
- 1.3.5 创建分佣记录表(commission_records)及其索引
- 主键索引
agent_id+status组合索引order_id索引rule_id索引
- 1.3.6 创建分佣审批表(commission_approvals)及其索引
- 主键索引
commission_record_id索引status索引
- 1.3.7 创建分佣模板表(commission_templates)及其索引
- 主键索引
template_name唯一索引
- 1.3.8 创建号卡运营商结算表(carrier_settlements)及其索引
- 主键索引
commission_record_id唯一索引agent_id+status组合索引
1.4 财务管理表
- 1.4.1 创建佣金提现申请表(commission_withdrawal_requests)及其索引
- 主键索引
agent_id+status组合索引created_at索引
- 1.4.2 创建佣金提现设置表(commission_withdrawal_settings)及其索引
- 主键索引
status索引
- 1.4.3 创建收款商户设置表(payment_merchant_settings)及其索引
- 主键索引
user_id+is_default组合索引merchant_type+status组合索引
1.5 系统管理表
- 1.5.1 创建开发能力配置表(dev_capability_configs)及其索引
- 主键索引
app_id唯一索引user_id+status组合索引
- 1.5.2 创建换卡申请表(card_replacement_requests)及其索引
- 主键索引
user_id+status组合索引old_iccid索引new_iccid索引
1.6 迁移脚本验证
- 1.6.1 编写迁移脚本的 down 部分(删除所有表)
- 1.6.2 在本地测试数据库执行 up 迁移
- 1.6.3 验证所有表和索引创建成功
- 1.6.4 执行 down 迁移验证回滚成功
- 1.6.5 编写迁移脚本的 README 说明(执行步骤、注意事项)
2. GORM 模型定义
2.1 目录结构
- 2.1.1 创建
internal/iot/model目录 - 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 核心业务模型
- 2.2.1 定义运营商(Carrier)模型
- 字段包括:id, carrier_code, carrier_name, description, status, created_at, updated_at
- 初始数据:中国移动(CMCC)、中国联通(CUCC)、中国电信(CTCC)
- 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 的情况下激活使用
- 所有字段必须显式指定
- 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
- 2.2.4 定义号卡(NumberCard)模型
- 字段包括:id, virtual_product_code, card_name, card_type, carrier, data_amount_mb, price, agent_id, status, created_at, updated_at
- 2.2.5 定义套餐系列(PackageSeries)模型
- 字段包括:id, series_code, series_name, description, status, created_at, updated_at
- 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
- 2.2.7 定义代理套餐分配(AgentPackageAllocation)模型
- 字段包括:id, agent_id, package_id, cost_price, retail_price, status, created_at, updated_at
- 2.2.8 定义设备-IoT卡绑定关系(DeviceSimBinding)模型
- 字段包括:id, device_id, iot_card_id, slot_number, bind_status, bound_at, unbound_at, created_at, updated_at
- 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 套餐和轮询相关模型
- 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为 NULLusage_type= "device" 时,device_id有值,iot_card_id为 NULLdata_usage_mb通过汇总卡的流量计算(单卡套餐直接读卡流量,设备级套餐汇总所有卡流量)
- 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数字越小优先级越高- 支持独立配置实名检查、卡流量检查、套餐流量检查
- 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 分佣相关模型
- 2.4.1 定义代理层级关系(AgentHierarchy)模型
- 字段包括:id, agent_id, parent_agent_id, agent_path, level, created_at, updated_at
- 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
- 2.4.3 定义阶梯分佣配置(CommissionLadder)模型
- 字段包括:id, rule_id, ladder_type, threshold_value, commission_mode, commission_value, created_at, updated_at
- 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
- 2.4.5 定义分佣记录(CommissionRecord)模型
- 字段包括:id, agent_id, order_id, rule_id, commission_type, amount, status, unfrozen_at, released_at, created_at, updated_at
- 2.4.6 定义分佣审批(CommissionApproval)模型
- 字段包括:id, commission_record_id, approver_id, status, reason, created_at, updated_at
- 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
- 2.4.8 定义号卡运营商结算(CarrierSettlement)模型
- 字段包括:id, commission_record_id, agent_id, settlement_month, settlement_amount, status, created_at, updated_at
2.5 财务管理模型
- 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
- 2.5.2 定义佣金提现设置(CommissionWithdrawalSetting)模型
- 字段包括:id, min_withdrawal_amount, max_withdrawal_amount, daily_withdrawal_limit, fee_rate, status, created_at, updated_at
- 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 系统管理模型
- 2.6.1 定义开发能力配置(DevCapabilityConfig)模型
- 字段包括:id, user_id, app_id, app_secret, callback_url, status, created_at, updated_at
- 2.6.2 定义换卡申请(CardReplacementRequest)模型
- 字段包括:id, user_id, old_iccid, new_iccid, reason, status, processed_by, processed_at, created_at, updated_at
3. 常量定义
3.1 核心业务常量
- 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 套餐和轮询相关常量
- 3.2.1 定义套餐使用类型常量:
- PackageUsageTypeSingleCard("single_card") - 单卡套餐
- PackageUsageTypeDevice("device") - 设备级套餐
- 3.2.2 定义套餐使用状态常量:
- PackageUsageStatusActive(1) - 生效中
- PackageUsageStatusExhausted(2) - 已用完
- PackageUsageStatusExpired(3) - 已过期
- 3.2.3 定义轮询配置卡条件常量:
- CardConditionNotRealName("not_real_name") - 未实名
- CardConditionRealName("real_name") - 已实名
- CardConditionActivated("activated") - 已激活
- CardConditionSuspended("suspended") - 已停用
- 3.2.4 定义流量使用记录来源常量:
- DataUsageSourcePolling("polling") - 轮询
- DataUsageSourceManual("manual") - 手动
- DataUsageSourceGateway("gateway") - Gateway 回调
3.3 分佣相关常量
- 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 财务管理常量
- 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 系统管理常量
- 3.5.1 定义系统管理常量:
- 换卡申请状态:ReplacementStatusPending(1), ReplacementStatusApproved(2), ReplacementStatusRejected(3), ReplacementStatusCompleted(4)
- 开发能力配置状态:DevCapabilityStatusEnabled(1), DevCapabilityStatusDisabled(2)
4. 模型和表结构文档
4.1 代码注释
- 4.1.1 为所有 GORM 模型添加中文结构体注释(描述表的业务用途)
- 4.1.2 为所有模型字段添加清晰的中文注释
- 4.1.3 为所有常量添加中文注释(说明枚举值含义)
- 4.1.4 在迁移脚本中为所有表和字段添加 SQL COMMENT
4.2 数据库设计文档
- 4.2.1 在
docs/iot-sim-management/目录下创建数据库设计.md - 4.2.2 使用 Markdown 表格描述所有表结构(字段名、类型、约束、说明)
- 4.2.3 使用 dbdiagram.io 或 draw.io 创建数据库 ERD 图
- 4.2.4 导出 ERD 图并保存到
docs/iot-sim-management/erd.png - 4.2.5 在
数据库设计.md中嵌入 ERD 图
4.3 模型使用说明
- 4.3.1 创建
docs/iot-sim-management/模型说明.md - 4.3.2 说明每个模型的用途和关键字段含义
- 4.3.3 说明表之间的关联关系(虽然没有外键,但逻辑关联需要说明)
- 4.3.4 说明关键枚举字段的取值和含义
- 4.3.5 说明特殊设计决策(如无外键约束、owner_type/owner_id 模式等)
4.4 轮询机制说明文档
- 4.4.1 创建
docs/iot-sim-management/轮询机制说明.md - 4.4.2 说明三个独立轮询流程:实名状态轮询、卡流量轮询、套餐流量检查
- 4.4.3 说明轮询配置的匹配规则和优先级
- 4.4.4 说明
enable_polling字段的使用场景 - 4.4.5 说明流量使用记录表的数据保留策略
4.5 项目文档更新
- 4.5.1 更新
README.md,添加 IoT SIM 管理模块描述 - 4.5.2 在 README 中添加数据库设计文档链接
- 4.5.3 在 README 中添加模型说明文档链接
- 4.5.4 在 README 中添加轮询机制说明文档链接
5. 数据迁移验证
5.1 本地验证
- 5.1.1 在本地 PostgreSQL 测试数据库执行迁移脚本 up
- 5.1.2 使用
\dt和\d table_name验证所有表创建成功 - 5.1.3 验证所有字段类型、默认值、NOT NULL 约束正确
- 5.1.4 使用
\di验证所有索引创建成功 - 5.1.5 验证唯一索引和组合索引的正确性
5.2 数据完整性验证
- 5.2.1 插入测试数据验证唯一索引生效(尝试插入重复 ICCID 应失败)
- 5.2.2 插入测试数据验证 NOT NULL 约束生效
- 5.2.3 插入测试数据验证 CHECK 约束生效(如金额 >= 0)
- 5.2.4 查询测试数据验证组合索引生效(使用 EXPLAIN ANALYZE)
- 5.2.5 验证运营商初始数据插入成功
5.3 回滚验证
- 5.3.1 执行迁移脚本 down
- 5.3.2 验证所有表和索引删除成功
- 5.3.3 重新执行 up 验证迁移脚本可重复执行
6. 代码质量检查
6.1 代码格式化
- 6.1.1 使用
go fmt格式化所有模型代码 - 6.1.2 使用
goimports整理导入语句 - 6.1.3 使用
golangci-lint检查代码质量
6.2 命名规范检查
- 6.2.1 验证所有 Go 字段名遵循驼峰命名法(PascalCase)
- 6.2.2 验证所有数据库字段名遵循下划线命名法(snake_case)
- 6.2.3 验证所有常量命名遵循 Go 规范(如 IotCardStatusInStock)
- 6.2.4 验证所有模型文件名遵循 Go 规范(snake_case,如 iot_card.go)
6.3 GORM 标签检查
- 6.3.1 验证所有字段都有
gorm:"column:字段名"标签 - 6.3.2 验证所有字段都有
json:"字段名"标签 - 6.3.3 验证所有字段的
comment标签包含中文说明 - 6.3.4 验证字符串字段的
type标签指定了长度(如type:varchar(100)) - 6.3.5 验证数值字段的
type标签指定了精度(如type:decimal(10,2))
完成标准
本阶段任务完成后,应该具备:
- ✅ 完整的数据库迁移脚本(up 和 down)
- ✅ 完整的 GORM 模型定义(所有表对应的 Go 结构体)
- ✅ 完整的常量定义(所有枚举值)
- ✅ 完整的数据库设计文档(ERD 图 + 表结构说明)
- ✅ 完整的模型使用说明文档
- ✅ 完整的轮询机制说明文档
- ✅ 数据库迁移在本地测试通过
- ✅ 所有代码遵循项目开发规范(命名、注释、格式)
不包含:业务逻辑实现、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 天前的记录或使用分区表
轮询逻辑(概念说明)
- 卡流量轮询:只轮询有生效套餐的卡,
enable_polling = true - 套餐流量检查:定期汇总卡的流量,判断套餐是否超额
- 实名状态轮询:定期检查卡的实名状态,实名后降低轮询频率
- 行业卡特殊处理: 行业卡的实名状态检查应该被禁用或设置为低优先级
- 三个流程独立运行:互不干扰,通过轮询配置表动态控制
分佣解冻逻辑(概念说明)
- 一次性分佣: 普通卡需要实名认证后才能解冻;行业卡无需实名认证,只需满足激活和充值条件
- 长期分佣: 普通卡需要实名认证后才能开始长期分佣;行业卡无需实名认证,满足其他条件即可
- 组合分佣: 行业卡的时间点条件从激活时开始计算(不是实名时)