Files
zt-closet-manage-backend/.codebuddy/plans/同步业务后端额度体系与虚拟支付改动_e8be4985.md
2026-09-11 01:47:20 +08:00

9.8 KiB
Raw Permalink Blame History

name, overview, todos
name overview todos
同步业务后端额度体系与虚拟支付改动 将业务服务 /root/zt-closet-backend 的最新改动同步到管理后台 /root/zt-closet-manage-backend:同步商品/订单新字段与 quota_grants 额度凭证模型,并将「额度人工调整」从改 user_quotas.total 重构为发放有有效期额度凭证(quota_grants),用户详情完整展示永久/每日额度与凭证列表、支持回收。
id content status
sync-models-constants 同步数据模型与常量:business.go 增改 Goods/Order/QuotaGrant/UserDailyUsage,constants.go 补 GoodsProduct/PayChannelVirtual/QuotaGrantSource 等 completed
id content status dependencies
sync-goods-order 同步商品与订单 DTO/Service:商品 valid_days 可编辑与 product 只读展示,订单 xpay 字段展示 completed
sync-models-constants
id content status
add-quota-config 新增 Quota 配置段:pkg/setting、global、main.go 与 config.example.yaml completed
id content status dependencies
quota-dao-dto 实现 QuotaGrantDao 与 UserDailyUsage 读取,移除旧 QuotaAdjustWithFlow,重构 dto/user.go completed
sync-models-constants
add-quota-config
id content status dependencies
rework-user-service 重构 service/user.go:详情完整额度计算与凭证列表、额度调整改凭证发放、新增凭证回收 completed
quota-dao-dto
id content status dependencies
router-handler-finalize 改造路由与 handler、补充错误码、更新 README 并执行 go build/vet 验证 completed
rework-user-service
sync-goods-order

产品概述

业务后端(/root/zt-closet-backend)已完成额度体系重构与商品、订单字段扩展,本次任务是将管理后台(/root/zt-closet-manage-backend)同步到新语义:新增有有效期额度凭证(quota_grants)的发放与回收、用户详情完整展示永久额度与每日额度、同步商品虚拟支付字段与订单 XPay 字段,保持与业务服务共用同一 MySQL 库、同风格四层架构。

核心功能

  • 数据模型同步:Goods 新增 valid_days(额度有效期天数)、product_id、product_status;Order 新增 xpay_product_id、xpay_platform、xpay_env;新增 QuotaGrant、UserDailyUsage 模型;user_quotas 语义更新为仅 Cos 永久额度。
  • 额度人工调整改为凭证发放:管理后台将用户额度调整从「改 user_quotas.total」改为「写 quota_grants 凭证」(source=加量包,ref_id=manual_uuid,可设有效期天数);Cos 为一次性库存,AI/社区/衣柜 为有效期内每日加量。
  • 凭证回收:支持按凭证 ID 软删除 quota_grants(含归属校验)。
  • 用户详情完整展示:Cos 永久额度(总额/已用/剩余)+ AI/社区/衣柜 每日额度(总额/当日已用/剩余)+ 该用户有效额度凭证列表;免费额度底值由管理后台新增 Quota 配置段提供(未配回落 20/3/10/5)。
  • 商品管理:valid_days 可编辑,product_id/product_status 只读展示(虚拟支付发布状态由业务侧维护)。
  • 订单管理:列表与详情展示 pay_channel=2(虚拟支付)及 xpay 平台/环境/道具 ID 字段。

技术栈

沿用现有管理后台技术栈与分层,不做技术栈变更:

  • Go 1.26 + Gin + GORM + MySQL(soft_delete)+ go-redis + viper + JWT + OpenTelemetry + slog。
  • 与业务服务共用同一 MySQL 业务库与 Redis。

实现方案

总体策略

严格对齐业务后端新额度语义:以「免费配置值 + 有效凭证」计算有效额度,凭证表作为可追溯、可回收的发放载体。商品/订单字段仅做模型与 DTO/Service 同步展示;额度调整与详情展示按新语义重构。

额度计算模型(管理后台侧)

管理后台不依赖业务 Redis 计数,直接读共享库 MySQL:

  • Cos 永久额度:Total = Quota配置.Cos + SUM(有效Cos凭证.amount),Used = user_quotas.used + SUM(有效Cos凭证.used)。
  • AI/社区/衣柜 每日额度:Total = Quota配置对应项 + SUM(有效凭证.amount),Used = user_daily_usages 今日对应计数,凭证 Used 恒 0。
  • 凭证有效性:expire_time=0 跟随 VIP(vip_expire>now 有效),否则 expire_time>now 有效。
flowchart LR
    A[管理员发放额度] --> B[写 quota_grants<br/>source=2 加量包<br/>ref_id=manual_uuid<br/>expire_time=now+days]
    B --> C[(quota_grants)]
    C --> D[用户详情计算]
    D --> E[Cos 永久额度<br/>免费配置 + 凭证库存]
    D --> F[AI/社区/衣柜 每日额度<br/>免费配置 + 凭证每日加量]
    G[(user_quotas)] --> E
    H[(user_daily_usages)] --> F
    I[管理员回收] -->|软删| C

关键设计决策

  1. 新增 QuotaSettingS{Cos,AI,OutfitShare,ClosetShare *int64} 配置段(指针类型支持显式 0,未配/负数回落 20/3/10/5,与业务 defaultQuotaValue 对齐),仅用于管理后台计算总额展示。
  2. 凭证发放请求改为 {quota_type, amount, expire_days},source=2 加量包、ref_id="manual_"+UUID、CreatedBy=管理员ID;不写 quota_flow_logs(与业务广告激励模式一致)。
  3. 凭证回收为软删除,DELETE /users/:uuid/grants/:id,按 id + user_id 归属校验,防越权。
  4. 商品 product_id/product_status 只读展示(由业务虚拟支付发布流程维护),valid_days 参与创建与更新。
  5. 每日额度「当日已用」读 user_daily_usages 今日 StatDate,避免依赖 Redis TTL 计数。
  6. 移除旧 QuotaAdjustWithFlow(改 user_quotas.total + 流水)逻辑,避免遗留与新语义冲突的写路径。
  7. 错误码新开 UserGrantNotFound=16003。

目录结构

/root/zt-closet-manage-backend/
├── configs/config.example.yaml          # [MODIFY] 新增 Quota 配置段(Cos/AI/OutfitShare/ClosetShare)
├── global/setting.go                    # [MODIFY] 新增 QuotaSetting 全局指针
├── pkg/setting/section.go               # [MODIFY] 新增 QuotaSettingS 结构体
├── pkg/errcode/admin_code.go            # [MODIFY] 新增 16003 额度凭证不存在
├── main.go                              # [MODIFY] setupSetting 读取 Quota 段
├── internal/
│   ├── mysqlmodel/business.go           # [MODIFY] Goods+3字段、Order+3字段、Quota注释、新增 QuotaGrant/UserDailyUsage
│   ├── dto/
│   │   ├── goods.go                     # [MODIFY] GoodsItem/Create/Update 增加 valid_days、product_id、product_status
│   │   ├── order.go                     # [MODIFY] OrderItem 增加 xpay 字段
│   │   └── user.go                      # [MODIFY] QuotaItem 语义、UserDetailResponse 增 Grants、QuotaAdjustRequest 改造、新增 UserGrantItem
│   ├── mysqldao/
│   │   ├── user.go                      # [MODIFY] 移除 QuotaAdjustWithFlow
│   │   └── quota.go                     # [NEW] QuotaGrantDao(Create/ListByUserID/GetByID/SoftDelete)+ UserDailyUsageGetByUserIDAndDate
│   ├── service/
│   │   ├── constants.go                 # [MODIFY] 新增 GoodsProduct*、PayChannelVirtual、QuotaGrantSource*、XPayPlatform*
│   │   ├── goods.go                     # [MODIFY] buildGoodsItem/Create/Update 处理新字段
│   │   ├── order.go                     # [MODIFY] buildOrderItem 增加 xpay 字段
│   │   └── user.go                      # [MODIFY] Detail 完整额度计算、QuotaAdjust 改凭证发放、新增 GrantRevoke
│   └── routers/
│       ├── router.go                    # [MODIFY] 新增 DELETE /users/:uuid/grants/:id
│       └── api/v1/user.go               # [MODIFY] 额度调整 handler 改参数、新增凭证回收 handler
└── README.md                            # [MODIFY] 更新接口、配置、业务规则说明

关键数据结构

// pkg/setting/section.go
type QuotaSettingS struct {
    Cos         *int64 // 免费上传额度(永久)
    AI          *int64 // 免费 AI 推荐额度(每日)
    OutfitShare *int64 // 免费社区分享额度(每日)
    ClosetShare *int64 // 免费衣柜分享额度(每日)
}

// internal/mysqlmodel/business.go
type QuotaGrant struct {
    Model
    UserID     int64  `gorm:"column:user_id;index:idx_grant_user_type_expire,priority:1"`
    QuotaType  int8   `gorm:"column:quota_type;index:idx_grant_user_type_expire,priority:2;uniqueIndex:uk_grant_ref_type,priority:2"`
    Amount     int64  `gorm:"column:amount"`
    Used       int64  `gorm:"column:used"`
    Source     int8   `gorm:"column:source"`
    ExpireTime int64  `gorm:"column:expire_time;index:idx_grant_user_type_expire,priority:3"`
    RefID      string `gorm:"column:ref_id;type:varchar(64);uniqueIndex:uk_grant_ref_type,priority:1"`
}

// internal/dto/user.go
type UserQuotaAdjustRequest struct {
    QuotaType  int8  `json:"quota_type" binding:"required,oneof=1 2 3 4"`
    Amount     int64 `json:"amount" binding:"required,min=1,max=100000000"`
    ExpireDays int64 `json:"expire_days" binding:"required,min=1,max=3650"`
}

实现注意事项

  • 性能:用户详情一次查询 user_quotas(Cos)、quota_grants(IN 用户)、user_daily_usages(今日),避免 N+1;凭证列表数量级小,无分页压力。
  • 安全:凭证回收必须校验 user_id 归属;发放时校验用户存在与参数合法性;所有 SQL 走 GORM 参数绑定。
  • 语义对齐:凭证有效性判断严格复刻业务 grantExpired;商品只读字段不提供写入入口,避免与业务虚拟支付发布流程冲突。
  • 兼容性:仅改管理后台内部逻辑,不改业务服务代码;旧 PUT /users/:uuid/quota 路由保留但请求体语义变更,前端联调需同步。
  • 验证:go build ./... 与 go vet ./... 必须通过。