Files
video-gen/DEPLOYMENT.md
2026-07-11 12:51:48 +08:00

743 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VideoGen 部署文档
## 项目结构
```
video_item/
├── video-gen-api/ # 后端 (Python FastAPI + SQLAlchemy + Alembic)
├── video-gen-app/ # 前台/用户端 (React 19 + Vite 8 + Ant Design 6)
├── video-gen-admin/ # 后台管理端 (React 19 + Vite 8 + Ant Design 6)
└── DEPLOYMENT.md # 本文档
```
**三个前端/后端的关系:** `video-gen-app` (用户前台) 和 `video-gen-admin` (管理后台) 都连接同一个 `video-gen-api` 后端。
---
## 一、环境要求
| 组件 | 版本要求 | 说明 |
|------|---------|------|
| Python | >= 3.10 | 推荐 3.12 |
| Node.js | >= 18 | 推荐 20+ |
| PostgreSQL | >= 14 | 推荐 16**必须** |
| Redis | >= 6 | 推荐用于: 限流/验证码/Celery/任务状态 |
| FFmpeg | 任意 | 用于视频封面截帧,留空时从 PATH 自动查找 |
| ca-certificates | 任意 | **必须**,HTTPS 请求需要(新服务器/容器常缺) |
| alipay-sdk-python | >=3.7.1160 | 可选,支付宝支付 |
| wechatpayv3 | >=2.0.2 | 可选,微信支付 |
| volcengine-python-sdk | >=1.1.0 | 可选,视频生成/短信 |
---
## 二、后端部署 (video-gen-api)
### 1. 安装依赖
```bash
# ⚠️ 新服务器/容器必须先装 CA 证书,否则 HTTPS(支付宝/火山等)全部失败
# CentOS/RHEL
sudo yum install -y ca-certificates
# Ubuntu/Debian
sudo apt-get install -y ca-certificates
cd video-gen-api
# 创建虚拟环境
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux/Mac
source .venv/bin/activate
# 安装基础依赖
pip install -e .
# 安装 PostgreSQL 驱动(生产环境必须)
pip install -e ".[pg]"
# 如需 Redis 支持(限流、验证码、Celery)
pip install -e ".[pg,redis]"
# 如需 Celery 异步任务(ChatAPI 生成流水线)
pip install -e ".[pg,redis,celery]"
# 如需支付宝
pip install -e ".[pg,redis,celery,alipay]"
# 如需微信支付
pip install -e ".[pg,redis,celery,alipay,wxpay]"
# 如需火山引擎 SDK(短信等)
pip install -e ".[pg,redis,celery,alipay,wxpay,volc]"
```
### 2. 配置环境变量
复制 `.env.example``.env`,修改关键配置:
```bash
cp .env.example .env
```
```ini
# ── 基础配置 ──
APP_NAME=VideoGen API
APP_VERSION=1.0.0
DEBUG=false
SECRET_KEY=改成一个随机的长字符串(JWT 签名密钥)
# ── 数据库(必须) ──
DATABASE_URL=postgresql+asyncpg://用户名:密码@localhost:5432/videogen
# ── Redis(可选,留空则禁用限流/验证码/Celery) ──
REDIS_URL=redis://localhost:6379/0
# ── JWT ──
JWT_ALGORITHM=HS256
JWT_EXPIRE_MINUTES=1440 # 普通登录 24h
JWT_EXPIRE_REMEMBER_MINUTES=10080 # 记住登录 7天
# ── 视频生成(火山引擎 Ark) ──
SEEDANCE_API_KEY=你的API Key
SEEDANCE_API_BASE=https://ark.cn-beijing.volces.com/api/v3
SEEDANCE_CALLBACK_URL=https://你的域名/api/generation-records/callback
# ── LLM 提示词优化 ──
LLM_API_BASE=https://api.openai.com/v1
LLM_API_KEY=
LLM_MODEL=gpt-4o
LLM_MOCK=true # true=使用 mock 响应,不调用真实 LLM
# ── 前后端通信加密(32字节 base64,留空则禁用) ──
ENCRYPTION_KEY=你的32字节base64密钥
# ── 存储路径(本地存储) ──
STORAGE_TYPE=local
STORAGE_LOCAL_PATH=./storage/generate/videos
STORAGE_IMAGE_LOCAL_PATH=./storage/generate/images
STORAGE_VIDEO_COVER_LOCAL_PATH=./storage/generate/covers
UPLOAD_LOCAL_PATH=./storage/uploads
# ── 跨域(生产环境务必限制域名,默认 ["*"] 允许所有) ──
CORS_ORIGINS=["https://你的前台域名.com", "https://你的后台域名.com"]
# ── 回调基础地址 ──
BASE_URL=https://你的域名
# ── 验证码 ──
CAPTCHA_ENABLED=true
# ── 短信(火山引擎 SDKSMS_MOCK=false 时生效) ──
SMS_MOCK=true
VOLC_SMS_ACCESS_KEY_ID=
VOLC_SMS_SECRET_ACCESS_KEY=
VOLC_SMS_ACCOUNT=消息组ID
VOLC_SMS_TEMPLATE_ID=模板ID
VOLC_SMS_SIGN=短信签名
# ── 支付(PAYMENT_MOCK=false 时生效) ──
PAYMENT_MOCK=true
WECHAT_MCH_ID=
WECHAT_API_KEY=
ALIPAY_APP_ID=
ALIPAY_PRIVATE_KEY=
ALIPAY_PUBLIC_KEY=
ALIPAY_NOTIFY_URL=
# ── Celery(可选,留空则禁用 ChatAPI 异步流水线) ──
CELERY_BROKER_URL=redis://localhost:6379/5
CELERY_RESULT_BACKEND=redis://localhost:6379/6
# ── FFmpeg(留空自动从 PATH 查找) ──
FFMPEG_BIN=/usr/bin/ffmpeg
```
> **关于 ENCRYPTION_KEY 的生成:** 需要 32 字节(256 位)的 base64 编码字符串。生成方式:`openssl rand -base64 32`。前后端必须使用**完全相同**的密钥。
### 3. 初始化数据库
```bash
# 创建 PostgreSQL 数据库
psql -U postgres -c "CREATE DATABASE videogen OWNER videogen;"
# 启动后端(首次启动自动建表)
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000
```
首次启动时会**自动创建所有数据表**(41 个 model)。
> ⚠️ **关于种子数据:** 代码中包含 `_seed_data()` 函数(创建管理员/演示用户、系统配置、引擎配置等),但当前在 `main.py` 中被**注释掉了**`# await _seed_data()`)。因此首次启动**不会**自动创建管理员账号。
>
> **如果你需要种子数据,**有以下选择:
> 1. 在 `main.py` 中取消注释 `# await _seed_data()` 后重启
> 2. 手动通过 API 或数据库脚本创建管理员账号
> 3. 自行编写独立的种子脚本调用 `_seed_data()`
### 4. 数据库迁移 (Alembic)
项目使用 Alembic 管理数据库结构变更。
```bash
cd video-gen-api
# 修改 model 后,自动生成迁移文件
python -m alembic revision --autogenerate -m "描述改动内容"
# 执行迁移
python -m alembic upgrade head
# 查看当前版本
python -m alembic current
# 查看迁移历史
python -m alembic history
# 回滚一步
python -m alembic downgrade -1
```
**部署流程:** 拉取代码后先执行 `alembic upgrade head`,再重启后端服务。
### 5. 生产运行
```bash
# 直接运行(推荐 4 workers
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
```
**systemd 服务文件** `/etc/systemd/system/videogen-api.service`
```ini
[Unit]
Description=VideoGen API
After=network.target postgresql.service
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/video-gen-api
Environment=PATH=/opt/video-gen-api/.venv/bin
ExecStart=/opt/video-gen-api/.venv/bin/python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
```bash
sudo systemctl daemon-reload
sudo systemctl enable videogen-api
sudo systemctl start videogen-api
```
### 6. Celery Worker(可选)
ChatAPI 异步生成流水线需要 Celery Worker,依赖 Redis 作为 Broker。
Celery 使用 **6 个队列**,按功能分离:
| 队列 | 用途 |
|------|------|
| `gen_chatapi_create` | ChatAPI 生成任务创建(含爆款开头/拆镜复刻的提词步骤) |
| `gen_provider_poll` | 轮询火山引擎生成状态 |
| `gen_result_download` | 下载生成的视频/图片结果 |
| `gen_recovery` | 容灾恢复任务(统一队列,避免占用业务 worker) |
| `gen_private_portrait` | 真人素材认证与同步 |
| `default` | 默认队列(用户 OAuth、清理任务等) |
```bash
# 启动 Worker(消费所有队列)
celery -A app.tasks.celery_app worker -l info -Q gen_chatapi_create,gen_provider_poll,gen_result_download,gen_recovery,gen_private_portrait,default
```
**systemd 服务文件** `/etc/systemd/system/videogen-worker.service`
```ini
[Unit]
Description=VideoGen Celery Worker
After=network.target redis.service
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/video-gen-api
Environment=PATH=/opt/video-gen-api/.venv/bin
ExecStart=/opt/video-gen-api/.venv/bin/celery -A app.tasks.celery_app worker -l info -Q gen_chatapi_create,gen_provider_poll,gen_result_download,gen_recovery,gen_private_portrait,default
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
### 7. Docker 部署(可选)
项目提供 `Dockerfile``docker-compose.yml`
> ⚠️ **注意:** 默认 `Dockerfile` 只安装基础依赖(`pip install .`),生产使用需改为 `".[pg,redis,celery]"`。
```bash
cd video-gen-api
# 使用前需修改 Dockerfile 第 6 行为:
# RUN pip install --no-cache-dir ".[pg,redis,celery]"
docker compose up -d
```
启动的服务:
| 服务 | 端口 | 说明 |
|------|------|------|
| api | 8000 | FastAPI 应用(`--reload` 开发模式) |
| worker | - | Celery Worker(消费所有队列) |
| postgres | 5432 | PostgreSQL 16 |
| redis | 6379 | Redis 7 |
### 8. Nginx 反向代理
```nginx
server {
listen 80;
server_name api.yourdomain.com;
# 上传文件大小限制(视频上传需要较大值)
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:8000;
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;
proxy_read_timeout 300s;
}
# 静态文件 (上传的视频/图片)
location /uploads/ {
alias /opt/video-gen-api/storage/uploads/;
expires 7d;
}
}
```
---
## 三、前台部署 (video-gen-app)
用户前台,面向最终用户。
### 1. 安装依赖 & 构建
```bash
cd video-gen-app
npm install
# 配置 API 地址(创建 .env.production
echo "VITE_API_BASE=https://api.yourdomain.com" > .env.production
# 如需前后端加密通信(与后端 ENCRYPTION_KEY 相同)
echo "VITE_ENCRYPTION_KEY=密钥" >> .env.production
# 构建
npm run build
```
构建产物在 `dist/` 目录。
### 2. 前端环境变量
| 变量 | 说明 | 默认值 |
|------|------|--------|
| `VITE_API_BASE` | 后端 API 地址 | `http://localhost:8000` |
| `VITE_USE_MOCK` | 是否使用 mock 数据(无需后端) | `false` |
| `VITE_ENCRYPTION_KEY` | 前后端通信加密密钥(需与后端一致) | 空(不加密) |
### 3. Nginx 配置
```nginx
server {
listen 80;
server_name yourdomain.com;
root /opt/video-gen-app/dist;
index index.html;
# SPA 路由:所有页面请求回退到 index.html
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源缓存(带 hash 的文件名可长期缓存)
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
```
---
## 四、后台管理部署 (video-gen-admin)
管理员后台,面向运营/管理人员。
### 1. 安装依赖 & 构建
```bash
cd video-gen-admin
npm install
# 配置 API 地址
echo "VITE_API_BASE=https://api.yourdomain.com" > .env.production
# 如需前后端加密通信
echo "VITE_ENCRYPTION_KEY=密钥" >> .env.production
# 构建
npm run build
```
### 2. 后台环境变量
| 变量 | 说明 | 默认值 |
|------|------|--------|
| `VITE_API_BASE` | 后端 API 地址 | `http://localhost:8000` |
| `VITE_USE_MOCK` | 是否使用 mock 数据 | `false` |
| `VITE_ENCRYPTION_KEY` | 前后端通信加密密钥 | 空(不加密) |
### 3. Nginx 配置
```nginx
server {
listen 80;
server_name admin.yourdomain.com;
root /opt/video-gen-admin/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
```
---
## 五、完整 Nginx 配置示例 (单机部署)
```nginx
# 后端 API
server {
listen 80;
server_name api.yourdomain.com;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:8000;
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;
proxy_read_timeout 300s;
}
location /uploads/ {
alias /opt/video-gen-api/storage/uploads/;
expires 7d;
}
}
# 前台
server {
listen 80;
server_name yourdomain.com;
root /opt/video-gen-app/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 1y;
}
}
# 后台管理
server {
listen 80;
server_name admin.yourdomain.com;
root /opt/video-gen-admin/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /assets/ {
expires 1y;
}
}
```
---
## 六、SSL 配置 (推荐)
使用 Certbot 获取免费证书:
```bash
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d admin.yourdomain.com -d api.yourdomain.com
```
---
## 七、默认账号
> ⚠️ 默认账号仅在种子数据被执行后存在(见第三节第 3 点说明)。
| 角色 | 用户名 | 手机号 | 密码 | 积分 |
|------|--------|--------|------|------|
| 管理员 | admin | 13800000000 | 123456 | 10000 |
| 演示用户 | demo | 13888888888 | 123456 | 2680 |
**首次部署后务必修改默认密码。**
---
## 八、架构说明
### 后端启动时的后台任务
后端启动时(`lifespan`)会自动启动以下**进程内**后台任务:
| 任务 | 说明 |
|------|------|
| `task_queue` (video_queue) | 内置 asyncio 任务队列,轮询视频/图片生成状态 |
| `upload_queue` | 上传任务队列 |
| `material_consumption_queue` | 素材消耗队列 |
| `token_refresh_scheduler` | 每 5 分钟检查并刷新即将过期的 token |
| `poll_pre_test_results` | 每分钟轮询前测结果 |
| `schedule_daily_sync` | 每天 9 点自动同步素材消耗 |
| `_order_expiry_loop` | 每分钟同步待支付订单状态 + 自动过期订单 |
加上 **Celery Worker**(可选,处理 ChatAPI 异步流水线)。
### 中间件栈(从外到内,即请求到达的顺序)
1. `RequestLoggingMiddleware` — 请求/响应日志记录
2. `AntiCrawlerMiddleware` — 反爬虫(拦截空 UA 和常见 bot)
3. `RateLimitMiddleware` — 滑动窗口限流(Redis 支撑)
4. `RequestEncryptMiddleware` — AES-256-GCM 请求/响应加密
5. `CORSMiddleware` — 跨域(expose `X-Encrypted` 响应头)
### 前后端通信加密
**机制:** AES-256-GCM 对称加密,前后端共享同一个 `ENCRYPTION_KEY`。使用 Web Crypto API(前端)和 `cryptography` 库(后端)。
**生效条件:** 同时满足以下两个条件才启用加密:
- 后端 `.env``ENCRYPTION_KEY` 非空
- 前端 `.env``VITE_ENCRYPTION_KEY` 非空
- 运行在安全上下文(HTTPS 或 localhost
**加密范围:**
| 请求类型 | 请求体 | 响应体 |
|---------|--------|--------|
| GET(无 body) | 不加密(无内容) | **加密** |
| POST/PUT/DELETE(有 body | **加密** | **加密** |
**工作流:**
1. 前端发送 POST 请求时,将 JSON 请求体加密为 `{ data: "<密文>" }`,并加 `X-Encrypted: true` 请求头
2. 后端中间件检测到 `X-Encrypted: true` 时解密请求体,处理完后加密响应体
3. 支付回调接口(`/payments/alipay/callback`, `/payments/wechat/callback`)白名单跳过加密
> **GET 请求注意:** GET 没有请求体,但响应仍会被加密。前端会自动检测并解密。
### 文件日志加密(独立机制)
与通信加密不同,**文件日志存储**使用另一套独立的 AES-CBC-256 加密:
| 日志类型 | 目录 | 加密方式 |
|---------|------|---------|
| 请求/响应日志 | `log/RequestResponse/{日期}.log` | AES-CBC-256,密钥硬编码 |
| AI 模型日志 | `log/AiModel/{日期}.log` | AES-CBC-256,密钥硬编码 |
日志加密密钥与 `ENCRYPTION_KEY` 无关,是代码中硬编码的值。解密工具:`/internal/decrypt-data` 页面。
### 内部管理端点
| 端点 | 用途 |
|------|------|
| `/internal/` | 后端入口导航页 |
| `/internal/health` | 健康检查 (`{"status": "ok"}`) |
| `/internal/status` | 服务状态监控页 (Celery/Redis 连接状态) |
| `/internal/decrypt-data` | 日志数据解密工具(AES-CBC) |
| `/internal/api-docs` | Swagger API 文档 |
| `/internal/api-redoc` | ReDoc API 文档 |
| `/uploads/` | 用户上传的静态文件(挂载为静态目录) |
| `/api/decrypt` | 解密接口(POST,供解密工具调用) |
### 前端 Mock 模式
前端支持 Mock 数据模式,无需后端即可开发:
- 设置 `VITE_USE_MOCK=true` 时,所有 API 调用返回本地假数据
- 适用场景:纯前端开发、演示、无后端环境
- 注意:mock 模式下仍会调用部分真实 API(如站点信息、验证码)
### 存储路径
| 路径 | 用途 |
|------|------|
| `storage/generate/videos/` | 生成的视频文件 |
| `storage/generate/images/` | 生成的图片文件 |
| `storage/generate/covers/` | 视频封面缩略图 |
| `storage/uploads/` | 用户上传的原始文件 |
### 外部服务依赖
| 服务 | 用途 | 是否必须 |
|------|------|---------|
| 火山引擎 Ark | 视频生成(Seedance 2.0)、图片生成(Seedream 5.0)、LLM | 是 |
| 火山引擎短信 | 短信验证码 | 否(可 mock) |
| 微信支付 / 支付宝 | 充值支付 | 否(可 mock,未完整实现) |
| FFmpeg | 视频封面截帧 | 否(留空自动查找) |
---
## 九、目录结构 (部署后)
```
/opt/
├── video-gen-api/ # 后端
│ ├── .env # 环境变量
│ ├── .venv/ # Python 虚拟环境
│ ├── app/ # 应用代码
│ │ ├── api/ # API 路由
│ │ │ ├── v1/ # v1 版本接口(前端用户端 + 部分管理接口)
│ │ │ └── admin/ # 管理端接口
│ │ ├── middleware/ # 中间件
│ │ ├── models/ # 数据模型 (41 个)
│ │ ├── services/ # 业务服务
│ │ ├── tasks/ # Celery 任务
│ │ ├── enums/ # 枚举定义
│ │ └── utils/ # 工具函数
│ ├── alembic/ # 数据库迁移文件
│ ├── storage/
│ │ ├── generate/
│ │ │ ├── videos/ # 生成的视频
│ │ │ ├── images/ # 生成的图片
│ │ │ └── covers/ # 视频封面
│ │ └── uploads/ # 用户上传
│ └── log/
│ ├── AiModel/ # AI 模型请求日志(加密)
│ └── RequestResponse/ # 请求响应日志(加密)
├── video-gen-app/dist/ # 前台构建产物
└── video-gen-admin/dist/ # 后台构建产物
```
---
## 十、常用运维命令
```bash
# 查看后端日志
sudo journalctl -u videogen-api -f
# 重启后端
sudo systemctl restart videogen-api
# 重启 Celery Worker
sudo systemctl restart videogen-worker
# 重新构建前端
cd /opt/video-gen-app && npm run build
cd /opt/video-gen-admin && npm run build
# 数据库备份
pg_dump -U videogen videogen > backup_$(date +%Y%m%d).sql
# 数据库恢复
psql -U videogen videogen < backup_20260512.sql
# 执行数据库迁移
cd /opt/video-gen-api && python -m alembic upgrade head
# 生成迁移文件
cd /opt/video-gen-api && python -m alembic revision --autogenerate -m "描述"
# 查看 Celery 活动任务
celery -A app.tasks.celery_app inspect active
```
---
## 十一、环境变量完整参考
### 后端 (video-gen-api/.env)
| 变量 | 必填 | 默认值 | 说明 |
|------|------|--------|------|
| `SECRET_KEY` | **是** | `change-me` | JWT 签名密钥 |
| `DATABASE_URL` | **是** | sqlite | PostgreSQL 连接串 |
| `REDIS_URL` | 否 | 空 | Redis 连接串,留空禁用限流/验证码 |
| `JWT_EXPIRE_MINUTES` | 否 | 1440 | Token 有效期(分钟) |
| `JWT_EXPIRE_REMEMBER_MINUTES` | 否 | 10080 | 记住登录 Token 有效期 |
| `SEEDANCE_API_KEY` | **是** | 空 | 火山引擎 API Key |
| `SEEDANCE_API_BASE` | 否 | 火山地址 | API 基础 URL |
| `SEEDANCE_CALLBACK_URL` | 否 | 空 | 生成结果回调 URL |
| `LLM_API_BASE` | 否 | OpenAI | LLM API 地址 |
| `LLM_API_KEY` | 否 | 空 | LLM API Key |
| `LLM_MODEL` | 否 | gpt-4o | LLM 模型名称 |
| `LLM_MOCK` | 否 | true | 是否 mock LLM 响应 |
| `ENCRYPTION_KEY` | 否 | 占位符 | 前后端通信加密密钥 |
| `SMS_MOCK` | 否 | true | 是否 mock 短信 |
| `PAYMENT_MOCK` | 否 | false | 是否 mock 支付 |
| `CORS_ORIGINS` | 否 | `["*"]` | 允许的跨域来源 |
| `BASE_URL` | 否 | 测试地址 | 站点基础 URL,用于回调拼接 |
| `STORAGE_TYPE` | 否 | local | 存储类型 |
| `UPLOAD_LOCAL_PATH` | 否 | `./storage/uploads` | 上传文件存储路径 |
| `FFMPEG_BIN` | 否 | 空 | FFmpeg 路径(留空自动查找) |
| `CAPTCHA_ENABLED` | 否 | true | 是否启用验证码 |
| `CELERY_BROKER_URL` | 否 | 空 | Celery Broker(留空禁用 Celery |
| `CELERY_RESULT_BACKEND` | 否 | 空 | Celery 结果后端 |
| `RATE_LIMIT_ENABLED` | 否 | true | 是否启用限流 |
### 前台 (video-gen-app/.env.production)
| 变量 | 必填 | 默认值 | 说明 |
|------|------|--------|------|
| `VITE_API_BASE` | **是** | localhost:8000 | 后端 API 地址 |
| `VITE_USE_MOCK` | 否 | false | 是否使用 mock 数据 |
| `VITE_ENCRYPTION_KEY` | 否 | 空 | 通信加密密钥(与后端一致) |
### 后台管理 (video-gen-admin/.env.production)
同前台。
---
## 十二、故障排查
| 现象 | 可能原因 | 解决方案 |
|------|---------|---------|
| 前端登录后 401 | Token 过期或 SECRET_KEY 不一致 | 检查后端 `SECRET_KEY` 是否变更 |
| 上传文件失败 413 | Nginx 上传大小限制 | 增大 `client_max_body_size` |
| 加密请求报错"解密失败" | 前后端密钥不一致 | 确保 `VITE_ENCRYPTION_KEY` = 后端 `ENCRYPTION_KEY` |
| 非 HTTPS 环境加密无效 | Web Crypto API 需要安全上下文 | 本地开发用 localhost,生产用 HTTPS |
| Celery 任务不执行 | Redis 未启动或地址错误 | 检查 `CELERY_BROKER_URL` 和 Redis |
| 限流不生效 | Redis 未配置 | 检查 `REDIS_URL` |
| 短信发送失败 | 火山配置缺失或 `SMS_MOCK=true` | 填入 `VOLC_SMS_*` 变量并设 `SMS_MOCK=false` |
| 视频封面无法生成 | FFmpeg 未安装 | 安装 FFmpeg 或设置 `FFMPEG_BIN` |
| HTTPS 请求支付宝/火山失败 | 缺少 CA 证书 | 安装 `ca-certificates` |
| 数据库迁移失败 | Model 定义与迁移不一致 | 重新生成迁移文件后执行 |