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

157 lines
9.8 KiB
Markdown
Raw Blame History

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