---
phase: 02-perm-fin-realname-poll
plan: "01"
subsystem: perm-fin-poll
tags:
  - permissions
  - finance
  - polling
  - enterprise
  - concurrency
dependency_graph:
  requires: []
  provides:
    - PERM-01
    - PERM-02
    - FIN-01
    - FIN-02
    - FIN-03
    - POLL-01
    - POLL-02
    - POLL-03
    - POLL-04
  affects:
    - internal/handler/admin/asset.go
    - internal/service/commission_withdrawal/service.go
    - internal/handler/admin/commission_withdrawal.go
    - internal/service/commission_withdrawal_setting/service.go
    - internal/store/postgres/wechat_config_store.go
    - internal/polling/scheduler.go
    - internal/service/iot_card/stop_resume_service.go
    - internal/service/asset/service.go
    - internal/store/postgres/package_store.go
    - internal/service/package_series/service.go
tech_stack:
  added: []
  patterns:
    - gorm.io/gorm/clause FOR UPDATE 行锁防并发
    - go-playground/validator 参数校验
    - 函数签名扩展（分页参数）
key_files:
  created: []
  modified:
    - internal/handler/admin/asset.go
    - internal/service/commission_withdrawal/service.go
    - internal/handler/admin/commission_withdrawal.go
    - internal/service/commission_withdrawal_setting/service.go
    - internal/store/postgres/wechat_config_store.go
    - internal/polling/scheduler.go
    - internal/service/iot_card/stop_resume_service.go
    - internal/service/asset/service.go
    - internal/model/dto/asset_dto.go
    - internal/store/postgres/package_store.go
    - internal/service/package_series/service.go
    - internal/bootstrap/handlers.go
    - internal/bootstrap/services.go
    - pkg/openapi/handlers.go
decisions:
  - 企业账号权限边界：Resolve 可查（删除拦截），Refresh 不可主动刷新（新增拦截）
  - GetPackages 分页在内存中排序后切片，避免改动 Store 层查询逻辑
  - Series 删除检查在 Service 层实现（非 DB 约束），符合项目禁止外键规范
  - CommissionWithdrawalHandler 新增 validator 字段注入，与其他 Handler 保持一致
metrics:
  duration: "约 10 分钟"
  completed_date: "2026-03-28"
  tasks: 2
  files: 14
---

# Phase 02 Plan 01: PERM + FIN + POLL 9项独立修复 Summary

企业账号权限边界（Resolve 可查/Refresh 只读）、提现流程数据完整性（审批人字段/remark 必填/激活并发锁）、轮询调度和停复机安全修复，全部为独立小修，共 9 个需求 8 个 commit。

## 执行结果

所有 9 个需求（PERM-01/02, FIN-01/02/03, POLL-01/02/03/04）均已修复，`go build ./...` 零新增错误（已有两个预存在的 `service/package` 字段缺失错误不在本 plan 范围内）。

## Task 1: PERM + FIN 修复

### PERM-01 (commit: 2a92ab6)
- **文件**: `internal/handler/admin/asset.go`
- **变更**: 删除 `Resolve` 方法中对企业账号的错误拦截（企业账号应可查询资产）

### PERM-02 (commit: 2a92ab6)  
- **文件**: `internal/handler/admin/asset.go`
- **变更**: `Refresh` 方法开头新增企业账号拦截（企业账号只读，不允许主动触发运营商刷新）

### FIN-01 (commit: 8f62496)
- **文件**: `internal/service/commission_withdrawal/service.go`
- **变更**: `Approve` 的 `updates` map 补充 `approved_by` 和 `approved_at` 字段

### FIN-02 (commit: 9ee2f0b)
- **文件**: `internal/handler/admin/commission_withdrawal.go`, `internal/bootstrap/handlers.go`, `pkg/openapi/handlers.go`
- **变更**: `CommissionWithdrawalHandler` 新增 `validator` 字段；`RejectWithdrawal` 补充 `validator.Struct` 参数验证，确保 `remark` 必填

### FIN-03 (commit: bdac4ab)
- **文件**: `internal/service/commission_withdrawal_setting/service.go`, `internal/store/postgres/wechat_config_store.go`
- **变更**: 激活配置事务内首步加 `clause.Locking{Strength: "UPDATE"}` 行锁，防止并发时两个事务同时置 `is_active=true`

## Task 2: POLL 修复

### POLL-01 (commit: 922a3d0)
- **文件**: `internal/polling/scheduler.go`
- **变更**: `processSchedule` 新增 `TaskTypePollingProtect` 的 `processManualQueue` 和 `processTimedQueue` 调用

### POLL-02 (commit: 8a53123)
- **文件**: `internal/service/iot_card/stop_resume_service.go`
- **变更**: `stopCardWithRetry` 和 `resumeCardWithRetry` 中 `gatewayClient==nil` 时返回 `errors.New(CodeInternalError, ...)` 而非 `nil`（原来假装成功会误更新卡状态）

### POLL-03 (commit: 8553a46)
- **文件**: `internal/model/dto/asset_dto.go`, `internal/service/asset/service.go`, `internal/handler/admin/asset.go`, `internal/handler/app/client_asset.go`
- **变更**: 新增 `AssetPackagesResult` DTO；`GetPackages` 签名新增 `page/pageSize` 参数（默认 page=1, pageSize=50, max=100）；admin handler 从 Query 参数读取；client_asset.go 调用处同步更新

### POLL-04 (commit: 47aa5f8)
- **文件**: `internal/store/postgres/package_store.go`, `internal/service/package_series/service.go`, `internal/bootstrap/services.go`
- **变更**: `PackageStore` 新增 `CountBySeriesID` 方法；`PackageSeries.Service` 注入 `packageStore` 字段；`Delete` 前检查关联套餐数量，有则拒绝删除

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 3 - Blocking] pkg/openapi/handlers.go 需同步更新签名**
- **Found during**: Task 1 FIN-02 完成后最终编译验证
- **Issue**: `CommissionWithdrawalHandler` 构造函数新增了 `validator` 参数，`pkg/openapi/handlers.go` 中文档生成器调用处仍使用旧签名导致编译失败
- **Fix**: `admin.NewCommissionWithdrawalHandler(nil)` 改为 `admin.NewCommissionWithdrawalHandler(nil, nil)`
- **Files modified**: `pkg/openapi/handlers.go`
- **Commit**: 754bbcd

## Known Stubs

无 — 所有修复均为实际业务逻辑，无留桩或占位符。

## Commits

| Commit | Message |
|--------|---------|
| 2a92ab6 | fix(perm): 修复企业账号资产权限边界 PERM-01/02 |
| 8f62496 | fix(fin): 补全提现审批人字段 FIN-01 |
| 9ee2f0b | fix(fin): 提现拒绝补 remark 必填校验 FIN-02 |
| bdac4ab | fix(fin): 激活配置并发行锁保护 FIN-03 |
| 922a3d0 | fix(poll): polling:protect 接入调度器 POLL-01 |
| 8a53123 | fix(poll): gatewayClient=nil 时停复机返回错误而非成功 POLL-02 |
| 8553a46 | fix(poll): GetPackages 接口新增分页 POLL-03 |
| 47aa5f8 | fix(poll): Series 删除前检查关联套餐 POLL-04 |
| 754bbcd | fix(fin): 同步更新 openapi handlers 中 CommissionWithdrawalHandler 签名 |

## Self-Check: PASSED

所有关键文件存在，所有 commits 均可在 git log 中查到。
