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

13 KiB
Raw Permalink Blame History

name, overview, todos
name overview todos
manage-backend-sync-with-business 将管理后台 /root/zt-closet-manage-backend 与业务服务 /root/zt-closet-backend 的最新改动对齐:补齐额度枚举(source=4、change_type=7)与订单两列、按「封禁为主」改造仪表盘审核指标、人工发放/回收额度补写流水、对齐免费额度配置值,并同步前端仪表盘字段。
id content status
dashboard-alignment 用 [skill:lsp-code-analysis] 定位字段引用后,改 stats.go、dto/dashboard.go、service/dashboard.go,待办与穿搭概况改为公开/封禁口径 completed
id content status dependencies
frontend-sync 同步前端 types/dashboard.ts 与 DashboardView.vue:待办改三项,穿搭饼图改为公开/私密/已封禁 completed
dashboard-alignment
id content status
enum-and-order-fields 补齐枚举与订单列:constants.go 加 source=4、change_type=7,模型与 DTO 补 order 两列快照及映射 completed
id content status
quota-flow-logs 人工发放与凭证回收在同一事务内补写额度流水,回收流水使用独立 order_no 避免撞唯一索引 completed
id content status
config-and-readme 对齐 Quota 配置值为 OutfitShare=3、ClosetShare=0,更新 README 说明审核口径、枚举、流水与生产配置同步 completed
id content status dependencies
verify 后端 gofmt、go build、go vet 全通过,前端执行构建与类型检查通过,核对无遗留引用 completed
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: 输出完整的引用清单,确保后端字段重命名与前端类型调整不遗漏任何调用点,避免出现未被察觉的契约断裂