feat(backend): 对齐业务服务额度与内容治理口径
仪表盘待办与穿搭概况改为公开/私密/已封禁口径,移除恒为零的待审核统计;补齐额度凭证来源 source=4 与流水 change_type=7 枚举及订单商品类型、额度有效期快照字段;管理员发放与回收额度凭证在同一事务内写入人工调整流水,回收流水使用独立 order_no 避免撞唯一索引,并增加凭证归属校验;对齐 Quota 配置免费额度值,同步更新 README 与配置说明。
This commit is contained in:
@@ -5,11 +5,11 @@
|
||||
## 核心功能
|
||||
|
||||
- **管理员账号**:账号密码登录(bcrypt 存储)、JWT 双 token(access/refresh)签发与刷新、登出、修改密码;超级管理员可增删改普通管理员、禁用/启用账号;初始超级管理员由配置在启动时幂等创建;禁用/删除账号的会话立即失效。
|
||||
- **仪表盘统计**:用户总数/今日新增/各状态分布、订单总数/各状态分布、累计与今日营收、累计退款、待处理退款数、待审核穿搭数、上架商品数,一次接口聚合返回。
|
||||
- **用户管理**:分页搜索(昵称/手机号/OpenID/状态)、详情(含永久额度 + 每日额度 + 额度凭证列表)、封禁/解封(临时按天/永久,写原因与期限)、额度发放(有有效期额度凭证)、额度凭证回收、VIP 人工调整(事务 + 人工调整流水)。
|
||||
- **仪表盘统计**:用户总数/今日新增/各状态分布、订单总数/各状态分布、累计与今日营收、累计退款、待处理退款数、公开展示中的穿搭数、已封禁穿搭数、上架商品数,一次接口聚合返回。
|
||||
- **用户管理**:分页搜索(昵称/手机号/OpenID/状态)、详情(含永久额度 + 每日额度 + 额度凭证列表)、封禁/解封(临时按天/永久,写原因与期限)、额度发放(有有效期额度凭证,同事务写人工调整流水)、额度凭证回收(同事务写人工调整流水)、VIP 人工调整(事务 + 人工调整流水)。
|
||||
- **商品管理**:分页列表(含下架)、新增、编辑(含 `valid_days` 额度有效期天数)、上下架、软删除;支持登记/修改微信虚拟支付道具 ID 与发布状态(仅「未发布/已发布」两态,已发布必须填道具 ID,道具 ID 全局唯一),运营无需再手工改库。**运营约定**:道具在微信后台手动创建;改价后必须同步微信侧道具价格,否则用户付款后发货金额校验会拒绝(拿不到权益)。
|
||||
- **订单与退款管理**:订单列表/详情(含虚拟支付 pay_channel=2 与 XPay 平台/环境/道具字段);退款申请审核——通过置「退款中」(实际打款由运营在微信商户平台手动完成)、驳回置「失败」并记录原因。
|
||||
- **内容审核**:公开穿搭列表/详情(含衣物明细)、审核通过/驳回(写 `outfit_audit_logs`)、封禁/解封;衣物列表/详情;衣柜分享列表、封禁/解封。
|
||||
- **订单与退款管理**:订单列表/详情(含商品类型与额度有效期天数快照、虚拟支付 pay_channel=2 与 XPay 平台/环境/道具字段);退款申请审核——通过置「退款中」(实际打款由运营在微信商户平台手动完成)、驳回置「失败」并记录原因。
|
||||
- **内容审核**:公开穿搭列表/详情(含衣物明细)、封禁/解封(**主要治理手段**)、审核通过/驳回(保留但已无待审数据,见「关键业务规则」);衣物列表/详情;衣柜分享列表、封禁/解封。
|
||||
- **通知推送**:单用户系统通知、全量广播(分批写入 `user_notifications` + 同步 Redis 未读计数,小程序端实时可见)。
|
||||
|
||||
## 技术栈
|
||||
@@ -101,7 +101,7 @@ curl http://localhost:8081/ping
|
||||
| `OTel` | OpenTelemetry | `Enabled`、`ServiceName`、`ExporterEndpoint`(OTLP gRPC)、`Insecure`、`SamplerRatio` |
|
||||
| `JWT` | 鉴权 | `SecretKey`(**必填**)、`Issuer`、`AccessTokenExpire`、`RefreshTokenExpire` |
|
||||
| `Admin` | 初始超管 | `InitialUsername`、`InitialPassword`(仅首次创建时使用) |
|
||||
| `Quota` | 免费额度底值 | `Cos`/`AI`/`OutfitShare`/`ClosetShare`(仅用于展示「总额度」,须与业务服务 `UserDefaultQuota` 免费值一致,未配回落 20/3/10/5) |
|
||||
| `Quota` | 免费额度底值 | `Cos`/`AI`/`OutfitShare`/`ClosetShare`(仅用于展示「总额度」,**须与业务服务 `UserDefaultQuota` 免费值一致**,当前对齐为 20/3/3/0;未配置则回落内置默认 20/3/10/5)。**该段不随代码发布**:生产机配置文件需手工同步,否则线上「每日额度」展示会与小程序端不一致 |
|
||||
| `Cos` | CDN 下载 | `CosDownloadDomain`、`CdnDownloadSecretKey`(用于把衣物图片/头像的相对 COS key 拼接为带鉴权签名的可访问 URL,须与业务服务 Cos 段一致) |
|
||||
|
||||
## API 概览
|
||||
@@ -134,7 +134,7 @@ curl http://localhost:8081/ping
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| GET | `/dashboard/summary` | 核心指标聚合 |
|
||||
| GET | `/dashboard/summary` | 核心指标聚合(`todo` 为:`refund_pending` 待处理退款、`outfit_public_total` 公开展示中的穿搭数、`outfit_banned` 已封禁穿搭数、`goods_on_shelf` 上架商品数;`content.outfit` 为公开/私密/已封禁分布) |
|
||||
|
||||
**用户管理**(路径参数 `:uuid` 为用户 UUID)
|
||||
|
||||
@@ -144,9 +144,9 @@ curl http://localhost:8081/ping
|
||||
| GET | `/users/:uuid` | 用户详情(含永久额度 + 每日额度 + 额度凭证列表 `grants`) |
|
||||
| PUT | `/users/:uuid/ban` | 封禁(json:ban_type 1临时/2永久、ban_days、reason) |
|
||||
| PUT | `/users/:uuid/unban` | 解封 |
|
||||
| PUT | `/users/:uuid/quota` | 额度发放(json:quota_type 1上传/2AI/3社区/4衣柜、amount、expire_days) |
|
||||
| PUT | `/users/:uuid/quota` | 额度发放(json:quota_type 1上传/2AI/3社区/4衣柜、amount、expire_days);同事务写 `quota_flow_logs` 人工调整流水 |
|
||||
| PUT | `/users/:uuid/vip` | VIP 人工调整(json:vip_type、vip_days、reason) |
|
||||
| DELETE | `/users/:uuid/grants/:id` | 回收额度凭证(软删) |
|
||||
| DELETE | `/users/:uuid/grants/:id` | 回收额度凭证(软删 + 归属校验);同事务写 `quota_flow_logs` 人工调整流水 |
|
||||
|
||||
**商品管理**
|
||||
|
||||
@@ -174,8 +174,8 @@ curl http://localhost:8081/ping
|
||||
| --- | --- | --- |
|
||||
| GET | `/outfits` | 穿搭列表(query:page/page_size/user_id/is_public/audit_status/status/keyword) |
|
||||
| GET | `/outfits/:uuid` | 穿搭详情(含衣物明细) |
|
||||
| POST | `/outfits/:uuid/audit` | 审核(json:result 1通过/2驳回、reason) |
|
||||
| POST | `/outfits/:uuid/ban` | 封禁穿搭 |
|
||||
| POST | `/outfits/:uuid/audit` | 审核(json:result 1通过/2驳回、reason)。**兼容保留**:业务侧公开即自动过审,实际已无 `audit_status=1` 的数据可操作,仅允许操作待审记录,否则返回状态不允许 |
|
||||
| POST | `/outfits/:uuid/ban` | 封禁穿搭(**主要治理手段**) |
|
||||
| POST | `/outfits/:uuid/unban` | 解封穿搭 |
|
||||
| GET | `/clothes` | 衣物列表(query:page/page_size/user_id/image_process_status/category_main/keyword) |
|
||||
| GET | `/clothes/:uuid` | 衣物详情 |
|
||||
@@ -202,10 +202,11 @@ curl http://localhost:8081/ping
|
||||
## 关键业务规则
|
||||
|
||||
- **退款审核状态机**:仅允许 `0 待处理 → 1 退款中`(通过)与 `0 待处理 → 3 失败`(驳回)。实际微信打款由运营在微信商户平台手动完成,业务服务的退款回调负责后续「成功(2)」流转与权益回收。
|
||||
- **额度体系**(与业务服务一致):`user_quotas` 仅存 Cos 永久额度;AI/社区/衣柜 为每日额度;有有效期赠送额度走 `quota_grants` 凭证(source:1 会员包 / 2 加量包 / 3 广告激励)。管理后台「额度发放」写入 `quota_grants`(source=2 加量包、`ref_id=manual_<uuid>`、`expire_time=now+expire_days*86400`):Cos 为一次性库存,AI/社区/衣柜 为有效期内每日加量;「凭证回收」软删除对应凭证。有效额度 = 免费配置值(`Quota` 段)+ 有效凭证,每日已用读 `user_daily_usages`。
|
||||
- **额度体系**(与业务服务一致):`user_quotas` 仅存 Cos 永久额度;AI/社区/衣柜 为每日额度;有有效期赠送额度走 `quota_grants` 凭证(source:1 会员包 / 2 加量包 / 3 广告激励 / 4 体验会员赠送)。管理后台「额度发放」写入 `quota_grants`(source=2 加量包、`ref_id=manual_<uuid>`、`expire_time=now+expire_days*86400`):Cos 为一次性库存,AI/社区/衣柜 为有效期内每日加量;「凭证回收」软删除对应凭证,仅「未用完的部分」失效(`Amount-Used`)。有效额度 = 免费配置值(`Quota` 段,须与业务服务 `UserDefaultQuota` 一致)+ 有效凭证,每日已用读 `user_daily_usages`。
|
||||
- **额度流水闭环**:管理后台的「额度发放」「凭证回收」在**同一事务内**写 `quota_flow_logs`(`change_type=5` 人工调整、`change_target=1`),流水的 `old_value`/`new_value` 取事务内真实剩余额度,保证「变更前 + 变更量 = 变更后」;发放流水的 `order_no` 用凭证 `ref_id`(与业务侧到期失效流水按 `ref_id` 关联的口径一致),回收流水使用独立的 `revoke_<uuid>`,避免撞 `uk_quota_flow_idem(order_no, quota_type, change_type)` 唯一索引。
|
||||
- **VIP 人工调整**:叠加语义(`vip_expire = max(当前到期, now) + vip_days*86400`),`vip_days=0` 表示取消会员;事务内更新 `users` + 写 `vip_flow_logs`(`change_type=5`、`source=4`)。
|
||||
- **用户封禁**:改 `users.status`(2 临时/3 永久)+ 原因与期限,业务服务鉴权中间件每次请求校验状态,**改库即生效**。
|
||||
- **穿搭可见性**:`is_public=2` 且 `audit_status=2` 且 `status=1` 三者同时满足才对外可见;审核驳回置 `audit_status=3`、封禁置 `status=2`。
|
||||
- **穿搭可见性与治理**:业务服务侧用户「公开穿搭」时会在同一次更新中写入 `is_public=2` 与 `audit_status=2`(**公开即自动过审**),因此本管理后台的「审核通过/驳回」已无待审数据(接口保留仅为兼容),仪表盘也不再输出「待审核穿搭」,改为输出「公开穿搭总数(不含已封禁)」与「已封禁穿搭数」。对外可见条件为 `is_public=2` 且 `audit_status=2` 且 `status=1`,**内容治理以封禁(`status=2`)为主**:封禁后立即从小程序社区、衣物社区入口与穿搭分享中隐藏,且用户自行「取消公开 → 再次公开」也无法恢复可见(公开动作只改 `is_public`/`audit_status`,不改 `status`)。
|
||||
- **通知未读计数**:管理后台自增业务服务的同一 Redis key(`ztcloset:notification:unread:<user_id>`),要求两者共用同一 Redis 实例与 DB。
|
||||
- **管理员会话**:access/refresh 双 token 会话写 Redis;禁用/删除管理员会失效其全部会话;JWTAuth 每次请求回查数据库状态,禁用立即生效(Redis 故障时 fail-open,但 DB 回查兜底拦截禁用账号)。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user