From 5e0c1dd2c14a8d2d591b7b7f94bf0aa5b6ce0c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=91=E8=90=8C=E8=8A=BD?= <3205788256@qq.com> Date: Wed, 24 Jun 2026 21:58:50 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E9=87=8D=E6=9E=84=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E8=BF=81=E7=A7=BB=E4=B8=8E=20nginx=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 1 + .../auth.api.shumengya.top.conf | 0 .../auth.shumengya.top.conf | 0 .../sproutgate-frontend.conf | 0 sproutgate-backend/.codex | 0 sproutgate-backend/build-Linux-amd.bat | 5 -- sproutgate-backend/build-linux-amd64.bat | 7 +- sproutgate-backend/cmd/migrate/main.go | 4 +- sproutgate-backend/docker-compose.yml | 5 ++ sproutgate-backend/internal/database/db.go | 77 +++++++++++++------ sproutgate-backend/后端文档.md | 37 ++++++--- 11 files changed, 91 insertions(+), 45 deletions(-) rename {公网配置 => nginx配置}/auth.api.shumengya.top.conf (100%) rename {公网配置 => nginx配置}/auth.shumengya.top.conf (100%) rename {公网配置 => nginx配置}/sproutgate-frontend.conf (100%) delete mode 100644 sproutgate-backend/.codex delete mode 100644 sproutgate-backend/build-Linux-amd.bat diff --git a/AGENTS.md b/AGENTS.md index 7cd0ed2..c5f49a4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,6 +33,7 @@ ## Security & Configuration Tips - Backend configuration is stored under `sproutgate-backend/data/config/` (admin, auth, email, check-in, registration invites). +- Backend MySQL connection comes only from environment variables (`DB_DSN`, or `DB_HOST`/`DB_PORT`/`DB_USER`/`DB_PASSWORD`/`DB_NAME`); no credentials are hardcoded. Set them in `sproutgate-backend/.env` (gitignored) for local dev — it's auto-loaded on `go run .`. - Frontend API base URL can be set via `sproutgate-frontend/.env` using `VITE_API_BASE`. - Avoid committing real credentials or production tokens; use local overrides for secrets. - API reference lives in `sproutgate-backend/API_DOCS.md` and is served at `GET /api/docs`. Brief JSON overview: `GET /` and `GET /api`. diff --git a/公网配置/auth.api.shumengya.top.conf b/nginx配置/auth.api.shumengya.top.conf similarity index 100% rename from 公网配置/auth.api.shumengya.top.conf rename to nginx配置/auth.api.shumengya.top.conf diff --git a/公网配置/auth.shumengya.top.conf b/nginx配置/auth.shumengya.top.conf similarity index 100% rename from 公网配置/auth.shumengya.top.conf rename to nginx配置/auth.shumengya.top.conf diff --git a/公网配置/sproutgate-frontend.conf b/nginx配置/sproutgate-frontend.conf similarity index 100% rename from 公网配置/sproutgate-frontend.conf rename to nginx配置/sproutgate-frontend.conf diff --git a/sproutgate-backend/.codex b/sproutgate-backend/.codex deleted file mode 100644 index e69de29..0000000 diff --git a/sproutgate-backend/build-Linux-amd.bat b/sproutgate-backend/build-Linux-amd.bat deleted file mode 100644 index 492af48..0000000 --- a/sproutgate-backend/build-Linux-amd.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -setlocal -cd /d "%~dp0" -call "%~dp0build-linux-amd64.bat" -exit /b %errorlevel% diff --git a/sproutgate-backend/build-linux-amd64.bat b/sproutgate-backend/build-linux-amd64.bat index 95c5a91..e952cef 100644 --- a/sproutgate-backend/build-linux-amd64.bat +++ b/sproutgate-backend/build-linux-amd64.bat @@ -22,15 +22,16 @@ echo [INFO] Working directory: %CD% echo [INFO] Building %APP_NAME% for linux amd64... echo [INFO] Output: %OUTPUT_FILE% -set "CGO_ENABLED=0" -set "GOOS=linux" -set "GOARCH=amd64" set "GOCACHE=%GOCACHE_DIR%" echo [INFO] Regenerating Swagger docs (swag)... go run github.com/swaggo/swag/cmd/swag@latest init -g main.go -o docs --parseInternal if errorlevel 1 goto fail_build +set "CGO_ENABLED=0" +set "GOOS=linux" +set "GOARCH=amd64" + go build -trimpath -ldflags "-s -w" -o "%OUTPUT_FILE%" . if errorlevel 1 goto fail_build diff --git a/sproutgate-backend/cmd/migrate/main.go b/sproutgate-backend/cmd/migrate/main.go index 8529338..7351a97 100644 --- a/sproutgate-backend/cmd/migrate/main.go +++ b/sproutgate-backend/cmd/migrate/main.go @@ -6,8 +6,8 @@ // // 环境变量(与主程序相同): // -// APP_ENV=production 使用生产数据库(默认使用开发测试库) -// DB_DSN 自定义 DSN(优先级最高) +// DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME 连接参数(DB_NAME 默认 sproutgate) +// DB_DSN 自定义 DSN(优先级最高) package main import ( diff --git a/sproutgate-backend/docker-compose.yml b/sproutgate-backend/docker-compose.yml index 4f16f99..2217a99 100644 --- a/sproutgate-backend/docker-compose.yml +++ b/sproutgate-backend/docker-compose.yml @@ -8,6 +8,11 @@ services: environment: PORT: "8080" DATA_DIR: /data + DB_HOST: ${DB_HOST} + DB_PORT: ${DB_PORT:-3306} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_NAME: ${DB_NAME:-sproutgate} volumes: - ./data:/data ports: diff --git a/sproutgate-backend/internal/database/db.go b/sproutgate-backend/internal/database/db.go index cd72c6b..e858ab6 100644 --- a/sproutgate-backend/internal/database/db.go +++ b/sproutgate-backend/internal/database/db.go @@ -4,12 +4,40 @@ import ( "fmt" "log" "os" + "strings" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" ) +// loadDotEnv 在当前工作目录查找 .env 文件并加载到进程环境变量中(已存在的变量不覆盖)。 +// 仅用于本地开发场景:生产部署通过 docker-compose / 容器环境变量直接注入,没有 .env 文件时静默跳过。 +func loadDotEnv() { + data, err := os.ReadFile(".env") + if err != nil { + return + } + for _, line := range strings.Split(string(data), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + key, value, ok := strings.Cut(line, "=") + if !ok { + continue + } + key = strings.TrimSpace(key) + if key == "" { + continue + } + if _, exists := os.LookupEnv(key); exists { + continue + } + os.Setenv(key, strings.TrimSpace(value)) + } +} + // DBConfig holds MySQL connection parameters. type DBConfig struct { Host string @@ -24,39 +52,42 @@ func (c DBConfig) DSN() string { c.User, c.Password, c.Host, c.Port, c.DBName) } -func devConfig() DBConfig { - return DBConfig{ - Host: "10.1.1.100", - Port: "3306", - User: "sproutgate-test", - Password: "sproutgate-test", - DBName: "sproutgate-test", +// envConfig 从环境变量读取连接参数。Host/User/Password 没有内置默认值,必须由 +// 部署环境(本地 shell、.env、docker-compose 等)显式提供;DBName 默认统一为 +// "sproutgate",开发和生产环境共用同一个库名。 +func envConfig() (DBConfig, error) { + host := os.Getenv("DB_HOST") + user := os.Getenv("DB_USER") + password := os.Getenv("DB_PASSWORD") + if host == "" || user == "" || password == "" { + return DBConfig{}, fmt.Errorf("缺少数据库环境变量,请设置 DB_HOST/DB_USER/DB_PASSWORD(或直接设置 DB_DSN)") } -} -func prodConfig() DBConfig { - return DBConfig{ - Host: "192.168.1.100", - Port: "3306", - User: "sproutgate", - Password: "sproutgate", - DBName: "sproutgate", + port := os.Getenv("DB_PORT") + if port == "" { + port = "3306" } + dbName := os.Getenv("DB_NAME") + if dbName == "" { + dbName = "sproutgate" + } + + return DBConfig{Host: host, Port: port, User: user, Password: password, DBName: dbName}, nil } // Open 根据环境变量打开数据库连接。 -// 优先级:DB_DSN > APP_ENV(production/prod -> 生产库) > 默认开发库 +// 优先级:DB_DSN(完整自定义连接串)> DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME func Open() (*gorm.DB, error) { + loadDotEnv() + dsn := os.Getenv("DB_DSN") if dsn == "" { - env := os.Getenv("APP_ENV") - if env == "production" || env == "prod" { - dsn = prodConfig().DSN() - log.Println("[database] 使用生产数据库 192.168.1.100:3306/sproutgate") - } else { - dsn = devConfig().DSN() - log.Println("[database] 使用开发数据库 10.1.1.100:3306/sproutgate-test") + cfg, err := envConfig() + if err != nil { + return nil, err } + dsn = cfg.DSN() + log.Printf("[database] 使用数据库 %s:%s/%s", cfg.Host, cfg.Port, cfg.DBName) } else { log.Println("[database] 使用自定义 DB_DSN") } diff --git a/sproutgate-backend/后端文档.md b/sproutgate-backend/后端文档.md index c40a5ce..bdf938d 100644 --- a/sproutgate-backend/后端文档.md +++ b/sproutgate-backend/后端文档.md @@ -15,7 +15,7 @@ | 路径 | 说明 | |------|------| | `main.go` | 入口:连接数据库、初始化 `Store`、注册路由 | -| `internal/database/` | MySQL 连接与环境选择(`DB_DSN` / `APP_ENV`) | +| `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 模型与业务方法 | @@ -25,24 +25,35 @@ ## 环境与数据库 -连接字符串优先级:**`DB_DSN` > 内置规则**。 +代码中**不再内置任何数据库地址或账号密码**,连接参数完全来自环境变量,连接字符串优先级:**`DB_DSN` > `DB_HOST`/`DB_PORT`/`DB_USER`/`DB_PASSWORD`/`DB_NAME`**。 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` +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` | 影响默认 MySQL 选择与 `/api/health` 返回的 `env` | 空则 health 中为 `development` | +| `APP_ENV` | 仅影响 `/api/health` 返回的 `env` 字段,不再决定数据库选择 | 空则 health 中为 `development` | | `GIN_MODE` | `release` 时 GORM 日志级别更安静(警告级) | debug 模式 | -| `DB_DSN` | 完整 MySQL DSN,覆盖上述内置地址 | 未设置 | +| `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` | -**建议**:生产部署时设置 `APP_ENV=production`,并确保 MySQL 防火墙与账号权限正确;敏感连接信息也可只通过 `DB_DSN` 注入,无需改代码。 +**建议**:生产部署通过 `docker-compose.yml` 旁的 `.env`(同样被 `.gitignore` 忽略)注入 `DB_HOST`/`DB_USER`/`DB_PASSWORD`,不要把真实账号密码写进任何会提交到仓库的文件。 ## 数据库表(AutoMigrate) @@ -66,16 +77,18 @@ 在 **`sproutgate-backend`** 目录下: ```bash -# 导入到当前环境对应的库(默认开发库,除非设置 APP_ENV 或 DB_DSN) +# 导入到 .env(或当前环境变量)指向的库 go run ./cmd/migrate --data-dir ./data ``` -Windows PowerShell 示例(写入生产库): +Windows PowerShell 示例(临时指定生产库连接参数): ```powershell -$env:APP_ENV = "production" +$env:DB_HOST = "192.168.1.100" +$env:DB_USER = "sproutgate" +$env:DB_PASSWORD = "<生产密码>" go run ./cmd/migrate --data-dir ./data -Remove-Item Env:APP_ENV # 可选:清除变量,避免影响本机其它命令 +Remove-Item Env:DB_HOST, Env:DB_USER, Env:DB_PASSWORD # 可选:清除变量,避免影响本机其它命令 ``` 迁移内容:`data/config/*.json`(写入 `app_configs` 与 `invite_codes`)、`data/users/*.json`(写入 `users`)。对已存在主键执行 **UPSERT**:同账号、同配置键会更新为迁移文件中的值。