first commit

This commit is contained in:
2026-09-11 01:47:20 +08:00
commit 303207d3cc
74 changed files with 8348 additions and 0 deletions
@@ -0,0 +1,157 @@
---
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 ./...` 必须通过。