# SproutGate 后端文档 ## 技术栈 - **语言**:Go 1.20+ - **Web 框架**:Gin;跨域中间件 **`github.com/gin-contrib/cors`** - **数据存储**:MySQL(通过 GORM + `gorm.io/driver/mysql`) - **JWT**:`github.com/golang-jwt/jwt/v5` - **密码哈希**:`golang.org/x/crypto/bcrypt` 业务数据与配置均保存在 MySQL 中,**不再使用** `data/users/*.json` 与 `data/config/*.json` 作为运行时数据源。仓库中的 `data/` 仅可作迁移脚本输入或本地备份参考。 ## 目录结构(要点) | 路径 | 说明 | |------|------| | `main.go` | 入口:连接数据库、初始化 `Store`、注册路由 | | `internal/database/` | MySQL 连接(`DB_DSN` 或 `DB_HOST`/`DB_USER`/`DB_PASSWORD`/`DB_NAME`/`DB_PORT`,支持 `.env` 本地加载) | | `internal/handlers/` | HTTP 处理:认证、资料、签到、公开页、管理端等 | | `internal/models/` | 领域模型(用户、待激活、重置密码、辅助邮箱等) | | `internal/storage/` | 持久化:`Store` + GORM 模型与业务方法 | | `internal/auth/` | JWT 签发与校验 | | `internal/email/` | 发信 | | `cmd/migrate/` | 一次性工具:将旧版 JSON `data/` 导入 MySQL | ## 环境与数据库 代码中**不再内置任何数据库地址或账号密码**,连接参数完全来自环境变量,连接字符串优先级:**`DB_DSN` > `DB_HOST`/`DB_PORT`/`DB_USER`/`DB_PASSWORD`/`DB_NAME`**。 1. **若设置 `DB_DSN`**:直接使用该完整 DSN(适合 CI、容器或临时切换)。 2. **否则**:用 `DB_HOST`/`DB_USER`/`DB_PASSWORD` 拼接 DSN,`DB_HOST`/`DB_USER`/`DB_PASSWORD` 三者缺一即报错退出;`DB_PORT` 默认 `3306`,`DB_NAME` 默认 `sproutgate`(开发、生产统一用这个库名,仅 host/账号不同)。 本地开发时,在 `sproutgate-backend/.env`(已在 `.gitignore` 中忽略,不会提交)里写: ``` DB_HOST=10.1.1.100 DB_PORT=3306 DB_USER=sproutgate-test DB_PASSWORD=sproutgate-test DB_NAME=sproutgate ``` `go run .` / `go run ./cmd/migrate` 启动时会自动从当前目录读取并加载 `.env`(已存在的环境变量不会被覆盖);生产部署通过容器/`docker-compose` 环境变量注入,不依赖 `.env` 文件。 其它常用环境变量: | 变量 | 说明 | 默认 | |------|------|------| | `PORT` | HTTP 监听端口 | `8080` | | `APP_ENV` | 仅影响 `/api/health` 返回的 `env` 字段,不再决定数据库选择 | 空则 health 中为 `development` | | `GIN_MODE` | `release` 时 GORM 日志级别更安静(警告级) | debug 模式 | | `DB_DSN` | 完整 MySQL DSN,覆盖 `DB_HOST` 等单项配置 | 未设置 | | `DB_HOST` / `DB_PORT` / `DB_USER` / `DB_PASSWORD` / `DB_NAME` | MySQL 连接参数;`DB_HOST`/`DB_USER`/`DB_PASSWORD` 必填,无内置默认值 | `DB_PORT=3306`,`DB_NAME=sproutgate` | | `GEO_LOOKUP_URL` | `GET /api/auth/me` 未带 `X-Visit-Location` 时,服务端按 IP 请求该基址反查展示地理位置(实现见 `internal/clientgeo`,会拼接 `?ip=`) | 默认 `https://cf-ip-geo.smyhub.com/api` | **建议**:生产部署通过 `docker-compose.yml` 旁的 `.env`(同样被 `.gitignore` 忽略)注入 `DB_HOST`/`DB_USER`/`DB_PASSWORD`,不要把真实账号密码写进任何会提交到仓库的文件。 ## 数据库表(AutoMigrate) 应用启动与 `migrate` 工具均会同步下列表结构(GORM `AutoMigrate`): | 表名 | 用途 | |------|------| | `users` | 用户主数据;签到/访问时间列表、`auth_clients` 等以 JSON 文本列存储 | | `pending_users` | 注册邮箱验证流程中的待激活用户 | | `password_resets` | 忘记密码验证码 | | `secondary_email_verifications` | 绑定辅助邮箱验证码 | | `app_configs` | 键值配置:`admin`、`auth`、`email`、`checkin`、`registration`(JSON) | | `invite_codes` | 注册邀请码 | | `profile_likes` | 公开用户主页点赞明细(点赞者、被赞者、自然日等) | | `profile_like_daily_quota` | 点赞者当日已用额度(与代码常量 `MaxProfileLikesPerDay` 配合) | 管理员令牌、JWT Secret、邮件 SMTP、签到奖励、是否强制邀请码等,均从 `app_configs` / `invite_codes` 读写,首次无记录时由 `Store` 按逻辑补全默认项。 ## 从旧 JSON 迁移到 MySQL 在 **`sproutgate-backend`** 目录下: ```bash # 导入到 .env(或当前环境变量)指向的库 go run ./cmd/migrate --data-dir ./data ``` Windows PowerShell 示例(临时指定生产库连接参数): ```powershell $env:DB_HOST = "192.168.1.100" $env:DB_USER = "sproutgate" $env:DB_PASSWORD = "<生产密码>" go run ./cmd/migrate --data-dir ./data Remove-Item Env:DB_HOST, Env:DB_USER, Env:DB_PASSWORD # 可选:清除变量,避免影响本机其它命令 ``` 迁移内容:`data/config/*.json`(写入 `app_configs` 与 `invite_codes`)、`data/users/*.json`(写入 `users`)。对已存在主键执行 **UPSERT**:同账号、同配置键会更新为迁移文件中的值。 ## HTTP 路由速览 - **`GET /`**、**`GET /api`**:API 简要说明 JSON(`main.go` 内嵌字段,含 `version`、`routePrefixes` 等)。**当前未注册**单独返回 Markdown 的 `/api/docs` 路由;对外长文档见仓库根目录 **`萌芽账户认证中心-第三方应用API接入文档.md`**。 - **`GET /api/health`**:`{ "status": "ok", "env": "" }`。 - **`/api/auth/*`**:登录、注册、邮箱验证、忘记/重置密码、辅助邮箱、令牌校验、`/me`、签到、更新资料等;可选请求头 `X-Auth-Client`、`X-Auth-Client-Name`(记录第三方应用接入)。 - **`/api/public/*`**: - **`GET /api/public/users`**:公开用户目录(未封禁;默认按 `createdAt` 升序)。 - **`GET /api/public/users/:account`**:公开资料 + 累计赞数;若带合法 Bearer,可附加「是否已赞今日」「当日剩余可点赞人数」等浏览者上下文。 - **`POST /api/public/users/:account/like`**:登录用户给指定主页点赞(不能赞自己;每人每主页每日一次;每自然日每名用户最多给 **5** 位不同用户点赞,常量见 `internal/storage/profile_likes.go`)。 - **`GET /api/public/registration-policy`**:是否强制邀请码等。 - **`/api/admin/*`**:需 **`X-Admin-Token`**(或 Query `token`):用户 CRUD、签到配置、注册策略与邀请码管理。 允许的 CORS 自定义头包含:`Authorization`、`X-Admin-Token`、`X-Visit-Ip`、`X-Visit-Location`、`X-Auth-Client`、`X-Auth-Client-Name` 等。 ## 本地开发命令 ```bash cd sproutgate-backend go mod tidy go run . ``` 默认监听 `:8080`。前端开发时请将 `VITE_API_BASE` 指向本服务(详见仓库根目录下 `sproutgate-frontend/前端文档.md`)。 ## 安全提示 - 勿将生产 `DB_DSN`、SMTP 密码、真实 `admin` 令牌提交到版本库。 - 旧版 `data/config/email.json` 等若含真实口令,迁移后应以环境或运维密钥管理为准,并限制数据库与 SMTP 账号权限。