feat: backend env config upgrade - multi-env (dev/prod), DB_* support, Docker compatible
Some checks failed
Build and Deploy / test-backend (push) Has been cancelled
Build and Deploy / build-backend (push) Has been cancelled
Build and Deploy / build-admin (push) Has been cancelled
Deploy to Production / build-backend (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
Some checks failed
Build and Deploy / test-backend (push) Has been cancelled
Build and Deploy / build-backend (push) Has been cancelled
Build and Deploy / build-admin (push) Has been cancelled
Deploy to Production / build-backend (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
6
backend/.env.dev
Normal file
6
backend/.env.dev
Normal file
@@ -0,0 +1,6 @@
|
||||
# Local development
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_USER=wecom
|
||||
DB_PASSWORD=password
|
||||
DB_NAME=wecom_ai
|
||||
10
backend/.env.example
Normal file
10
backend/.env.example
Normal file
@@ -0,0 +1,10 @@
|
||||
# Database (optional: set DATABASE_URL directly, or use DB_* below)
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_USER=wecom
|
||||
DB_PASSWORD=password
|
||||
DB_NAME=wecom
|
||||
DATABASE_URL=
|
||||
|
||||
# Sync URL for Alembic (optional; default: built from DB_*)
|
||||
# DATABASE_URL_SYNC=
|
||||
@@ -5,13 +5,13 @@ from sqlalchemy import engine_from_config
|
||||
from sqlalchemy.engine import Connection
|
||||
from sqlalchemy import pool
|
||||
|
||||
from app.config import settings
|
||||
from app.models import Base
|
||||
from config.settings import DATABASE_URL_SYNC
|
||||
|
||||
config = context.config
|
||||
if config.config_file_name is not None:
|
||||
fileConfig(config.config_file_name)
|
||||
config.set_main_option("sqlalchemy.url", settings.database_url_sync)
|
||||
config.set_main_option("sqlalchemy.url", DATABASE_URL_SYNC)
|
||||
|
||||
target_metadata = Base.metadata
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
# 数据库 URL 由 config.settings 提供(环境变量优先,支持 DB_* 拼接,容器兼容)
|
||||
from config.settings import DATABASE_URL, DATABASE_URL_SYNC
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
|
||||
|
||||
api_host: str = "0.0.0.0"
|
||||
api_port: int = 8000
|
||||
database_url: str = "postgresql+asyncpg://wecom:wecom_secret@localhost:5432/wecom_ai"
|
||||
database_url_sync: str = "postgresql://wecom:wecom_secret@localhost:5432/wecom_ai"
|
||||
database_url: str = DATABASE_URL
|
||||
database_url_sync: str = DATABASE_URL_SYNC
|
||||
|
||||
jwt_secret: str = "change-me"
|
||||
jwt_algorithm: str = "HS256"
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
|
||||
|
||||
api_host: str = "0.0.0.0"
|
||||
api_port: int = 8000
|
||||
database_url: str = "postgresql+asyncpg://wecom:wecom_secret@localhost:5432/wecom_ai"
|
||||
database_url_sync: str = "postgresql://wecom:wecom_secret@localhost:5432/wecom_ai"
|
||||
jwt_secret: str = "change-me"
|
||||
jwt_algorithm: str = "HS256"
|
||||
jwt_expire_minutes: int = 60
|
||||
wecom_corp_id: str = ""
|
||||
wecom_agent_id: str = ""
|
||||
wecom_secret: str = ""
|
||||
wecom_token: str = ""
|
||||
wecom_encoding_aes_key: str = ""
|
||||
wecom_api_base: str = "https://qyapi.weixin.qq.com"
|
||||
wecom_api_timeout: int = 10
|
||||
wecom_api_retries: int = 2
|
||||
log_level: str = "INFO"
|
||||
log_json: bool = True
|
||||
|
||||
|
||||
settings = Settings()
|
||||
1
backend/config/__init__.py
Normal file
1
backend/config/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Config package: env-based settings, DATABASE_URL from env or DB_*.
|
||||
48
backend/config/settings.py
Normal file
48
backend/config/settings.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
统一配置加载:环境变量优先,fallback 到 .env,无 DATABASE_URL 时按 DB_* 拼接。
|
||||
支持多环境(dev/prod)、容器(DB_HOST=db)、向后兼容。
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# 环境变量优先;fallback 到 .env(不覆盖已存在的系统变量)
|
||||
def _load_dotenv():
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
except ImportError:
|
||||
return
|
||||
env = os.getenv("ENV", "").lower()
|
||||
base = Path(__file__).resolve().parent.parent
|
||||
if env == "prod":
|
||||
load_dotenv(base / ".env.prod", override=False)
|
||||
elif env == "dev":
|
||||
load_dotenv(base / ".env.dev", override=False)
|
||||
load_dotenv(base / ".env", override=False)
|
||||
|
||||
|
||||
_load_dotenv()
|
||||
|
||||
|
||||
def build_database_url_async() -> str:
|
||||
"""拼接异步数据库 URL(postgresql+asyncpg)。"""
|
||||
user = os.getenv("DB_USER", "wecom")
|
||||
password = os.getenv("DB_PASSWORD", "password")
|
||||
host = os.getenv("DB_HOST", "localhost")
|
||||
port = os.getenv("DB_PORT", "5432")
|
||||
db = os.getenv("DB_NAME", "wecom_ai")
|
||||
return f"postgresql+asyncpg://{user}:{password}@{host}:{port}/{db}"
|
||||
|
||||
|
||||
def build_database_url_sync() -> str:
|
||||
"""拼接同步数据库 URL(postgresql,Alembic/psycopg2)。"""
|
||||
user = os.getenv("DB_USER", "wecom")
|
||||
password = os.getenv("DB_PASSWORD", "password")
|
||||
host = os.getenv("DB_HOST", "localhost")
|
||||
port = os.getenv("DB_PORT", "5432")
|
||||
db = os.getenv("DB_NAME", "wecom_ai")
|
||||
return f"postgresql://{user}:{password}@{host}:{port}/{db}"
|
||||
|
||||
|
||||
# 优先使用环境变量,否则按 DB_* 拼接(向后兼容)
|
||||
DATABASE_URL: str = os.getenv("DATABASE_URL") or build_database_url_async()
|
||||
DATABASE_URL_SYNC: str = os.getenv("DATABASE_URL_SYNC") or build_database_url_sync()
|
||||
59
backend/docs/config.md
Normal file
59
backend/docs/config.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# 环境配置说明
|
||||
|
||||
## 多环境与加载顺序
|
||||
|
||||
- **系统环境变量** 优先于任何文件。
|
||||
- **config/settings.py** 会按 `ENV` 选择 dotenv 文件,再统一从环境变量或 `DB_*` 拼接数据库 URL。
|
||||
- 若已设置 `DATABASE_URL` / `DATABASE_URL_SYNC`,则直接使用,否则用 `DB_HOST`、`DB_PORT`、`DB_USER`、`DB_PASSWORD`、`DB_NAME` 自动拼接。
|
||||
|
||||
## 环境与文件
|
||||
|
||||
| 环境 | 建议使用的文件 | 说明 |
|
||||
|------|----------------|------|
|
||||
| **dev** | `.env.dev` | 本地开发,`DB_HOST=localhost` |
|
||||
| **prod / Docker** | `.env.prod` 或 compose 传入的 env | 容器内 `DB_HOST=db`(compose 服务名) |
|
||||
| 任意 | `.env` | 可选,可覆盖部分变量 |
|
||||
|
||||
## 使用方式
|
||||
|
||||
### 本地开发(dev)
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
cp .env.example .env.dev # 首次可复制后按需修改
|
||||
# 可选:设置 ENV=dev 以显式加载 .env.dev
|
||||
export ENV=dev
|
||||
# 或直接依赖系统已设置的 DB_* / DATABASE_URL
|
||||
alembic upgrade head
|
||||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
使用 `.env.dev` 时,默认 `DB_HOST=localhost`,数据库连接本机 PostgreSQL。
|
||||
|
||||
### Docker / 生产(prod)
|
||||
|
||||
- 在 **docker-compose** 或 **k8s** 中通过环境变量传入配置,不要写死 localhost。
|
||||
- 示例:在 compose 中为 backend 服务设置:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- DB_HOST=db
|
||||
- DB_PORT=5432
|
||||
- DB_USER=wecom
|
||||
- DB_PASSWORD=xxx
|
||||
- DB_NAME=wecom_ai
|
||||
```
|
||||
|
||||
或使用 `env_file: .env.prod`(`.env.prod` 中 `DB_HOST=db`)。
|
||||
|
||||
- 容器内应用和 Alembic 迁移都会使用上述变量;不再依赖 localhost。
|
||||
|
||||
### CI/CD
|
||||
|
||||
- 在流水线中设置 `DB_HOST`、`DB_PORT`、`DB_USER`、`DB_PASSWORD`、`DB_NAME`,或直接设置 `DATABASE_URL` / `DATABASE_URL_SYNC`。
|
||||
- 无需在代码或镜像中写死数据库地址。
|
||||
|
||||
## 向后兼容
|
||||
|
||||
- 若仍在使用旧版只配置 `DATABASE_URL` 的 `.env`,无需修改,会继续生效。
|
||||
- 未设置 `DATABASE_URL` 时,将使用 `DB_*` 拼接;未设置 `DB_NAME` 时默认库名为 `wecom_ai`。
|
||||
@@ -4,8 +4,8 @@
|
||||
# 镜像标签
|
||||
TAG=latest
|
||||
|
||||
# 数据库配置
|
||||
DATABASE_URL=postgresql://postgres:CHANGE_ME@db:5432/wecom_ai
|
||||
# 数据库配置(backend 也支持仅设置 DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME,自动拼接)
|
||||
DATABASE_URL=postgresql+asyncpg://postgres:CHANGE_ME@db:5432/wecom_ai
|
||||
DATABASE_URL_SYNC=postgresql://postgres:CHANGE_ME@db:5432/wecom_ai
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=CHANGE_ME
|
||||
|
||||
@@ -61,8 +61,13 @@ services:
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
# 注意:镜像构建时已经包含了配置,无需挂载
|
||||
# 如果需要覆盖配置,取消下面的注释并确保 nginx.conf 路径正确
|
||||
# volumes:
|
||||
# - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
environment:
|
||||
- NGINX_HOST=_
|
||||
- NGINX_PORT=80
|
||||
depends_on:
|
||||
- backend
|
||||
- admin
|
||||
|
||||
@@ -44,7 +44,7 @@ services:
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./deploy/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./deploy/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
depends_on:
|
||||
- backend
|
||||
- admin
|
||||
|
||||
Reference in New Issue
Block a user