refactor: 统一 .env 配置 — 合并 backend/.env + .docker.env 到根目录

- Go 服务 godotenv.Load("../.env") → godotenv.Load("../../.env")
- ethend.sh/config.js 读取路径改为根目录 .env
- 删除 .docker.env.example 和 backend/.env.example,统一为 .env.example
- Docker compose 默认读取根 .env,无需 --env-file
- 同步更新全部文档

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-30 10:12:54 +08:00
parent 43d256e197
commit 46441335c0
12 changed files with 49 additions and 92 deletions
-58
View File
@@ -1,58 +0,0 @@
# ========== Cyrene 生产环境 Docker 部署配置 ==========
# 复制此文件为 .docker.env 并填入真实值
# cp .docker.env.example .docker.env
# 使用方式: docker compose --env-file .docker.env up -d
# ========== LLM API(必填) ==========
LLM_API_URL=https://api.openai.com/v1
LLM_API_KEY=sk-xxxxx
LLM_MODEL=gpt-4o
LLM_FALLBACK_MODEL=gpt-4o-mini
# ========== 管理员账号(必填) ==========
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change-me-to-secure-password
ADMIN_NICKNAME=管理员
# ========== 安全密钥(必填) ==========
JWT_SECRET=change-me-to-random-secret-string
JWT_EXPIRY_HOURS=720
INTERNAL_SERVICE_TOKEN=change-me-to-random-token
# ========== 数据库 ==========
POSTGRES_USER=cyrene
POSTGRES_PASSWORD=change-me-to-random-password
POSTGRES_DB=cyrene_ai
# ========== Redis ==========
REDIS_PASSWORD=
# ========== MinIO 对象存储 ==========
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=change-me-to-random-password
# ========== 注册与访问控制 ==========
REGISTRATION_ENABLED=false
ALLOWED_ORIGINS=http://localhost:5173,http://localhost:9090
# ========== WebSocket ==========
WS_MAX_CONNECTIONS=1000
SESSION_IDLE_TIMEOUT_MIN=30
# ========== 后台自主思考 ==========
ENABLE_BACKGROUND_THINKING=true
# ========== Webhook(可选) ==========
WEBHOOK_API_KEY=
# ========== 管理控制台端口 ==========
ETHEND_PORT=9090
# ========== 反向代理端口(避免与已有 nginx 等服务冲突) ==========
CADDY_HTTP_PORT=80
CADDY_HTTPS_PORT=443
# ========== 域名与 HTTPS(有域名时填写) ==========
# 留空 = 仅 HTTP;填写域名后 Caddy 自动申请 Let's Encrypt 证书
DOMAIN=
ACME_EMAIL=admin@example.com
+15
View File
@@ -87,3 +87,18 @@ WSL_USER_PASSWORD=cyrene
SANDBOX_CONTAINER=cyrene-sandbox
SANDBOX_IMAGE=ubuntu:22.04
HOST_EXEC_MAX_TIMEOUT=300
# ========== Docker 反向代理端口 ==========
CADDY_HTTP_PORT=80
CADDY_HTTPS_PORT=443
# ========== 域名与 HTTPSDocker 生产环境有域名时填写) ==========
DOMAIN=
ACME_EMAIL=admin@example.com
# ========== 管理控制台端口 (ethend) ==========
ETHEND_PORT=9090
# ========== WebSocket 最大连接数 ==========
WS_MAX_CONNECTIONS=1000
SESSION_IDLE_TIMEOUT_MIN=30
+7 -7
View File
@@ -35,8 +35,8 @@ Windows 提供两个启动脚本:
### 1. 配置环境变量
```bash
cp backend/.env.example backend/.env
# 编辑 backend/.env,至少配置:
cp .env.example .env
# 编辑 .env,至少配置:
# LLM_API_URL / LLM_API_KEY / LLM_MODEL
# ADMIN_USERNAME / ADMIN_PASSWORD
```
@@ -73,7 +73,7 @@ cp backend/.env.example backend/.env
### 1. 配置 + 数据库
```bash
cp backend/.env.example backend/.env # 编辑配置
cp .env.example .env # 编辑配置
docker compose -f docker-compose.dev.db.yml up -d
```
@@ -117,11 +117,11 @@ docker compose -f docker-compose.dev.yml up -d
```bash
# 1. 配置环境变量
cp .docker.env.example .docker.env
# 编辑 .docker.env,填入真实的 API Key 和密码
cp .env.example .env
# 编辑 .env,填入真实的 API Key 和密码
# 2. 启动所有服务
docker compose --env-file .docker.env up -d
docker compose up -d
```
包含 Caddy 反向代理(自动 TLS)。详细说明见 [docs/deploy/docker-compose.md](docs/deploy/docker-compose.md)。
@@ -179,7 +179,7 @@ Cyrene/
## 核心环境变量
完整列表见 `backend/.env.example`
完整列表见 `.env.example`
### 必填
+9 -9
View File
@@ -26,7 +26,7 @@
| Docker 配置 | `docker-compose*.yml`, `backend/*/Dockerfile` | 容器化部署配置 |
| Caddy 配置 | `Caddyfile` | 反向代理配置 |
| 文档 | `docs/`, `Deploy.md`, `Migration.md` | 项目文档 |
| 环境变量模板 | `backend/.env.example` | 配置参考模板 |
| 环境变量模板 | `.env.example` | 配置参考模板 |
| 脚本 | `scripts/` | 辅助脚本(migrate.sh, setup-whisper.sh 等) |
| 许可证 | `LICENSE` | 项目许可证 |
@@ -38,7 +38,7 @@
| Windows 可执行文件 | `*.exe` | 旧的 Windows 编译产物 |
| Node.js 依赖 | `node_modules/`, `frontend/web/node_modules/`, `frontend/node_modules/`, `ethend/node_modules/` | 体积大,通过 `npm install` 重新安装 |
| 前端构建产物 | `frontend/web/dist/` | 通过 `npm run build` 重新构建 |
| 敏感配置文件 | `backend/.env` | 包含 API 密钥和密码 |
| 敏感配置文件 | `.env` | 包含 API 密钥和密码 |
| 锁文件 | `package-lock.json`, `frontend/web/package-lock.json`, `frontend/package-lock.json` | 跨平台 npm 依赖树可能不同 |
| Git 内部数据 | `.git/objects`, `.git/refs`, `.git/logs` | 减小压缩包体积 |
| 日志文件 | `*.log`, `logs/`, `debug/logs/` | 运行时产物 |
@@ -56,17 +56,17 @@ cd Cyrene
git checkout dev
```
克隆完成后,手动创建 `backend/.env` 文件:
克隆完成后,手动创建 `.env` 文件:
```bash
# 在 Windows 命令行 (cmd) 中:
copy backend\.env.example backend\.env
copy .env.example .env
# 或在 PowerShell 中:
Copy-Item backend\.env.example backend\.env
Copy-Item .env.example .env
```
然后编辑 [`backend/.env`](backend/.env),填入实际的 API 密钥、数据库密码等配置值。
然后编辑 [`.env`](.env),填入实际的 API 密钥、数据库密码等配置值。
---
@@ -142,7 +142,7 @@ wsl --install -d Ubuntu-22.04
**方式 A:使用 `.env` 文件(推荐)**
项目各服务会自动读取 [`backend/.env`](backend/.env.example),将 `.env.example` 复制为 `.env` 并填入实际值即可。
项目各服务会自动读取 [`.env`](.env.example),将 `.env.example` 复制为 `.env` 并填入实际值即可。
**方式 B:命令行临时设置 (cmd)**
@@ -218,7 +218,7 @@ npm run dev
### 6.3 数据库配置
1. 确保 PostgreSQL 服务已启动
2. 创建数据库和用户(参考 [`backend/.env.example`](backend/.env.example) 中的配置):
2. 创建数据库和用户(参考 [`.env.example`](.env.example) 中的配置):
```sql
CREATE USER cyrene WITH PASSWORD 'your-password';
@@ -227,7 +227,7 @@ CREATE DATABASE cyrene_ai OWNER cyrene;
CREATE EXTENSION IF NOT EXISTS vector;
```
3. 在 [`backend/.env`](backend/.env.example) 中配置数据库连接信息。
3. 在 [`.env`](.env.example) 中配置数据库连接信息。
### 6.4 基础设施服务
+2 -2
View File
@@ -71,8 +71,8 @@
### 1. 配置环境变量
```bash
cp backend/.env.example backend/.env
# 编辑 backend/.env,至少配置:
cp .env.example .env
# 编辑 .env,至少配置:
# LLM_API_URL / LLM_API_KEY / LLM_MODEL
# ADMIN_USERNAME / ADMIN_PASSWORD
```
+2 -2
View File
@@ -46,8 +46,8 @@ import (
var cfg Config
func main() {
// 自动加载 .env 文件(来自 backend/.env
if err := godotenv.Load("../.env"); err != nil {
// 自动加载 .env 文件(来自仓库根目录
if err := godotenv.Load("../../.env"); err != nil {
log.Println("ℹ 未找到 .env 文件,将使用环境变量或默认值")
}
+2 -2
View File
@@ -24,8 +24,8 @@ import (
func main() {
logger.SetDefault(logger.New("gateway"))
// 自动加载 .env 文件(来自 backend/.env
if err := godotenv.Load("../.env"); err != nil {
// 自动加载 .env 文件(来自仓库根目录
if err := godotenv.Load("../../.env"); err != nil {
logger.Println("ℹ 未找到 .env 文件,将使用环境变量或默认值")
}
+2 -2
View File
@@ -104,7 +104,7 @@ Cyrene(昔涟)是一个 AI 数字伴侣系统,以 React SPA 为前端,Go
#### 3.1.1 启动流程
1. 加载 `backend/.env` 环境变量
1. 加载 `.env` 环境变量
2. 初始化人格加载器(`persona.NewLoader`)——从 `internal/persona/` 目录读取 YAML 配置
3. 初始化 LLM 适配器:优先加载 `models.json``ModelSelector`;无配置文件时回退到 `.env`
4. 初始化记忆系统(`memory.NewStore` + `NewRetriever` + `NewExtractor`)——PostgreSQL 持久化
@@ -790,7 +790,7 @@ node test/test_final_e2e.mjs
### 环境变量 (.env)
位于 `backend/.env`,基础设施与 LLM 回退配置:
位于 `.env`,基础设施与 LLM 回退配置:
```
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
+5 -5
View File
@@ -4,12 +4,12 @@
```bash
# 1. 配置环境变量
cp .docker.env.example .docker.env
# 编辑 .docker.env,填入真实的 API Key 和密码
cp .env.example .env
# 编辑 .env,填入真实的 API Key 和密码
# 有域名时设置 DOMAIN=your-domain.com
# 2. 启动所有服务
docker compose --env-file .docker.env up -d
docker compose up -d
# 3. 查看状态
docker compose ps
@@ -176,7 +176,7 @@ cyrene_minio Up 9000-9001/tcp
## 环境变量
所有变量在 `.docker.env` 中配置,完整模板见 [.docker.env.example](../../.docker.env.example)。
所有变量在 `.env` 中配置,完整模板见 [.env.example](../../.env.example)。
### 必填(服务启动 panic 若缺失)
@@ -205,7 +205,7 @@ cyrene_minio Up 9000-9001/tcp
## 域名与 HTTPS
`.docker.env` 中设置 `DOMAIN``ACME_EMAIL`
`.env` 中设置 `DOMAIN``ACME_EMAIL`
```bash
# 无域名(仅 HTTP
+1 -1
View File
@@ -30,7 +30,7 @@ wsl --import Ubuntu-22.04 C:\WSL\Ubuntu-22.04 ubuntu-wsl.tar.wsl
### 2. 配置 .env
编辑 `backend/.env`(或从 `.env.example` 复制):
编辑 `.env`(或从 `.env.example` 复制):
```bash
HOST_EXEC_BACKEND=wsl
+2 -2
View File
@@ -95,9 +95,9 @@ check_deps() {
# ========== 加载 .env ==========
load_env() {
local env_file="$ROOT/backend/.env"
local env_file="$ROOT/.env"
if [ -f "$env_file" ]; then
echo -e "${GREEN}✓ 加载环境变量: backend/.env${NC}"
echo -e "${GREEN}✓ 加载环境变量: .env${NC}"
set -a
source "$env_file"
set +a
+2 -2
View File
@@ -14,10 +14,10 @@ const ROOT = path.resolve(__dirname, '../..');
const isWin = os.platform() === 'win32';
// 读取 backend/.env 文件,将值合并到 process.env(不覆盖已有的环境变量)
// 读取根目录 .env 文件,将值合并到 process.env(不覆盖已有的环境变量)
// 这样 ethend 启动各服务时能传递用户配置的凭据
function loadEnvFile() {
const envPath = path.join(ROOT, 'backend', '.env');
const envPath = path.join(ROOT, '.env');
try {
const content = fs.readFileSync(envPath, 'utf-8');
for (const line of content.split('\n')) {