feat(GOV-006): 建立环境配置与双部署基线

This commit is contained in:
2026-08-13 10:54:55 +08:00
parent 4ce33d8c7d
commit 9203fdd0c2
43 changed files with 846 additions and 11 deletions
+23
View File
@@ -0,0 +1,23 @@
name: a-share-analysis-development
services:
redis:
image: redis:7.2.5-alpine
container_name: a-share-analysis-dev-redis
command: ["redis-server", "--appendonly", "yes"]
ports:
- "127.0.0.1:6379:6379"
volumes:
- ../../.local/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
networks:
- a-share-analysis-dev
networks:
a-share-analysis-dev:
name: a-share-analysis-dev
+30
View File
@@ -0,0 +1,30 @@
# 应用镜像和启动入口将在 Web/Server 脚手架落地后验证。本文件先固定生产配置边界。
name: a-share-analysis-production
services:
web:
image: ${A_SHARE_WEB_IMAGE:?必须提供不可变 Web 镜像引用}
env_file: ${A_SHARE_WEB_ENV_FILE:-/etc/a-share-analysis/web.env}
ports:
- "127.0.0.1:8080:80"
restart: unless-stopped
api:
image: ${A_SHARE_SERVER_IMAGE:?必须提供不可变 Server 镜像引用}
command: ["node", "dist/apps/api/main.js"]
env_file: ${A_SHARE_API_ENV_FILE:-/etc/a-share-analysis/api.env}
ports:
- "127.0.0.1:3000:3000"
restart: unless-stopped
scheduler:
image: ${A_SHARE_SERVER_IMAGE:?必须提供不可变 Server 镜像引用}
command: ["node", "dist/apps/scheduler/main.js"]
env_file: ${A_SHARE_SCHEDULER_ENV_FILE:-/etc/a-share-analysis/scheduler.env}
restart: unless-stopped
worker:
image: ${A_SHARE_SERVER_IMAGE:?必须提供不可变 Server 镜像引用}
command: ["node", "dist/apps/worker/main.js"]
env_file: ${A_SHARE_WORKER_ENV_FILE:-/etc/a-share-analysis/worker.env}
restart: unless-stopped
+31
View File
@@ -0,0 +1,31 @@
# 运行环境;本地源码运行固定为 development。
APP_ENV=development
# API 只监听本机,避免开发服务暴露到局域网。
API_HOST=127.0.0.1
API_PORT=3000
LOG_LEVEL=debug
# 第一阶段实际启用的 Redis。
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_DATABASE=0
REDIS_TLS=false
# 第一阶段关闭 MySQL;启用后下列连接变量变为必填。
MYSQL_ENABLED=false
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DATABASE=a_share_analysis_dev
MYSQL_USERNAME=
MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci
# 第一阶段关闭付费 AI;启用后 BASE_URL、API_KEY 和 MODEL 变为必填。
AI_ENABLED=false
AI_BASE_URL=
AI_API_KEY=
AI_MODEL=
AI_TIMEOUT_MS=30000
+18
View File
@@ -0,0 +1,18 @@
# Scheduler 只负责触发时间和调度锁。
APP_ENV=development
LOG_LEVEL=debug
SCHEDULER_TIMEZONE=Asia/Shanghai
SCHEDULER_ENABLED=true
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_DATABASE=1
REDIS_TLS=false
# 第一阶段关闭 RabbitMQ,任务通过服务内 Adapter 调用。
RABBITMQ_ENABLED=false
RABBITMQ_URL=
RABBITMQ_EXCHANGE=a-share-analysis
RABBITMQ_PREFETCH=10
+5
View File
@@ -0,0 +1,5 @@
# VITE 变量会进入浏览器,只允许公开配置。
VITE_APP_ENV=development
VITE_APP_TITLE=A-Share Analysis
VITE_API_BASE_URL=http://127.0.0.1:3000/api
VITE_ENABLE_DEVTOOLS=true
+34
View File
@@ -0,0 +1,34 @@
# 开发环境使用确定性模拟行情,不访问生产数据源。
APP_ENV=development
LOG_LEVEL=debug
MARKET_DATA_MODE=mock
MARKET_DATA_PROVIDER=deterministic-fixture
MARKET_DATA_BASE_URL=
MARKET_DATA_API_KEY=
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_DATABASE=2
REDIS_TLS=false
MYSQL_ENABLED=false
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DATABASE=a_share_analysis_dev
MYSQL_USERNAME=
MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci
RABBITMQ_ENABLED=false
RABBITMQ_URL=
RABBITMQ_EXCHANGE=a-share-analysis
RABBITMQ_PREFETCH=10
AI_ENABLED=false
AI_BASE_URL=
AI_API_KEY=
AI_MODEL=
AI_TIMEOUT_MS=30000
+28
View File
@@ -0,0 +1,28 @@
# 生产进程必须显式使用 production,禁止回退开发默认值。
APP_ENV=production
API_HOST=127.0.0.1
API_PORT=3000
LOG_LEVEL=info
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_DATABASE=0
REDIS_TLS=false
# 第一阶段关闭;启用后必须填写真实生产连接,但不得提交本文件副本。
MYSQL_ENABLED=false
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DATABASE=a_share_analysis
MYSQL_USERNAME=
MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci
AI_ENABLED=false
AI_BASE_URL=
AI_API_KEY=
AI_MODEL=
AI_TIMEOUT_MS=30000
+16
View File
@@ -0,0 +1,16 @@
APP_ENV=production
LOG_LEVEL=info
SCHEDULER_TIMEZONE=Asia/Shanghai
SCHEDULER_ENABLED=true
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_DATABASE=1
REDIS_TLS=false
RABBITMQ_ENABLED=false
RABBITMQ_URL=
RABBITMQ_EXCHANGE=a-share-analysis
RABBITMQ_PREFETCH=10
+5
View File
@@ -0,0 +1,5 @@
# VITE 变量会进入浏览器,只允许公开配置。
VITE_APP_ENV=production
VITE_APP_TITLE=A-Share Analysis
VITE_API_BASE_URL=/api
VITE_ENABLE_DEVTOOLS=false
+34
View File
@@ -0,0 +1,34 @@
# 生产环境必须使用 live,启动校验拒绝 mock。
APP_ENV=production
LOG_LEVEL=info
MARKET_DATA_MODE=live
MARKET_DATA_PROVIDER=
MARKET_DATA_BASE_URL=
MARKET_DATA_API_KEY=
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=
REDIS_DATABASE=2
REDIS_TLS=false
MYSQL_ENABLED=false
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DATABASE=a_share_analysis
MYSQL_USERNAME=
MYSQL_PASSWORD=
MYSQL_CHARSET=utf8mb4
MYSQL_COLLATION=utf8mb4_general_ci
RABBITMQ_ENABLED=false
RABBITMQ_URL=
RABBITMQ_EXCHANGE=a-share-analysis
RABBITMQ_PREFETCH=10
AI_ENABLED=false
AI_BASE_URL=
AI_API_KEY=
AI_MODEL=
AI_TIMEOUT_MS=30000
@@ -0,0 +1,20 @@
server {
listen 80;
server_name _;
root /opt/a-share-analysis/current/web/dist;
index index.html;
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
try_files $uri $uri/ /index.html;
}
}
@@ -0,0 +1,19 @@
[Unit]
Description=A Share Analysis API
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=a-share
Group=a-share
WorkingDirectory=/opt/a-share-analysis/current
EnvironmentFile=/etc/a-share-analysis/api.env
ExecStart=/usr/bin/node server/dist/apps/api/main.js
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,19 @@
[Unit]
Description=A Share Analysis Scheduler
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=a-share
Group=a-share
WorkingDirectory=/opt/a-share-analysis/current
EnvironmentFile=/etc/a-share-analysis/scheduler.env
ExecStart=/usr/bin/node server/dist/apps/scheduler/main.js
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,19 @@
[Unit]
Description=A Share Analysis Worker
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=a-share
Group=a-share
WorkingDirectory=/opt/a-share-analysis/current
EnvironmentFile=/etc/a-share-analysis/worker.env
ExecStart=/usr/bin/node server/dist/apps/worker/main.js
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target