--- name: 修复中高等级代码问题 overview: 修复三次代码审查报告中「中等及以上」问题(排除限流 M11、虚拟订单垃圾堆积 M15):广告激励加配置开关+服务端定价、退款改为管理员操作、XPay 退款反查、vip_type 推导、iOS 退款问询、platform 校验、pay_time 兜底、上传请求体限制。 todos: - id: adreward-config content: 新增 AdReward 配置段与错误码,改造广告激励为开关加服务端定价 status: completed - id: xpay-refund-verify content: 新增微信侧退款查询并接入 XPay 退款推送反查 status: completed - id: refund-manual-review content: 重写自动退款为待审核退款单并兼容已取消订单退款流转 status: completed - id: vip-type-derive content: 改造 VIPGrantIdempotent 按最终到期时长推导会员类型 status: completed - id: virtualpay-fixes content: 修复 iOS 退款问询、平台真实性校验与支付时间兜底 status: completed - id: upload-body-limit content: 上传 handler 入口增加请求体大小限制 status: completed - id: update-report-verify content: 更新审查报告修复状态并执行编译与静态检查验证 status: completed dependencies: - adreward-config - xpay-refund-verify - refund-manual-review - vip-type-derive - virtualpay-fixes - upload-body-limit --- ## 用户需求 针对三次代码审查报告,修复中等及以上问题(排除公开接口限流、虚拟支付订单禁取消带来的垃圾订单堆积两项),并落实两项产品调整: 1. **广告激励配置化与防刷**:广告激励额度在 config 中配置「是否开启」;每种 reward_type 的发放金额改为服务端配置固定值,前端不再传金额,从根源杜绝刷额度。 2. **退款管理员操作**:取消订单自动调微信退款的行为改为生成待审核退款单,由管理员在后台手动退款,所有退款均由管理员操作。 3. **修复范围**:严重问题 S1-new(XPay 退款推送无反查)、S2-new(广告激励刷额度);中等问题 M1-new(自动退款卡死)、M2-new(会员类型覆盖)、M3(iOS 退款问询无条件建议退款)、M4(platform 可伪造)、M9(并发支付时间无兜底)、M12(上传请求体无大小限制)。 ## 核心功能 - 广告激励开关关闭时接口返回明确的「未开启」错误;开启后按服务端配置金额发放,前端仅传奖励类型与广告记录 ID。 - XPay 退款推送在处理前反查微信侧退款真实性,未通过拒绝发放并触发微信重试。 - 取消后已付款订单生成待审核退款单,退款回调兼容「已取消」订单的退款流转,且不误回收从未发放的权益。 - 会员续费时会员类型按最终到期时长自动推导,年度会员续月包不再被降级。 - iOS 退款问询按权益消耗情况细化同意/拒绝。 - 虚拟支付发货时校验微信侧真实平台,支付时间统一兜底。 - 上传接口在解析 multipart 前限制请求体大小。 ## 视觉/交互 本任务为后端逻辑修复,不涉及界面视觉与交互变更。 ## 技术栈 - 语言:Go 1.27 - 框架:Gin v1.12、GORM + MySQL(含 soft_delete)、go-redis v9、viper(仅读 YAML) - 微信:微信支付 V3 官方 SDK、小程序虚拟支付(XPay)自研 HMAC-SHA256 签名客户端 - 复用项目既有模式:`errcode` 语义化错误、事务幂等、best-effort 告警、`*int64` 配置指针区分「未配置/显式 0」 ## 实现方式 按 8 个修复点分 6 组独立实施,均沿既有分层(handler → service → dao / pkg 客户端)推进,不改动架构: 1. **广告激励(S2)**:新增 `AdReward` 配置段与错误码,DTO 移除金额字段,`Grant` 校验开关并从配置取金额。 2. **XPay 退款反查(S1)**:`wechat` 层补退款状态查询,`handleRefundNotify` 在权益回退前反查微信侧真实性。 3. **退款管理员操作(M1)**:`autoRefundCancelledOrder` 重写为待审核退款单,`settleRefundSuccess` 兼容「已取消」订单。 4. **会员类型推导(M2)**:`VIPGrantIdempotent` 原生 SQL 按最终到期时长推导会员类型。 5. **虚拟支付细节(M3/M4/M9)**:iOS 退款问询细化、平台真实性校验、支付时间兜底。 6. **上传限制(M12)**:handler 入口加 `http.MaxBytesReader`。 ## 架构设计 ```mermaid flowchart LR A[config AdReward] --> B[adreward.Grant] B --> C[QuotaGrant] D[XPay 退款推送] --> E[handleRefundNotify] E --> F[QueryOrder 反查] F --> G[settleRefundSuccess] H[PayNotify Cancelled] --> I[autoRefundCancelledOrder] I --> J[待审核 RefundFlowLog] K[grantVIP] --> L[VIPGrantIdempotent SQL 推导类型] M[Upload handler] --> N[MaxBytesReader] --> O[service.Upload] ``` ## 目录结构 以下为本次修改/新增的文件: ``` zt-closet-backend/ ├── configs/ │ └── config.example.yaml # [MODIFY] 新增 AdReward 配置段(Enable + 各类型金额,含注释) ├── global/ │ └── setting.go # [MODIFY] 注册 AdRewardSetting 全局指针 ├── main.go # [MODIFY] setupSetting() 读取 AdReward 段并做默认值兜底 ├── pkg/ │ ├── setting/ │ │ └── section.go # [MODIFY] 新增 AdRewardSettingS 结构体 │ ├── errcode/ │ │ └── quota_code.go # [MODIFY] 新增 AdRewardDisabled 错误码 │ └── wechat/ │ └── virtualpay.go # [MODIFY] XPayOrderInfo 补退款状态字段 + 退款状态判断 └── internal/ ├── dto/ │ └── adreward.go # [MODIFY] 移除 Amount 字段 ├── mysqldao/ │ └── user.go # [MODIFY] VIPGrantIdempotent 按最终到期时长推导 vip_type ├── routers/api/v1/ │ └── clothes.go # [MODIFY] Upload handler 入口加 MaxBytesReader └── service/ ├── adreward.go # [MODIFY] Grant 校验开关 + 服务端定价 ├── virtualpay.go # [MODIFY] 退款反查、iOS 问询细化、platform 校验、pay_time 兜底 └── order.go # [MODIFY] autoRefundCancelledOrder 改待审核、settleRefundSuccess 兼容 Cancelled、grantVIP 调整 ``` ## 实现注意事项 - **S1 字段待确认**:XPay 官方退款查询/平台字段未联调确认,新增字段与状态枚举处必须保留「待确认」注释,不臆造字段名;未通过反查一律 `OrderRealityCheckFailed(70009)` + `ErrCode:1` 触发微信重试。 - **M1 防误回收**:「已取消但已付款」的订单权益从未发放,`settleRefundSuccess` 对该场景只做 `Cancelled->Refunded` 流转与退款信息记录,**跳过 `revokeOrderBenefits`**,避免误扣用户其他来源的会员天数/额度凭证。 - **M2 保持 Trial**:`ensureTrialVIP` 复用 `VIPGrantIdempotent` 传 `Trial(4)`,SQL 推导时须保留 Trial 不参与年度/月度推导。 - **M2 SQL 求值顺序**:依赖 MySQL 单表 UPDATE SET 从左到右求值,先计算 `vip_expire` 再推导 `vip_type`,与现有「显式控制 SET 顺序」注释保持一致。 - **M4 不信任前端**:platform 的资损判断改为以微信侧反查结果为准,保留 env 校验。 - **M12 余量**:`MaxBytesReader` 上限按 `MaxSizeMB*1024*1024 + 1MB`(multipart 边界开销),超限返回上传超限语义错误,避免误伤合法请求。 - **安全**:广告激励金额服务端定价后,不再接收客户端金额;退款反查沿 HMAC 签名服务端 API,无法被伪造。 - **验证**:全部改动完成后 `go build ./...` 与 `go vet ./...` 通过,并核对 linter。 ## 推荐扩展 ### Skill - **lsp-code-analysis** - 用途:追踪 `settleRefundSuccess`、`VIPGrantIdempotent`、`QuotaGrant`、`verifyXPayOrderPaid` 等关键符号的定义与全部调用点,确认改动影响面,避免遗漏调用链或误改 Trial 场景。 - 预期结果:明确各修复点的完整调用链,验证「Cancelled 订单跳过权益回退」「Trial 保持」等分支覆盖所有相关调用方。 ### SubAgent - **code-explorer** - 用途:跨目录核对涉及文件与调用点,补充确认 `errcode` 分段、`QuotaGrantDao` 查询能力、`RefundFlowLog` 字段等实现细节。 - 预期结果:产出修复所需的精确文件与函数清单,支撑分组实施。