Files
junhong_cmp_fiber/openspec/changes/archive/2026-02-25-separate-agent-card-wallets/tasks.md
huang 18daeae65a
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m17s
feat: 钱包系统分离 - 代理钱包与卡钱包完全隔离
## 变更概述
将统一钱包系统拆分为代理钱包和卡钱包两个独立系统,实现数据表和代码层面的完全隔离。

## 数据库变更
- 新增 6 张表:tb_agent_wallet、tb_agent_wallet_transaction、tb_agent_recharge_record、tb_card_wallet、tb_card_wallet_transaction、tb_card_recharge_record
- 删除 3 张旧表:tb_wallet、tb_wallet_transaction、tb_recharge_record
- 代理钱包:按 (shop_id, wallet_type) 唯一标识,支持主钱包和分佣钱包
- 卡钱包:按 (resource_type, resource_id) 唯一标识,支持物联网卡和设备

## 代码变更
- Model 层:新增 AgentWallet、AgentWalletTransaction、AgentRechargeRecord、CardWallet、CardWalletTransaction、CardRechargeRecord 模型
- Store 层:新增 6 个独立 Store,支持事务、乐观锁、Redis 缓存
- Service 层:重构 commission_calculation、commission_withdrawal、order、recharge 等 8 个服务
- Bootstrap 层:更新 Store 和 Service 依赖注入
- 常量层:按钱包类型重新组织常量和 Redis Key 生成函数

## 技术特性
- 乐观锁:使用 version 字段防止并发冲突
- 多租户:支持 shop_id_tag 和 enterprise_id_tag 过滤
- 事务管理:所有余额变动使用事务保证 ACID
- 缓存策略:Cache-Aside 模式,余额变动后删除缓存

## 业务影响
- 代理钱包和卡钱包业务完全隔离,互不影响
- 为独立监控、优化、扩展打下基础
- 提升代理钱包的稳定性和独立性

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-25 09:51:00 +08:00

17 KiB
Raw Blame History

钱包系统分离 - 实施任务清单

1. 数据库迁移 - 创建新表结构

  • 1.1 创建代理钱包主表迁移文件(tb_agent_wallet),包含 shop_id、wallet_type、balance、frozen_balance、version 等字段,添加唯一索引和多租户索引
  • 1.2 创建代理钱包交易记录表迁移文件(tb_agent_wallet_transaction),包含 agent_wallet_id、shop_id、transaction_type、amount、balance_before、balance_after 等字段,添加 4 个查询索引
  • 1.3 创建代理充值记录表迁移文件(tb_agent_recharge_record),包含 recharge_no、amount、payment_method、status 等字段,添加状态和店铺索引
  • 1.4 创建卡钱包主表迁移文件(tb_card_wallet),包含 resource_type、resource_id、balance、frozen_balance、version 等字段,添加唯一索引和多租户索引
  • 1.5 创建卡钱包交易记录表迁移文件(tb_card_wallet_transaction),包含 card_wallet_id、resource_type、resource_id、transaction_type、amount 等字段,添加 4 个查询索引
  • 1.6 创建卡充值记录表迁移文件(tb_card_recharge_record),包含 recharge_no、amount、payment_method、status 等字段,添加状态和资源索引
  • 1.7 执行数据库迁移,验证 6 张新表创建成功,检查索引和约束

2. 代理钱包系统 - Model 层实现

  • 2.1 创建 internal/model/agent_wallet.go,定义 AgentWallet 结构体,包含 ShopID、WalletType、Balance、FrozenBalance、Version、BaseModel 等字段
  • 2.2 在 agent_wallet.go 中定义 AgentWalletTransaction 结构体,包含 AgentWalletID、ShopID、TransactionType、Amount、BalanceBefore、BalanceAfter 等字段
  • 2.3 在 agent_wallet.go 中定义 AgentRechargeRecord 结构体,包含 UserID、AgentWalletID、ShopID、RechargeNo、Amount、PaymentMethod、Status 等字段
  • 2.4 为所有 Model 实现 TableName() 方法返回对应的表名tb_agent_wallet、tb_agent_wallet_transaction、tb_agent_recharge_record
  • 2.5 添加中文注释说明每个字段的用途和约束
  • 2.6 编译验证 Model 定义正确,无语法错误

3. 代理钱包系统 - Store 层实现

  • 3.1 创建 internal/store/postgres/agent_wallet_store.go,定义 AgentWalletStore 结构体,包含 db 和 redis 字段
  • 3.2 实现 NewAgentWalletStore 构造函数
  • 3.3 实现 GetCommissionWallet(ctx, shopID) 方法,查询店铺的分佣钱包
  • 3.4 实现 GetMainWallet(ctx, shopID) 方法,查询店铺的主钱包
  • 3.5 实现 GetByShopIDAndType(ctx, shopID, walletType) 方法,根据店铺 ID 和钱包类型查询
  • 3.6 实现 GetByID(ctx, id) 方法,根据钱包 ID 查询
  • 3.7 实现 DeductFrozenBalanceWithTx(ctx, tx, walletID, amount) 方法,从冻结余额扣款(带事务)
  • 3.8 实现 UnfreezeBalanceWithTx(ctx, tx, walletID, amount) 方法,解冻余额到可用余额(带事务)
  • 3.9 实现 FreezeBalanceWithTx(ctx, tx, walletID, amount, version) 方法,冻结余额(带事务,使用乐观锁)
  • 3.10 实现 GetShopCommissionSummaryBatch(ctx, shopIDs) 方法,批量获取店铺佣金钱包汇总
  • 3.11 创建 internal/store/postgres/agent_wallet_transaction_store.go,定义 AgentWalletTransactionStore 结构体
  • 3.12 实现 CreateWithTx(ctx, tx, transaction) 方法,创建代理钱包交易记录(带事务)
  • 3.13 实现 ListByShopID(ctx, shopID, offset, limit) 方法,按店铺查询交易记录(支持分页)
  • 3.14 创建 internal/store/postgres/agent_recharge_store.go,定义 AgentRechargeStore 结构体
  • 3.15 实现充值记录的 CRUD 方法Create、GetByRechargeNo、UpdateStatus 等)
  • 3.16 编译验证 Store 层代码正确,无语法错误

4. 卡钱包系统 - Model 层实现

  • 4.1 创建 internal/model/card_wallet.go,定义 CardWallet 结构体,包含 ResourceType、ResourceID、Balance、FrozenBalance、Version、BaseModel 等字段
  • 4.2 在 card_wallet.go 中定义 CardWalletTransaction 结构体,包含 CardWalletID、ResourceType、ResourceID、TransactionType、Amount、BalanceBefore、BalanceAfter 等字段
  • 4.3 在 card_wallet.go 中定义 CardRechargeRecord 结构体,包含 UserID、CardWalletID、ResourceType、ResourceID、RechargeNo、Amount、PaymentMethod、Status 等字段
  • 4.4 为所有 Model 实现 TableName() 方法返回对应的表名tb_card_wallet、tb_card_wallet_transaction、tb_card_recharge_record
  • 4.5 添加中文注释说明每个字段的用途和约束
  • 4.6 编译验证 Model 定义正确,无语法错误

5. 卡钱包系统 - Store 层实现

  • 5.1 创建 internal/store/postgres/card_wallet_store.go,定义 CardWalletStore 结构体,包含 db 和 redis 字段
  • 5.2 实现 NewCardWalletStore 构造函数
  • 5.3 实现 GetByResourceTypeAndID(ctx, resourceType, resourceID) 方法,根据资源类型和 ID 查询钱包
  • 5.4 实现 GetByID(ctx, id) 方法,根据钱包 ID 查询
  • 5.5 实现 DeductBalanceWithTx(ctx, tx, walletID, amount, version) 方法,扣款(带事务,使用乐观锁)
  • 5.6 实现 AddBalanceWithTx(ctx, tx, walletID, amount) 方法,增加余额(带事务)
  • 5.7 创建 internal/store/postgres/card_wallet_transaction_store.go,定义 CardWalletTransactionStore 结构体
  • 5.8 实现 CreateWithTx(ctx, tx, transaction) 方法,创建卡钱包交易记录(带事务)
  • 5.9 实现 ListByResourceID(ctx, resourceType, resourceID, offset, limit) 方法,按资源查询交易记录(支持分页)
  • 5.10 创建 internal/store/postgres/card_recharge_store.go,定义 CardRechargeStore 结构体
  • 5.11 实现充值记录的 CRUD 方法Create、GetByRechargeNo、UpdateStatus 等)
  • 5.12 编译验证 Store 层代码正确,无语法错误

6. 常量定义更新

  • 6.1 更新 pkg/constants/wallet.go,按钱包类型重新组织常量定义
  • 6.2 添加代理钱包专用常量AgentRechargeOrderPrefix、AgentRechargeMinAmount、AgentRechargeMaxAmount
  • 6.3 添加卡钱包专用常量CardWalletResourceTypeIotCard、CardWalletResourceTypeDevice、CardRechargeOrderPrefix、CardRechargeMinAmount、CardRechargeMaxAmount
  • 6.4 定义 Redis Key 生成函数:RedisAgentWalletBalanceKey(shopID, walletType)
  • 6.5 定义 Redis Key 生成函数:RedisAgentWalletLockKey(shopID, walletType)
  • 6.6 定义 Redis Key 生成函数:RedisCardWalletBalanceKey(resourceType, resourceID)
  • 6.7 定义 Redis Key 生成函数:RedisCardWalletLockKey(resourceType, resourceID)
  • 6.8 为所有常量和函数添加中文注释
  • 6.9 编译验证常量定义正确,无语法错误

7. Bootstrap 层 - 注册新 Store

  • 7.1 在 internal/bootstrap/stores.go 中添加 AgentWalletStore 字段到 Stores 结构体
  • 7.2 在 internal/bootstrap/stores.go 中添加 AgentWalletTransactionStore 字段到 Stores 结构体
  • 7.3 在 internal/bootstrap/stores.go 中添加 AgentRechargeStore 字段到 Stores 结构体
  • 7.4 在 internal/bootstrap/stores.go 中添加 CardWalletStore 字段到 Stores 结构体
  • 7.5 在 internal/bootstrap/stores.go 中添加 CardWalletTransactionStore 字段到 Stores 结构体
  • 7.6 在 internal/bootstrap/stores.go 中添加 CardRechargeStore 字段到 Stores 结构体
  • 7.7 在 NewStores() 函数中初始化所有新 Store 实例(调用 NewXxxStore 构造函数)
  • 7.8 编译验证 Bootstrap 层代码正确,无语法错误

8. Service 层重构 - 佣金相关服务

  • 8.1 更新 internal/service/commission_calculation/service.go,将 WalletStore 依赖改为 AgentWalletStore
  • 8.2 更新 internal/service/commission_calculation/service.go 中所有调用钱包的方法,使用新的 AgentWalletStore API
  • 8.3 更新 internal/service/commission_withdrawal/service.go,将 WalletStore 依赖改为 AgentWalletStore
  • 8.4 更新 internal/service/commission_withdrawal/service.go 中所有调用钱包的方法,使用新的 AgentWalletStore API
  • 8.5 更新 internal/service/shop_commission/service.go,将 WalletStore 依赖改为 AgentWalletStore
  • 8.6 更新 internal/service/shop_commission/service.go 中所有调用钱包的方法,使用新的 AgentWalletStore API
  • 8.7 更新 internal/service/my_commission/service.go,将 WalletStore 依赖改为 AgentWalletStore
  • 8.8 更新 internal/service/my_commission/service.go 中所有调用钱包的方法,使用新的 AgentWalletStore API
  • 8.9 编译验证所有佣金相关服务重构正确,无语法错误

9. Service 层重构 - 订单服务

  • 9.1 更新 internal/service/order/service.go,将 WalletStore 依赖改为 AgentWalletStoreCardWalletStore
  • 9.2 更新 internal/service/order/service.go 中的 WalletPay() 方法,使用新的 AgentWalletStore 和 CardWalletStore API根据买家类型分别处理
  • 9.3 更新 internal/service/order/service.go 中的 HandlePaymentCallback() 方法,使用新的钱包 API
  • 9.4 更新 internal/service/order/service.go 中所有其他调用钱包的方法,使用新的钱包 Store API
  • 9.5 编译验证订单服务重构正确,无语法错误

10. Service 层重构 - 充值服务(注:实际采用原地重构方案,未拆分为两个独立服务)

  • 10.1 更新 internal/service/recharge/service.go,将依赖从 WalletStore 改为 CardWalletStore、CardWalletTransactionStore、CardRechargeStore
  • 10.2 更新 Service 构造函数 New(),注入新的 CardWallet 相关 Store
  • 10.3 更新 Create() 方法,使用 CardRechargeStore 创建充值订单,使用 CardWalletStore 查询钱包
  • 10.4 更新 HandlePaymentCallback() 方法,使用 CardRechargeStore 和 CardWalletStore 处理支付回调
  • 10.5 更新 buildRechargeResponse() 方法,适配 CardRechargeRecord 模型
  • 10.6 更新 List() 方法,使用 CardRechargeStore.List() 查询充值记录
  • 10.7 更新 GetByID() 方法,使用 CardRechargeStore.GetByID() 查询充值订单
  • 10.8 更新所有佣金触发逻辑,使用 AgentWalletStore 处理佣金入账
  • 10.9 在 CardRechargeStore 中添加 List()、UpdatePaymentInfo()、UpdateStatusWithOptimisticLock() 方法
  • 10.10 更新 bootstrap/services.go注入 CardRecharge、CardWallet、CardWalletTransaction Store
  • 10.11 编译验证充值服务重构正确,无语法错误

11. Bootstrap 层 - 更新 Service 依赖注入

  • 11.1 在 internal/bootstrap/services.go 中更新 CommissionCalculationService注入 AgentWalletStore 和 AgentWalletTransactionStore
  • 11.2 在 internal/bootstrap/services.go 中更新 CommissionWithdrawalService注入 AgentWalletStore 和 AgentWalletTransactionStore
  • 11.3 在 internal/bootstrap/services.go 中更新 ShopCommissionService注入 AgentWalletStore
  • 11.4 在 internal/bootstrap/services.go 中更新 MyCommissionService注入 AgentWalletStore 和 AgentWalletTransactionStore
  • 11.5 在 internal/bootstrap/services.go 中更新 OrderService注入 AgentWalletStore 和 CardWalletStore
  • 11.6 在 internal/bootstrap/services.go 中更新 RechargeService注入 CardRechargeStore、CardWalletStore、CardWalletTransactionStore
  • 11.7 在 internal/bootstrap/worker_services.go 中更新 CommissionCalculationService注入 AgentWalletStore 和 AgentWalletTransactionStore
  • 11.8 在 pkg/queue/types.go 中更新 WorkerStores添加 AgentWallet 和 AgentWalletTransaction 字段
  • 11.9 编译验证 Service 依赖注入更新正确,无语法错误

12. 清理旧代码 - 删除旧 Model 和 Store

  • 12.1 删除 internal/model/wallet.go 文件(包含 Wallet、WalletTransaction、RechargeRecord、WalletMetadata
  • 12.2 删除 internal/store/postgres/wallet_store.go 文件
  • 12.3 删除 internal/store/postgres/wallet_transaction_store.go 文件
  • 12.4 从 internal/bootstrap/stores.go 中移除 WalletStore 和 WalletTransactionStore 字段
  • 12.5 从 internal/bootstrap/stores.goNewStores() 函数中移除 WalletStore 和 WalletTransactionStore 初始化
  • 12.6 编译检查,确保无旧代码引用残留

13. 数据库迁移 - 删除旧表

  • 13.1 创建删除旧表的迁移文件DROP TABLE tb_wallet、tb_wallet_transaction、tb_recharge_record
  • 13.2 执行数据库迁移,验证旧表删除成功
  • 13.3 检查数据库中只剩下新的 6 张表

14. 手动测试 - 代理钱包核心流程

  • 14.1 测试代理钱包创建:为店铺 ID 10 创建主钱包和分佣钱包
  • 14.2 测试代理钱包充值:主钱包充值 100000 分1000 元),验证余额正确
  • 14.3 测试代理钱包扣款:主钱包扣款 30000 分300 元),验证余额正确,创建交易记录
  • 14.4 测试余额不足场景:尝试扣款超过可用余额,验证返回"余额不足"错误
  • 14.5 测试冻结余额:分佣钱包冻结 50000 分用于提现,验证 frozen_balance 增加,可用余额减少
  • 14.6 测试解冻余额:取消提现,验证冻结余额减少,可用余额恢复
  • 14.7 测试并发扣款:模拟两个并发请求同时扣款,验证乐观锁生效(一个成功,一个失败重试)
  • 14.8 测试交易记录查询:按店铺 ID 查询交易历史,验证分页和排序正确

15. 手动测试 - 卡钱包核心流程

  • 15.1 测试卡钱包创建为物联网卡resource_type=iot_card, resource_id=100创建钱包
  • 15.2 测试卡钱包充值:卡钱包充值 10000 分100 元),验证余额正确
  • 15.3 测试卡钱包扣款:购买套餐扣款 3000 分30 元),验证余额正确,创建交易记录
  • 15.4 测试订单退款:退款 3000 分,验证余额恢复,创建退款交易记录
  • 15.5 测试余额不足场景:尝试扣款超过可用余额,验证返回"余额不足"错误
  • 15.6 测试设备钱包为设备resource_type=device, resource_id=200创建钱包验证设备的多张卡共享钱包
  • 15.7 测试并发扣款:模拟两个并发请求同时扣款,验证乐观锁生效
  • 15.8 测试交易记录查询:按资源 ID 查询交易历史,验证分页和排序正确

16. 手动测试 - 充值流程

  • 16.1 测试代理充值最小金额限制:尝试充值 50 元,验证返回"充值金额不能低于 100 元"错误
  • 16.2 测试代理充值订单创建:创建充值订单,验证生成唯一的 recharge_noARCH 前缀),状态为"待支付"
  • 16.3 测试代理充值支付完成:模拟支付回调,验证状态从"待支付"变为"已支付"
  • 16.4 测试代理充值到账:处理充值到账,验证钱包余额增加,状态变为"已完成",创建交易记录
  • 16.5 测试卡充值最小金额限制:尝试充值 0.5 元,验证返回"充值金额不能低于 1 元"错误
  • 16.6 测试卡充值订单创建:创建充值订单,验证生成唯一的 recharge_noCRCH 前缀),状态为"待支付"
  • 16.7 测试卡充值支付完成:模拟支付回调,验证状态从"待支付"变为"已支付"
  • 16.8 测试卡充值到账:处理充值到账,验证钱包余额增加,状态变为"已完成",创建交易记录

17. 数据一致性验证

  • 17.1 验证代理钱包交易记录的 balance_before 和 balance_after 准确性:查询所有交易记录,计算余额变动,与实际余额对比
  • 17.2 验证卡钱包交易记录的 balance_before 和 balance_after 准确性:查询所有交易记录,计算余额变动,与实际余额对比
  • 17.3 验证乐观锁 version 字段在并发场景下的有效性:模拟高并发扣款,验证 version 正确递增,无丢失更新
  • 17.4 验证 Redis 缓存一致性:余额变动后,检查缓存是否被正确删除,下次查询是否重新加载

18. 最终验证和清理

  • 18.1 运行 go build ./... 编译整个项目,确保无编译错误
  • 18.2 运行 go mod tidy 清理未使用的依赖
  • 18.3 检查所有文件的中文注释是否完整
  • 18.4 检查所有常量是否定义在 pkg/constants/ 中,无硬编码
  • 18.5 检查所有错误返回是否使用 errors.New()errors.Wrap(),无 fmt.Errorf()
  • 18.6 使用 gofmt -w . 格式化所有代码
  • 18.7 检查 git status确认所有变更符合预期
  • 18.8 准备提交代码,编写 Git Commit 信息(中文)

注意事项

  1. 任务顺序不可颠倒:必须先完成数据库迁移和 Model 层,再实现 Store 层,最后重构 Service 层
  2. 逐项标记完成:每完成一个任务,将 [ ] 改为 [x]
  3. 遇到问题时停止:如果某个任务无法完成或发现设计问题,立即停止并与团队讨论
  4. 编译验证:每个阶段完成后必须编译验证,确保无语法错误
  5. 手动测试不可跳过:所有核心流程必须手动测试验证,确保功能正确