first commit

This commit is contained in:
2026-09-11 01:41:52 +08:00
commit 9f22e6ccae
263 changed files with 28935 additions and 0 deletions
@@ -0,0 +1,73 @@
---
name: 收藏单条状态查询接口
overview: 参照点赞的 GET /like/:targetUUID,为收藏新增 GET /collect/:targetUUID 单条收藏状态查询接口(返回 is_collected + collect_count),补齐前端进入穿搭详情时的收藏状态初始化能力。
todos:
- id: add-collect-status-api
content: 新增收藏单条状态查询 DTO、Service、Handler 与路由注册
status: completed
- id: sync-collect-docs
content: 同步 README 与接口文档,补充 GET /collect/:targetUUID 说明
status: completed
dependencies:
- add-collect-status-api
- id: verify-collect-build
content: 执行 go build ./... 验证编译通过
status: completed
dependencies:
- add-collect-status-api
---
## 用户需求
收藏状态无法正确初始化——后端缺少「单条收藏状态」查询接口。点赞已有 `GET /like/:targetUUID`(返回 `is_liked` + `like_count`),收藏仅有 `POST /collect`(收藏/取消)和 `GET /collect`(我的收藏列表),前端进入穿搭详情时无法获知当前用户是否已收藏该穿搭。
## 核心功能
参照点赞接口,为收藏补齐 `GET /collect/:targetUUID` 单条状态查询:
- 返回当前用户是否已收藏(`is_collected`)与该穿搭收藏总数(`collect_count`)
- Redis 优先、异常回落 MySQL,与点赞查询策略严格对称
- 校验穿搭存在性与可见性(非本人仅可查询公开可见穿搭)
## 技术栈
- Go 1.27 + Gin + GORM + go-redis,沿用现有分层(handler → service → dao / redisdao)
- 复用现有收藏底层能力,不新增 DAO/Redis 方法
## 实现方式
严格对齐点赞 `GET /like/:targetUUID` 的实现模式,新增收藏单条状态查询链路。
### 关键决策
- **字段命名对称**:点赞 `is_liked`/`like_count`,收藏用 `is_collected`/`collect_count`。
- **路径参数命名对齐**:`targetUUID`(驼峰,与点赞一致),避免前端两套传参方式不一致。
- **回落策略一致**:是否已收藏与收藏总数均 Redis 优先;Redis 出错或计数为 0 时回落 MySQL 兜底,保证缓存冷启动/漂移时数据正确。
- **仅新增不改旧**:收藏的收藏/取消与列表逻辑保持不动,降低回归风险。
### 数据流
`GET /collect/:targetUUID` → handler 取 `targetUUID` → service 校验穿搭(存在 + 可见性)→ Redis 查收藏状态/计数 → 异常回落 MySQL → 返回 `{is_collected, collect_count}`
## 目录结构
```
zt-closet-backend/
├── internal/
│ ├── dto/
│ │ └── collect.go # [MODIFY] 新增 CollectGetByTargetRequest/Response
│ ├── service/
│ │ └── collect.go # [MODIFY] 新增 GetByTarget 方法
│ └── routers/
│ ├── router.go # [MODIFY] 注册 GET /collect/:targetUUID
│ └── api/v1/
│ └── collect.go # [MODIFY] 新增 GetByTarget handler
├── README.md # [MODIFY] API 概览收藏小节新增接口行
└── 接口文档.md # [MODIFY] 接口总表与 5.8 节新增接口说明
```
## 实现细节
- DTO 定义与点赞完全对应:`CollectGetByTargetRequest{ TargetUUID string json:"target_uuid" binding:"required" }`、`CollectGetByTargetResponse{ UserIsCollected bool json:"is_collected"; CollectCount int64 json:"collect_count" }`。
- Service `GetByTarget` 内部逻辑:先 `OutfitGetByUUID`(不存在返回 `TargetNotFound`、非本人且未公开返回 `OutfitNoPermission`),再取 `targetID`,随后 `CollectIsMember`(Redis 优先,err 回落 `CollectGetByTargetAndUser` 判断 `Status == InteractStatusOn`),最后 `CollectCount`(Redis 优先,`err != nil || count == 0` 回落 `CollectCountByTarget`)。
- Handler 与路由均对齐点赞:path 参数 `targetUUID`,空值返回 `InvalidParams`;路由注册在鉴权组内,`/collect`(精确路径)与 `/collect/:targetUUID`(参数路径)在 Gin 路由树中可共存。