8.8 KiB
8.8 KiB
name, overview, todos
| name | overview | todos | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| redismodel 从0全量设计 | 以 internal/mysqlmodel 全部实体语义为基准,从 0 重新设计 internal/redismodel 的 Redis key 常量层,覆盖认证、用户、点赞、收藏、配额、锁、星座、通知、分享等全部业务,文件组织与术语对齐 mysqlmodel。 |
|
产品概述
以 internal/mysqlmodel 的实体与字段术语为唯一语义基准,从 0 重新设计 internal/redismodel 的 Redis key 常量层。本次只交付 key 常量定义,不写任何 redisdao 操作函数(redisdao 已清空,由用户后续补充),也不改动 middleware。
核心功能
- 全局命名空间前缀
RedisPrefix = "ztcloset:"独立成文件,不再挂靠在 auth.go - 认证与会话:access/refresh token 映射,以及
user_id -> token 集合的 Set 反向索引(支持多端登录) - 用户缓存:
user_id -> 用户鉴权核心信息(对齐User.Status语义) - 点赞/收藏:按
type:target_id分桶的 Set key,成员为 user_id - 配额:每日计数 key(对齐
UserDailyUsage的 AI/社区分享/衣柜分享三字段)与总配额 key(对齐Quota.QuotaType四类枚举) - 缓存与计数:星座运势缓存、通知未读数、衣柜分享访问计数、公开穿搭浏览计数
- 分布式锁与幂等:下单防重、支付回调幂等、退款回调幂等、AI 推荐防并发、AI 星座防并发、衣柜/穿搭审核防重
- 文件组织对齐 mysqlmodel 的模块划分(like/collect 分开,删除旧的 org.go)
技术栈
- 语言:Go
- 改动范围:仅
internal/redismodel下的 key 常量定义 - Redis 客户端(已存在,不修改):
global.RedisEngine(github.com/redis/go-redis/v9) - 语义基准:
internal/mysqlmodel全部实体
实现方案
总体策略
推翻旧的 4 个文件(auth.go、quota.go、org.go、lock.go),按 mysqlmodel 的实体划分重新组织为 11 个文件。每个文件只包含对应业务模块的 key 常量,常量名与 key 字符串均对齐 mysqlmodel 的字段/枚举术语。所有 key 统一携带 ztcloset: 前缀。
关键设计决策
- 命名空间收敛:
RedisPrefix抽到独立keys.go,作为全包共享前缀,消除跨文件隐式依赖。 - 文件对齐 mysqlmodel:删除语义不符的
org.go,点赞、收藏分别用like.go、collect.go;新增user.go、closet.go、outfit.go、horoscope.go、notification.go对应各实体。 - 术语统一:
community → outfit_share(社区分享/搭配分享,对齐UserDailyUsage.OutfitShareCount)、wardrobe_share → closet_share(对齐CLosetShareCount)、upload → cos(对齐Quota.QuotaType=1=cos)。 - token 一对多:
KeyAuthUserToken改为复数KeyAuthUserTokens,key 用auth:user:tokens:%d并明确为 Set 语义,解决单值无法表达多端登录的问题。 - 配额双维度:每日计数按
UserDailyUsage的三个具名字段拆分;总配额用quota:total:%d:%d(user_id:quota_type)参数化覆盖Quota.QuotaType全部 4 类,与数据库表结构(user_id + quota_type 唯一)完全对齐。 - 锁与幂等维度:下单用 order_id、支付回调用 order_no、退款回调用 refund_no、AI 推荐/星座用 user_id 维度防并发、审核用 target_id 防重,均对齐 mysqlmodel 对应字段。
- 纯流水不设计:
QuotaFlowLog、VIPFlowLog为纯流水日志;Goods、Clothes、ClosetShareItem、OutfitItem为低频/关系数据,均无需 Redis key,避免过度设计。
目录结构
internal/redismodel/
├── keys.go # [NEW] 全局 RedisPrefix = "ztcloset:"
├── auth.go # [MODIFY] 移除 RedisPrefix;KeyAuthUserToken 改为复数 Set 语义
├── user.go # [NEW] KeyUserInfo 用户鉴权缓存 key
├── like.go # [NEW] KeyLikeSet(由旧 org.go 拆分)
├── collect.go # [NEW] KeyCollectSet(由旧 org.go 拆分)
├── quota.go # [MODIFY] 每日计数对齐 UserDailyUsage;总配额参数化对齐 QuotaType
├── closet.go # [NEW] KeyClosetShareView 衣柜分享访问计数
├── outfit.go # [NEW] KeyOutfitView 公开穿搭浏览计数
├── horoscope.go # [NEW] KeyHoroscope 星座运势缓存
├── notification.go # [NEW] KeyNotificationUnread 通知未读数
├── lock.go # [MODIFY] 补齐全量锁/幂等 key 与参数注释
└── org.go # [DELETE] 内容已拆分至 like.go / collect.go
关键代码结构
修复后的 key 常量全集(均为常量定义,无函数):
// keys.go
const RedisPrefix = "ztcloset:"
// auth.go
const (
KeyAuthAccess = RedisPrefix + "auth:access:%s" // access_token -> user_id(String)
KeyAuthRefresh = RedisPrefix + "auth:refresh:%s" // refresh_token -> user_id(String)
KeyAuthUserTokens = RedisPrefix + "auth:user:tokens:%d" // user_id -> token 集合(Set,支持多端登录)
)
// user.go
const KeyUserInfo = RedisPrefix + "user:info:%d" // user_id -> 用户鉴权核心信息(String/JSON,含 Status)
// like.go
const KeyLikeSet = RedisPrefix + "like:set:%d:%d" // like_type:target_id,成员为 user_id(Set)
// collect.go
const KeyCollectSet = RedisPrefix + "collect:set:%d:%d" // collect_type:target_id,成员为 user_id(Set)
// quota.go
const (
KeyQuotaDailyAI = RedisPrefix + "quota:daily:ai:%d:%s" // user_id:date,当日AI推荐次数
KeyQuotaDailyOutfitShare = RedisPrefix + "quota:daily:outfit_share:%d:%s" // user_id:date,当日社区分享次数(搭配分享)
KeyQuotaDailyClosetShare = RedisPrefix + "quota:daily:closet_share:%d:%s" // user_id:date,当日衣柜分享次数
KeyQuotaTotal = RedisPrefix + "quota:total:%d:%d" // user_id:quota_type,总配额(1=cos 2=AI 3=社区分享 4=衣柜分享)
)
// closet.go
const KeyClosetShareView = RedisPrefix + "closet:share:view:%s" // share_uuid,衣柜分享访问计数(INCR)
// outfit.go
const KeyOutfitView = RedisPrefix + "outfit:view:%d" // outfit_id,公开穿搭浏览计数(INCR)
// horoscope.go
const KeyHoroscope = RedisPrefix + "horoscope:%s:%d" // zodiac:stat_date(YYYYMMDD),星座运势缓存(String/JSON)
// notification.go
const KeyNotificationUnread = RedisPrefix + "notification:unread:%d" // user_id,未读消息数(INCR/DECR)
// lock.go
const (
KeyLockOrderCreate = RedisPrefix + "lock:order:create:%d" // order_id,下单防重
KeyLockPayCallback = RedisPrefix + "lock:pay:callback:%s" // order_no,支付回调幂等
KeyLockRefundCallback = RedisPrefix + "lock:refund:callback:%s" // refund_no,退款回调幂等
KeyLockAIRecommend = RedisPrefix + "lock:ai:recommend:%d" // user_id,AI推荐防并发
KeyLockAIHoroscope = RedisPrefix + "lock:ai:horoscope:%d:%s" // user_id:zodiac,AI星座防并发
KeyLockClosetAudit = RedisPrefix + "lock:audit:closet:%d" // target_id,衣柜分享审核防重
KeyLockOutfitAudit = RedisPrefix + "lock:audit:outfit:%d" // target_id,穿搭审核防重
)
实现注意事项
- 校验仅针对
redismodel包:go build ./internal/redismodel/与read_lints(路径限定在internal/redismodel)。不要运行go build ./...,因为redisdao已清空而middleware/lzcwyjwt.go仍引用redisdao.UserInfoGet,全量编译会失败(该问题由用户后续补 redisdao 解决,不在本次范围)。 - key 字符串变更属于破坏性变更,依赖可清库/未上线前提(用户已确认)。
- 所有注释需标明占位符含义与数据结构类型(String/Set/INCR/JSON),为后续 redisdao 实现提供契约。