# 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 兼容对象存储服务 ### 安装和运行 1. **克隆项目** ```bash git clone cd CarrotSkin/backend ``` 2. **安装依赖** ```bash go mod download ``` 3. **配置环境** ```bash # 复制环境变量文件 cp .env.example .env # 编辑 .env 文件配置数据库、RustFS等服务连接信息 ``` **注意**:项目完全依赖 `.env` 文件进行配置,不再使用 YAML 配置文件,便于 Docker 容器化部署。 4. **初始化数据库** ```bash # 创建数据库 createdb carrotskin # 或者使用PostgreSQL客户端 psql -h localhost -U postgres -c "CREATE DATABASE carrotskin;" ``` > 💡 **提示**: 项目使用 GORM 的 `AutoMigrate` 功能自动创建和更新数据库表结构,无需手动执行SQL脚本。首次启动时会自动创建所有表。 5. **运行服务** 方式一:使用启动脚本(推荐) ```bash # Linux/Mac chmod +x start.sh ./start.sh # Windows start.bat ``` 方式二:直接运行 ```bash # 设置环境变量(或使用.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` - 生成头像上传URL - `PUT /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` - 生成材质上传URL - `POST /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 配置文件,便于容器化部署: 1. **配置来源**: 环境变量 或 `.env` 文件 2. **环境变量格式**: 使用下划线分隔,全大写,如 `DATABASE_HOST` 3. **容器部署**: 直接在容器运行时设置环境变量即可 **主要环境变量**: ```bash # 数据库配置 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 │ ← 数据存储层 └──────────────┴──────────────────────┘ ``` ### 架构特点 1. **函数式设计**: 所有业务逻辑以独立函数形式实现,无结构体方法,降低耦合度 2. **管理器模式**: 使用 `sync.Once` 实现线程安全的单例管理器,统一管理核心依赖 3. **按需获取**: 通过管理器函数按需获取依赖,避免链式传递,代码更清晰 4. **自动迁移**: 使用 GORM AutoMigrate 自动管理数据库表结构 5. **高性能**: 使用 jsoniter 替代标准库 json,提升序列化性能 ### 核心模块 1. **认证模块** (`internal/handler/auth_handler.go`) - JWT令牌生成和验证(通过 `auth.MustGetJWTService()` 获取) - bcrypt密码加密 - 邮箱验证码注册 - 密码重置功能 - 登录日志记录(支持用户名/邮箱登录) 2. **用户模块** (`internal/handler/user_handler.go`) - 用户信息管理 - 头像上传(预签名URL,通过 `storage.MustGetClient()` 获取) - 密码修改(需原密码验证) - 邮箱更换(需验证码) - 积分系统 3. **邮箱验证模块** (`internal/service/verification_service.go`) - 验证码生成(6位数字) - 验证码存储(Redis,10分钟有效期,通过 `redis.MustGetClient()` 获取) - 发送频率限制(1分钟) - 邮件发送(HTML格式,通过 `email.MustGetService()` 获取) 4. **材质模块** (`internal/handler/texture_handler.go`) - 材质上传(预签名URL) - 材质搜索和收藏 - Hash去重 - 下载统计 5. **档案模块** (`internal/handler/profile_handler.go`) - Minecraft角色管理 - RSA密钥生成(RSA-2048) - 活跃状态管理 - 档案数量限制 6. **管理器模块** (`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/` - 可复用的公共库 ### 开发规范 1. **代码风格**: 遵循Go官方代码规范,使用 `gofmt` 格式化 2. **架构模式**: 使用函数式设计,避免不必要的结构体和方法 3. **依赖管理**: 通过管理器函数获取依赖(如 `database.MustGetDB()`),避免链式传递 4. **错误处理**: 使用统一的错误响应格式 (`model.NewErrorResponse`) 5. **日志记录**: 使用 Zap 结构化日志,通过 `logger.MustGetLogger()` 获取实例 6. **JSON序列化**: 使用 jsoniter 替代标准库 json,提升性能 7. **RESTful API**: 遵循 REST 设计原则,合理使用HTTP方法 ### 添加新功能 1. 在 `internal/model/` 定义数据模型(GORM会自动迁移) 2. 在 `internal/repository/` 实现数据访问函数(使用 `database.MustGetDB()` 获取数据库) 3. 在 `internal/service/` 实现业务逻辑函数(按需使用管理器获取依赖) 4. 在 `internal/handler/` 实现HTTP处理函数(使用管理器获取logger、jwtService等) 5. 在 `internal/handler/routes.go` 注册路由 **示例**: ```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() // ... 处理逻辑 } ``` ## 部署 ### 本地开发 ```bash # 安装依赖 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),创建所有表结构 - 如果对象存储未配置,会记录警告但服务仍可启动 - 检查日志确认所有服务初始化成功 ### 生产部署 ```bash # 构建二进制文件 go build -o carrotskin-server cmd/server/main.go # 运行服务 ./carrotskin-server ``` ### Docker部署 ```bash # 构建镜像 docker build -t carrotskin-backend:latest . # 启动服务 docker-compose up -d ``` ## 故障排查 ### 常见问题 1. **数据库连接失败** - 检查 `.env` 中的数据库配置(`DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_USERNAME`, `DATABASE_PASSWORD`, `DATABASE_NAME`) - 确认PostgreSQL服务已启动 - 验证数据库用户权限 - 确认数据库已创建:`createdb carrotskin` 或 `psql -c "CREATE DATABASE carrotskin;"` - 检查数据库迁移日志,确认表结构创建成功 2. **Redis连接失败** - 检查Redis服务是否运行:`redis-cli ping` - 验证 `.env` 中的Redis配置 - 确认Redis密码是否正确 - 检查防火墙规则 3. **RustFS/MinIO连接失败** - 检查存储服务是否运行 - 验证访问密钥是否正确(`RUSTFS_ACCESS_KEY`, `RUSTFS_SECRET_KEY`) - 确认存储桶是否已创建(`RUSTFS_BUCKET_TEXTURES`, `RUSTFS_BUCKET_AVATARS`) - 检查网络连接和端口(`RUSTFS_ENDPOINT`) - **注意**: 如果对象存储连接失败,服务仍可启动,但上传功能不可用 4. **邮件发送失败** - 检查 `EMAIL_ENABLED=true` - 验证SMTP服务器地址和端口 - 确认邮箱用户名和密码正确 - 检查邮件服务商是否需要开启SMTP - 查看日志获取详细错误信息 5. **验证码相关问题** - 验证码过期(10分钟有效期) - 发送过于频繁(1分钟限制) - Redis存储失败(检查Redis连接) - 邮件未收到(检查垃圾邮件) 6. **JWT验证失败** - 检查 `JWT_SECRET` 是否配置 - 验证令牌是否过期(默认168小时) - 确认请求头中包含 `Authorization: Bearer ` - Token格式是否正确 ### 调试技巧 1. **查看日志** ```bash # 实时查看日志 tail -f logs/app.log # 搜索错误日志 grep "ERROR" logs/app.log ``` 2. **测试Redis连接** ```bash redis-cli -h localhost -p 6379 -a your_password > PING > KEYS * ``` 3. **测试数据库连接** ```bash psql -h localhost -U postgres -d carrotskin \dt # 查看所有表 ``` 4. **测试邮件配置** - 使用Swagger文档测试 `/api/v1/auth/send-code` 接口 - 检查邮件服务商是否限制发送频率 ### 开发调试 启用详细日志: ```bash # 在 .env 中设置 LOG_LEVEL=debug SERVER_MODE=debug ```