## 1. 数据库迁移(建新表) - [ ] 1.1 创建迁移文件:新建 `tb_recharge_order` 表(含所有字段和索引,参考 design.md 决策 4 的字段定义) - [ ] 1.2 创建迁移文件:新建 `tb_payment` 表(含所有字段和索引,参考 design.md 决策 3 的字段定义) ## 2. Model 层 - [ ] 2.1 新建 `internal/model/recharge_order.go`:定义 `RechargeOrder` 模型、状态常量(1待支付 2已支付 3已关闭 4已退款)、`AutoPurchaseStatus` 常量(pending/success/failed) - [ ] 2.2 新建 `internal/model/payment.go`:定义 `Payment` 模型、状态常量(1待支付 2已支付 3已失败 4已退款)、`OrderType` 常量(package_order / recharge_order) ## 3. Store 层 - [ ] 3.1 新建 `internal/store/postgres/recharge_order_store.go`:实现 Create、GetByRechargeOrderNo、GetByID、UpdateStatus(乐观锁)、ListByCard、ListByDevice - [ ] 3.2 新建 `internal/store/postgres/payment_store.go`:实现 Create、GetByPaymentNo、UpdateStatus、UpdatePaymentInfo、ListByOrderID - [ ] 3.3 在 `internal/bootstrap/stores.go` 中注册 `RechargeOrderStore` 和 `PaymentStore` ## 4. 强充创建流程重写 - [ ] 4.1 修改 `internal/service/client_order/service.go` 的 `createForceRechargeOrder`:改为写 `tb_recharge_order` + `tb_payment`,移除对 `rechargeRecordStore` 的调用 - [ ] 4.2 修改幂等键逻辑:`!claimed` 时 GET Redis 值,若为 recharge_order_no 则查 `tb_recharge_order`,status=1 时返回已有充值订单(含 `idempotent: true` 标志),status≠1 时删 key 允许重建 - [ ] 4.3 调整 `markClientPurchaseCreated`:存入 `recharge_order_no`(来自 `tb_recharge_order`,不再存充值记录号) - [ ] 4.4 修改 `ClientOrderService` 结构体:注入 `rechargeOrderStore` 和 `paymentStore`,移除 `rechargeRecordStore` 字段 - [ ] 4.5 修改 `internal/bootstrap/handlers.go`:更新 `ClientOrderService` 的依赖注入 ## 5. 支付回调链路完全重写 - [ ] 5.1 新建 `internal/service/recharge_order/service.go`:实现 `HandlePaymentCallback(ctx, paymentNo, paymentMethod, transactionID)`——查 `tb_payment` → 乐观锁更新 `tb_payment.status=2` → 更新 `tb_recharge_order.status=2` → 事务内增加钱包余额 + 创建钱包流水 + 更新累计充值 → 触发 auto_purchase 任务(若 linked_package_ids 非空) - [ ] 5.2 修改 `internal/handler/callback/payment.go`:`dispatchWechatCallback` 改为查 `tb_payment` by payment_no,找到则调 `rechargeOrderService.HandlePaymentCallback`;CRCH 前缀单号不再路由到旧 `RechargeService` - [ ] 5.3 修改 `internal/bootstrap/handlers.go`:注入 `rechargeOrderService` 到支付回调 Handler - [ ] 5.4 修改 `internal/service/wechat_config/service.go` 的 `resolvePaymentConfigID`:CRCH 前缀路由从 `AssetRechargeStore.GetByRechargeNo` 改为 `RechargeOrderStore.GetByRechargeOrderNo`,获取 `payment_config_id` 用于微信支付回调验签 - [ ] 5.5 修改 `internal/store/postgres/wechat_config_store.go` 的 `CountPendingRechargesByConfigID`:SQL 从 `tb_asset_recharge_record` 改为查询 `tb_recharge_order`(按 `payment_config_id` 统计待支付充值数,用于删除配置前检查) ## 6. 普通充值流程迁移 - [ ] 6.1 修改 `internal/handler/app/client_wallet.go` 的 `CreateRecharge`:改为调用新的充值订单创建逻辑,写 `tb_recharge_order` + `tb_payment`,移除对旧 `RechargeService.Create` 的调用 - [ ] 6.2 修改 `internal/handler/app/client_wallet.go` 的 `GetRechargeRecords`:改为从 `tb_recharge_order` 查询 ## 7. PayOrder 增加支付记录 - [ ] 7.1 修改 `internal/service/order/service.go` 的 `WalletPay`:在扣款事务中增加 `INSERT tb_payment`(method=wallet,status=2,order_type=package_order) - [ ] 7.2 在 `WalletPay` 中增加幂等检查:若 `tb_payment` 中已有该 order_id 且 status=2 的记录,直接返回成功,不重复扣款 ## 8. auto_purchase 任务迁移 - [ ] 8.1 修改 `internal/task/auto_purchase.go`:任务 payload 改为传 `recharge_order_id`,从 `tb_recharge_order` 读取 linked_package_ids,移除对 `tb_asset_recharge_record` 的读取 - [ ] 8.2 修改 `auto_purchase.go`:创建套餐订单(`tb_order`)的同时在同一事务内创建 `tb_payment`(method=wallet,status=2,order_type=package_order) - [ ] 8.3 修改 `auto_purchase.go`:任务完成/失败后更新 `tb_recharge_order.auto_purchase_status`,移除对 `tb_asset_recharge_record` 的写入 ## 9. 新增充值订单独立接口 - [ ] 9.1 新增 `internal/handler/app/client_recharge_order.go`:实现 `ListRechargeOrders`(GET `/api/c/v1/recharge-orders`,按 identifier + generation 查 `tb_recharge_order`,支持 status 过滤)和 `GetRechargeOrderDetail`(GET `/api/c/v1/recharge-orders/:id`) - [ ] 9.2 新增对应 DTO:`ClientRechargeOrderListRequest`、`ClientRechargeOrderListItem`(含 auto_purchase_status、recharge_order_no、amount、status、status_name、created_at) - [ ] 9.3 注册路由:在 C 端路由组中注册 `/api/c/v1/recharge-orders` 相关路由 - [ ] 9.4 修改 `ClientCreateOrderResponse`:`recharge` 分支返回 `recharge_order_no`(来自新表),增加 `idempotent` bool 字段 ## 10. 删除旧代码 - [ ] 10.1 删除 `internal/service/recharge/service.go` 中全部写方法和回调处理(HandlePaymentCallback、Create 等),若无其他引用则删除整个文件 - [ ] 10.2 删除 `internal/store/postgres/asset_recharge_store.go` 全部内容(无需保留任何方法) - [ ] 10.3 删除 `internal/model/asset_wallet.go` 中的 `AssetRechargeRecord` 模型定义 - [ ] 10.4 从 `internal/bootstrap/stores.go` 和 `handlers.go` 中移除 `AssetRechargeStore` 的所有注册和注入 - [ ] 10.5 从 `internal/service/client_order/service.go` 中移除 `rechargeRecordStore` 字段和全部引用 - [ ] 10.6 运行 `go build ./...`,修复所有因删除旧代码引起的编译错误 ## 11. 验证 - [ ] 11.1 用 PostgreSQL MCP 验证:发起强充后 `tb_recharge_order` 和 `tb_payment` 均有新记录,`tb_asset_recharge_record` 无新记录 - [ ] 11.2 用 PostgreSQL MCP 验证:微信支付回调后 `tb_payment.status=2`,`tb_recharge_order.status=2`,钱包余额正确增加 - [ ] 11.3 用 PostgreSQL MCP 验证:auto_purchase 完成后 `tb_order` 新增套餐订单,`tb_recharge_order.auto_purchase_status=success` - [ ] 11.4 手动验证:GET `/api/c/v1/recharge-orders` 正确返回充值订单列表;GET `/api/c/v1/orders` 仍只返回套餐订单 - [ ] 11.5 手动验证:重复发起相同参数的下单请求,返回 HTTP 200 且 `idempotent=true`,不报"订单正在创建中" - [ ] 11.6 手动验证:普通充值(非强充)写 `tb_recharge_order`,回调后钱包余额正确增加 - [ ] 11.7 手动验证:PayOrder 支付套餐后 `tb_payment` 有对应 wallet 支付记录,重复调用幂等返回成功 ## 12. 删除旧表(最后执行) - [ ] 12.1 确认 `tb_asset_recharge_record` 无任何新写入(检查该表 updated_at 最新时间是否在部署前) - [ ] 12.2 创建迁移文件:`DROP TABLE tb_asset_recharge_record` - [ ] 12.3 执行迁移,确认表已删除