first commit

This commit is contained in:
2026-09-11 01:41:52 +08:00
commit 9f22e6ccae
263 changed files with 28935 additions and 0 deletions
@@ -0,0 +1,148 @@
---
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` 字段等实现细节。
- 预期结果:产出修复所需的精确文件与函数清单,支撑分组实施。