# 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` / `APP_ENV`) | | `internal/handlers/` | HTTP 处理:认证、资料、签到、公开页、管理端等 | | `internal/models/` | 领域模型(用户、待激活、重置密码、辅助邮箱等) | | `internal/storage/` | 持久化:`Store` + GORM 模型与业务方法 | | `internal/auth/` | JWT 签发与校验 | | `internal/email/` | 发信 | | `cmd/migrate/` | 一次性工具:将旧版 JSON `data/` 导入 MySQL | ## 环境与数据库 连接字符串优先级:**`DB_DSN` > 内置规则**。 1. **若设置 `DB_DSN`**:直接使用该完整 DSN(适合 CI、容器或临时切换)。 2. **否则**:根据 `APP_ENV` 选择内置库: - `APP_ENV=production` 或 `prod` → 生产库:`192.168.1.100:3306` / 库名 `sproutgate` / 用户 `sproutgate` - 未设置或其它值 → 开发/测试库:`10.1.1.100:3306` / 库名 `sproutgate-test` / 用户 `sproutgate-test` 其它常用环境变量: | 变量 | 说明 | 默认 | |------|------|------| | `PORT` | HTTP 监听端口 | `8080` | | `APP_ENV` | 影响默认 MySQL 选择与 `/api/health` 返回的 `env` | 空则 health 中为 `development` | | `GIN_MODE` | `release` 时 GORM 日志级别更安静(警告级) | debug 模式 | | `DB_DSN` | 完整 MySQL DSN,覆盖上述内置地址 | 未设置 | | `GEO_LOOKUP_URL` | `GET /api/auth/me` 未带 `X-Visit-Location` 时,服务端按 IP 请求该基址反查展示地理位置(实现见 `internal/clientgeo`,会拼接 `?ip=`) | 默认 `https://cf-ip-geo.smyhub.com/api` | **建议**:生产部署时设置 `APP_ENV=production`,并确保 MySQL 防火墙与账号权限正确;敏感连接信息也可只通过 `DB_DSN` 注入,无需改代码。 ## 数据库表(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 # 导入到当前环境对应的库(默认开发库,除非设置 APP_ENV 或 DB_DSN) go run ./cmd/migrate --data-dir ./data ``` Windows PowerShell 示例(写入生产库): ```powershell $env:APP_ENV = "production" go run ./cmd/migrate --data-dir ./data Remove-Item Env:APP_ENV # 可选:清除变量,避免影响本机其它命令 ``` 迁移内容:`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 账号权限。