- 完善 GORM 模型规范:货币字段使用 int64(分为单位)、JSONB 字段规范、模型结构规范 - 修复所有 IoT 模型的架构违规问题 - 更新 CLAUDE.md 开发指南,补充完整的数据库设计规范和模型示例 - 添加数据库迁移脚本(000006)用于架构重构 - 归档 OpenSpec 变更文档(2026-01-12-fix-iot-models-violations) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
21 KiB
Tasks
本文档列出修复 IoT 模型架构违规所需的所有任务,按优先级和依赖关系排序。
阶段 1: 核心业务实体模型修复(必须优先完成)
Task 1.1: 修复 IoT 卡模型 (IotCard)
文件: internal/model/iot_card.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
CostPrice、DistributePrice)从float64改为int64,数据库类型从decimal(10,2)改为bigint - 表名从
iot_cards改为tb_iot_card ICCID唯一索引添加where:deleted_at IS NULL- 所有关联 ID 字段(
CarrierID、OwnerID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过 - 使用
gofmt格式化代码 - 与
Account模型对比,确保风格一致
Task 1.2: 修复设备模型 (Device)
文件: internal/model/device.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
devices改为tb_device DeviceNo唯一索引添加where:deleted_at IS NULL- 所有关联 ID 字段(
OwnerID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过 - 使用
gofmt格式化代码
Task 1.3: 修复号卡模型 (NumberCard)
文件: internal/model/number_card.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
Price)从float64改为int64,数据库类型从decimal(10,2)改为bigint - 表名从
number_cards改为tb_number_card VirtualProductCode唯一索引添加where:deleted_at IS NULL- 关联 ID 字段(
AgentID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过 - 使用
gofmt格式化代码
Task 1.4: 修复运营商模型 (Carrier)
文件: internal/model/carrier.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
carriers改为tb_carrier CarrierCode唯一索引添加where:deleted_at IS NULL- 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过 - 使用
gofmt格式化代码
阶段 2: 套餐和订单模型修复
Task 2.1: 修复套餐系列模型 (PackageSeries)
文件: internal/model/package.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
package_series改为tb_package_series SeriesCode唯一索引添加where:deleted_at IS NULL- 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 2.2: 修复套餐模型 (Package)
文件: internal/model/package.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
Price)从float64改为int64,数据库类型从decimal(10,2)改为bigint - 表名从
packages改为tb_package PackageCode唯一索引添加where:deleted_at IS NULL- 关联 ID 字段(
SeriesID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 2.3: 修复代理套餐分配模型 (AgentPackageAllocation)
文件: internal/model/package.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
CostPrice、RetailPrice)从float64改为int64 - 表名从
agent_package_allocations改为tb_agent_package_allocation - 关联 ID 字段(
AgentID、PackageID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 2.4: 修复套餐使用情况模型 (PackageUsage)
文件: internal/model/package.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
package_usages改为tb_package_usage - 关联 ID 字段(
OrderID、PackageID、IotCardID、DeviceID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 2.5: 修复设备-SIM 卡绑定模型 (DeviceSimBinding)
文件: internal/model/package.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
device_sim_bindings改为tb_device_sim_binding - 添加复合索引:
DeviceID和SlotPosition使用index:idx_device_slot - 关联 ID 字段(
IotCardID)添加独立index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 2.6: 修复订单模型 (Order)
文件: internal/model/order.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
Amount)从float64改为int64 CarrierOrderData从pq.StringArray改为datatypes.JSON,添加import "gorm.io/datatypes"- 表名从
orders改为tb_order OrderNo唯一索引添加where:deleted_at IS NULL- 关联 ID 字段(
IotCardID、DeviceID、NumberCardID、PackageID、UserID、AgentID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过 - 检查
datatypes.JSON导入是否正确
阶段 3: 分佣系统模型修复
Task 3.1: 修复代理层级模型 (AgentHierarchy)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
agent_hierarchies改为tb_agent_hierarchy AgentID唯一索引添加where:deleted_at IS NULL- 关联 ID 字段(
ParentAgentID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 3.2: 修复分佣规则模型 (CommissionRule)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
CommissionValue)从float64改为int64 - 表名从
commission_rules改为tb_commission_rule - 关联 ID 字段(
AgentID、SeriesID、PackageID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 3.3: 修复阶梯分佣配置模型 (CommissionLadder)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
CommissionValue)从float64改为int64 - 表名从
commission_ladder改为tb_commission_ladder - 关联 ID 字段(
RuleID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 3.4: 修复组合分佣条件模型 (CommissionCombinedCondition)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
OneTimeCommissionValue、LongTermCommissionValue)从float64改为int64 - 表名从
commission_combined_conditions改为tb_commission_combined_condition RuleID唯一索引添加where:deleted_at IS NULL- 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 3.5: 修复分佣记录模型 (CommissionRecord)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
Amount)从float64改为int64 - 表名从
commission_records改为tb_commission_record - 关联 ID 字段(
AgentID、OrderID、RuleID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 3.6: 修复分佣审批模型 (CommissionApproval)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
commission_approvals改为tb_commission_approval - 关联 ID 字段(
CommissionRecordID、ApproverID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 3.7: 修复分佣模板模型 (CommissionTemplate)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
CommissionValue)从float64改为int64 - 表名从
commission_templates改为tb_commission_template TemplateName唯一索引添加where:deleted_at IS NULL- 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 3.8: 修复运营商结算模型 (CarrierSettlement)
文件: internal/model/commission.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
SettlementAmount)从float64改为int64,数据库类型从decimal(18,2)改为bigint - 表名从
carrier_settlements改为tb_carrier_settlement CommissionRecordID唯一索引添加where:deleted_at IS NULL- 关联 ID 字段(
AgentID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
阶段 4: 财务和系统模型修复
Task 4.1: 修复佣金提现申请模型 (CommissionWithdrawalRequest)
文件: internal/model/financial.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
Amount、Fee、ActualAmount)从float64改为int64,数据库类型从decimal(18,2)改为bigint AccountInfo从pq.StringArray改为datatypes.JSON- 表名从
commission_withdrawal_requests改为tb_commission_withdrawal_request - 关联 ID 字段(
AgentID、ApprovedBy)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过 - 检查
datatypes.JSON导入是否正确
Task 4.2: 修复佣金提现设置模型 (CommissionWithdrawalSetting)
文件: internal/model/financial.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 金额字段(
MinWithdrawalAmount)从float64改为int64,数据库类型从decimal(10,2)改为bigint - 表名从
commission_withdrawal_settings改为tb_commission_withdrawal_setting - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 4.3: 修复收款商户设置模型 (PaymentMerchantSetting)
文件: internal/model/financial.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
payment_merchant_settings改为tb_payment_merchant_setting - 关联 ID 字段(
UserID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 4.4: 修复开发能力配置模型 (DevCapabilityConfig)
文件: internal/model/system.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
dev_capability_configs改为tb_dev_capability_config AppID唯一索引添加where:deleted_at IS NULL- 关联 ID 字段(
UserID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 4.5: 修复换卡申请模型 (CardReplacementRequest)
文件: internal/model/system.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
card_replacement_requests改为tb_card_replacement_request - 关联 ID 字段(
UserID、ApprovedBy)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 4.6: 修复轮询配置模型 (PollingConfig)
文件: internal/model/polling.go
修改内容:
- 嵌入
gorm.Model和BaseModel - 移除手动定义的
ID、CreatedAt、UpdatedAt字段 - 所有字段显式指定
column标签 - 表名从
polling_configs改为tb_polling_config ConfigName唯一索引添加where:deleted_at IS NULL- 关联 ID 字段(
CarrierID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过
Task 4.7: 修复流量使用记录模型 (DataUsageRecord)
文件: internal/model/data_usage.go
修改内容:
- 不嵌入
gorm.Model(简化模型,只包含 ID 和 CreatedAt) - 不嵌入
BaseModel(日志表不需要审计) - 保留
ID、CreatedAt字段,移除UpdatedAt - 所有字段显式指定
column标签 - 表名从
data_usage_records改为tb_data_usage_record - 关联 ID 字段(
IotCardID)添加index标签 - 完善所有字段的中文注释
验证方法:
- 运行
go build确保编译通过 - 确认模型不包含
UpdatedAt和DeletedAt
阶段 5: 验证和测试
Task 5.1: 编译验证
内容:
- 运行
go build ./...确保所有模型文件编译通过 - 运行
gofmt -w internal/model/格式化所有模型文件 - 运行
go vet ./internal/model/静态分析检查
依赖: 所有模型修复任务完成
验证方法:
- 无编译错误
- 无静态分析警告
Task 5.2: 模型定义一致性检查
内容:
- 手动检查所有模型是否遵循规范(参考验证清单)
- 对比
Account模型,确保风格一致 - 检查所有金额字段是否使用
int64类型 - 检查所有表名是否使用
tb_前缀 + 单数 - 检查所有唯一索引是否包含
where:deleted_at IS NULL
依赖: Task 5.1
验证方法:
- 完成验证清单(设计文档第 8 节)
Task 5.3: 生成数据库迁移脚本(可选)
内容:
- 如果 IoT 模块尚未创建迁移脚本,跳过此任务
- 如果已有迁移脚本,生成新的迁移脚本或修改现有脚本
- 包含表重命名、字段修改、索引创建等 SQL 语句
依赖: Task 5.2
验证方法:
- 在开发环境测试迁移脚本
- 确认所有表和字段正确创建
Task 5.4: 文档更新
内容:
- 更新 IoT SIM 管理提案(
openspec/changes/archive/2026-01-12-iot-sim-management/)的模型定义部分(可选) - 在
docs/目录创建模型修复总结文档(可选) - 更新
README.md添加模型规范说明(可选)
依赖: Task 5.2
验证方法:
- 文档清晰易懂,准确反映当前实现
Task 5.5: 更新全局规范文档
内容:
- 更新
CLAUDE.md中的数据库设计原则和模型规范部分 - 确保 CLAUDE.md 中的示例代码与修复后的模型风格完全一致
- 如果需要,更新
openspec/AGENTS.md(如果其中包含模型相关指导) - 添加或完善以下规范内容:
- GORM 模型字段规范(显式 column 标签、类型定义、注释要求)
- 金额字段使用整数类型(分为单位)的详细说明和示例
- 表名命名规范(
tb_前缀 + 单数) - BaseModel 嵌入和审计字段使用说明
- 唯一索引软删除兼容性(
where:deleted_at IS NULL) - JSONB 字段使用
datatypes.JSON类型的说明
具体修改位置(CLAUDE.md):
-
数据库设计原则 部分:
- 补充完整的 GORM 模型字段定义规范
- 添加金额字段整数存储的要求和理由
- 添加字段标签完整性要求(显式 column、type、comment)
-
GORM 模型字段规范 新增小节:
**GORM 模型字段规范:** - 数据库字段名必须使用下划线命名法(snake_case),如 `user_id`、`email_address`、`created_at` - Go 结构体字段名必须使用驼峰命名法(PascalCase),如 `UserID`、`EmailAddress`、`CreatedAt` - **所有字段必须显式指定数据库列名**:使用 `gorm:"column:字段名"` 标签明确指定数据库字段名,不依赖 GORM 的自动转换 - 示例:`UserID uint gorm:"column:user_id;not null" json:"user_id"` - 禁止省略 `column:` 标签,即使 GORM 能自动推断字段名 - 这确保了 Go 字段名和数据库字段名的映射关系清晰可见,避免命名歧义 - 字符串字段长度必须明确定义且保持一致性: - 短文本(名称、标题等):`VARCHAR(255)` 或 `VARCHAR(100)` - 中等文本(描述、备注等):`VARCHAR(500)` 或 `VARCHAR(1000)` - 长文本(内容、详情等):`TEXT` 类型 - 货币金额字段必须使用 `int64` 类型,数据库类型为 `bigint`,单位为"分"(1元 = 100分) - 所有字段必须添加中文注释,说明字段用途和业务含义 -
示例代码更新:
- 将现有的模型示例(如果有)更新为包含完整字段标签的版本
依赖: Task 5.2
验证方法:
- CLAUDE.md 中的规范描述与实际实现的模型完全一致
- 所有示例代码可以直接复制使用,无需修改
- 规范描述清晰、完整、无歧义
- 运行
git diff CLAUDE.md检查修改内容
依赖关系图
阶段 1 (核心模型)
├─ Task 1.1: IotCard
├─ Task 1.2: Device
├─ Task 1.3: NumberCard
└─ Task 1.4: Carrier
↓
阶段 2 (套餐和订单)
├─ Task 2.1: PackageSeries
├─ Task 2.2: Package (依赖 Task 2.1)
├─ Task 2.3: AgentPackageAllocation (依赖 Task 2.2)
├─ Task 2.4: PackageUsage (依赖 Task 2.2)
├─ Task 2.5: DeviceSimBinding (依赖 Task 1.1, Task 1.2)
└─ Task 2.6: Order (依赖 Task 1.1, Task 1.2, Task 1.3, Task 2.2)
↓
阶段 3 (分佣系统)
├─ Task 3.1: AgentHierarchy
├─ Task 3.2: CommissionRule
├─ Task 3.3: CommissionLadder (依赖 Task 3.2)
├─ Task 3.4: CommissionCombinedCondition (依赖 Task 3.2)
├─ Task 3.5: CommissionRecord (依赖 Task 3.2)
├─ Task 3.6: CommissionApproval (依赖 Task 3.5)
├─ Task 3.7: CommissionTemplate
└─ Task 3.8: CarrierSettlement (依赖 Task 3.5)
↓
阶段 4 (财务和系统)
├─ Task 4.1: CommissionWithdrawalRequest
├─ Task 4.2: CommissionWithdrawalSetting
├─ Task 4.3: PaymentMerchantSetting
├─ Task 4.4: DevCapabilityConfig
├─ Task 4.5: CardReplacementRequest
├─ Task 4.6: PollingConfig
└─ Task 4.7: DataUsageRecord (依赖 Task 1.1)
↓
阶段 5 (验证和测试)
├─ Task 5.1: 编译验证
├─ Task 5.2: 一致性检查 (依赖 Task 5.1)
├─ Task 5.3: 生成迁移脚本 (依赖 Task 5.2, 可选)
├─ Task 5.4: 文档更新 (依赖 Task 5.2, 可选)
└─ Task 5.5: 更新全局规范文档 (依赖 Task 5.2, 必需)
估算工作量
- 阶段 1: 约 2-3 小时(4 个核心模型)
- 阶段 2: 约 3-4 小时(6 个套餐和订单模型)
- 阶段 3: 约 4-5 小时(8 个分佣系统模型)
- 阶段 4: 约 3-4 小时(7 个财务和系统模型)
- 阶段 5: 约 2-3 小时(验证、测试和全局规范文档更新)
总计: 约 14-19 小时(~2-3 个工作日)
注意事项
- 并行执行: 阶段内的任务可以并行执行(除非明确依赖)
- 增量提交: 建议每完成一个阶段提交一次 Git commit
- 回归测试: 修复完成后需要运行完整的单元测试套件(如有)
- 代码审查: 修复完成后需要进行 Code Review,确保符合项目规范