---
phase: 01-p0
plan: 03
subsystem: 充值回调链路 / 自动购包任务
tags: [bug-fix, queue, asynq, recharge, commission, auto-purchase]
dependency_graph:
  requires: [01-01]
  provides: [充值回调→自动购包入队, 自动购包→佣金任务入队, AutoPurchaseHandler注册]
  affects: [internal/service/recharge, internal/task, pkg/queue]
tech_stack:
  added: []
  patterns: [asynq任务入队, 事务外触发异步任务, 依赖注入]
key_files:
  created: []
  modified:
    - internal/service/recharge/service.go
    - internal/bootstrap/services.go
    - internal/task/auto_purchase.go
    - pkg/queue/handler.go
decisions:
  - "佣金任务在事务提交成功后入队（事务外），防止任务提交后事务回滚引发数据一致性问题"
  - "自动购包入队失败不影响充值成功，仅记录 Error 日志"
  - "AutoPurchaseHandler 的 AssetRechargeStore / AssetWalletTransactionStore 传 nil，由 NewAutoPurchaseHandler 内部按需初始化"
metrics:
  duration: "~8 分钟"
  completed_date: "2026-03-27"
  tasks: 2
  files_changed: 4
---

# Phase 01 Plan 03: 充值回调触发自动购包 + 佣金链补全 Summary

打通完整链路：充值回调 → 自动购包任务入队 → 执行购包 → 佣金计算任务入队（CRITICAL-04 + CRITICAL-05）。

## Tasks Completed

| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | recharge.Service 注入 queueClient，触发自动购包（CRITICAL-04 Part 1） | 9a4d87a | service/recharge/service.go, bootstrap/services.go |
| 2 | AutoPurchaseHandler 注入 asynqClient + 注册 + 触发佣金（CRITICAL-04 Part 2 + CRITICAL-05） | 030425b | task/auto_purchase.go, pkg/queue/handler.go |

## Changes Summary

### Task 1 — CRITICAL-04 Part 1

**`internal/service/recharge/service.go`**
- `Service` struct 新增字段：`queueClient *queue.Client`
- `New()` 函数末尾新增参数：`queueClient *queue.Client`
- `HandlePaymentCallback` 事务成功后，检查 `LinkedPackageIDs` 非空时，调用 `queueClient.EnqueueTask(TaskTypeAutoPurchaseAfterRecharge)`
  - 入队失败不影响充值成功，仅记录 Error 日志

**`internal/bootstrap/services.go`**
- `rechargeSvc.New(...)` 末尾追加 `deps.QueueClient` 参数

### Task 2 — CRITICAL-04 Part 2 + CRITICAL-05

**`internal/task/auto_purchase.go`**
- `AutoPurchaseHandler` struct 新增字段：`asynqClient *asynq.Client`
- `NewAutoPurchaseHandler()` 在 `redisClient` 参数之后新增 `asynqClient *asynq.Client`
- `ProcessTask` 事务前声明 `var createdOrderID uint`，事务内 `tx.Create(order)` 成功后赋值
- 事务提交成功后（事务外）入队 `TaskTypeCommission`（QueueLow，MaxRetry=3）
  - 使用 `sonic.Marshal` 序列化（符合项目规范）
  - 入队失败仅 Warn 日志，不影响购包结果

**`pkg/queue/handler.go`**
- `RegisterHandlers()` 末尾调用 `h.registerAutoPurchaseHandler()`
- 新增方法 `registerAutoPurchaseHandler()`：
  - 调用 `task.NewAutoPurchaseHandler(...)` 传入 `h.asynqClient`
  - `h.mux.HandleFunc(TaskTypeAutoPurchaseAfterRecharge, ...)`

## 关键代码路径

```
个人客户充值微信支付回调
  └─ recharge.HandlePaymentCallback()
       ├─ 事务：更新状态、增加余额、触发一次性佣金
       └─ 事务成功后：
            └─ queueClient.EnqueueTask(TaskTypeAutoPurchaseAfterRecharge, {recharge_id})
                   └─ Worker: AutoPurchaseHandler.ProcessTask()
                        ├─ 扣款、创建订单、激活套餐（事务内）
                        └─ 事务成功后：
                             └─ asynqClient.EnqueueContext(TaskTypeCommission, {order_id})
                                    └─ Worker: CommissionCalculationHandler.HandleCommissionCalculation()
```

## Verification Results

```bash
# 编译验证
go build ./... → 通过，无错误

# 入队代码存在
rg "TaskTypeAutoPurchaseAfterRecharge" internal/service/recharge/service.go
→ s.queueClient.EnqueueTask(ctx, constants.TaskTypeAutoPurchaseAfterRecharge, ...)

rg "TaskTypeCommission" internal/task/auto_purchase.go
→ asynq.NewTask(constants.TaskTypeCommission, ...)

# handler 注册
rg "registerAutoPurchaseHandler|TaskTypeAutoPurchaseAfterRecharge" pkg/queue/handler.go
→ h.registerAutoPurchaseHandler()
→ h.mux.HandleFunc(constants.TaskTypeAutoPurchaseAfterRecharge, ...)

# bootstrap 传入 queueClient
rg "rechargeSvc.New" internal/bootstrap/services.go
→ rechargeSvc.New(..., deps.QueueClient)
```

## CRITICAL Requirements Status

| 需求 | 状态 | 说明 |
|------|------|------|
| CRITICAL-04 | ✅ 完成 | 充值回调后自动购包入队 + AutoPurchaseHandler 注册 |
| CRITICAL-05 | ✅ 完成 | 自动购包成功后佣金链触发（事务外入队） |

## Deviations from Plan

None — 按计划执行，无偏差。

## Known Stubs

None — 所有代码路径均已实现，无占位符。

## Self-Check: PASSED

- [x] `internal/service/recharge/service.go` 存在 ✓
- [x] `internal/bootstrap/services.go` 存在 ✓
- [x] `internal/task/auto_purchase.go` 存在 ✓
- [x] `pkg/queue/handler.go` 存在 ✓
- [x] commit 9a4d87a 存在 ✓
- [x] commit 030425b 存在 ✓
- [x] `go build ./...` 通过 ✓
