Files
zt-closet-manage-backend/.codebuddy/plans/manage-backend-sync-with-business_535c9ab0.md
zhengchiliu 0863234bc5 feat(backend): 对齐业务服务额度与内容治理口径
仪表盘待办与穿搭概况改为公开/私密/已封禁口径,移除恒为零的待审核统计;补齐额度凭证来源 source=4 与流水 change_type=7 枚举及订单商品类型、额度有效期快照字段;管理员发放与回收额度凭证在同一事务内写入人工调整流水,回收流水使用独立 order_no 避免撞唯一索引,并增加凭证归属校验;对齐 Quota 配置免费额度值,同步更新 README 与配置说明。
2026-09-16 02:58:56 +08:00

160 lines
13 KiB
Markdown
Raw Permalink 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: manage-backend-sync-with-business
overview: 将管理后台 /root/zt-closet-manage-backend 与业务服务 /root/zt-closet-backend 的最新改动对齐:补齐额度枚举(source=4、change_type=7)与订单两列、按「封禁为主」改造仪表盘审核指标、人工发放/回收额度补写流水、对齐免费额度配置值,并同步前端仪表盘字段。
todos:
- id: dashboard-alignment
content: 用 [skill:lsp-code-analysis] 定位字段引用后,改 stats.go、dto/dashboard.go、service/dashboard.go,待办与穿搭概况改为公开/封禁口径
status: completed
- id: frontend-sync
content: 同步前端 types/dashboard.ts 与 DashboardView.vue:待办改三项,穿搭饼图改为公开/私密/已封禁
status: completed
dependencies:
- dashboard-alignment
- id: enum-and-order-fields
content: 补齐枚举与订单列:constants.go 加 source=4、change_type=7,模型与 DTO 补 order 两列快照及映射
status: completed
- id: quota-flow-logs
content: 人工发放与凭证回收在同一事务内补写额度流水,回收流水使用独立 order_no 避免撞唯一索引
status: completed
- id: config-and-readme
content: 对齐 Quota 配置值为 OutfitShare=3、ClosetShare=0,更新 README 说明审核口径、枚举、流水与生产配置同步
status: completed
- id: verify
content: 后端 gofmt、go build、go vet 全通过,前端执行构建与类型检查通过,核对无遗留引用
status: completed
dependencies:
- dashboard-alignment
- frontend-sync
- enum-and-order-fields
- quota-flow-logs
- config-and-readme
---
## 需求概述
业务服务已更新为「用户公开穿搭即自动过审」等内容治理与额度体系新实现,管理后台存在口径滞后。本次需让管理后台与业务服务最新实现对齐:修正已失效的仪表盘审核口径(改为以封禁为主)、补齐新增枚举与订单快照字段、让管理员人工发放与回收额度产生额度流水,并对齐免费额度配置值。
## 核心功能
- 仪表盘待办区不再展示恒为 0 的「待审核穿搭」,改为展示「公开穿搭总数」与「已封禁穿搭数」;穿搭内容概况图由「待审核/已通过/未通过」改为「公开/私密/已封禁」,管理后台前端同步展示。
- 内容治理以封禁为主:审核通过/驳回接口保留但降级为兼容用途(实际已无待审数据);封禁后内容立即从小程序社区隐藏,且用户自行取消公开再重新公开也无法恢复可见。
- 用户额度凭证的来源标识新增「体验会员赠送」,额度流水新增「到期失效」类型,用户详情与文档能正确解释这些取值,不再出现未知来源。
- 订单列表与详情新增展示「商品类型快照」与「额度有效期天数快照」,便于人工退款与权益核对。
- 管理员人工发放额度、回收额度时同步产生一条「人工调整」额度流水,小程序端额度明细能看到对应的增加与扣减记录,不再出现只有到期失效扣减、没有发放来源的账实不符。
- 免费额度配置值与管理后台展示口径对齐业务服务实际配置(社区分享 3、衣柜分享 0),用户详情页每日额度显示不再偏大。
## 技术栈
- 后端:Go 1.26 + Gin + GORM + MySQL + go-redis + viper + OpenTelemetry(沿用现有四层架构,不新增任何依赖)
- 前端:Vue3 + TypeScript + Element Plus + ECharts(沿用现有工程与图表组件)
- 数据库:与业务服务共用同一 MySQL 库,管理后台只读写业务表、不做任何业务表 DDL
## 实现方案
按「数据口径优先、展示跟随、文档收尾」推进,全部改动为存量文件修改,无新增模块。
1. **仪表盘口径对齐(封禁为主)**:删除不可达的 `is_public=2 AND audit_status=1` 统计,待办改为两个有效指标——公开穿搭总数(`is_public=2`)与已封禁穿搭(`status=2`);穿搭内容概况由 `audit_status` 分组改为 `is_public` 分组(公开/私密)并保留封禁数。选择该口径而非仅修统计条件,是因为业务侧公开动作在同一事务内写入 `is_public=2` 与 `audit_status=2`,审核已不再是公开的前置环节,封禁才是唯一有效治理手段。
2. **枚举与镜像补齐**:按业务侧常量新增 `QuotaGrantSourceTrial=4`、`QuotaChangeTypeExpire=7`,同步补齐 DTO 与模型注释;Order 模型补 `GoodsType`、`QuotaValidDays` 两列快照并在订单 DTO 与映射函数中透出。
3. **补写人工额度流水**:在人工发放与凭证回收的既有事务内各写一条 `quota_flow_logs` 记录(`change_type=5` 人工调整、`change_target=1` 调整),字段语义与唯一索引规则完全照搬业务侧实现,使业务侧到期失效任务补记的流水能与发放流水形成闭环。
4. **配置对齐**:仅修改显式 YAML 值(示例模板与本地配置),代码内兜底常量保持与业务服务兜底一致不动;生产机配置不随代码发布,README 明确提示需手工同步。
5. **前端同步**:后端字段变更后前端需同步,否则待办区仍显示「待审核穿搭」空值、饼图标签失真。
## 实现注意事项
- **流水唯一索引**:`quota_flow_logs` 唯一索引为 `(order_no, quota_type, change_type)`。发放流水沿用 `order_no = ref_id (manual_<uuid>)` 与业务侧到期失效任务按 `ref_id` 关联的习惯一致;**回收流水必须使用不同的 order_no**(如 `revoke_<uuid>`),否则与同一凭证的发放流水(同为 change_type=5)撞唯一索引导致写入失败。
- **事务内取数**:发放/回收的 `old_value`/`new_value` 必须基于同一事务连接读取调整前后的有效额度,不能读全局引擎(会读到事务外的旧值)。优先复用用户详情已有的额度计算逻辑,必要时抽取为可传入事务句柄的内部函数;发放场景亦可按「新增量」直接推算。
- **流水失败即整体回滚**:流水写入必须与凭证写入同事务,避免出现「凭证已发但无流水」的新一轮账实不符。
- **配置兜底值不动**:只改 `configs/config.example.yaml` 与 `configs/config.yaml` 的显式值,`internal/service/constants.go` 中的兜底常量保持不变(与业务服务兜底值一致,实施时复核业务侧确认)。
- **生产机配置需手工同步**:`configs/config.yaml` 被 .gitignore 忽略,部署走挂载,发布后需手工改生产机文件,README 必须写明,否则线上展示仍偏大。
- **不要顺带统一 Redis 前缀**:管理后台全局前缀是 `ztclosetadmin:`,通知未读计数必须继续使用独立的 `ztcloset:` 前缀(已与业务服务一致),本次不涉及。
- **不要镜像 `clothes.original_image_path`**:该列是业务服务本地路径,同步进模型或 DTO 会泄露服务器路径,保持现状。
- **不补未镜像表**:`closet_share_items`、`outfit_shares`、`benefit_grant_tasks` 等 10 张表按用户决定本次不补。
- **前端引用需先全量检索**:改前端类型定义前先检索仓库内对 `todo.outfit_pending_audit`、`content.outfit` 的全部引用,避免漏改导致类型检查失败。
- **仪表盘统计开销**:待办新增一次 `status=2` 计数,`outfits` 表该列无独立前导索引,属可接受的全表计数;若后续穿搭量级变大,可复用内容概况已有的封禁统计结果,避免重复查询。
## 架构设计
沿用现有分层,不引入新模式。改动链路为:业务服务写入的业务表 → 管理后台 `mysqldao` 聚合/读写 → `service` 组装口径 → `dto` 输出 → 管理后台前端渲染。
- 仪表盘:`mysqldao/stats.go`(聚合)→ `service/dashboard.go`(映射)→ `dto/dashboard.go`(契约)→ 前端 `types/dashboard.ts` + `DashboardView.vue`
- 订单:`mysqlmodel/business.go`(镜像列)→ `service/order.go`(映射)→ `dto/order.go`(契约)
- 额度:`service/user.go`(事务编排)→ `mysqldao/user.go`(新增流水写入)→ `mysqlmodel`(流水模型,已有)
## 目录结构
```
zt-closet-manage-backend/
├── internal/
│ ├── mysqldao/
│ │ ├── stats.go # [MODIFY] 待办统计去掉不可达条件,改为 is_public=2 与 status=2 两次计数;
│ │ │ # 穿搭内容概况由 audit_status 分组改为 is_public 分组,内部结构体的
│ │ │ # OutfitPending/Passed/Rejected 替换为 OutfitPublic/OutfitPrivate,保留封禁计数
│ │ └── user.go # [MODIFY] 新增额度流水写入方法(插入 quota_flow_logs),
│ │ # 并新增/抽取可在事务连接上计算某用户某额度类型有效额度的读方法
│ ├── dto/
│ │ ├── dashboard.go # [MODIFY] DashboardTodo 去掉 OutfitPendingAudit,新增 OutfitPublicTotal、
│ │ │ # OutfitBanned;DashboardOutfitStats 改为 Total/Public/Private/Banned
│ │ ├── order.go # [MODIFY] OrderItem 新增 goods_type、quota_valid_days 两个 JSON 字段
│ │ └── user.go # [MODIFY] UserGrantItem.Source 注释补 4=体验会员赠送
│ ├── mysqlmodel/
│ │ └── business.go # [MODIFY] Order 模型补 GoodsType、QuotaValidDays 两列(与业务表列名严格一致);
│ │ # QuotaGrant.Source 注释补 4;QuotaFlowLog.ChangeType 注释补 7
│ └── service/
│ ├── constants.go # [MODIFY] 新增 QuotaGrantSourceTrial=4、QuotaChangeTypeExpire=7,
│ │ # 并对齐业务侧注释(兜底额度常量保持不变)
│ ├── dashboard.go # [MODIFY] 按新字段结构映射待办与穿搭概况
│ ├── order.go # [MODIFY] buildOrderItem 透出 goods_type、quota_valid_days
│ └── user.go # [MODIFY] 人工发放、凭证回收在同一事务内补写额度流水
│ # (发放 change_num 为增量,回收为负的凭证数量;
│ # 回收的 order_no 不得与发放相同)
├── configs/
│ ├── config.example.yaml # [MODIFY] Quota 段 OutfitShare 10 改 3、ClosetShare 5 改 0
│ └── config.yaml # [MODIFY] 同上(本地实际配置,已被 .gitignore 忽略)
└── README.md # [MODIFY] 说明公开即自动过审、治理靠封禁(且封禁不可被用户绕过)、
# 仪表盘新字段含义、source=4 与 change_type=7、人工发放/回收会写流水、
# 免费额度值对齐说明与生产机配置需手工同步的提示
zt-closet-manage-frontend/
├── src/types/dashboard.ts # [MODIFY] 待办类型去掉 outfit_pending_audit、新增 outfit_public_total 与
│ # outfit_banned;穿搭概况类型改为 public/private/banned
└── src/views/dashboard/
└── DashboardView.vue # [MODIFY] 待办区改为「待处理退款 / 公开穿搭 / 已封禁」三项;
# 穿搭饼图数据源改为公开/私密/已封禁并更新图例与配色
```
## 关键代码结构
仪表盘契约(改后):
```
// DashboardTodo 待办与内容概览。
type DashboardTodo struct {
RefundPending int64 `json:"refund_pending"` // 待处理退款
OutfitPublicTotal int64 `json:"outfit_public_total"` // 公开穿搭总数(is_public=2)
OutfitBanned int64 `json:"outfit_banned"` // 已封禁穿搭(status=2)
GoodsOnShelf int64 `json:"goods_on_shelf"` // 上架商品数
}
// DashboardOutfitStats 穿搭内容概况。
type DashboardOutfitStats struct {
Total int64 `json:"total"` // 穿搭总数
Public int64 `json:"public"` // 公开(is_public=2)
Private int64 `json:"private"` // 私密(is_public=1)
Banned int64 `json:"banned"` // 已封禁(status=2)
}
```
额度流水写入(新增 DAO 方法签名,实现照搬业务侧字段语义):
```
// QuotaFlowLogCreate 写入一条额度流水(调用方需传入事务句柄,保证与凭证变更同事务)。
func (d *UserDao) QuotaFlowLogCreate(ctx context.Context, tx *gorm.DB, flow *mysqlmodel.QuotaFlowLog) error
```
## Agent Extensions
### Skill
- **lsp-code-analysis**
- Purpose: 在修改仪表盘与订单相关结构体字段前,做语义级影响分析——定位 `DashboardTodo`、`DashboardOutfitStats`、`OrderItem`、`UserGrantItem` 等类型的全部定义与引用位置,并在前端仓库定位 `outfit_pending_audit`、`content.outfit` 的所有使用点
- Expected outcome: 输出完整的引用清单,确保后端字段重命名与前端类型调整不遗漏任何调用点,避免出现未被察觉的契约断裂