aa75691c49d037ed9bb58ecd9a43723118408c1e
CarrotSkin Backend
一个功能完善的Minecraft皮肤站后端系统,采用单体架构设计,基于Go语言和Gin框架开发。
✨ 核心功能
- ✅ 用户认证系统 - 注册、登录、JWT认证、积分系统
- ✅ 邮箱验证系统 - 注册验证、找回密码、更换邮箱(基于Redis的验证码)
- ✅ 材质管理系统 - 皮肤/披风上传、搜索、收藏、下载统计
- ✅ 角色档案系统 - Minecraft角色创建、管理、RSA密钥生成
- ✅ 文件存储 - MinIO/RustFS对象存储集成、预签名URL上传
- ✅ 缓存系统 - Redis缓存、验证码存储、频率限制
- ✅ 权限管理 - Casbin RBAC权限控制
- ✅ 数据审计 - 登录日志、操作审计、下载记录
项目结构
backend/
├── cmd/ # 应用程序入口
│ └── server/ # 主服务器入口
│ └── main.go # 服务初始化、路由注册
├── internal/ # 私有应用代码
│ ├── handler/ # HTTP处理器(函数式)
│ │ ├── routes.go # 路由注册
│ │ ├── auth_handler.go
│ │ ├── user_handler.go
│ │ └── ...
│ ├── service/ # 业务逻辑服务(函数式)
│ │ ├── common.go # 公共声明(jsoniter等)
│ │ ├── user_service.go
│ │ └── ...
│ ├── repository/ # 数据访问层(函数式)
│ │ ├── user_repository.go
│ │ └── ...
│ ├── model/ # 数据模型(GORM)
│ ├── middleware/ # 中间件
│ └── types/ # 类型定义
├── pkg/ # 公共库代码
│ ├── auth/ # 认证授权
│ │ └── manager.go # JWT服务管理器
│ ├── config/ # 配置管理
│ │ └── manager.go # 配置管理器
│ ├── database/ # 数据库连接
│ │ ├── manager.go # 数据库管理器(AutoMigrate)
│ │ └── postgres.go # PostgreSQL连接
│ ├── email/ # 邮件服务
│ │ └── manager.go # 邮件服务管理器
│ ├── logger/ # 日志系统
│ │ └── manager.go # 日志管理器
│ ├── redis/ # Redis客户端
│ │ └── manager.go # Redis管理器
│ ├── storage/ # 文件存储(RustFS/MinIO)
│ │ └── manager.go # 存储管理器
│ ├── utils/ # 工具函数
│ └── validator/ # 数据验证
├── docs/ # API定义和文档(Swagger)
├── configs/ # 配置文件
│ └── casbin/ # Casbin权限配置
├── go.mod # Go模块依赖
├── go.sum # Go模块校验
├── start.sh # Linux/Mac启动脚本
├── .env # 环境变量配置
└── README.md # 项目说明
技术栈
- 语言: Go 1.23+
- 框架: Gin Web Framework
- 数据库: PostgreSQL 15+ (GORM ORM)
- 缓存: Redis 6.0+
- 存储: RustFS/MinIO (S3兼容对象存储)
- 权限: Casbin RBAC
- 日志: Zap (结构化日志)
- 配置: 环境变量 (.env) + Viper
- JSON: jsoniter (高性能JSON序列化)
- 文档: Swagger/OpenAPI 3.0
快速开始
环境要求
- Go 1.21或更高版本
- PostgreSQL 15或更高版本
- Redis 6.0或更高版本
- RustFS 或其他 S3 兼容对象存储服务
安装和运行
- 克隆项目
git clone <repository-url>
cd CarrotSkin/backend
- 安装依赖
go mod download
- 配置环境
# 复制环境变量文件
cp .env.example .env
# 编辑 .env 文件配置数据库、RustFS等服务连接信息
注意:项目完全依赖 .env 文件进行配置,不再使用 YAML 配置文件,便于 Docker 容器化部署。
- 初始化数据库
# 创建数据库
createdb carrotskin
# 或者使用PostgreSQL客户端
psql -h localhost -U postgres -c "CREATE DATABASE carrotskin;"
💡 提示: 项目使用 GORM 的
AutoMigrate功能自动创建和更新数据库表结构,无需手动执行SQL脚本。首次启动时会自动创建所有表。
- 运行服务
方式一:使用启动脚本(推荐)
# Linux/Mac
chmod +x start.sh
./start.sh
# Windows
start.bat
方式二:直接运行
# 设置环境变量(或使用.env文件)
export DATABASE_HOST=localhost
export DATABASE_PORT=5432
# ... 其他环境变量
# 运行服务
go run cmd/server/main.go
💡 提示:
- 启动脚本会自动加载
.env文件中的环境变量- 首次启动时会自动执行数据库迁移(AutoMigrate)
- 如果对象存储未配置,服务仍可启动(相关功能不可用)
服务启动后:
- 服务地址: http://localhost:8080
- Swagger文档: http://localhost:8080/swagger/index.html
- 健康检查: http://localhost:8080/health
API接口
认证相关
POST /api/v1/auth/register- 用户注册(需邮箱验证码)POST /api/v1/auth/login- 用户登录(支持用户名/邮箱)POST /api/v1/auth/send-code- 发送验证码(注册/重置密码/更换邮箱)POST /api/v1/auth/reset-password- 重置密码(需验证码)
用户相关(需认证)
GET /api/v1/user/profile- 获取用户信息PUT /api/v1/user/profile- 更新用户信息(头像、密码)POST /api/v1/user/avatar/upload-url- 生成头像上传URLPUT /api/v1/user/avatar- 更新头像POST /api/v1/user/change-email- 更换邮箱(需验证码)
材质管理
公开接口:
GET /api/v1/texture- 搜索材质GET /api/v1/texture/:id- 获取材质详情
认证接口:
POST /api/v1/texture/upload-url- 生成材质上传URLPOST /api/v1/texture- 创建材质记录PUT /api/v1/texture/:id- 更新材质DELETE /api/v1/texture/:id- 删除材质POST /api/v1/texture/:id/favorite- 切换收藏状态GET /api/v1/texture/my- 我的材质列表GET /api/v1/texture/favorites- 我的收藏列表
角色档案
公开接口:
GET /api/v1/profile/:uuid- 获取档案详情
认证接口:
POST /api/v1/profile- 创建角色档案(UUID由后端生成)GET /api/v1/profile- 我的档案列表PUT /api/v1/profile/:uuid- 更新档案DELETE /api/v1/profile/:uuid- 删除档案POST /api/v1/profile/:uuid/activate- 设置活跃档案
系统配置
GET /api/v1/system/config- 获取系统配置
配置管理
环境变量配置
项目完全依赖环境变量进行配置,不使用 YAML 配置文件,便于容器化部署:
- 配置来源: 环境变量 或
.env文件 - 环境变量格式: 使用下划线分隔,全大写,如
DATABASE_HOST - 容器部署: 直接在容器运行时设置环境变量即可
主要环境变量:
# 数据库配置
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USERNAME=postgres
DATABASE_PASSWORD=your_password
DATABASE_NAME=carrotskin
# Redis配置
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_DATABASE=0
REDIS_POOL_SIZE=10
# RustFS对象存储配置 (S3兼容)
RUSTFS_ENDPOINT=127.0.0.1:9000
RUSTFS_ACCESS_KEY=your_access_key
RUSTFS_SECRET_KEY=your_secret_key
RUSTFS_USE_SSL=false
RUSTFS_BUCKET_TEXTURES=carrot-skin-textures
RUSTFS_BUCKET_AVATARS=carrot-skin-avatars
# JWT配置
JWT_SECRET=your-jwt-secret-key
JWT_EXPIRE_HOURS=168
# 邮件配置
EMAIL_ENABLED=true
EMAIL_SMTP_HOST=smtp.example.com
EMAIL_SMTP_PORT=587
EMAIL_USERNAME=noreply@example.com
EMAIL_PASSWORD=your_email_password
EMAIL_FROM_NAME=CarrotSkin
动态配置(存储在数据库中):
- 积分系统配置(注册奖励、签到积分等)
- 用户限制配置(最大材质数、最大角色数等)
- 网站设置(站点名称、公告、维护模式等)
完整的环境变量列表请参考 .env.example 文件。
数据库自动迁移
项目使用 GORM 的 AutoMigrate 功能自动管理数据库表结构:
- 首次启动: 自动创建所有表结构
- 模型更新: 自动添加新字段、索引等
- 类型转换: 自动处理字段类型变更(如枚举类型转为varchar)
- 外键管理: 自动管理外键关系
注意事项:
- 生产环境建议先备份数据库再执行迁移
- 某些复杂变更(如删除字段)可能需要手动处理
- 枚举类型在PostgreSQL中存储为varchar,避免类型兼容问题
架构设计
面向过程的函数式架构
项目采用面向过程的函数式架构,摒弃不必要的面向对象抽象,使用独立函数和单例管理器模式,代码更简洁、可维护性更强:
┌─────────────────────────────────────┐
│ Handler 层 (函数) │ ← 路由处理、参数验证、响应格式化
├─────────────────────────────────────┤
│ Service 层 (函数) │ ← 业务逻辑、权限检查、数据验证
├─────────────────────────────────────┤
│ Repository 层 (函数) │ ← 数据库操作、关联查询
├─────────────────────────────────────┤
│ Manager 层 (单例模式) │ ← 核心依赖管理(线程安全)
│ - database.MustGetDB() │
│ - logger.MustGetLogger() │
│ - auth.MustGetJWTService() │
│ - redis.MustGetClient() │
│ - email.MustGetService() │
│ - storage.MustGetClient() │
│ - config.MustGetConfig() │
├──────────────┬──────────────────────┤
│ PostgreSQL │ Redis │ RustFS │ ← 数据存储层
└──────────────┴──────────────────────┘
架构特点
- 函数式设计: 所有业务逻辑以独立函数形式实现,无结构体方法,降低耦合度
- 管理器模式: 使用
sync.Once实现线程安全的单例管理器,统一管理核心依赖 - 按需获取: 通过管理器函数按需获取依赖,避免链式传递,代码更清晰
- 自动迁移: 使用 GORM AutoMigrate 自动管理数据库表结构
- 高性能: 使用 jsoniter 替代标准库 json,提升序列化性能
核心模块
-
认证模块 (
internal/handler/auth_handler.go)- JWT令牌生成和验证(通过
auth.MustGetJWTService()获取) - bcrypt密码加密
- 邮箱验证码注册
- 密码重置功能
- 登录日志记录(支持用户名/邮箱登录)
- JWT令牌生成和验证(通过
-
用户模块 (
internal/handler/user_handler.go)- 用户信息管理
- 头像上传(预签名URL,通过
storage.MustGetClient()获取) - 密码修改(需原密码验证)
- 邮箱更换(需验证码)
- 积分系统
-
邮箱验证模块 (
internal/service/verification_service.go)- 验证码生成(6位数字)
- 验证码存储(Redis,10分钟有效期,通过
redis.MustGetClient()获取) - 发送频率限制(1分钟)
- 邮件发送(HTML格式,通过
email.MustGetService()获取)
-
材质模块 (
internal/handler/texture_handler.go)- 材质上传(预签名URL)
- 材质搜索和收藏
- Hash去重
- 下载统计
-
档案模块 (
internal/handler/profile_handler.go)- Minecraft角色管理
- RSA密钥生成(RSA-2048)
- 活跃状态管理
- 档案数量限制
-
管理器模块 (
pkg/*/manager.go)- 数据库管理器:
database.MustGetDB()- 线程安全的数据库连接 - 日志管理器:
logger.MustGetLogger()- 结构化日志实例 - JWT管理器:
auth.MustGetJWTService()- JWT服务实例 - Redis管理器:
redis.MustGetClient()- Redis客户端 - 邮件管理器:
email.MustGetService()- 邮件服务 - 存储管理器:
storage.MustGetClient()- 对象存储客户端 - 配置管理器:
config.MustGetConfig()- 应用配置
- 数据库管理器:
技术特性
-
架构优势:
- 面向过程的函数式设计,代码简洁清晰
- 单例管理器模式,线程安全的依赖管理
- 按需获取依赖,避免链式传递
- 自动数据库迁移(AutoMigrate)
-
安全性:
- bcrypt密码加密、JWT令牌认证
- 邮箱验证码(注册/重置密码/更换邮箱)
- Casbin RBAC权限控制
- 频率限制(防暴力破解)
-
性能:
- jsoniter 高性能JSON序列化(替代标准库)
- PostgreSQL索引优化
- Redis缓存(验证码、会话等)
- 预签名URL减轻服务器压力
- 连接池管理
-
可靠性:
- 事务保证数据一致性
- 完整的错误处理和日志记录
- 优雅关闭和资源清理
- 对象存储连接失败时服务仍可启动
-
可扩展:
- 清晰的函数式架构
- 管理器模式统一管理依赖
- 环境变量配置(便于容器化)
-
审计:
- 登录日志(成功/失败)
- 操作审计
- 下载记录
开发指南
代码结构
cmd/server/- 应用入口,初始化服务internal/handler/- HTTP请求处理internal/service/- 业务逻辑实现internal/repository/- 数据库操作internal/model/- 数据模型定义internal/types/- 请求/响应类型定义internal/middleware/- 中间件(JWT、CORS、日志等)pkg/- 可复用的公共库
开发规范
- 代码风格: 遵循Go官方代码规范,使用
gofmt格式化 - 架构模式: 使用函数式设计,避免不必要的结构体和方法
- 依赖管理: 通过管理器函数获取依赖(如
database.MustGetDB()),避免链式传递 - 错误处理: 使用统一的错误响应格式 (
model.NewErrorResponse) - 日志记录: 使用 Zap 结构化日志,通过
logger.MustGetLogger()获取实例 - JSON序列化: 使用 jsoniter 替代标准库 json,提升性能
- RESTful API: 遵循 REST 设计原则,合理使用HTTP方法
添加新功能
- 在
internal/model/定义数据模型(GORM会自动迁移) - 在
internal/repository/实现数据访问函数(使用database.MustGetDB()获取数据库) - 在
internal/service/实现业务逻辑函数(按需使用管理器获取依赖) - 在
internal/handler/实现HTTP处理函数(使用管理器获取logger、jwtService等) - 在
internal/handler/routes.go注册路由
示例:
// Repository层
func FindUserByID(id uint) (*model.User, error) {
db := database.MustGetDB()
var user model.User
err := db.First(&user, id).Error
return &user, err
}
// Service层
func GetUserProfile(userID uint) (*model.User, error) {
logger := logger.MustGetLogger()
user, err := repository.FindUserByID(userID)
if err != nil {
logger.Error("获取用户失败", zap.Error(err))
return nil, err
}
return user, nil
}
// Handler层
func GetUserProfile(c *gin.Context) {
logger := logger.MustGetLogger()
jwtService := auth.MustGetJWTService()
// ... 处理逻辑
}
部署
本地开发
# 安装依赖
go mod download
# 配置环境变量(创建.env文件或直接export)
cp .env.example .env
# 编辑 .env 文件
# 启动服务
# 方式1: 使用启动脚本
./start.sh # Linux/Mac
start.bat # Windows
# 方式2: 直接运行
go run cmd/server/main.go
首次启动:
- 会自动执行数据库迁移(AutoMigrate),创建所有表结构
- 如果对象存储未配置,会记录警告但服务仍可启动
- 检查日志确认所有服务初始化成功
生产部署
# 构建二进制文件
go build -o carrotskin-server cmd/server/main.go
# 运行服务
./carrotskin-server
Docker部署
# 构建镜像
docker build -t carrotskin-backend:latest .
# 启动服务
docker-compose up -d
故障排查
常见问题
-
数据库连接失败
- 检查
.env中的数据库配置(DATABASE_HOST,DATABASE_PORT,DATABASE_USERNAME,DATABASE_PASSWORD,DATABASE_NAME) - 确认PostgreSQL服务已启动
- 验证数据库用户权限
- 确认数据库已创建:
createdb carrotskin或psql -c "CREATE DATABASE carrotskin;" - 检查数据库迁移日志,确认表结构创建成功
- 检查
-
Redis连接失败
- 检查Redis服务是否运行:
redis-cli ping - 验证
.env中的Redis配置 - 确认Redis密码是否正确
- 检查防火墙规则
- 检查Redis服务是否运行:
-
RustFS/MinIO连接失败
- 检查存储服务是否运行
- 验证访问密钥是否正确(
RUSTFS_ACCESS_KEY,RUSTFS_SECRET_KEY) - 确认存储桶是否已创建(
RUSTFS_BUCKET_TEXTURES,RUSTFS_BUCKET_AVATARS) - 检查网络连接和端口(
RUSTFS_ENDPOINT) - 注意: 如果对象存储连接失败,服务仍可启动,但上传功能不可用
-
邮件发送失败
- 检查
EMAIL_ENABLED=true - 验证SMTP服务器地址和端口
- 确认邮箱用户名和密码正确
- 检查邮件服务商是否需要开启SMTP
- 查看日志获取详细错误信息
- 检查
-
验证码相关问题
- 验证码过期(10分钟有效期)
- 发送过于频繁(1分钟限制)
- Redis存储失败(检查Redis连接)
- 邮件未收到(检查垃圾邮件)
-
JWT验证失败
- 检查
JWT_SECRET是否配置 - 验证令牌是否过期(默认168小时)
- 确认请求头中包含
Authorization: Bearer <token> - Token格式是否正确
- 检查
调试技巧
- 查看日志
# 实时查看日志
tail -f logs/app.log
# 搜索错误日志
grep "ERROR" logs/app.log
- 测试Redis连接
redis-cli -h localhost -p 6379 -a your_password
> PING
> KEYS *
- 测试数据库连接
psql -h localhost -U postgres -d carrotskin
\dt # 查看所有表
- 测试邮件配置
- 使用Swagger文档测试
/api/v1/auth/send-code接口 - 检查邮件服务商是否限制发送频率
- 使用Swagger文档测试
开发调试
启用详细日志:
# 在 .env 中设置
LOG_LEVEL=debug
SERVER_MODE=debug
Description
Languages
Go
97.4%
Python
2.5%
Dockerfile
0.1%