package model import ( "time" "gorm.io/gorm" ) // Role 用户角色 type Role string const ( RoleUser Role = "user" RoleAdmin Role = "admin" ) // 内容审核状态 const ( ContentStatusPending = "pending" ContentStatusPublished = "published" ContentStatusRejected = "rejected" ) // 帖子类型 const ( PostTypeNormal = "normal" PostTypeQuestion = "question" ) // User 用户表 type User struct { ID uint `gorm:"primaryKey" json:"id"` Username string `gorm:"uniqueIndex;size:128;not null" json:"username"` Email string `gorm:"index;size:128;default:''" json:"-"` Password string `gorm:"size:128;not null" json:"-"` Nickname string `gorm:"size:64" json:"nickname"` Avatar string `gorm:"size:512" json:"avatar"` Role Role `gorm:"size:16;default:user" json:"role"` Banned bool `gorm:"default:false" json:"banned"` TokenVersion int `gorm:"default:0" json:"-"` // token 版本号,改密码/封禁时递增使旧 JWT 失效 CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` } // RefreshToken 刷新令牌表(支持服务端撤销、一次性轮转与盗用检测) // - TokenHash: token 的 SHA-256,数据库不存明文 // - TokenCipher: token 的 AES-GCM 密文,仅存在于"当前有效"行;轮转后旧行立即抹除。 // 保留它是为了在轮转宽限期内把【同一个】新 token 返回给并发重放请求(见 service 层) // - RotatedTo/RotatedAt: 轮转链,用于宽限重放判定与盗用(吊销后重放)杀全家族 type RefreshToken struct { ID uint `gorm:"primaryKey" json:"id"` UserID uint `gorm:"index;not null" json:"user_id"` TokenHash string `gorm:"uniqueIndex;size:64;not null" json:"-"` TokenCipher string `gorm:"size:512;default:''" json:"-"` ExpiresAt time.Time `gorm:"index;not null" json:"expires_at"` Revoked bool `gorm:"default:false;index" json:"revoked"` RotatedTo uint `gorm:"index;default:0" json:"-"` RotatedAt *time.Time `gorm:"index" json:"-"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // Board 论坛板块 type Board struct { ID uint `gorm:"primaryKey" json:"id"` Name string `gorm:"size:64;not null" json:"name"` Description string `gorm:"size:512" json:"description"` Icon string `gorm:"size:64;default:''" json:"icon"` ColorIndex int `gorm:"default:-1" json:"color_index"` SortOrder int `gorm:"default:0" json:"sort_order"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` } // Post 帖子 type Post struct { ID uint `gorm:"primaryKey" json:"id"` BoardID uint `gorm:"index;not null" json:"board_id"` UserID uint `gorm:"index;not null" json:"user_id"` Title string `gorm:"size:256;not null" json:"title"` Content string `gorm:"type:text;not null" json:"content"` Tags string `gorm:"size:256" json:"tags"` PostType string `gorm:"size:16;default:normal;index" json:"post_type"` Pinned int `gorm:"default:0" json:"pinned"` Recommended bool `gorm:"default:false;index" json:"recommended"` Status string `gorm:"size:16;default:published;index" json:"status"` LikeCount int `gorm:"default:0" json:"like_count"` ViewCount int `gorm:"default:0" json:"view_count"` CommentCount int `gorm:"default:0" json:"comment_count"` Liked bool `gorm:"-" json:"liked"` // 当前用户是否已点赞(展示字段,不入库) CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` Board Board `gorm:"foreignKey:BoardID" json:"board,omitempty"` User User `gorm:"foreignKey:UserID" json:"user,omitempty"` } // Comment 评论 type Comment struct { ID uint `gorm:"primaryKey" json:"id"` PostID uint `gorm:"index;not null" json:"post_id"` UserID uint `gorm:"index;not null" json:"user_id"` Content string `gorm:"type:text;not null" json:"content"` Status string `gorm:"size:16;default:published;index" json:"status"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` User User `gorm:"foreignKey:UserID" json:"user,omitempty"` } // Like 点赞记录(联合唯一索引防止重复点赞) type Like struct { ID uint `gorm:"primaryKey" json:"id"` PostID uint `gorm:"uniqueIndex:idx_post_user;not null" json:"post_id"` UserID uint `gorm:"uniqueIndex:idx_post_user;not null" json:"user_id"` CreatedAt time.Time `json:"created_at"` } // Checkin 每日签到记录(用户+日期联合唯一,防止重复签到) type Checkin struct { ID uint `gorm:"primaryKey" json:"id"` UserID uint `gorm:"uniqueIndex:idx_checkin_user_date;not null" json:"user_id"` CheckinDate time.Time `gorm:"type:date;uniqueIndex:idx_checkin_user_date;not null" json:"checkin_date"` Points int `gorm:"not null;default:5" json:"points"` // 当日所得积分 CreatedAt time.Time `json:"created_at"` } // 通知类型 const ( NotificationTypeComment = "comment" // 评论了你的帖子 NotificationTypeLike = "like" // 点赞了你的帖子 ) // Notification 站内通知 type Notification struct { ID uint `gorm:"primaryKey" json:"id"` UserID uint `gorm:"index;not null" json:"user_id"` // 接收通知的用户 ActorID uint `gorm:"not null" json:"actor_id"` // 触发通知的用户 Type string `gorm:"size:16;not null;index" json:"type"` // comment | like PostID uint `gorm:"index;not null" json:"post_id"` // 关联帖子 CommentID uint `gorm:"index" json:"comment_id"` // 关联评论(点赞时为 0) Content string `gorm:"size:256" json:"content"` // 内容预览 IsRead bool `gorm:"default:false;index" json:"is_read"` CreatedAt time.Time `json:"created_at"` Actor User `gorm:"foreignKey:ActorID" json:"actor,omitempty"` Post Post `gorm:"foreignKey:PostID" json:"post,omitempty"` }