新增钱包、换卡、标签系统的数据模型和规范

本次提交完成 add-wallet-transfer-tag-models 提案的实施和归档:

## 新增功能模块
- 钱包系统:用户/代理钱包管理,支持充值、扣款、退款、乐观锁防并发
- 换卡记录:物联卡更换历史追溯,包含套餐快照(JSONB)
- 标签系统:设备/IoT卡/号卡的统一标签管理
- 运营商渠道:四大运营商(CMCC/CUCC/CTCC/CBN)的渠道管理

## 数据库变更
- 新增 6 张表:tb_wallet, tb_wallet_transaction, tb_recharge_record, tb_card_replacement_record, tb_tag, tb_resource_tag
- 修改 2 张表:tb_carrier(新增渠道字段), tb_order(新增混合支付字段)
- 迁移版本:v6 → v7(执行时间 282.5ms)

## 代码变更
- 新增 8 个 Go 模型(符合统一规范:gorm.Model + BaseModel)
- 新增 40+ 个常量定义(含完整中文注释)
- 新增 7 个 Redis Key 生成函数
- 修复模型规范:移除重复字段,统一使用 gorm.Model 嵌入

## 文档变更
- 新增 3 个业务文档:数据模型设计、字段说明、迁移验证报告
- 更新 AGENTS.md:新增 Model 模型规范和常量注释规范
- 新增 4 个 OpenSpec 规范:wallet, carrier, card-replacement, tag
- 更新 1 个 OpenSpec 规范:iot-order(支持混合支付)

## 验证通过
-  LSP 诊断:所有模型和常量文件无错误
-  OpenSpec 验证:openspec validate --strict 通过
-  迁移执行:表结构创建成功,索引正确
-  提案归档:2026-01-13-add-wallet-transfer-tag-models

变更文件统计:29 个文件,新增 3682 行
This commit is contained in:
2026-01-13 15:47:32 +08:00
parent 2150fb6ab9
commit 6e2dc325d7
29 changed files with 3682 additions and 87 deletions

97
internal/model/wallet.go Normal file
View File

@@ -0,0 +1,97 @@
package model
import (
"database/sql/driver"
"encoding/json"
"time"
"gorm.io/gorm"
)
// Wallet 钱包模型
// 用户和代理的资金账户,支持充值、消费、提现等操作
// 使用乐观锁version字段防止并发余额冲突
type Wallet struct {
gorm.Model
BaseModel `gorm:"embedded"`
UserID uint `gorm:"column:user_id;not null;index:idx_wallet_user,priority:1;comment:用户ID" json:"user_id"`
WalletType string `gorm:"column:wallet_type;type:varchar(20);not null;uniqueIndex:idx_wallet_user_type_currency,priority:2;comment:钱包类型 user-用户钱包 agent-代理钱包" json:"wallet_type"`
Balance int64 `gorm:"column:balance;type:bigint;not null;default:0;comment:余额(分)" json:"balance"`
FrozenBalance int64 `gorm:"column:frozen_balance;type:bigint;not null;default:0;comment:冻结余额(分)" json:"frozen_balance"`
Currency string `gorm:"column:currency;type:varchar(10);not null;default:'CNY';uniqueIndex:idx_wallet_user_type_currency,priority:3;comment:币种" json:"currency"`
Status int `gorm:"column:status;type:int;not null;default:1;index:idx_wallet_status;comment:钱包状态 1-正常 2-冻结 3-关闭" json:"status"`
Version int `gorm:"column:version;type:int;not null;default:0;comment:版本号(乐观锁)" json:"version"`
}
// TableName 指定表名
func (Wallet) TableName() string {
return "tb_wallet"
}
// WalletMetadata 钱包交易扩展信息
// 用于存储交易相关的额外数据JSONB格式
type WalletMetadata map[string]interface{}
// Value 实现 driver.Valuer 接口
func (m WalletMetadata) Value() (driver.Value, error) {
return json.Marshal(m)
}
// Scan 实现 sql.Scanner 接口
func (m *WalletMetadata) Scan(value interface{}) error {
if value == nil {
*m = make(WalletMetadata)
return nil
}
bytes, ok := value.([]byte)
if !ok {
return nil
}
return json.Unmarshal(bytes, m)
}
// WalletTransaction 钱包交易记录模型
// 记录所有钱包余额变动,包含变动前后余额用于对账
// 支持关联业务对象(订单、分佣、提现等)
type WalletTransaction struct {
gorm.Model
WalletID uint `gorm:"column:wallet_id;not null;index:idx_wallet_tx_wallet;comment:钱包ID" json:"wallet_id"`
UserID uint `gorm:"column:user_id;not null;index:idx_wallet_tx_user;comment:用户ID" json:"user_id"`
TransactionType string `gorm:"column:transaction_type;type:varchar(20);not null;comment:交易类型 recharge-充值 deduct-扣款 refund-退款 commission-分佣 withdrawal-提现" json:"transaction_type"`
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:变动金额(分)正数为增加 负数为减少" json:"amount"`
BalanceBefore int64 `gorm:"column:balance_before;type:bigint;not null;comment:变动前余额(分)" json:"balance_before"`
BalanceAfter int64 `gorm:"column:balance_after;type:bigint;not null;comment:变动后余额(分)" json:"balance_after"`
Status int `gorm:"column:status;type:int;not null;default:1;comment:交易状态 1-成功 2-失败 3-处理中" json:"status"`
ReferenceType *string `gorm:"column:reference_type;type:varchar(50);index:idx_wallet_tx_ref,priority:1;comment:关联业务类型 order/commission/withdrawal/topup" json:"reference_type,omitempty"`
ReferenceID *uint `gorm:"column:reference_id;type:bigint;index:idx_wallet_tx_ref,priority:2;comment:关联业务ID" json:"reference_id,omitempty"`
Remark *string `gorm:"column:remark;type:text;comment:备注" json:"remark,omitempty"`
Metadata WalletMetadata `gorm:"column:metadata;type:jsonb;comment:扩展信息" json:"metadata,omitempty"`
Creator uint `gorm:"column:creator;comment:创建人ID" json:"creator"`
}
// TableName 指定表名
func (WalletTransaction) TableName() string {
return "tb_wallet_transaction"
}
// RechargeRecord 充值记录模型
// 用户和代理的钱包充值订单,记录支付流程和状态
type RechargeRecord struct {
gorm.Model
BaseModel `gorm:"embedded"`
UserID uint `gorm:"column:user_id;not null;index:idx_recharge_user;comment:用户ID" json:"user_id"`
WalletID uint `gorm:"column:wallet_id;not null;comment:钱包ID" json:"wallet_id"`
RechargeNo string `gorm:"column:recharge_no;type:varchar(50);not null;uniqueIndex:idx_recharge_no;comment:充值订单号" json:"recharge_no"`
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:充值金额(分)" json:"amount"`
PaymentMethod string `gorm:"column:payment_method;type:varchar(20);not null;comment:支付方式 alipay-支付宝 wechat-微信 bank-银行转账 offline-线下" json:"payment_method"`
PaymentChannel *string `gorm:"column:payment_channel;type:varchar(50);comment:支付渠道" json:"payment_channel,omitempty"`
PaymentTransactionID *string `gorm:"column:payment_transaction_id;type:varchar(100);comment:第三方支付交易号" json:"payment_transaction_id,omitempty"`
Status int `gorm:"column:status;type:int;not null;default:1;index:idx_recharge_status;comment:充值状态 1-待支付 2-已支付 3-已完成 4-已关闭 5-已退款" json:"status"`
PaidAt *time.Time `gorm:"column:paid_at;comment:支付时间" json:"paid_at,omitempty"`
CompletedAt *time.Time `gorm:"column:completed_at;comment:完成时间" json:"completed_at,omitempty"`
}
// TableName 指定表名
func (RechargeRecord) TableName() string {
return "tb_recharge_record"
}