# CTMS 分支环境安装配置指南 本文定义 `dev`、`main`、`release` 三类分支对应的推荐部署环境、配置文件、初始化步骤与验证命令。分支本身不会自动切换运行模式,实际模式由后端环境变量 `ENV` 决定。 ## 分支与环境映射 | 分支 | 分支定位 | 推荐环境 | 后端 `ENV` | 用途 | | --- | --- | --- | --- | --- | | `dev` | 日常开发与集成 | 开发环境 | `development` | 功能开发、联调、自测、内部集成 | | `main` | 下一版本候选 | 预发布 / 验收环境 | `production` | 回归测试、验收、发布候选验证 | | `release` | 当前稳定生产线 | 生产环境 | `production` | 正式生产部署、生产 hotfix | 推广路径保持为: ```text feature/* -> dev -> main -> release ``` 不要把 `release` 当作日常开发分支使用。`main` 应只接收已经准备进入候选版本范围的变更。 ## 公共前置条件 所有环境都需要: - Docker 与 Docker Compose - 可写的 `pg_data/` 数据目录 - 端口 `8888`、`8000`、`5432` 未被占用 - 后端镜像可安装 `backend/requirements.txt` 中的依赖 - 前端镜像可执行 `npm ci` 与 `npm run build` 当前 compose 服务拓扑: ```text nginx -> backend -> db ``` 对外入口: - 前端:`http://localhost:8888` - 后端 API:同域 `/api/v1/*` - 健康检查:`http://localhost:8888/health` ## dev 分支:开发环境 `dev` 默认用于本地开发和内部集成,推荐使用 `ENV=development`。 ### 1. 切换分支 ```bash git checkout dev git pull --rebase origin dev ``` ### 2. 配置 `.env` 根目录 `.env` 不提交到仓库。开发环境推荐: ```env COMPOSE_PROJECT_NAME=ctms_dev ENV=development JWT_SECRET_KEY=dev-secret LOGIN_RSA_KEY_ID=default LOGIN_RSA_PRIVATE_KEY= ``` 说明: - `ENV=development` 会启用开发行为。 - 未配置 `LOGIN_RSA_PRIVATE_KEY` 时,后端启动后会生成临时 RSA 私钥。 - 后端重启后临时公钥会变化,已有登录页应刷新后重新登录。 - `JWT_SECRET_KEY=dev-secret` 只允许本地开发使用。 ### 3. 启动 ```bash docker compose up -d --build backend nginx ``` 如果需要首次启动完整栈: ```bash docker compose up -d --build ``` ### 4. 开发模式行为 `development` 模式下: - FastAPI `debug=True` - 应用启动时会执行 `Base.metadata.create_all` - 应用启动时会确保默认管理员存在 - 未配置 RSA 私钥时允许临时生成 这些行为只适合开发,不适合生产。 ### 5. 验证 ```bash docker compose ps docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV)" curl -i http://127.0.0.1:8888/health curl -i http://127.0.0.1:8888/api/v1/auth/login-key ``` 预期: ```text ENV=development GET /health -> 200 GET /api/v1/auth/login-key -> 200, key_id=default ``` ## main 分支:预发布 / 验收环境 `main` 是下一正式版本候选分支,应按生产模式运行,但不直接承载正式生产流量。 ### 1. 切换分支 ```bash git checkout main git pull --rebase origin main ``` ### 2. 配置 `.env` 预发布环境应使用 `ENV=production`,并配置独立于生产的密钥: ```env COMPOSE_PROJECT_NAME=ctms_staging ENV=production JWT_SECRET_KEY= LOGIN_RSA_KEY_ID=staging-YYYYMMDD LOGIN_RSA_PRIVATE_KEY= ``` 生成密钥示例: ```bash openssl rand -hex 32 openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 ``` 要求: - `JWT_SECRET_KEY` 不得使用 `dev-secret`。 - `LOGIN_RSA_PRIVATE_KEY` 必须固定保存,不能每次部署重新生成。 - staging 私钥不得复用 production 私钥。 ### 3. 初始化数据库 生产模式不会自动建表或自动补管理员。首次部署或迁移前执行: ```bash docker compose run --rm backend-init ``` 该步骤应运行 Alembic migration,并确保固定管理员账号存在。 ### 4. 启动 ```bash docker compose up -d --build ``` ### 5. 验证 ```bash docker compose config docker compose ps docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV); print(settings.JWT_SECRET_KEY == 'dev-secret'); print(bool(settings.LOGIN_RSA_PRIVATE_KEY))" curl -i http://127.0.0.1:8888/health curl -i http://127.0.0.1:8888/api/v1/auth/login-key ``` 预期: ```text ENV=production JWT_SECRET_KEY == dev-secret -> False LOGIN_RSA_PRIVATE_KEY_SET -> True GET /health -> 200 GET /api/v1/auth/login-key -> 200 ``` ### 6. 验收门禁 在把 `main` 推进到 `release` 前,至少执行: ```bash docker compose run --rm -v "$PWD/backend/tests:/code/tests:ro" backend python -m pytest cd frontend && npm run test:unit cd frontend && npm run type-check cd frontend && npm run build ``` ## release 分支:生产环境 `release` 是正式生产稳定分支。只有正式发布和生产 hotfix 应进入该分支。 ### 1. 切换分支 ```bash git checkout release git pull --rebase origin release ``` ### 2. 配置 `.env` 生产环境必须使用生产专用配置: ```env COMPOSE_PROJECT_NAME=ctms_prod ENV=production JWT_SECRET_KEY= LOGIN_RSA_KEY_ID=prod-YYYYMMDD LOGIN_RSA_PRIVATE_KEY= ``` 要求: - `.env` 必须只保存在部署机器或密钥管理系统中。 - 不得提交 `.env`、私钥、JWT 密钥。 - `JWT_SECRET_KEY` 轮换会使既有 token 失效,应安排维护窗口。 - `LOGIN_RSA_PRIVATE_KEY` 轮换会影响新登录密钥获取,应同步更新 `LOGIN_RSA_KEY_ID`。 ### 3. HTTPS 要求 登录加密依赖浏览器 WebCrypto。生产访问必须使用 HTTPS: - `https://正式域名` - 本地 `localhost` 是浏览器安全上下文例外,但不能代表生产可用性 如果生产仍通过 `http://服务器IP:8888` 访问,前端会拒绝执行登录加密。 ### 4. 初始化与迁移 首次部署或每次包含 migration 的发布: ```bash docker compose run --rm backend-init ``` 确认 migration 成功后再启动或滚动重启服务。 ### 5. 启动 ```bash docker compose up -d --build ``` ### 6. 生产验证 ```bash docker compose ps docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV); print(settings.JWT_SECRET_KEY == 'dev-secret'); print(bool(settings.LOGIN_RSA_PRIVATE_KEY)); print(settings.LOGIN_RSA_KEY_ID)" curl -i https:///health curl -i https:///api/v1/auth/login-key ``` 预期: ```text ENV=production JWT_SECRET_KEY == dev-secret -> False LOGIN_RSA_PRIVATE_KEY_SET -> True GET /health -> 200 GET /api/v1/auth/login-key -> 200 ``` ### 7. 多实例约束 当前登录 challenge 默认保存在后端进程内: - 单实例、单 worker:可直接使用 - 多实例或多 worker:必须满足以下至少一项 - 使用共享缓存保存 challenge,例如 Redis - 启用粘性会话,确保 `/login-key` 与 `/login` 命中同一后端进程 - 将后端限制为单 worker 单副本 如果不满足,上线后可能出现偶发登录失败。 ## 环境变量说明 | 变量 | dev | main/staging | release/production | 说明 | | --- | --- | --- | --- | --- | | `COMPOSE_PROJECT_NAME` | `ctms_dev` | `ctms_staging` | `ctms_prod` | 防止不同环境容器名、网络名冲突 | | `ENV` | `development` | `production` | `production` | 后端运行模式 | | `JWT_SECRET_KEY` | `dev-secret` | 强随机 | 强随机 | JWT 签名密钥 | | `LOGIN_RSA_KEY_ID` | `default` | `staging-YYYYMMDD` | `prod-YYYYMMDD` | 登录 RSA 密钥版本 | | `LOGIN_RSA_PRIVATE_KEY` | 空 | staging 私钥 | production 私钥 | RSA 私钥,生产模式必填 | ## 常见问题 ### 登录页提示当前浏览器环境不支持安全登录加密 原因:非 HTTPS、非 localhost 的访问环境不满足 WebCrypto 安全上下文要求。 处理: - 本地使用 `http://localhost:8888` - staging/production 使用 HTTPS 域名 ### production 模式启动失败,提示必须配置 LOGIN_RSA_PRIVATE_KEY 原因:`ENV=production` 时必须提供固定 RSA 私钥。 处理: ```bash openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 ``` 将输出 PEM 写入 `.env` 的 `LOGIN_RSA_PRIVATE_KEY`,换行使用 `\n` 转义。 ### 切换分支后环境不符合预期 分支不会自动修改 `.env`。切换分支后应重新确认: ```bash docker compose config docker compose exec backend python -c "from app.core.config import settings; print(settings.ENV)" ``` 必要时修改 `.env` 并重启: ```bash docker compose up -d --build backend nginx ```