feat: bootstrap commercial AI drama platform
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
COMPOSE_PROJECT_NAME=ai-drama-platform
|
||||
PUBLIC_ORIGIN=http://localhost
|
||||
HTTP_PORT=80
|
||||
VITE_API_BASE=
|
||||
|
||||
# Application secrets. Generate long random values; do not commit the real file.
|
||||
AI_DRAMA_SESSION_SECRET=replace-with-a-long-random-secret
|
||||
AI_DRAMA_OIDC_STORAGE_KEY=replace-with-a-different-long-random-secret
|
||||
AI_DRAMA_MFA_ENCRYPTION_KEY=replace-with-32-byte-base64-or-hex-key
|
||||
|
||||
# Optional SAML IdP certificate. It can be PEM text or base64 certificate content.
|
||||
AI_DRAMA_SAML_IDP_CERT=
|
||||
|
||||
# Provisioned provider contract. Current business runtime remains SQLite.
|
||||
POSTGRES_DB=ai_drama
|
||||
POSTGRES_USER=ai_drama
|
||||
POSTGRES_PASSWORD=replace-with-postgres-password
|
||||
REDIS_PASSWORD=replace-with-redis-password
|
||||
MINIO_ROOT_USER=ai-drama-admin
|
||||
MINIO_ROOT_PASSWORD=replace-with-minio-password
|
||||
MINIO_BUCKET=ai-drama
|
||||
MINIO_API_PORT=9000
|
||||
MINIO_CONSOLE_PORT=9001
|
||||
@@ -0,0 +1,18 @@
|
||||
# 私有商业部署 Profile
|
||||
|
||||
`docker-compose.production.yml` 提供一套可审计的私有部署边界:前端 Nginx、API、独立 Worker、PostgreSQL、Redis 和 MinIO/S3-compatible 对象存储。
|
||||
|
||||
当前代码的业务数据库仍由 `server/db.mjs` 使用 Node 24 SQLite 驱动,生产 compose 会把 PostgreSQL、Redis 和对象存储启动起来并注入连接契约,但不会把 SQLite 伪装成 PostgreSQL 运行时。完成 PostgreSQL/Redis/对象存储 provider 迁移后,才可以把对应 `PLATFORM_*` 变量切换为业务真源。
|
||||
|
||||
## 启动
|
||||
|
||||
```bash
|
||||
cd /Users/xz/Documents/daima/ai短剧/ai-drama-platform
|
||||
cp deploy/.env.production.example .env.production
|
||||
# 编辑 .env.production,替换全部 replace-with-* 值
|
||||
docker compose --env-file .env.production -f deploy/docker-compose.production.yml up -d --build
|
||||
```
|
||||
|
||||
默认入口是 `http://localhost/`。第一次上线前应额外完成 HTTPS 反向代理、备份策略、把 MinIO 镜像替换为经过验证的固定 digest、容器镜像签名、日志收集、PostgreSQL/Redis/对象存储 provider 迁移,以及自有模型 Runner 的网络隔离和审计批准。
|
||||
|
||||
本地 SQLite 运行时提供系统管理员快照接口:`POST /api/system/backups`。它只创建 `data/backups/` 下的 SQLite 文件并写审计,不替代生产环境的 PostgreSQL、对象存储和异地备份策略;部署上线前应验证快照可读性,并配置独立备份保留和恢复演练。
|
||||
@@ -0,0 +1,13 @@
|
||||
FROM node:24-bookworm-slim
|
||||
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
COPY . .
|
||||
RUN mkdir -p /app/data /app/storage /app/exports
|
||||
|
||||
EXPOSE 8787
|
||||
CMD ["node", "server/local-api.mjs"]
|
||||
@@ -0,0 +1,132 @@
|
||||
name: ai-drama-platform
|
||||
|
||||
# Deployment boundary for a commercial private installation.
|
||||
# The current application runtime still uses SQLite through AI_DRAMA_DB_PATH.
|
||||
# PostgreSQL, Redis and S3-compatible storage are provisioned here as the
|
||||
# target provider contract; switching business runtime adapters is a separate
|
||||
# implementation step and must not be inferred from this compose file.
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB:-ai_drama}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-ai_drama}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD:?set REDIS_PASSWORD}"]
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
object-storage:
|
||||
image: minio/minio:latest
|
||||
restart: unless-stopped
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${MINIO_ROOT_USER:?set MINIO_ROOT_USER}
|
||||
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?set MINIO_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- object-storage-data:/data
|
||||
ports:
|
||||
- "${MINIO_API_PORT:-9000}:9000"
|
||||
- "${MINIO_CONSOLE_PORT:-9001}:9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/api.Dockerfile
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
AI_DRAMA_API_PORT: 8787
|
||||
AI_DRAMA_API_ORIGIN: ${PUBLIC_ORIGIN:-http://localhost}
|
||||
AI_DRAMA_FRONTEND_ORIGIN: ${PUBLIC_ORIGIN:-http://localhost}
|
||||
AI_DRAMA_DB_PATH: /app/data/platform.sqlite
|
||||
AI_DRAMA_ALLOW_DEV_CONTEXT: "0"
|
||||
AI_DRAMA_SESSION_SECRET: ${AI_DRAMA_SESSION_SECRET:?set AI_DRAMA_SESSION_SECRET}
|
||||
AI_DRAMA_OIDC_STORAGE_KEY: ${AI_DRAMA_OIDC_STORAGE_KEY:?set AI_DRAMA_OIDC_STORAGE_KEY}
|
||||
AI_DRAMA_MFA_ENCRYPTION_KEY: ${AI_DRAMA_MFA_ENCRYPTION_KEY:?set AI_DRAMA_MFA_ENCRYPTION_KEY}
|
||||
AI_DRAMA_SAML_IDP_CERT: ${AI_DRAMA_SAML_IDP_CERT:-}
|
||||
PLATFORM_POSTGRES_URL: postgresql://${POSTGRES_USER:-ai_drama}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-ai_drama}
|
||||
PLATFORM_REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
PLATFORM_OBJECT_STORAGE_ENDPOINT: http://object-storage:9000
|
||||
PLATFORM_OBJECT_STORAGE_BUCKET: ${MINIO_BUCKET:-ai-drama}
|
||||
PLATFORM_OBJECT_STORAGE_ACCESS_KEY: ${MINIO_ROOT_USER}
|
||||
PLATFORM_OBJECT_STORAGE_SECRET_KEY: ${MINIO_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- platform-data:/app/data
|
||||
- platform-storage:/app/storage
|
||||
- platform-exports:/app/exports
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
object-storage:
|
||||
condition: service_healthy
|
||||
expose:
|
||||
- "8787"
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8787/api/health').then(r => { if (!r.ok) process.exit(1) }).catch(() => process.exit(1))"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
worker:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/api.Dockerfile
|
||||
restart: unless-stopped
|
||||
command: ["npm", "run", "worker"]
|
||||
environment:
|
||||
AI_DRAMA_DB_PATH: /app/data/platform.sqlite
|
||||
AI_DRAMA_SESSION_SECRET: ${AI_DRAMA_SESSION_SECRET:?set AI_DRAMA_SESSION_SECRET}
|
||||
PLATFORM_REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379/0
|
||||
volumes:
|
||||
- platform-data:/app/data
|
||||
- platform-storage:/app/storage
|
||||
- platform-exports:/app/exports
|
||||
depends_on:
|
||||
api:
|
||||
condition: service_healthy
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/frontend.Dockerfile
|
||||
args:
|
||||
VITE_API_BASE: ${VITE_API_BASE:-}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${HTTP_PORT:-80}:80"
|
||||
depends_on:
|
||||
api:
|
||||
condition: service_healthy
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
redis-data:
|
||||
object-storage-data:
|
||||
platform-data:
|
||||
platform-storage:
|
||||
platform-exports:
|
||||
@@ -0,0 +1,15 @@
|
||||
FROM node:24-bookworm-slim AS build
|
||||
|
||||
WORKDIR /app
|
||||
ARG VITE_API_BASE=
|
||||
ENV VITE_API_BASE=$VITE_API_BASE
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:1.27-alpine
|
||||
COPY deploy/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
@@ -0,0 +1,31 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://api:8787;
|
||||
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;
|
||||
client_max_body_size 2g;
|
||||
}
|
||||
|
||||
location /scim/ {
|
||||
proxy_pass http://api:8787;
|
||||
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;
|
||||
client_max_body_size 20m;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user