3462 lines
82 KiB
Markdown
3462 lines
82 KiB
Markdown
# AI视频平台开发文档
|
||
|
||
## 1. 项目目标
|
||
|
||
### 1.1 项目定位
|
||
|
||
建设一个类似 `plotparty.ai` 的 AI 视频生成平台,面向普通用户和内容创作者,提供以下能力:
|
||
|
||
- 用户注册、登录、充值、查看积分余额
|
||
- 用户通过密钥兑换积分
|
||
- 用户可编辑用户名、头像等个人资料
|
||
- 用户可创建自己的邀请链接或邀请码
|
||
- 用户提交 AI 视频生成任务
|
||
- 用户上传图片、音频、视频等参考素材
|
||
- 用户可查看自己全部视频生成记录,并可自行删除记录
|
||
- 平台根据后台配置调用不同第三方视频模型 API
|
||
- 平台根据后台价格规则按秒对用户进行积分扣费
|
||
- 管理员后台可配置多个视频模型供应商,并为每个前台视频模型绑定一个或多个供应商模型
|
||
- 管理员后台可配置注册赠送积分、邀请奖励积分、邀请码功能是否开启
|
||
- 管理员在后台配置 API、模型、积分价格、充值比例、套餐、公告和风控策略
|
||
- 平台记录完整的任务、计费、充值、回调和操作日志
|
||
|
||
### 1.2 首期范围
|
||
|
||
首版建议聚焦下面 4 个核心闭环:
|
||
|
||
1. 用户充值到账
|
||
2. 用户发起视频生成任务
|
||
3. 后端异步调用第三方模型并查询结果
|
||
4. 管理员可动态调整模型、价格和充值配置
|
||
|
||
### 1.3 不在首版强制范围内
|
||
|
||
- 社区广场、作品公开发布、点赞评论
|
||
- 多租户代理分销
|
||
- 多级分销返佣
|
||
- 自研模型推理集群
|
||
- 视频在线剪辑器
|
||
- 高级工作流编排
|
||
|
||
这些能力可以在首版稳定后迭代。
|
||
|
||
## 2. 技术选型
|
||
|
||
### 2.1 最终建议
|
||
|
||
后端使用 `Python`,数据库使用 `MySQL`。
|
||
|
||
### 2.2 选型理由
|
||
|
||
对于本项目,真正复杂的地方是:
|
||
|
||
- 对接多个第三方 AI 视频 API
|
||
- 长任务异步调度
|
||
- 充值、扣费、退款和幂等控制
|
||
- 后台频繁调整业务规则
|
||
|
||
这类场景更偏向“业务编排”和“集成开发”,不是 CPU 密集型高性能计算,因此优先选择开发效率更高、AI 生态更成熟的 Python。
|
||
|
||
### 2.3 推荐技术栈
|
||
|
||
#### 后端
|
||
|
||
- `Python 3.12`
|
||
- `FastAPI`
|
||
- `SQLAlchemy 2.0`
|
||
- `Alembic`
|
||
- `Pydantic v2`
|
||
- `Celery` 或 `Dramatiq`
|
||
- `Redis`
|
||
- `MySQL 8.0`
|
||
|
||
#### 前端
|
||
|
||
- `Next.js`
|
||
- `React`
|
||
- `TypeScript`
|
||
- `Tailwind CSS`
|
||
- 用户端可用 `shadcn/ui`
|
||
- 管理端可用 `Ant Design`
|
||
|
||
#### 基础设施
|
||
|
||
- `Nginx`
|
||
- `Docker / Docker Compose`
|
||
- 对象存储:`MinIO / S3 / OSS / COS`
|
||
- 文件分发:`CDN`
|
||
- 监控:`Prometheus + Grafana`
|
||
- 错误追踪:`Sentry`
|
||
|
||
### 2.4 架构决策
|
||
|
||
#### 服务形态
|
||
|
||
采用“前后端分离 + 单后端服务 + 异步任务 Worker”的结构。
|
||
|
||
#### API 风格
|
||
|
||
采用 `REST API`,首版不建议引入 GraphQL。
|
||
|
||
#### 鉴权策略
|
||
|
||
用户端采用 `JWT Access Token + Refresh Token`。
|
||
后台管理员使用单独的管理员账号体系和 RBAC 权限控制。
|
||
|
||
#### 实时反馈方式
|
||
|
||
首版建议以“轮询任务状态”为主,后续可增加 `SSE` 推送。
|
||
|
||
#### 项目结构
|
||
|
||
后端采用“按业务模块划分”的 feature-first 结构,避免 controller/service/repository 全项目散落。
|
||
|
||
## 3. 系统总体架构
|
||
|
||
### 3.1 逻辑架构
|
||
|
||
系统分为以下几个部分:
|
||
|
||
1. 用户前台
|
||
2. 管理后台
|
||
3. 业务 API 服务
|
||
4. 异步任务服务
|
||
5. MySQL 数据库
|
||
6. Redis 缓存与队列
|
||
7. 对象存储
|
||
8. 第三方支付服务
|
||
9. 第三方 AI 视频模型服务
|
||
|
||
### 3.2 推荐部署结构
|
||
|
||
```text
|
||
用户浏览器 / 管理后台
|
||
|
|
||
Nginx
|
||
|
|
||
-------------------------
|
||
| |
|
||
Next.js Frontend FastAPI Backend
|
||
|
|
||
----------------------------------
|
||
| | |
|
||
MySQL Redis Object Storage
|
||
|
|
||
Celery Worker
|
||
|
|
||
----------------------------------
|
||
| | |
|
||
OpenAI 官方格式 Seedance 格式 其他扩展格式
|
||
```
|
||
|
||
### 3.3 核心原则
|
||
|
||
- 业务 API 不直接阻塞等待视频生成完成
|
||
- 所有扣费必须有流水
|
||
- 所有第三方回调必须幂等
|
||
- 所有模型调用必须做抽象适配,不将业务逻辑直接耦合到某一家 API
|
||
- 所有后台配置变更必须保留操作日志
|
||
|
||
## 4. 角色与权限
|
||
|
||
### 4.1 用户角色
|
||
|
||
- 普通用户
|
||
- 管理员
|
||
- 超级管理员
|
||
|
||
### 4.2 普通用户能力
|
||
|
||
- 注册 / 登录 / 退出
|
||
- 查看个人资料
|
||
- 修改用户名、头像、昵称
|
||
- 兑换积分密钥
|
||
- 创建和管理自己的邀请码 / 邀请链接
|
||
- 查看邀请数据和奖励记录
|
||
- 上传素材
|
||
- 创建视频生成任务
|
||
- 查看任务列表和详情
|
||
- 删除自己的任务记录
|
||
- 下载生成结果
|
||
- 查看积分余额和流水
|
||
- 发起充值
|
||
|
||
### 4.3 管理员能力
|
||
|
||
- 管理用户
|
||
- 查看充值订单
|
||
- 查看视频任务
|
||
- 配置积分兑换密钥
|
||
- 配置注册赠送积分规则
|
||
- 配置邀请奖励规则
|
||
- 配置多个视频供应商账号
|
||
- 配置供应商模型与平台模型
|
||
- 配置价格规则
|
||
- 配置充值套餐和充值赠送比例
|
||
- 处理失败订单和人工补单
|
||
- 查看回调日志、任务日志、系统日志
|
||
|
||
### 4.4 RBAC 权限模块
|
||
|
||
后台建议最少拆分以下权限:
|
||
|
||
- `user:view`
|
||
- `user:edit`
|
||
- `order:view`
|
||
- `wallet:view`
|
||
- `wallet:manual_adjust`
|
||
- `task:view`
|
||
- `task:retry`
|
||
- `provider:view`
|
||
- `provider:edit`
|
||
- `pricing:view`
|
||
- `pricing:edit`
|
||
- `growth:view`
|
||
- `growth:edit`
|
||
- `redeem:view`
|
||
- `redeem:edit`
|
||
- `system:view`
|
||
- `system:edit`
|
||
|
||
## 5. 核心业务流程
|
||
|
||
### 5.1 用户充值流程
|
||
|
||
```text
|
||
用户选择充值套餐
|
||
-> 创建充值订单
|
||
-> 跳转支付
|
||
-> 第三方支付回调
|
||
-> 校验签名与订单状态
|
||
-> 幂等更新订单为已支付
|
||
-> 增加用户积分钱包余额
|
||
-> 写入钱包流水
|
||
-> 返回支付结果
|
||
```
|
||
|
||
#### 关键要求
|
||
|
||
- 支付回调必须验签
|
||
- 订单状态更新必须幂等
|
||
- 钱包积分增加必须和订单状态更新在同一事务中
|
||
- 同一订单只能入账一次
|
||
|
||
### 5.2 视频生成流程
|
||
|
||
```text
|
||
用户提交生成参数
|
||
-> 校验模型是否启用
|
||
-> 计算预估积分费用
|
||
-> 校验积分余额
|
||
-> 冻结预扣积分
|
||
-> 创建本地任务记录
|
||
-> 投递异步任务
|
||
-> Worker 调用第三方视频生成 API
|
||
-> 保存第三方任务ID
|
||
-> 定时轮询任务状态
|
||
-> 成功后下载/转存结果
|
||
-> 按规则完成最终结算
|
||
-> 更新任务状态
|
||
-> 用户查看并下载结果
|
||
```
|
||
|
||
#### 推荐结算策略
|
||
|
||
为了兼容不同模型与不同供应商格式,建议使用:
|
||
|
||
- 提交任务时:冻结预扣积分
|
||
- 任务成功时:正式扣减积分
|
||
- 任务失败时:解冻积分
|
||
- 若平台后续需要按供应商实际成本二次修正:执行补扣或退回积分差额
|
||
|
||
这样可以同时满足:
|
||
|
||
- 用户提交前能看到大致费用
|
||
- 平台可以控制风险
|
||
- 后期支持不同模型差异化积分定价
|
||
|
||
### 5.3 后台价格配置流程
|
||
|
||
```text
|
||
管理员配置模型价格规则
|
||
-> 配置是否启用
|
||
-> 选择平台视频模型
|
||
-> 配置每秒积分价格
|
||
-> 配置最低积分扣费
|
||
-> 配置生效时间和版本
|
||
-> 保存版本化价格配置
|
||
-> 新任务按最新生效版本计费
|
||
```
|
||
|
||
### 5.4 人工补单与钱包调整流程
|
||
|
||
管理员后台允许人工修正:
|
||
|
||
- 充值成功但未到账
|
||
- 任务失败需补偿
|
||
- 手工赠送积分
|
||
- 风控冻结后恢复
|
||
|
||
所有人工调整都必须:
|
||
|
||
- 记录操作人
|
||
- 记录原因
|
||
- 记录前后积分
|
||
- 写入钱包流水
|
||
- 可审计
|
||
|
||
### 5.5 密钥兑换积分流程
|
||
|
||
```text
|
||
用户输入兑换密钥
|
||
-> 后端校验密钥格式
|
||
-> 查询兑换密钥状态
|
||
-> 校验是否已使用、是否过期、是否禁用
|
||
-> 对兑换密钥记录加锁
|
||
-> 增加用户积分
|
||
-> 写入钱包流水
|
||
-> 标记兑换密钥为已使用
|
||
-> 写入兑换记录
|
||
-> 返回兑换结果
|
||
```
|
||
|
||
#### 关键要求
|
||
|
||
- 一个兑换密钥默认只能使用一次
|
||
- 必须使用数据库事务 + 行锁防止重复兑换
|
||
- 后台可生成批量兑换密钥或手动导入兑换密钥
|
||
- 所有兑换失败原因必须明确记录
|
||
|
||
### 5.6 新用户注册赠送积分流程
|
||
|
||
```text
|
||
用户完成注册
|
||
-> 后端读取注册赠送规则
|
||
-> 若规则开启,则给用户发放注册奖励积分
|
||
-> 写入钱包流水
|
||
-> 写入奖励发放记录
|
||
```
|
||
|
||
#### 关键要求
|
||
|
||
- 每个用户只能获得一次注册赠送
|
||
- 注册赠送是否开启、赠送多少积分由后台控制
|
||
- 注册赠送积分应有单独业务类型,不能与充值积分混淆
|
||
|
||
### 5.7 邀请奖励流程
|
||
|
||
推荐将邀请奖励触发条件定义为:
|
||
|
||
- 新用户通过邀请码或邀请链接注册成功
|
||
- 该新用户首次发生有效积分消费
|
||
- 邀请人获得一次邀请奖励积分
|
||
|
||
```text
|
||
新用户使用邀请码注册
|
||
-> 建立邀请关系
|
||
-> 新用户完成首次有效消费
|
||
-> 系统检查该邀请关系是否已发奖
|
||
-> 若未发奖且邀请奖励功能开启
|
||
-> 向邀请人发放积分奖励
|
||
-> 写入钱包流水
|
||
-> 更新邀请关系奖励状态
|
||
```
|
||
|
||
#### 关键要求
|
||
|
||
- 每个被邀请用户只能触发一次邀请奖励
|
||
- 奖励应在“首次有效消费成功”后发放,而不是注册后立即发放
|
||
- 有效消费建议定义为:首次 `final_points > 0` 且任务状态为 `succeeded`
|
||
- 后台可控制是否开启邀请奖励以及奖励多少积分
|
||
- 必须防刷,不能允许同设备批量注册反复薅奖励
|
||
|
||
### 5.8 视频记录删除规则
|
||
|
||
用户删除视频记录时,不建议物理删除数据库记录,建议采用“用户侧软删除”:
|
||
|
||
```text
|
||
用户点击删除任务记录
|
||
-> 校验该任务属于当前用户
|
||
-> 更新任务记录为用户不可见
|
||
-> 保留后台审计信息和财务流水
|
||
-> 前台默认不再展示该记录
|
||
```
|
||
|
||
#### 关键要求
|
||
|
||
- 用户删除仅影响前台可见性,不影响后台审计
|
||
- 已生成文件可按延迟清理策略处理,不建议立即物理删除
|
||
- 充值、积分、奖励相关记录不得被用户删除
|
||
|
||
## 6. 第三方视频模型接入设计
|
||
|
||
### 6.1 基本原则
|
||
|
||
首版明确只支持两种视频 API 协议格式:
|
||
|
||
- `openai_official_video`
|
||
- `seedance_video_generation`
|
||
|
||
同时遵循以下原则:
|
||
|
||
- 管理后台可以配置多个供应商账号
|
||
- 一个供应商账号下可以配置多个供应商模型
|
||
- 前台展示的是“平台视频模型”,不是直接暴露供应商模型
|
||
- 一个平台视频模型可以绑定多个供应商模型,用于主备切换或故障回退
|
||
- 业务层只面向统一适配器接口,不直接耦合 OpenAI 或 Seedance 原始协议
|
||
|
||
### 6.2 统一适配器接口
|
||
|
||
#### 推荐抽象接口
|
||
|
||
```python
|
||
class VideoProviderAdapter(Protocol):
|
||
api_format: str
|
||
|
||
def submit_task(self, payload: dict) -> SubmitResult: ...
|
||
def query_task(self, external_task_id: str) -> QueryResult: ...
|
||
def download_result(self, external_task_id: str, variant: str = "video") -> bytes: ...
|
||
def cancel_task(self, external_task_id: str) -> CancelResult: ...
|
||
def remix_task(self, external_task_id: str, payload: dict) -> SubmitResult: ...
|
||
def normalize_webhook(self, payload: dict) -> CallbackResult: ...
|
||
```
|
||
|
||
### 6.3 OpenAI 官方视频格式适配说明
|
||
|
||
根据 OpenAI 官方文档,当前视频 API 的核心接口格式如下:
|
||
|
||
- `POST /v1/videos` 创建视频生成任务
|
||
- `GET /v1/videos/{video_id}` 查询任务状态
|
||
- `GET /v1/videos/{video_id}/content` 下载最终视频内容
|
||
- `POST /v1/videos/{video_id}/remix` 基于已有视频生成 remix
|
||
- 支持 webhook 事件:`video.completed`、`video.failed`
|
||
|
||
OpenAI 官方格式的关键特点:
|
||
|
||
- 创建接口使用 `multipart/form-data`
|
||
- 核心参数包括:`prompt`、`model`、`seconds`、`size`
|
||
- 可选 `input_reference` 图片作为首帧参考
|
||
- 当前官方文档公开的模型包括 `sora-2`、`sora-2-pro`
|
||
- 任务状态主要包括 `queued`、`in_progress`、`completed`、`failed`
|
||
- 视频完成后通过 `/content` 下载,下载资产可能存在 `expires_at`
|
||
- 支持 `variant` 下载派生资源,例如缩略图或 spritesheet
|
||
|
||
平台接入 OpenAI 官方格式时,后端需要注意:
|
||
|
||
- 请求体不是 JSON,而是 `multipart/form-data`
|
||
- 参数校验要按 OpenAI 允许值做白名单校验
|
||
- 完成后立即下载并转存到自己的对象存储
|
||
- webhook 验签必须按 OpenAI 官方 webhook secret 做校验
|
||
- 前台不要直接暴露 OpenAI 原始模型名和下载地址
|
||
|
||
#### OpenAI 官方格式示例
|
||
|
||
```bash
|
||
curl -X POST "https://api.openai.com/v1/videos" \
|
||
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||
-H "Content-Type: multipart/form-data" \
|
||
-F 'prompt=A cinematic shot of a paper airplane flying through a neon city at night' \
|
||
-F 'model=sora-2' \
|
||
-F 'seconds=8' \
|
||
-F 'size=1280x720' \
|
||
-F 'input_reference=@frame.png;type=image/png'
|
||
```
|
||
|
||
典型返回结构:
|
||
|
||
```json
|
||
{
|
||
"id": "video_123",
|
||
"object": "video",
|
||
"model": "sora-2",
|
||
"status": "queued",
|
||
"progress": 0,
|
||
"seconds": "8",
|
||
"size": "1280x720"
|
||
}
|
||
```
|
||
|
||
### 6.4 Seedance 格式适配说明
|
||
|
||
根据你项目目录中的 `Seedance_2.0_客户使用手册.docx`,可确认其核心特点:
|
||
|
||
- 通过 `POST /v1/video/generations` 创建异步生成任务
|
||
- 通过 `GET /v1/video/generations/{id}` 查询状态
|
||
- 支持 `seedance` 和 `seedance-fast`
|
||
- 支持文本、图片、视频、音频组合输入
|
||
- 支持 `generate_audio`、`ratio`、`duration`
|
||
- 生成结果需要尽快下载,文档里提到结果链接存在有效期
|
||
|
||
因此平台内部要统一做以下事情:
|
||
|
||
- 提交任务后保存第三方任务 ID
|
||
- 定时查询第三方任务状态
|
||
- 成功后将结果文件转存到自己的对象存储
|
||
- 不依赖第三方临时链接作为最终下载地址
|
||
|
||
#### Seedance 格式示例
|
||
|
||
```json
|
||
{
|
||
"model": "seedance",
|
||
"content": [
|
||
{
|
||
"type": "text",
|
||
"text": "夜晚的城市高架桥上,一辆银色跑车高速穿行,镜头跟拍,霓虹反光强烈。"
|
||
},
|
||
{
|
||
"type": "image_url",
|
||
"image_url": {
|
||
"url": "https://example.com/reference.png"
|
||
},
|
||
"role": "reference_image"
|
||
}
|
||
],
|
||
"generate_audio": true,
|
||
"ratio": "16:9",
|
||
"duration": 8
|
||
}
|
||
```
|
||
|
||
典型查询接口:
|
||
|
||
```text
|
||
GET /v1/video/generations/{task_id}
|
||
```
|
||
|
||
### 6.5 平台模型与供应商绑定设计
|
||
|
||
为了支持“多个供应商 + 每个前台视频单独定价”,数据结构上必须区分三层:
|
||
|
||
1. 供应商账号:如 OpenAI 主账号、Seedance 主账号
|
||
2. 供应商模型:如 `sora-2`、`sora-2-pro`、`seedance`、`seedance-fast`
|
||
3. 平台视频模型:用户前台看到的产品模型,如“标准视频”“高速视频”“高清视频”
|
||
|
||
推荐后台工作流:
|
||
|
||
1. 先新增多个供应商账号
|
||
2. 为每个供应商账号录入一个协议格式:`openai_official_video` 或 `seedance_video_generation`
|
||
3. 在供应商账号下录入供应商模型
|
||
4. 创建平台视频模型
|
||
5. 将一个平台视频模型绑定一个或多个供应商模型
|
||
6. 设置主供应商、优先级和故障切换顺序
|
||
|
||
首版建议使用最简单可控的优先级策略:
|
||
|
||
- 同一个平台视频模型可以绑定多个供应商模型
|
||
- 默认按优先级从高到低依次尝试
|
||
- 主供应商失败、限流或超时后切换到下一个供应商
|
||
- 前台价格不因供应商切换而变化,价格只绑定平台视频模型
|
||
|
||
### 6.6 模型差异抽象字段
|
||
|
||
后台配置中建议统一维护以下模型能力字段:
|
||
|
||
- 是否支持文生视频
|
||
- 是否支持图生视频
|
||
- 是否支持首尾帧
|
||
- 是否支持视频参考
|
||
- 是否支持音频参考
|
||
- 是否支持生成音频
|
||
- 支持的分辨率
|
||
- 支持的宽高比
|
||
- 支持的时长范围
|
||
- 默认时长
|
||
- 单次最大文件数
|
||
- 是否支持联网搜索
|
||
|
||
这样用户前台就能根据模型能力动态渲染表单。
|
||
|
||
## 7. 功能模块拆解
|
||
|
||
### 7.1 用户端
|
||
|
||
#### 账户系统
|
||
|
||
- 手机号 / 邮箱注册登录
|
||
- 验证码登录
|
||
- 密码登录
|
||
- 忘记密码
|
||
- 绑定手机号 / 邮箱
|
||
- 设置用户名
|
||
- 设置头像
|
||
- 设置昵称
|
||
|
||
#### 钱包系统
|
||
|
||
- 当前积分余额
|
||
- 冻结积分
|
||
- 可用积分
|
||
- 充值入口
|
||
- 兑换码入口
|
||
- 充值记录
|
||
- 消费记录
|
||
- 退款记录
|
||
- 奖励记录
|
||
|
||
#### 素材系统
|
||
|
||
- 上传图片
|
||
- 上传音频
|
||
- 上传视频
|
||
- 删除素材
|
||
- 查看素材列表
|
||
|
||
#### 视频任务系统
|
||
|
||
- 创建任务
|
||
- 查看任务进度
|
||
- 查看失败原因
|
||
- 查看结果视频
|
||
- 再次生成
|
||
- 复制参数重建任务
|
||
- 删除自己的任务记录
|
||
|
||
#### 邀请系统
|
||
|
||
- 生成邀请码
|
||
- 生成邀请链接
|
||
- 查看邀请人数
|
||
- 查看邀请奖励记录
|
||
- 查看待奖励邀请用户
|
||
|
||
### 7.2 管理后台
|
||
|
||
#### 控制台
|
||
|
||
- 今日充值金额
|
||
- 今日订单数
|
||
- 今日任务数
|
||
- 成功率
|
||
- 用户增长
|
||
- 模型调用分布
|
||
|
||
#### 用户管理
|
||
|
||
- 用户列表
|
||
- 用户详情
|
||
- 积分余额查看
|
||
- 冻结/解冻用户
|
||
- 人工调整积分
|
||
- 查看邀请关系
|
||
- 查看邀请码
|
||
|
||
#### 充值管理
|
||
|
||
- 充值订单列表
|
||
- 订单状态筛选
|
||
- 回调日志
|
||
- 异常订单补偿
|
||
|
||
#### 兑换密钥管理
|
||
|
||
- 批量生成兑换密钥
|
||
- 手动导入兑换密钥
|
||
- 设置兑换积分数量
|
||
- 设置有效期
|
||
- 查看兑换记录
|
||
- 禁用兑换密钥
|
||
|
||
#### 视频任务管理
|
||
|
||
- 任务列表
|
||
- 任务状态筛选
|
||
- 按模型筛选
|
||
- 查看原始请求参数
|
||
- 查看第三方返回
|
||
- 重试任务
|
||
- 标记补偿
|
||
|
||
#### 供应商管理
|
||
|
||
- 可配置多个供应商账号
|
||
- 第三方平台名称
|
||
- 协议格式类型
|
||
- Base URL
|
||
- API Key
|
||
- Secret
|
||
- Webhook Secret
|
||
- 默认超时时间
|
||
- 重试策略
|
||
- 是否启用
|
||
|
||
#### 供应商模型管理
|
||
|
||
- 供应商模型名称
|
||
- 供应商模型编码
|
||
- 所属平台
|
||
- 是否上架
|
||
- 能力标签
|
||
- 默认参数
|
||
|
||
#### 平台视频模型管理
|
||
|
||
- 平台模型名称
|
||
- 前台展示名称
|
||
- 绑定多个供应商模型
|
||
- 默认路由供应商
|
||
- 默认参数
|
||
- 是否上架
|
||
|
||
#### 价格配置管理
|
||
|
||
- 按平台视频模型定价
|
||
- 每秒积分价格
|
||
- 最低积分扣费
|
||
- 生效时间
|
||
- 版本管理
|
||
|
||
#### 增长奖励配置管理
|
||
|
||
- 是否开启新用户注册送积分
|
||
- 注册赠送积分数量
|
||
- 是否开启邀请奖励
|
||
- 邀请奖励积分数量
|
||
- 邀请奖励触发条件说明
|
||
|
||
#### 充值配置管理
|
||
|
||
- 固定充值套餐
|
||
- 赠送比例
|
||
- 实付与到账换算比例
|
||
- 活动时间范围
|
||
- 是否启用
|
||
|
||
#### 系统配置管理
|
||
|
||
- 网站标题
|
||
- 首页公告
|
||
- 用户协议
|
||
- 隐私政策
|
||
- 上传大小限制
|
||
- 允许的文件类型
|
||
|
||
## 8. 数据库设计
|
||
|
||
### 8.1 设计原则
|
||
|
||
- 使用 `MySQL 8.0`
|
||
- 人民币字段使用 `DECIMAL(10,2)`,禁止使用浮点
|
||
- 积分字段使用 `BIGINT UNSIGNED`
|
||
- 主键使用 `BIGINT UNSIGNED`
|
||
- 对外展示 ID 使用字符串型 `public_id`
|
||
- 所有表保留 `created_at`、`updated_at`
|
||
- 关键业务表加 `deleted_at` 实现软删除时要谨慎,钱包流水表不建议软删除
|
||
|
||
### 8.2 核心表清单
|
||
|
||
首版建议至少包含以下表:
|
||
|
||
1. `users`
|
||
2. `user_auths`
|
||
3. `admin_users`
|
||
4. `roles`
|
||
5. `permissions`
|
||
6. `admin_user_roles`
|
||
7. `wallets`
|
||
8. `wallet_transactions`
|
||
9. `growth_reward_rules`
|
||
10. `redeem_codes`
|
||
11. `invite_codes`
|
||
12. `invite_relations`
|
||
13. `recharge_plans`
|
||
14. `recharge_orders`
|
||
15. `payment_channels`
|
||
16. `provider_accounts`
|
||
17. `provider_models`
|
||
18. `video_models`
|
||
19. `video_model_supplier_bindings`
|
||
20. `pricing_rules`
|
||
21. `media_assets`
|
||
22. `video_generation_tasks`
|
||
23. `video_task_events`
|
||
24. `callback_logs`
|
||
25. `system_configs`
|
||
26. `operation_logs`
|
||
|
||
### 8.3 关键表设计
|
||
|
||
#### users
|
||
|
||
```sql
|
||
CREATE TABLE users (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
public_id VARCHAR(64) NOT NULL UNIQUE,
|
||
username VARCHAR(64) NULL DEFAULT NULL,
|
||
nickname VARCHAR(100) NOT NULL DEFAULT '',
|
||
avatar_url VARCHAR(500) NOT NULL DEFAULT '',
|
||
email VARCHAR(191) NOT NULL DEFAULT '',
|
||
mobile VARCHAR(32) NOT NULL DEFAULT '',
|
||
password_hash VARCHAR(255) NOT NULL DEFAULT '',
|
||
status TINYINT NOT NULL DEFAULT 1 COMMENT '1正常 2禁用 3冻结',
|
||
last_login_at DATETIME NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
UNIQUE KEY uk_users_username (username),
|
||
KEY idx_users_email (email),
|
||
KEY idx_users_mobile (mobile),
|
||
KEY idx_users_status (status)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### wallets
|
||
|
||
```sql
|
||
CREATE TABLE wallets (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
balance_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
frozen_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
total_recharged_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
total_consumed_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
total_refunded_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
UNIQUE KEY uk_wallets_user_id (user_id),
|
||
CONSTRAINT fk_wallets_user_id FOREIGN KEY (user_id) REFERENCES users(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### wallet_transactions
|
||
|
||
```sql
|
||
CREATE TABLE wallet_transactions (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
transaction_no VARCHAR(64) NOT NULL UNIQUE,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
wallet_id BIGINT UNSIGNED NOT NULL,
|
||
biz_type VARCHAR(32) NOT NULL COMMENT 'recharge/redeem_code/signup_reward/invite_reward/freeze/consume/refund/unfreeze/manual_adjust',
|
||
direction VARCHAR(16) NOT NULL COMMENT 'in/out/freeze/unfreeze',
|
||
amount_points BIGINT UNSIGNED NOT NULL,
|
||
balance_before_points BIGINT UNSIGNED NOT NULL,
|
||
balance_after_points BIGINT UNSIGNED NOT NULL,
|
||
frozen_before_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
frozen_after_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
related_type VARCHAR(32) NOT NULL DEFAULT '',
|
||
related_id BIGINT UNSIGNED NULL,
|
||
remark VARCHAR(255) NOT NULL DEFAULT '',
|
||
operator_type VARCHAR(16) NOT NULL DEFAULT 'system' COMMENT 'system/admin/user',
|
||
operator_id BIGINT UNSIGNED NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
KEY idx_wallet_tx_user_id (user_id),
|
||
KEY idx_wallet_tx_biz_type (biz_type),
|
||
KEY idx_wallet_tx_related (related_type, related_id),
|
||
CONSTRAINT fk_wallet_tx_user_id FOREIGN KEY (user_id) REFERENCES users(id),
|
||
CONSTRAINT fk_wallet_tx_wallet_id FOREIGN KEY (wallet_id) REFERENCES wallets(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### growth_reward_rules
|
||
|
||
```sql
|
||
CREATE TABLE growth_reward_rules (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
rule_type VARCHAR(32) NOT NULL COMMENT 'signup_reward/invite_reward',
|
||
enabled TINYINT NOT NULL DEFAULT 0,
|
||
reward_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
trigger_condition VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'on_register/on_first_consume',
|
||
remark VARCHAR(255) NOT NULL DEFAULT '',
|
||
updated_by_admin_id BIGINT UNSIGNED NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
UNIQUE KEY uk_growth_reward_rules_type (rule_type)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### redeem_codes
|
||
|
||
```sql
|
||
CREATE TABLE redeem_codes (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
batch_no VARCHAR(64) NOT NULL,
|
||
redeem_code VARCHAR(64) NOT NULL UNIQUE,
|
||
points BIGINT UNSIGNED NOT NULL,
|
||
status VARCHAR(32) NOT NULL DEFAULT 'unused' COMMENT 'unused/used/expired/disabled',
|
||
used_by_user_id BIGINT UNSIGNED NULL,
|
||
wallet_transaction_id BIGINT UNSIGNED NULL,
|
||
expired_at DATETIME NULL,
|
||
used_at DATETIME NULL,
|
||
created_by_admin_id BIGINT UNSIGNED NULL,
|
||
remark VARCHAR(255) NOT NULL DEFAULT '',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_redeem_codes_batch_no (batch_no),
|
||
KEY idx_redeem_codes_status (status),
|
||
KEY idx_redeem_codes_used_by_user_id (used_by_user_id),
|
||
CONSTRAINT fk_redeem_codes_used_by_user_id FOREIGN KEY (used_by_user_id) REFERENCES users(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### invite_codes
|
||
|
||
```sql
|
||
CREATE TABLE invite_codes (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
invite_code VARCHAR(32) NOT NULL UNIQUE,
|
||
invite_link VARCHAR(255) NOT NULL DEFAULT '',
|
||
status TINYINT NOT NULL DEFAULT 1 COMMENT '1启用 0停用',
|
||
is_default TINYINT NOT NULL DEFAULT 0,
|
||
max_use_count INT UNSIGNED NULL,
|
||
used_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_invite_codes_user_id (user_id),
|
||
KEY idx_invite_codes_status (status),
|
||
CONSTRAINT fk_invite_codes_user_id FOREIGN KEY (user_id) REFERENCES users(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### invite_relations
|
||
|
||
```sql
|
||
CREATE TABLE invite_relations (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
inviter_user_id BIGINT UNSIGNED NOT NULL,
|
||
invitee_user_id BIGINT UNSIGNED NOT NULL,
|
||
invite_code_id BIGINT UNSIGNED NOT NULL,
|
||
reward_status VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT 'pending/eligible/rewarded/invalid',
|
||
reward_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
first_consumed_task_id BIGINT UNSIGNED NULL,
|
||
first_consumed_at DATETIME NULL,
|
||
rewarded_at DATETIME NULL,
|
||
reward_wallet_transaction_id BIGINT UNSIGNED NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
UNIQUE KEY uk_invite_relations_invitee_user_id (invitee_user_id),
|
||
KEY idx_invite_relations_inviter_user_id (inviter_user_id),
|
||
KEY idx_invite_relations_reward_status (reward_status),
|
||
CONSTRAINT fk_invite_relations_inviter_user_id FOREIGN KEY (inviter_user_id) REFERENCES users(id),
|
||
CONSTRAINT fk_invite_relations_invitee_user_id FOREIGN KEY (invitee_user_id) REFERENCES users(id),
|
||
CONSTRAINT fk_invite_relations_invite_code_id FOREIGN KEY (invite_code_id) REFERENCES invite_codes(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### recharge_plans
|
||
|
||
```sql
|
||
CREATE TABLE recharge_plans (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
name VARCHAR(100) NOT NULL,
|
||
pay_amount DECIMAL(10,2) NOT NULL,
|
||
point_ratio INT UNSIGNED NOT NULL DEFAULT 10 COMMENT '1元兑换多少积分',
|
||
give_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
bonus_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
sort_order INT NOT NULL DEFAULT 0,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
start_at DATETIME NULL,
|
||
end_at DATETIME NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_recharge_plans_status (status)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### recharge_orders
|
||
|
||
```sql
|
||
CREATE TABLE recharge_orders (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
order_no VARCHAR(64) NOT NULL UNIQUE,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
recharge_plan_id BIGINT UNSIGNED NULL,
|
||
payment_channel_code VARCHAR(32) NOT NULL,
|
||
pay_amount DECIMAL(10,2) NOT NULL,
|
||
point_ratio_snapshot INT UNSIGNED NOT NULL,
|
||
give_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
bonus_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
arrival_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
currency VARCHAR(16) NOT NULL DEFAULT 'CNY',
|
||
status VARCHAR(32) NOT NULL COMMENT 'pending/paid/failed/cancelled/refunded',
|
||
third_party_order_no VARCHAR(100) NOT NULL DEFAULT '',
|
||
paid_at DATETIME NULL,
|
||
expired_at DATETIME NULL,
|
||
callback_payload JSON NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_recharge_orders_user_id (user_id),
|
||
KEY idx_recharge_orders_status (status),
|
||
KEY idx_recharge_orders_paid_at (paid_at),
|
||
CONSTRAINT fk_recharge_orders_user_id FOREIGN KEY (user_id) REFERENCES users(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### provider_accounts
|
||
|
||
```sql
|
||
CREATE TABLE provider_accounts (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
provider_code VARCHAR(32) NOT NULL UNIQUE,
|
||
provider_name VARCHAR(100) NOT NULL,
|
||
api_format VARCHAR(64) NOT NULL COMMENT 'openai_official_video/seedance_video_generation',
|
||
base_url VARCHAR(255) NOT NULL,
|
||
api_key_encrypted TEXT NOT NULL,
|
||
api_secret_encrypted TEXT NULL,
|
||
webhook_secret_encrypted TEXT NULL,
|
||
timeout_seconds INT NOT NULL DEFAULT 60,
|
||
max_retries INT NOT NULL DEFAULT 3,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
remark VARCHAR(255) NOT NULL DEFAULT '',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_provider_accounts_status (status)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### provider_models
|
||
|
||
```sql
|
||
CREATE TABLE provider_models (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
provider_account_id BIGINT UNSIGNED NOT NULL,
|
||
model_code VARCHAR(64) NOT NULL,
|
||
model_name VARCHAR(100) NOT NULL,
|
||
request_content_type VARCHAR(64) NOT NULL DEFAULT 'application/json',
|
||
scene_type VARCHAR(32) NOT NULL DEFAULT 'video_generation',
|
||
supports_text_to_video TINYINT NOT NULL DEFAULT 1,
|
||
supports_image_to_video TINYINT NOT NULL DEFAULT 0,
|
||
supports_video_reference TINYINT NOT NULL DEFAULT 0,
|
||
supports_audio_reference TINYINT NOT NULL DEFAULT 0,
|
||
supports_generate_audio TINYINT NOT NULL DEFAULT 0,
|
||
supports_remix TINYINT NOT NULL DEFAULT 0,
|
||
supports_webhook TINYINT NOT NULL DEFAULT 0,
|
||
min_duration INT NOT NULL DEFAULT 4,
|
||
max_duration INT NOT NULL DEFAULT 15,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
default_ratio VARCHAR(20) NOT NULL DEFAULT '16:9',
|
||
default_resolution VARCHAR(20) NOT NULL DEFAULT '720p',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
UNIQUE KEY uk_provider_model (provider_account_id, model_code),
|
||
KEY idx_provider_models_status (status),
|
||
CONSTRAINT fk_provider_models_provider_account_id FOREIGN KEY (provider_account_id) REFERENCES provider_accounts(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### video_models
|
||
|
||
```sql
|
||
CREATE TABLE video_models (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
model_key VARCHAR(64) NOT NULL UNIQUE,
|
||
model_name VARCHAR(100) NOT NULL,
|
||
frontend_title VARCHAR(100) NOT NULL,
|
||
frontend_description VARCHAR(255) NOT NULL DEFAULT '',
|
||
default_duration_seconds INT NOT NULL DEFAULT 8,
|
||
default_ratio VARCHAR(20) NOT NULL DEFAULT '16:9',
|
||
default_resolution VARCHAR(20) NOT NULL DEFAULT '720p',
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
sort_order INT NOT NULL DEFAULT 0,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_video_models_status (status)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### video_model_supplier_bindings
|
||
|
||
```sql
|
||
CREATE TABLE video_model_supplier_bindings (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
video_model_id BIGINT UNSIGNED NOT NULL,
|
||
provider_model_id BIGINT UNSIGNED NOT NULL,
|
||
routing_priority INT NOT NULL DEFAULT 100,
|
||
is_primary TINYINT NOT NULL DEFAULT 0,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
timeout_seconds_override INT NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
UNIQUE KEY uk_video_model_provider_model (video_model_id, provider_model_id),
|
||
KEY idx_video_model_bindings_priority (video_model_id, routing_priority),
|
||
CONSTRAINT fk_video_model_bindings_video_model_id FOREIGN KEY (video_model_id) REFERENCES video_models(id),
|
||
CONSTRAINT fk_video_model_bindings_provider_model_id FOREIGN KEY (provider_model_id) REFERENCES provider_models(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### pricing_rules
|
||
|
||
```sql
|
||
CREATE TABLE pricing_rules (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
rule_name VARCHAR(100) NOT NULL,
|
||
video_model_id BIGINT UNSIGNED NOT NULL,
|
||
billing_mode VARCHAR(32) NOT NULL DEFAULT 'per_second',
|
||
points_per_second INT UNSIGNED NOT NULL,
|
||
minimum_points INT UNSIGNED NOT NULL DEFAULT 0,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
effective_at DATETIME NOT NULL,
|
||
expired_at DATETIME NULL,
|
||
version_no INT NOT NULL DEFAULT 1,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_pricing_rules_model_id (video_model_id),
|
||
KEY idx_pricing_rules_status (status),
|
||
KEY idx_pricing_rules_effective_at (effective_at),
|
||
CONSTRAINT fk_pricing_rules_video_model_id FOREIGN KEY (video_model_id) REFERENCES video_models(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### media_assets
|
||
|
||
```sql
|
||
CREATE TABLE media_assets (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
asset_no VARCHAR(64) NOT NULL UNIQUE,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
media_type VARCHAR(16) NOT NULL COMMENT 'image/video/audio',
|
||
source_type VARCHAR(16) NOT NULL DEFAULT 'upload' COMMENT 'upload/generated/imported',
|
||
original_filename VARCHAR(255) NOT NULL,
|
||
mime_type VARCHAR(100) NOT NULL DEFAULT '',
|
||
file_size BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
storage_bucket VARCHAR(100) NOT NULL,
|
||
storage_key VARCHAR(255) NOT NULL,
|
||
public_url VARCHAR(500) NOT NULL DEFAULT '',
|
||
status VARCHAR(32) NOT NULL DEFAULT 'active',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_media_assets_user_id (user_id),
|
||
KEY idx_media_assets_media_type (media_type),
|
||
CONSTRAINT fk_media_assets_user_id FOREIGN KEY (user_id) REFERENCES users(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### video_generation_tasks
|
||
|
||
```sql
|
||
CREATE TABLE video_generation_tasks (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
task_no VARCHAR(64) NOT NULL UNIQUE,
|
||
user_id BIGINT UNSIGNED NOT NULL,
|
||
video_model_id BIGINT UNSIGNED NOT NULL,
|
||
provider_account_id BIGINT UNSIGNED NOT NULL,
|
||
provider_model_id BIGINT UNSIGNED NOT NULL,
|
||
provider_binding_id BIGINT UNSIGNED NULL,
|
||
pricing_rule_id BIGINT UNSIGNED NOT NULL,
|
||
external_task_id VARCHAR(100) NOT NULL DEFAULT '',
|
||
submit_mode VARCHAR(32) NOT NULL DEFAULT 'async',
|
||
task_status VARCHAR(32) NOT NULL COMMENT 'created/queued/running/succeeded/failed/cancelled',
|
||
generation_mode VARCHAR(32) NOT NULL COMMENT 'text_to_video/image_to_video/multimodal',
|
||
prompt_text TEXT NULL,
|
||
request_payload JSON NOT NULL,
|
||
response_payload JSON NULL,
|
||
duration_seconds INT NOT NULL DEFAULT 5,
|
||
ratio VARCHAR(20) NOT NULL DEFAULT '16:9',
|
||
resolution VARCHAR(20) NOT NULL DEFAULT '720p',
|
||
generate_audio TINYINT NOT NULL DEFAULT 0,
|
||
estimated_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
frozen_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
final_points BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
supplier_cost_amount DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||
supplier_cost_currency VARCHAR(16) NOT NULL DEFAULT '',
|
||
result_asset_id BIGINT UNSIGNED NULL,
|
||
fail_reason VARCHAR(500) NOT NULL DEFAULT '',
|
||
submitted_at DATETIME NULL,
|
||
started_at DATETIME NULL,
|
||
finished_at DATETIME NULL,
|
||
next_poll_at DATETIME NULL,
|
||
poll_count INT NOT NULL DEFAULT 0,
|
||
user_visible TINYINT NOT NULL DEFAULT 1,
|
||
user_deleted_at DATETIME NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_video_tasks_user_id (user_id),
|
||
KEY idx_video_tasks_status (task_status),
|
||
KEY idx_video_tasks_external_task_id (external_task_id),
|
||
KEY idx_video_tasks_next_poll_at (next_poll_at),
|
||
KEY idx_video_tasks_user_visible (user_id, user_visible),
|
||
CONSTRAINT fk_video_tasks_user_id FOREIGN KEY (user_id) REFERENCES users(id),
|
||
CONSTRAINT fk_video_tasks_video_model_id FOREIGN KEY (video_model_id) REFERENCES video_models(id),
|
||
CONSTRAINT fk_video_tasks_provider_account_id FOREIGN KEY (provider_account_id) REFERENCES provider_accounts(id),
|
||
CONSTRAINT fk_video_tasks_provider_model_id FOREIGN KEY (provider_model_id) REFERENCES provider_models(id),
|
||
CONSTRAINT fk_video_tasks_provider_binding_id FOREIGN KEY (provider_binding_id) REFERENCES video_model_supplier_bindings(id),
|
||
CONSTRAINT fk_video_tasks_pricing_rule_id FOREIGN KEY (pricing_rule_id) REFERENCES pricing_rules(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### video_task_events
|
||
|
||
```sql
|
||
CREATE TABLE video_task_events (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
video_task_id BIGINT UNSIGNED NOT NULL,
|
||
event_type VARCHAR(32) NOT NULL,
|
||
event_message VARCHAR(255) NOT NULL DEFAULT '',
|
||
payload JSON NULL,
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
KEY idx_video_task_events_task_id (video_task_id),
|
||
KEY idx_video_task_events_event_type (event_type),
|
||
CONSTRAINT fk_video_task_events_video_task_id FOREIGN KEY (video_task_id) REFERENCES video_generation_tasks(id)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
#### callback_logs
|
||
|
||
```sql
|
||
CREATE TABLE callback_logs (
|
||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||
source_type VARCHAR(32) NOT NULL COMMENT 'payment/provider',
|
||
source_code VARCHAR(32) NOT NULL,
|
||
related_no VARCHAR(64) NOT NULL DEFAULT '',
|
||
request_headers JSON NULL,
|
||
request_body JSON NULL,
|
||
verify_status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||
process_status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||
response_body TEXT NULL,
|
||
error_message VARCHAR(500) NOT NULL DEFAULT '',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
KEY idx_callback_logs_source (source_type, source_code),
|
||
KEY idx_callback_logs_related_no (related_no)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||
```
|
||
|
||
### 8.4 索引建议
|
||
|
||
以下字段必须建立索引:
|
||
|
||
- 用户登录查询:`email`、`mobile`
|
||
- 用户名查询:`username`
|
||
- 钱包流水列表:`user_id`、`created_at`
|
||
- 充值订单查询:`order_no`、`user_id`、`status`
|
||
- 兑换密钥查询:`redeem_code`、`status`
|
||
- 邀请码查询:`invite_code`、`user_id`
|
||
- 邀请关系查询:`invitee_user_id`、`inviter_user_id`、`reward_status`
|
||
- 任务轮询:`task_status`、`next_poll_at`
|
||
- 第三方回调:`external_task_id`
|
||
- 用户任务列表:`user_id`、`user_visible`、`created_at`
|
||
- 管理后台筛选:`video_model_id`、`provider_model_id`、`created_at`
|
||
|
||
### 8.5 金额与积分字段规范
|
||
|
||
金额与积分相关统一规定:
|
||
|
||
- 用户钱包单位:积分
|
||
- 积分字段统一使用 `BIGINT UNSIGNED`
|
||
- 支付金额单位:元
|
||
- 人民币字段统一使用 `DECIMAL(10,2)`
|
||
- 积分建议为整数,不使用小数积分
|
||
- 建议后台配置基础兑换比例,例如 `1 元 = 100 积分`
|
||
- 业务内部结算不允许使用 `float`
|
||
|
||
### 8.6 数据一致性要求
|
||
|
||
- 钱包积分更新必须使用事务
|
||
- 钱包积分扣减必须带版本控制或 `select ... for update`
|
||
- 充值回调必须通过唯一订单号防重
|
||
- 视频任务成功结算必须保证“状态更新 + 钱包流水”一致
|
||
- 兑换密钥兑换必须通过行锁保证只成功一次
|
||
- 注册赠送必须通过唯一用户校验只发放一次
|
||
- 邀请奖励必须通过唯一 invitee 校验只发放一次
|
||
- 供应商故障切换时不得重复提交同一任务到多个供应商,除非显式进入补偿重试流程
|
||
|
||
## 9. 后端模块设计
|
||
|
||
### 9.1 推荐目录结构
|
||
|
||
```text
|
||
backend/
|
||
app/
|
||
common/
|
||
config/
|
||
db/
|
||
errors/
|
||
middleware/
|
||
security/
|
||
utils/
|
||
modules/
|
||
auth/
|
||
users/
|
||
invites/
|
||
redeem_codes/
|
||
growth_rules/
|
||
wallets/
|
||
payments/
|
||
providers/
|
||
pricing/
|
||
assets/
|
||
video_tasks/
|
||
admins/
|
||
system/
|
||
workers/
|
||
scripts/
|
||
tests/
|
||
alembic/
|
||
```
|
||
|
||
### 9.2 模块职责
|
||
|
||
#### auth
|
||
|
||
- 注册登录
|
||
- JWT 签发与刷新
|
||
- 权限校验
|
||
|
||
#### users
|
||
|
||
- 个人资料查询
|
||
- 用户名与头像修改
|
||
- 用户状态校验
|
||
|
||
#### invites
|
||
|
||
- 邀请码生成
|
||
- 邀请关系建立
|
||
- 邀请奖励发放
|
||
- 邀请统计查询
|
||
|
||
#### redeem_codes
|
||
|
||
- 兑换密钥校验
|
||
- 兑换事务处理
|
||
- 兑换记录查询
|
||
|
||
#### growth_rules
|
||
|
||
- 注册赠送规则读取
|
||
- 邀请奖励规则读取
|
||
- 后台增长规则维护
|
||
|
||
#### wallets
|
||
|
||
- 钱包积分查询
|
||
- 冻结和解冻
|
||
- 积分扣减和退款
|
||
- 人工调账
|
||
|
||
#### payments
|
||
|
||
- 创建充值订单
|
||
- 调起支付
|
||
- 回调验签
|
||
- 到账处理
|
||
|
||
#### providers
|
||
|
||
- 多供应商账号配置
|
||
- OpenAI 官方格式适配器
|
||
- Seedance 格式适配器
|
||
- API 调用封装
|
||
- 回调标准化
|
||
- 供应商故障切换
|
||
|
||
#### pricing
|
||
|
||
- 价格规则查询
|
||
- 积分价格计算器
|
||
- 活动和赠送策略
|
||
|
||
#### assets
|
||
|
||
- 上传凭证
|
||
- 文件转存
|
||
- 文件元数据记录
|
||
|
||
#### video_tasks
|
||
|
||
- 创建任务
|
||
- 调度 worker
|
||
- 状态查询
|
||
- 结果保存
|
||
- 最终结算
|
||
|
||
## 10. API 设计
|
||
|
||
### 10.1 设计规范
|
||
|
||
- 路径使用复数资源名
|
||
- 响应统一包装
|
||
- 错误响应统一结构
|
||
- 列表接口统一分页
|
||
- 异步任务创建返回 `202 Accepted` 或 `200 + taskId`
|
||
|
||
### 10.2 推荐响应格式
|
||
|
||
#### 成功
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "ok",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
#### 失败
|
||
|
||
```json
|
||
{
|
||
"code": 40001,
|
||
"message": "insufficient balance",
|
||
"requestId": "req_xxx",
|
||
"errors": [
|
||
{
|
||
"field": "balance",
|
||
"reason": "not enough"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 10.3 用户端接口
|
||
|
||
#### 认证
|
||
|
||
- `POST /api/v1/auth/register`
|
||
- `POST /api/v1/auth/login`
|
||
- `POST /api/v1/auth/refresh`
|
||
- `POST /api/v1/auth/logout`
|
||
- `GET /api/v1/auth/me`
|
||
|
||
#### 个人资料
|
||
|
||
- `GET /api/v1/profile`
|
||
- `PUT /api/v1/profile`
|
||
|
||
#### 钱包
|
||
|
||
- `GET /api/v1/wallet`
|
||
- `GET /api/v1/wallet/transactions`
|
||
- `POST /api/v1/wallet/recharge-orders`
|
||
- `GET /api/v1/wallet/recharge-orders`
|
||
- `POST /api/v1/wallet/redeem-codes/exchange`
|
||
- `GET /api/v1/wallet/redeem-records`
|
||
|
||
#### 邀请
|
||
|
||
- `GET /api/v1/invite`
|
||
- `POST /api/v1/invite/codes`
|
||
- `GET /api/v1/invite/relations`
|
||
- `GET /api/v1/invite/rewards`
|
||
|
||
#### 素材
|
||
|
||
- `POST /api/v1/assets/upload-token`
|
||
- `POST /api/v1/assets`
|
||
- `GET /api/v1/assets`
|
||
- `DELETE /api/v1/assets/{assetId}`
|
||
|
||
#### 视频任务
|
||
|
||
- `GET /api/v1/video-models`
|
||
- `POST /api/v1/video-tasks`
|
||
- `GET /api/v1/video-tasks`
|
||
- `GET /api/v1/video-tasks/{taskId}`
|
||
- `POST /api/v1/video-tasks/{taskId}/retry`
|
||
- `POST /api/v1/video-tasks/{taskId}/cancel`
|
||
- `DELETE /api/v1/video-tasks/{taskId}`
|
||
|
||
### 10.4 管理后台接口
|
||
|
||
#### 用户与钱包
|
||
|
||
- `GET /api/v1/admin/users`
|
||
- `GET /api/v1/admin/users/{userId}`
|
||
- `POST /api/v1/admin/users/{userId}/wallet-adjust`
|
||
- `GET /api/v1/admin/users/{userId}/invite-relations`
|
||
|
||
#### 充值管理
|
||
|
||
- `GET /api/v1/admin/recharge-orders`
|
||
- `GET /api/v1/admin/recharge-orders/{orderId}`
|
||
- `POST /api/v1/admin/recharge-orders/{orderId}/repair`
|
||
|
||
#### 兑换密钥与增长奖励管理
|
||
|
||
- `GET /api/v1/admin/redeem-codes`
|
||
- `POST /api/v1/admin/redeem-codes/batch-create`
|
||
- `POST /api/v1/admin/redeem-codes/import`
|
||
- `PUT /api/v1/admin/redeem-codes/{id}/disable`
|
||
- `GET /api/v1/admin/growth-rules`
|
||
- `PUT /api/v1/admin/growth-rules/signup`
|
||
- `PUT /api/v1/admin/growth-rules/invite`
|
||
- `GET /api/v1/admin/invite-relations`
|
||
|
||
#### 平台和模型管理
|
||
|
||
- `GET /api/v1/admin/provider-accounts`
|
||
- `POST /api/v1/admin/provider-accounts`
|
||
- `PUT /api/v1/admin/provider-accounts/{id}`
|
||
- `GET /api/v1/admin/provider-models`
|
||
- `POST /api/v1/admin/provider-models`
|
||
- `PUT /api/v1/admin/provider-models/{id}`
|
||
- `GET /api/v1/admin/video-models`
|
||
- `POST /api/v1/admin/video-models`
|
||
- `PUT /api/v1/admin/video-models/{id}`
|
||
- `GET /api/v1/admin/video-model-bindings`
|
||
- `POST /api/v1/admin/video-model-bindings`
|
||
- `PUT /api/v1/admin/video-model-bindings/{id}`
|
||
|
||
#### 价格管理
|
||
|
||
- `GET /api/v1/admin/pricing-rules`
|
||
- `POST /api/v1/admin/pricing-rules`
|
||
- `PUT /api/v1/admin/pricing-rules/{id}`
|
||
- `POST /api/v1/admin/pricing-rules/{id}/publish`
|
||
|
||
#### 任务管理
|
||
|
||
- `GET /api/v1/admin/video-tasks`
|
||
- `GET /api/v1/admin/video-tasks/{id}`
|
||
- `POST /api/v1/admin/video-tasks/{id}/retry`
|
||
- `POST /api/v1/admin/video-tasks/{id}/refund`
|
||
|
||
## 11. 价格与充值设计
|
||
|
||
### 11.1 积分充值体系
|
||
|
||
首版建议采用“人民币充值 -> 积分到账”的积分钱包制。
|
||
|
||
例如:
|
||
|
||
- 用户支付 100 元
|
||
- 后台基础兑换比例配置为 `1 元 = 100 积分`
|
||
- 则基础到账 10000 积分
|
||
- 若活动赠送 1000 积分,则最终到账 11000 积分
|
||
|
||
因此要区分:
|
||
|
||
- `pay_amount`:用户实付金额
|
||
- `give_points`:基础到账积分
|
||
- `bonus_points`:赠送积分
|
||
- `arrival_points`:最终到账积分
|
||
|
||
### 11.2 价格规则设计
|
||
|
||
价格中心必须按“平台视频模型”单独配置价格。
|
||
|
||
首版统一采用:
|
||
|
||
- `按秒计费`
|
||
- `单位为积分`
|
||
- `每个平台视频模型单独设置 points_per_second`
|
||
|
||
例如:
|
||
|
||
- 标准视频:`120 积分/秒`
|
||
- 高速视频:`80 积分/秒`
|
||
- 高清视频:`200 积分/秒`
|
||
|
||
注意:
|
||
|
||
- 前台用户选择的是平台视频模型
|
||
- 后台真正路由到哪个供应商模型,不影响前台价格展示
|
||
- 这样可以在不中断用户体验的情况下切换供应商
|
||
|
||
### 11.3 推荐计费公式
|
||
|
||
```text
|
||
最终扣费积分 =
|
||
max(
|
||
最低积分扣费,
|
||
请求时长秒数 * 每秒积分价格
|
||
)
|
||
```
|
||
|
||
例如:
|
||
|
||
- 某平台视频模型价格为 `120 积分/秒`
|
||
- 用户提交 `8 秒`
|
||
- 最低扣费为 `500 积分`
|
||
- 最终扣费 = `max(500, 8 * 120) = 960 积分`
|
||
|
||
### 11.4 计费秒数标准
|
||
|
||
首版建议统一按“用户提交的请求时长”计费,而不是按供应商最终生成时长回写计费。
|
||
|
||
原因:
|
||
|
||
- 用户在提交前就能明确看到积分消耗
|
||
- OpenAI 与 Seedance 的返回格式不完全一致
|
||
- 避免因供应商返回的时长轻微偏差产生争议
|
||
|
||
### 11.5 供应商格式差异下的参数校验
|
||
|
||
首版在前台选择平台视频模型后,后端仍需依据实际命中的供应商模型做二次参数校验:
|
||
|
||
- OpenAI 官方格式:
|
||
- `seconds` 只允许官方支持的档位
|
||
- `size` 必须是官方允许的分辨率
|
||
- 有图参考时需使用 `multipart/form-data`
|
||
- Seedance 格式:
|
||
- `duration` 允许整数秒
|
||
- `content` 为多模态数组
|
||
- `generate_audio`、`ratio`、`tools` 等走 JSON 提交
|
||
|
||
### 11.6 首版建议
|
||
|
||
首版不要引入过于复杂的倍率系统,定价中心只保留:
|
||
|
||
- 平台视频模型
|
||
- 每秒积分价格
|
||
- 最低积分扣费
|
||
- 生效时间
|
||
- 版本号
|
||
|
||
### 11.7 积分来源与优先级
|
||
|
||
平台首版建议明确区分积分来源:
|
||
|
||
- 充值积分
|
||
- 兑换密钥积分
|
||
- 注册赠送积分
|
||
- 邀请奖励积分
|
||
- 人工补偿积分
|
||
|
||
建议所有积分都进入同一个钱包余额,但在流水中区分业务类型。
|
||
|
||
### 11.8 注册赠送与邀请奖励的发放规则
|
||
|
||
推荐规则如下:
|
||
|
||
- 注册赠送:
|
||
- 注册成功后立即发放
|
||
- 每个用户仅一次
|
||
- 邀请奖励:
|
||
- 仅当被邀请用户首次成功消费后发放
|
||
- 每个被邀请用户仅触发一次
|
||
- 若邀请关系被判定异常,则不发放奖励
|
||
|
||
### 11.9 密钥兑换规则
|
||
|
||
推荐规则如下:
|
||
|
||
- 默认一密一用
|
||
- 支持设置过期时间
|
||
- 支持后台批量生成
|
||
- 支持后台单个禁用
|
||
- 兑换后不可撤销,若需回收,应通过人工调账处理
|
||
|
||
## 12. 异步任务与调度设计
|
||
|
||
### 12.1 队列任务分类
|
||
|
||
- `submit_video_task`
|
||
- `poll_video_task_status`
|
||
- `finalize_video_task`
|
||
- `download_result_asset`
|
||
- `retry_failed_task`
|
||
- `grant_signup_reward`
|
||
- `grant_invite_reward`
|
||
|
||
### 12.2 轮询策略
|
||
|
||
推荐指数退避轮询:
|
||
|
||
- 第 1 次:10 秒后
|
||
- 第 2 次:20 秒后
|
||
- 第 3 次:30 秒后
|
||
- 第 4 次后:60 秒固定
|
||
- 最大轮询时间:根据模型 SLA 配置,例如 30 分钟
|
||
|
||
### 12.3 超时处理
|
||
|
||
若任务超时:
|
||
|
||
- 标记任务为失败或超时
|
||
- 释放冻结积分
|
||
- 记录第三方超时原因
|
||
- 可由管理员手动重试
|
||
|
||
## 13. 文件与对象存储设计
|
||
|
||
### 13.1 存储对象分类
|
||
|
||
- 用户上传原始图片
|
||
- 用户上传音频
|
||
- 用户上传视频参考
|
||
- 生成结果视频
|
||
- 缩略图和封面
|
||
|
||
### 13.2 推荐策略
|
||
|
||
- 浏览器直接上传对象存储,后端签发上传凭证
|
||
- 上传完成后由后端写入 `media_assets`
|
||
- 生成结果统一转存到自有桶
|
||
- 文件路径按日期和用户 ID 分层
|
||
|
||
示例:
|
||
|
||
```text
|
||
uploads/user/10001/images/2026/04/17/xxx.png
|
||
uploads/user/10001/videos/2026/04/17/xxx.mp4
|
||
generated/video/2026/04/17/task_xxx/result.mp4
|
||
```
|
||
|
||
### 13.3 下载控制
|
||
|
||
- 用户自己的文件可查看
|
||
- 生成结果可设置临时签名 URL
|
||
- 管理员可查看所有文件
|
||
|
||
## 14. 安全设计
|
||
|
||
### 14.1 必须实现
|
||
|
||
- HTTPS
|
||
- JWT 鉴权
|
||
- 管理后台 RBAC
|
||
- 管理后台强密码策略
|
||
- 管理后台建议开启二次验证
|
||
- 支付回调验签
|
||
- API Key 加密存储
|
||
- 限流
|
||
- 上传文件类型校验
|
||
- 敏感操作审计日志
|
||
- 密码使用 `Argon2id` 或 `bcrypt` 哈希存储
|
||
- 下载地址使用签名 URL
|
||
- 所有关键写操作支持幂等控制
|
||
|
||
### 14.2 风控建议
|
||
|
||
- 单用户分钟级任务创建频率限制
|
||
- 单用户每日消费上限
|
||
- 可疑账号风控标签
|
||
- 支付失败次数限制
|
||
- 超大文件拒绝上传
|
||
- 兑换密钥尝试次数限制
|
||
- 邀请码尝试次数限制
|
||
- 同 IP / 同设备注册频率限制
|
||
- 同设备多账号邀请奖励限制
|
||
|
||
### 14.3 数据安全
|
||
|
||
- API Key 使用应用层加密后保存
|
||
- 不在日志中输出完整秘钥
|
||
- 对回调报文脱敏存储
|
||
- 定期备份 MySQL 和对象存储元数据
|
||
- 用户密码、Token、支付报文中的敏感字段必须脱敏
|
||
- 生成视频原始供应商下载地址不直接暴露给前端
|
||
|
||
### 14.4 必须落实的安全基线
|
||
|
||
这部分不是建议,而是上线前必须落实:
|
||
|
||
1. 注册、登录、兑换密钥、创建任务、支付回调全部记录 request id
|
||
2. 所有创建类接口都校验登录态和用户状态
|
||
3. 所有查询类接口都校验资源归属,禁止越权查看他人任务
|
||
4. `DELETE /video-tasks/{id}` 只能删除自己的记录,且为软删除
|
||
5. 兑换密钥必须通过数据库事务加锁,防止并发重复兑换
|
||
6. 邀请奖励发放必须检查是否已奖励过,不能重复发奖
|
||
7. 后台接口必须进行角色权限校验,不能只依赖前端菜单隐藏
|
||
8. 对象存储桶不得设置公开读写
|
||
9. 上传文件必须做 MIME、扩展名、大小三重校验
|
||
10. 生产环境必须关闭调试模式和详细堆栈输出
|
||
|
||
### 14.5 邀请与兑换的防刷要求
|
||
|
||
邀请奖励和兑换密钥是最容易被攻击的两个模块,必须重点处理:
|
||
|
||
#### 兑换密钥防刷
|
||
|
||
- 单用户单位时间兑换失败次数限制
|
||
- 单 IP 单位时间兑换失败次数限制
|
||
- 兑换密钥使用后立即失效
|
||
- 后台支持一键禁用批次
|
||
- 对异常批量尝试行为进行告警
|
||
|
||
#### 邀请奖励防刷
|
||
|
||
- 同一被邀请用户只允许绑定一次邀请关系
|
||
- 同设备、同 IP、同支付标识可作为风控参考
|
||
- 邀请奖励必须延迟到首次有效消费后发放
|
||
- 可配置最小有效消费积分阈值,例如消费满 100 积分才触发奖励
|
||
- 若命中风控规则,可将奖励状态置为 `invalid`
|
||
|
||
### 14.6 用户删除记录的安全要求
|
||
|
||
用户删除视频记录时必须满足:
|
||
|
||
- 仅影响用户前台可见性
|
||
- 不删除任务日志、积分流水、邀请奖励触发依据
|
||
- 不删除后台审计记录
|
||
- 管理后台仍可检索该记录
|
||
|
||
### 14.7 推荐安全中间件
|
||
|
||
后端建议至少接入:
|
||
|
||
- 请求 ID 中间件
|
||
- 统一异常处理中间件
|
||
- JWT 鉴权中间件
|
||
- RBAC 权限中间件
|
||
- 频率限制中间件
|
||
- 管理后台操作审计中间件
|
||
|
||
## 15. 监控与日志
|
||
|
||
### 15.1 必备日志
|
||
|
||
- 请求日志
|
||
- 错误日志
|
||
- 支付回调日志
|
||
- 第三方 API 调用日志
|
||
- 视频任务事件日志
|
||
- 管理员操作日志
|
||
|
||
### 15.2 核心监控指标
|
||
|
||
- 注册用户数
|
||
- 充值转化率
|
||
- 任务提交成功率
|
||
- 第三方接口成功率
|
||
- 任务平均完成时长
|
||
- 模型调用成本
|
||
- 钱包积分扣费失败次数
|
||
|
||
### 15.3 告警建议
|
||
|
||
- 第三方接口连续失败
|
||
- 支付回调异常激增
|
||
- 队列积压
|
||
- MySQL 连接数过高
|
||
- Redis 内存过高
|
||
|
||
## 16. 开发阶段划分
|
||
|
||
### 16.1 Phase 1:MVP
|
||
|
||
目标:打通最小商业闭环。
|
||
|
||
包含:
|
||
|
||
- 用户登录注册
|
||
- 钱包与充值
|
||
- 兑换密钥
|
||
- 注册赠送积分
|
||
- 邀请码与邀请奖励
|
||
- 两种供应商协议接入:`OpenAI 官方格式 + Seedance 格式`
|
||
- 文生视频和图生视频
|
||
- 任务列表和详情
|
||
- 管理后台配置模型和价格
|
||
|
||
### 16.2 Phase 2:增强版
|
||
|
||
包含:
|
||
|
||
- 多模型接入
|
||
- 音频参考和视频参考
|
||
- 优惠活动和充值赠送
|
||
- 管理台统计报表
|
||
- 失败任务补偿
|
||
- SSE 任务状态推送
|
||
|
||
### 16.3 Phase 3:平台化
|
||
|
||
包含:
|
||
|
||
- 社区作品广场
|
||
- API 对外开放
|
||
- 渠道商体系
|
||
- 团队工作区
|
||
- 自动化风控与推荐
|
||
|
||
## 17. 建议开发排期
|
||
|
||
### 第 1 周
|
||
|
||
- 项目初始化
|
||
- 用户认证
|
||
- MySQL 基础表
|
||
- 钱包系统
|
||
|
||
### 第 2 周
|
||
|
||
- 充值订单
|
||
- 支付回调
|
||
- 素材上传
|
||
- 管理后台基础框架
|
||
|
||
### 第 3 周
|
||
|
||
- 视频任务创建
|
||
- 第三方模型接入
|
||
- Celery 轮询任务
|
||
- 结果转存
|
||
|
||
### 第 4 周
|
||
|
||
- 价格配置
|
||
- 后台模型管理
|
||
- 任务管理
|
||
- 错误处理与监控
|
||
|
||
### 第 5 周
|
||
|
||
- 联调测试
|
||
- 压测
|
||
- 修复异常流程
|
||
- 预发布上线
|
||
|
||
## 18. 测试方案
|
||
|
||
### 18.1 单元测试
|
||
|
||
- 价格计算器
|
||
- 钱包扣费逻辑
|
||
- 充值入账逻辑
|
||
- 兑换密钥兑换逻辑
|
||
- 注册赠送逻辑
|
||
- 邀请奖励发放逻辑
|
||
- 第三方适配器
|
||
|
||
### 18.2 集成测试
|
||
|
||
- 登录注册
|
||
- 充值下单
|
||
- 密钥兑换
|
||
- 邀请码注册
|
||
- 支付回调
|
||
- 任务创建到完成
|
||
- 失败退回积分
|
||
|
||
### 18.3 关键用例
|
||
|
||
- 重复支付回调只入账一次
|
||
- 任务失败后积分正确返还
|
||
- 同一个兑换密钥不能重复兑换
|
||
- 同一个被邀请用户不能重复触发邀请奖励
|
||
- 第三方返回慢时任务不会重复提交
|
||
- 多供应商绑定时主供应商失败可自动切换到备用供应商
|
||
- OpenAI 官方格式和 Seedance 格式都能正确映射到统一任务模型
|
||
- 管理员停用模型后前台不可选
|
||
|
||
## 19. 上线建议
|
||
|
||
### 19.1 生产环境组件
|
||
|
||
- `1 x Nginx`
|
||
- `1 x Next.js`
|
||
- `2 x FastAPI`
|
||
- `2 x Celery Worker`
|
||
- `1 x MySQL 主库`
|
||
- `1 x Redis`
|
||
- `1 x MinIO/OSS`
|
||
|
||
### 19.2 备份策略
|
||
|
||
- MySQL 每日全量备份
|
||
- 二进制日志保留至少 7 天
|
||
- 对象存储开启版本控制或跨区域备份
|
||
|
||
### 19.3 上线前检查
|
||
|
||
- 环境变量是否完整
|
||
- 支付回调域名是否正确
|
||
- CORS 白名单是否正确
|
||
- JWT 密钥是否已替换
|
||
- API Key 是否加密保存
|
||
- 监控和告警是否生效
|
||
|
||
## 20. 首版最终建议
|
||
|
||
### 20.1 技术结论
|
||
|
||
本项目首版推荐方案如下:
|
||
|
||
- 后端:`Python + FastAPI`
|
||
- 数据库:`MySQL 8`
|
||
- 缓存与队列:`Redis`
|
||
- 异步任务:`Celery`
|
||
- 前端:`Next.js + React`
|
||
- 管理后台:`Next.js Admin` 或独立 `React + Ant Design`
|
||
|
||
### 20.2 业务结论
|
||
|
||
首版优先实现:
|
||
|
||
1. 钱包充值
|
||
2. 视频生成
|
||
3. 后台配置多供应商、平台视频模型与积分价格
|
||
4. OpenAI 官方格式与 Seedance 格式双适配
|
||
5. 日志与回调幂等
|
||
|
||
### 20.3 架构结论
|
||
|
||
一定要从第一天就做好这 5 件事:
|
||
|
||
1. 第三方模型适配层
|
||
2. 钱包流水审计
|
||
3. 平台模型与供应商绑定层
|
||
4. 任务异步化
|
||
5. 后台动态积分价格配置
|
||
|
||
这五项决定后续能不能稳定扩展成真正的平台。
|
||
|
||
## 21. 开发落地规范
|
||
|
||
### 21.1 文档使用方式
|
||
|
||
这份文档应同时承担以下三个角色:
|
||
|
||
- 产品需求说明书
|
||
- 技术设计说明书
|
||
- 开发实施说明书
|
||
|
||
开发时建议按下面顺序阅读:
|
||
|
||
1. 先读 `1-6` 章,理解业务目标、供应商设计和计费方式
|
||
2. 再读 `8-12` 章,确定数据库、接口、积分规则和任务调度
|
||
3. 最后读 `21-31` 章,按页面、接口、状态机和验收标准落地开发
|
||
|
||
### 21.2 MVP 开发完成标准
|
||
|
||
满足以下条件,才可认为首版可上线测试:
|
||
|
||
1. 用户可注册、登录、退出,并正常刷新登录态
|
||
2. 用户可查看积分余额、充值套餐、充值记录、积分流水
|
||
3. 用户支付成功后,积分能准确到账且回调幂等
|
||
4. 用户可上传图片素材并发起视频任务
|
||
5. 前台可展示平台视频模型列表,并显示每秒积分价格
|
||
6. 用户可创建视频任务并看到预估扣费积分
|
||
7. 后端可根据平台视频模型路由到供应商模型
|
||
8. 平台至少支持 `OpenAI 官方格式` 和 `Seedance 格式`
|
||
9. 任务完成后能转存结果并在前台查看
|
||
10. 任务失败后能退回冻结积分
|
||
11. 用户可通过兑换密钥成功兑换积分
|
||
12. 用户可修改用户名、头像等资料
|
||
13. 邀请码注册、首次消费、邀请奖励链路可用
|
||
14. 用户可查看并软删除自己的视频记录
|
||
15. 管理后台可配置供应商账号、供应商模型、平台视频模型、模型绑定关系、价格规则、增长奖励规则、兑换密钥
|
||
16. 所有关键业务有日志、操作记录和错误追踪
|
||
|
||
### 21.3 项目分仓建议
|
||
|
||
建议首版使用单仓库,结构如下:
|
||
|
||
```text
|
||
AIVideo/
|
||
backend/
|
||
frontend-web/
|
||
frontend-admin/
|
||
docs/
|
||
deploy/
|
||
scripts/
|
||
sql/
|
||
```
|
||
|
||
如果团队规模较小,也可以采用:
|
||
|
||
```text
|
||
AIVideo/
|
||
apps/
|
||
api/
|
||
web/
|
||
admin/
|
||
packages/
|
||
shared-types/
|
||
deploy/
|
||
docs/
|
||
```
|
||
|
||
### 21.4 后端推荐文件清单
|
||
|
||
后端建议至少包含以下文件:
|
||
|
||
```text
|
||
backend/
|
||
app/
|
||
main.py
|
||
common/
|
||
config/settings.py
|
||
db/session.py
|
||
db/base.py
|
||
middleware/request_id.py
|
||
middleware/auth.py
|
||
errors/app_error.py
|
||
responses/api_response.py
|
||
security/jwt.py
|
||
security/encryptor.py
|
||
utils/time.py
|
||
utils/id_gen.py
|
||
modules/
|
||
auth/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
users/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
invites/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
redeem_codes/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
growth_rules/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
wallets/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
payments/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
channels/
|
||
alipay.py
|
||
wechat.py
|
||
assets/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
storage.py
|
||
providers/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
adapters/
|
||
base.py
|
||
openai_video.py
|
||
seedance_video.py
|
||
mapper.py
|
||
video_models/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
pricing/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
calculator.py
|
||
video_tasks/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
orchestrator.py
|
||
admins/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
system/
|
||
router.py
|
||
service.py
|
||
schema.py
|
||
repository.py
|
||
workers/
|
||
celery_app.py
|
||
tasks_video_submit.py
|
||
tasks_video_poll.py
|
||
tasks_video_finalize.py
|
||
tasks_recharge_repair.py
|
||
tasks_signup_reward.py
|
||
tasks_invite_reward.py
|
||
models/
|
||
user.py
|
||
wallet.py
|
||
growth_reward_rule.py
|
||
redeem_code.py
|
||
invite_code.py
|
||
invite_relation.py
|
||
recharge_order.py
|
||
provider_account.py
|
||
provider_model.py
|
||
video_model.py
|
||
pricing_rule.py
|
||
media_asset.py
|
||
video_generation_task.py
|
||
callback_log.py
|
||
tests/
|
||
unit/
|
||
integration/
|
||
alembic/
|
||
requirements.txt
|
||
```
|
||
|
||
### 21.5 前台与后台推荐文件清单
|
||
|
||
前台建议至少包含以下页面和模块:
|
||
|
||
```text
|
||
frontend-web/
|
||
src/
|
||
app/
|
||
login/page.tsx
|
||
register/page.tsx
|
||
workspace/create/page.tsx
|
||
workspace/tasks/page.tsx
|
||
workspace/tasks/[taskNo]/page.tsx
|
||
workspace/assets/page.tsx
|
||
wallet/page.tsx
|
||
wallet/recharge/page.tsx
|
||
wallet/redeem/page.tsx
|
||
invite/page.tsx
|
||
profile/page.tsx
|
||
components/
|
||
video-model-select.tsx
|
||
create-task-form.tsx
|
||
asset-uploader.tsx
|
||
task-status-badge.tsx
|
||
points-balance-card.tsx
|
||
redeem-code-form.tsx
|
||
invite-summary-card.tsx
|
||
lib/
|
||
api.ts
|
||
auth.ts
|
||
types.ts
|
||
```
|
||
|
||
后台建议至少包含以下页面和模块:
|
||
|
||
```text
|
||
frontend-admin/
|
||
src/
|
||
app/
|
||
admin/login/page.tsx
|
||
admin/dashboard/page.tsx
|
||
admin/users/page.tsx
|
||
admin/recharge-orders/page.tsx
|
||
admin/redeem-codes/page.tsx
|
||
admin/growth-rules/page.tsx
|
||
admin/invite-relations/page.tsx
|
||
admin/provider-accounts/page.tsx
|
||
admin/provider-models/page.tsx
|
||
admin/video-models/page.tsx
|
||
admin/video-model-bindings/page.tsx
|
||
admin/pricing-rules/page.tsx
|
||
admin/video-tasks/page.tsx
|
||
admin/callback-logs/page.tsx
|
||
admin/system-config/page.tsx
|
||
components/
|
||
provider-account-form.tsx
|
||
provider-model-form.tsx
|
||
video-model-form.tsx
|
||
pricing-rule-form.tsx
|
||
redeem-code-batch-form.tsx
|
||
growth-rule-form.tsx
|
||
task-detail-drawer.tsx
|
||
lib/
|
||
api.ts
|
||
auth.ts
|
||
table-columns.ts
|
||
```
|
||
|
||
## 22. 页面与路由详细清单
|
||
|
||
### 22.1 用户前台页面路由
|
||
|
||
建议前台路由如下:
|
||
|
||
```text
|
||
/
|
||
/login
|
||
/register
|
||
/forgot-password
|
||
/workspace/create
|
||
/workspace/tasks
|
||
/workspace/tasks/[taskNo]
|
||
/workspace/assets
|
||
/wallet
|
||
/wallet/recharge
|
||
/wallet/redeem
|
||
/wallet/orders
|
||
/wallet/transactions
|
||
/invite
|
||
/profile
|
||
```
|
||
|
||
### 22.2 用户前台页面说明
|
||
|
||
#### 首页 `/`
|
||
|
||
页面目标:
|
||
|
||
- 展示平台主卖点
|
||
- 引导登录和充值
|
||
- 引导进入创建页
|
||
|
||
页面模块:
|
||
|
||
- 顶部导航
|
||
- Banner
|
||
- 平台视频模型展示卡片
|
||
- 常见问题
|
||
- 页脚
|
||
|
||
#### 登录页 `/login`
|
||
|
||
表单字段:
|
||
|
||
- `account`:邮箱或手机号,必填
|
||
- `password`:密码,必填
|
||
|
||
交互要求:
|
||
|
||
- 登录成功跳转到 `/workspace/create`
|
||
- 登录失败显示统一错误提示
|
||
|
||
#### 注册页 `/register`
|
||
|
||
表单字段:
|
||
|
||
- `email` 或 `mobile`
|
||
- `password`
|
||
- `confirmPassword`
|
||
- `verificationCode`
|
||
|
||
校验规则:
|
||
|
||
- 密码长度至少 8 位
|
||
- 两次密码必须一致
|
||
- 邮箱或手机号必须未注册
|
||
|
||
#### 创建页 `/workspace/create`
|
||
|
||
页面目标:
|
||
|
||
- 选择平台视频模型
|
||
- 输入提示词
|
||
- 上传参考素材
|
||
- 预估积分
|
||
- 创建任务
|
||
|
||
页面字段:
|
||
|
||
- `videoModelId`:平台视频模型 ID,必选
|
||
- `prompt`:提示词,必填
|
||
- `durationSeconds`:时长秒数,必填
|
||
- `resolution`:分辨率,必选
|
||
- `ratio`:宽高比,必选
|
||
- `generateAudio`:是否生成音频
|
||
- `referenceImageAssetIds`:参考图片列表
|
||
- `referenceVideoAssetIds`:参考视频列表
|
||
- `referenceAudioAssetIds`:参考音频列表
|
||
|
||
页面行为:
|
||
|
||
- 选择平台视频模型后请求模型详情和价格规则
|
||
- 输入时长后实时计算预估积分
|
||
- 提交前再次向后端确认价格
|
||
- 若积分不足,提示去充值
|
||
|
||
#### 任务列表页 `/workspace/tasks`
|
||
|
||
表格字段:
|
||
|
||
- 任务编号
|
||
- 平台视频模型名称
|
||
- 任务状态
|
||
- 时长秒数
|
||
- 预估积分
|
||
- 最终积分
|
||
- 创建时间
|
||
- 操作
|
||
|
||
操作按钮:
|
||
|
||
- 查看详情
|
||
- 复制参数重建
|
||
- 失败后重试
|
||
- 删除记录
|
||
|
||
#### 任务详情页 `/workspace/tasks/[taskNo]`
|
||
|
||
页面模块:
|
||
|
||
- 任务基础信息
|
||
- 原始请求参数
|
||
- 任务时间线
|
||
- 最终结果视频
|
||
- 失败原因
|
||
- 积分结算信息
|
||
|
||
#### 素材页 `/workspace/assets`
|
||
|
||
页面功能:
|
||
|
||
- 上传素材
|
||
- 筛选图片/视频/音频
|
||
- 删除素材
|
||
- 复制素材 URL
|
||
|
||
#### 钱包页 `/wallet`
|
||
|
||
页面功能:
|
||
|
||
- 当前积分
|
||
- 冻结积分
|
||
- 可用积分
|
||
- 充值入口
|
||
- 兑换入口
|
||
- 最近流水
|
||
|
||
#### 充值页 `/wallet/recharge`
|
||
|
||
页面功能:
|
||
|
||
- 展示充值套餐
|
||
- 展示每个套餐对应到账积分
|
||
- 创建充值订单
|
||
- 跳转支付
|
||
|
||
#### 兑换页 `/wallet/redeem`
|
||
|
||
页面功能:
|
||
|
||
- 输入兑换密钥
|
||
- 查看兑换说明
|
||
- 查看最近兑换记录
|
||
|
||
表单字段:
|
||
|
||
- `redeemCode`
|
||
|
||
#### 邀请页 `/invite`
|
||
|
||
页面功能:
|
||
|
||
- 展示自己的邀请码
|
||
- 展示邀请链接
|
||
- 一键复制邀请码
|
||
- 一键复制邀请链接
|
||
- 手动生成新邀请码
|
||
- 查看邀请人数
|
||
- 查看已奖励积分
|
||
- 查看待奖励邀请关系
|
||
|
||
#### 个人中心 `/profile`
|
||
|
||
页面功能:
|
||
|
||
- 修改用户名
|
||
- 修改昵称
|
||
- 上传头像
|
||
- 查看绑定信息
|
||
- 查看账号状态
|
||
|
||
### 22.3 管理后台页面路由
|
||
|
||
建议后台路由如下:
|
||
|
||
```text
|
||
/admin/login
|
||
/admin/dashboard
|
||
/admin/users
|
||
/admin/users/[id]
|
||
/admin/recharge-orders
|
||
/admin/recharge-orders/[id]
|
||
/admin/redeem-codes
|
||
/admin/growth-rules
|
||
/admin/invite-relations
|
||
/admin/provider-accounts
|
||
/admin/provider-accounts/create
|
||
/admin/provider-models
|
||
/admin/video-models
|
||
/admin/video-model-bindings
|
||
/admin/pricing-rules
|
||
/admin/video-tasks
|
||
/admin/video-tasks/[id]
|
||
/admin/callback-logs
|
||
/admin/system-config
|
||
/admin/operation-logs
|
||
```
|
||
|
||
### 22.4 管理后台页面说明
|
||
|
||
#### 仪表盘 `/admin/dashboard`
|
||
|
||
指标卡片:
|
||
|
||
- 今日充值金额
|
||
- 今日充值订单数
|
||
- 今日任务创建数
|
||
- 今日任务成功率
|
||
- 今日积分消耗
|
||
- 供应商失败率
|
||
|
||
图表:
|
||
|
||
- 最近 7 天充值趋势
|
||
- 最近 7 天任务趋势
|
||
- 各平台视频模型调用分布
|
||
- 各供应商调用分布
|
||
|
||
#### 供应商账号页 `/admin/provider-accounts`
|
||
|
||
列表字段:
|
||
|
||
- 供应商名称
|
||
- 协议格式
|
||
- Base URL
|
||
- 状态
|
||
- 超时秒数
|
||
- 重试次数
|
||
- 更新时间
|
||
|
||
创建/编辑字段:
|
||
|
||
- `providerCode`
|
||
- `providerName`
|
||
- `apiFormat`
|
||
- `baseUrl`
|
||
- `apiKey`
|
||
- `apiSecret`
|
||
- `webhookSecret`
|
||
- `timeoutSeconds`
|
||
- `maxRetries`
|
||
- `status`
|
||
- `remark`
|
||
|
||
#### 供应商模型页 `/admin/provider-models`
|
||
|
||
列表字段:
|
||
|
||
- 供应商
|
||
- 模型编码
|
||
- 模型名称
|
||
- 是否支持图生视频
|
||
- 是否支持音频参考
|
||
- 是否支持 webhook
|
||
- 状态
|
||
|
||
创建/编辑字段:
|
||
|
||
- `providerAccountId`
|
||
- `modelCode`
|
||
- `modelName`
|
||
- `requestContentType`
|
||
- `supportsTextToVideo`
|
||
- `supportsImageToVideo`
|
||
- `supportsVideoReference`
|
||
- `supportsAudioReference`
|
||
- `supportsGenerateAudio`
|
||
- `supportsRemix`
|
||
- `supportsWebhook`
|
||
- `minDuration`
|
||
- `maxDuration`
|
||
- `defaultRatio`
|
||
- `defaultResolution`
|
||
- `status`
|
||
|
||
#### 平台视频模型页 `/admin/video-models`
|
||
|
||
列表字段:
|
||
|
||
- 平台模型名称
|
||
- 前台展示名称
|
||
- 默认时长
|
||
- 默认分辨率
|
||
- 状态
|
||
- 排序
|
||
|
||
创建/编辑字段:
|
||
|
||
- `modelKey`
|
||
- `modelName`
|
||
- `frontendTitle`
|
||
- `frontendDescription`
|
||
- `defaultDurationSeconds`
|
||
- `defaultRatio`
|
||
- `defaultResolution`
|
||
- `status`
|
||
- `sortOrder`
|
||
|
||
#### 平台模型绑定页 `/admin/video-model-bindings`
|
||
|
||
列表字段:
|
||
|
||
- 平台视频模型
|
||
- 供应商
|
||
- 供应商模型
|
||
- 是否主路由
|
||
- 路由优先级
|
||
- 状态
|
||
|
||
创建/编辑字段:
|
||
|
||
- `videoModelId`
|
||
- `providerModelId`
|
||
- `routingPriority`
|
||
- `isPrimary`
|
||
- `status`
|
||
- `timeoutSecondsOverride`
|
||
|
||
#### 价格规则页 `/admin/pricing-rules`
|
||
|
||
列表字段:
|
||
|
||
- 平台视频模型
|
||
- 每秒积分价格
|
||
- 最低积分
|
||
- 生效时间
|
||
- 失效时间
|
||
- 版本号
|
||
- 状态
|
||
|
||
创建/编辑字段:
|
||
|
||
- `ruleName`
|
||
- `videoModelId`
|
||
- `pointsPerSecond`
|
||
- `minimumPoints`
|
||
- `effectiveAt`
|
||
- `expiredAt`
|
||
- `versionNo`
|
||
- `status`
|
||
|
||
#### 兑换密钥页 `/admin/redeem-codes`
|
||
|
||
列表字段:
|
||
|
||
- 批次号
|
||
- 兑换密钥
|
||
- 对应积分
|
||
- 状态
|
||
- 使用人
|
||
- 使用时间
|
||
- 过期时间
|
||
|
||
创建/编辑字段:
|
||
|
||
- `batchNo`
|
||
- `points`
|
||
- `quantity`
|
||
- `expiredAt`
|
||
- `remark`
|
||
|
||
#### 增长奖励规则页 `/admin/growth-rules`
|
||
|
||
字段:
|
||
|
||
- `signupRewardEnabled`
|
||
- `signupRewardPoints`
|
||
- `inviteRewardEnabled`
|
||
- `inviteRewardPoints`
|
||
- `inviteRewardTrigger`
|
||
|
||
#### 邀请关系页 `/admin/invite-relations`
|
||
|
||
列表字段:
|
||
|
||
- 邀请人
|
||
- 被邀请用户
|
||
- 邀请码
|
||
- 注册时间
|
||
- 首次消费时间
|
||
- 奖励状态
|
||
- 奖励积分
|
||
- 奖励时间
|
||
|
||
#### 视频任务页 `/admin/video-tasks`
|
||
|
||
列表字段:
|
||
|
||
- 任务编号
|
||
- 用户 ID
|
||
- 平台视频模型
|
||
- 供应商
|
||
- 供应商模型
|
||
- 任务状态
|
||
- 请求时长
|
||
- 预估积分
|
||
- 最终积分
|
||
- 创建时间
|
||
|
||
详情页字段:
|
||
|
||
- 原始提交参数
|
||
- 标准化参数
|
||
- 供应商提交报文
|
||
- 供应商返回报文
|
||
- 时间线
|
||
- 回调日志
|
||
- 结算记录
|
||
|
||
## 23. 统一 DTO 与接口字段规范
|
||
|
||
### 23.1 创建视频任务请求 DTO
|
||
|
||
后端对外统一接收如下结构:
|
||
|
||
```json
|
||
{
|
||
"videoModelId": 1,
|
||
"prompt": "夜晚的未来城市上空,一架银色飞行器低空掠过,镜头跟拍。",
|
||
"durationSeconds": 8,
|
||
"resolution": "1280x720",
|
||
"ratio": "16:9",
|
||
"generateAudio": true,
|
||
"referenceImageAssetIds": [1001],
|
||
"referenceVideoAssetIds": [],
|
||
"referenceAudioAssetIds": []
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
- `videoModelId`:平台视频模型 ID,必填
|
||
- `prompt`:提示词,必填,建议长度 1 到 4000
|
||
- `durationSeconds`:请求时长,必填
|
||
- `resolution`:分辨率,必填
|
||
- `ratio`:宽高比,必填
|
||
- `generateAudio`:是否生成音频,必填
|
||
- `referenceImageAssetIds`:参考图片素材 ID 列表
|
||
- `referenceVideoAssetIds`:参考视频素材 ID 列表
|
||
- `referenceAudioAssetIds`:参考音频素材 ID 列表
|
||
|
||
### 23.2 创建视频任务响应 DTO
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "ok",
|
||
"data": {
|
||
"taskNo": "vt_202604170001",
|
||
"taskStatus": "queued",
|
||
"estimatedPoints": 960,
|
||
"frozenPoints": 960
|
||
}
|
||
}
|
||
```
|
||
|
||
### 23.3 任务详情响应 DTO
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "ok",
|
||
"data": {
|
||
"taskNo": "vt_202604170001",
|
||
"taskStatus": "succeeded",
|
||
"videoModel": {
|
||
"id": 1,
|
||
"name": "标准视频"
|
||
},
|
||
"provider": {
|
||
"providerCode": "openai-main",
|
||
"modelCode": "sora-2"
|
||
},
|
||
"durationSeconds": 8,
|
||
"estimatedPoints": 960,
|
||
"finalPoints": 960,
|
||
"resultVideoUrl": "https://cdn.example.com/generated/xxx.mp4",
|
||
"failReason": "",
|
||
"createdAt": "2026-04-17T18:00:00+08:00",
|
||
"finishedAt": "2026-04-17T18:03:12+08:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 23.4 创建充值订单请求 DTO
|
||
|
||
```json
|
||
{
|
||
"rechargePlanId": 1,
|
||
"paymentChannelCode": "alipay"
|
||
}
|
||
```
|
||
|
||
### 23.5 创建充值订单响应 DTO
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "ok",
|
||
"data": {
|
||
"orderNo": "rc_202604170001",
|
||
"payAmount": "100.00",
|
||
"arrivalPoints": 11000,
|
||
"payUrl": "https://payment.example.com/pay/xxx"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 23.6 管理后台供应商账号请求 DTO
|
||
|
||
```json
|
||
{
|
||
"providerCode": "openai-main",
|
||
"providerName": "OpenAI 主账号",
|
||
"apiFormat": "openai_official_video",
|
||
"baseUrl": "https://api.openai.com",
|
||
"apiKey": "sk-xxx",
|
||
"apiSecret": "",
|
||
"webhookSecret": "whsec_xxx",
|
||
"timeoutSeconds": 120,
|
||
"maxRetries": 3,
|
||
"status": 1,
|
||
"remark": "生产主账号"
|
||
}
|
||
```
|
||
|
||
### 23.7 管理后台价格规则请求 DTO
|
||
|
||
```json
|
||
{
|
||
"ruleName": "标准视频默认价格",
|
||
"videoModelId": 1,
|
||
"pointsPerSecond": 120,
|
||
"minimumPoints": 500,
|
||
"effectiveAt": "2026-04-18 00:00:00",
|
||
"expiredAt": null,
|
||
"versionNo": 1,
|
||
"status": 1
|
||
}
|
||
```
|
||
|
||
### 23.8 个人资料更新请求 DTO
|
||
|
||
```json
|
||
{
|
||
"username": "neo_director",
|
||
"nickname": "Neo",
|
||
"avatarUrl": "https://cdn.example.com/avatar/1001.png"
|
||
}
|
||
```
|
||
|
||
### 23.9 兑换密钥请求 DTO
|
||
|
||
```json
|
||
{
|
||
"redeemCode": "SPRING-2026-ABCD-1234"
|
||
}
|
||
```
|
||
|
||
### 23.10 邀请码创建响应 DTO
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"message": "ok",
|
||
"data": {
|
||
"inviteCode": "NEO88",
|
||
"inviteLink": "https://example.com/register?inviteCode=NEO88"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 23.11 注册请求 DTO 补充字段
|
||
|
||
若用户通过邀请码或邀请链接注册,注册请求体建议增加:
|
||
|
||
```json
|
||
{
|
||
"account": "user@example.com",
|
||
"password": "12345678",
|
||
"verificationCode": "123456",
|
||
"inviteCode": "NEO88"
|
||
}
|
||
```
|
||
|
||
## 24. 状态机与枚举规范
|
||
|
||
### 24.1 充值订单状态
|
||
|
||
推荐枚举:
|
||
|
||
- `pending`
|
||
- `paid`
|
||
- `failed`
|
||
- `cancelled`
|
||
- `refunded`
|
||
|
||
状态流转:
|
||
|
||
```text
|
||
pending -> paid
|
||
pending -> failed
|
||
pending -> cancelled
|
||
paid -> refunded
|
||
```
|
||
|
||
### 24.2 视频任务状态
|
||
|
||
推荐枚举:
|
||
|
||
- `created`
|
||
- `queued`
|
||
- `submitting`
|
||
- `submitted`
|
||
- `running`
|
||
- `succeeded`
|
||
- `failed`
|
||
- `cancelled`
|
||
- `timed_out`
|
||
|
||
状态流转:
|
||
|
||
```text
|
||
created -> queued
|
||
queued -> submitting
|
||
submitting -> submitted
|
||
submitted -> running
|
||
running -> succeeded
|
||
running -> failed
|
||
running -> timed_out
|
||
queued -> cancelled
|
||
running -> cancelled
|
||
```
|
||
|
||
### 24.3 钱包流水业务类型
|
||
|
||
推荐枚举:
|
||
|
||
- `recharge`
|
||
- `redeem_code`
|
||
- `signup_reward`
|
||
- `invite_reward`
|
||
- `freeze`
|
||
- `consume`
|
||
- `unfreeze`
|
||
- `refund`
|
||
- `manual_adjust`
|
||
|
||
### 24.4 供应商协议枚举
|
||
|
||
推荐枚举:
|
||
|
||
- `openai_official_video`
|
||
- `seedance_video_generation`
|
||
|
||
### 24.5 兑换密钥状态
|
||
|
||
推荐枚举:
|
||
|
||
- `unused`
|
||
- `used`
|
||
- `expired`
|
||
- `disabled`
|
||
|
||
### 24.6 邀请奖励状态
|
||
|
||
推荐枚举:
|
||
|
||
- `pending`
|
||
- `eligible`
|
||
- `rewarded`
|
||
- `invalid`
|
||
|
||
## 25. 供应商适配器实现细则
|
||
|
||
### 25.1 标准化内部请求结构
|
||
|
||
所有业务层进入适配器之前,统一整理成如下内部结构:
|
||
|
||
```json
|
||
{
|
||
"taskNo": "vt_202604170001",
|
||
"videoModelId": 1,
|
||
"providerAccountId": 10,
|
||
"providerModelId": 21,
|
||
"prompt": "夜晚的未来城市上空,一架银色飞行器低空掠过,镜头跟拍。",
|
||
"durationSeconds": 8,
|
||
"resolution": "1280x720",
|
||
"ratio": "16:9",
|
||
"generateAudio": true,
|
||
"referenceImages": [
|
||
{
|
||
"assetId": 1001,
|
||
"url": "https://storage.example.com/uploads/1001.png"
|
||
}
|
||
],
|
||
"referenceVideos": [],
|
||
"referenceAudios": []
|
||
}
|
||
```
|
||
|
||
### 25.2 OpenAI 适配器映射规则
|
||
|
||
映射建议:
|
||
|
||
- `prompt` -> `prompt`
|
||
- `providerModel.modelCode` -> `model`
|
||
- `durationSeconds` -> `seconds`
|
||
- `resolution` -> `size`
|
||
- `referenceImages[0].url` -> `input_reference`
|
||
|
||
请求格式:
|
||
|
||
- 使用 `multipart/form-data`
|
||
- 由适配器自行构造 multipart 边界和文件流
|
||
|
||
查询规则:
|
||
|
||
- 使用 `GET /v1/videos/{video_id}`
|
||
- 当状态为 `completed` 时,再调用 `/content` 下载
|
||
|
||
### 25.3 Seedance 适配器映射规则
|
||
|
||
映射建议:
|
||
|
||
- `providerModel.modelCode` -> `model`
|
||
- `prompt` -> `content[].text`
|
||
- `referenceImages` -> `content[].image_url`
|
||
- `referenceVideos` -> `content[].video_url`
|
||
- `referenceAudios` -> `content[].audio_url`
|
||
- `durationSeconds` -> `duration`
|
||
- `ratio` -> `ratio`
|
||
- `generateAudio` -> `generate_audio`
|
||
|
||
请求格式:
|
||
|
||
- 使用 `application/json`
|
||
|
||
查询规则:
|
||
|
||
- 使用 `GET /v1/video/generations/{id}`
|
||
- 当返回成功状态时读取视频 URL 并下载转存
|
||
|
||
### 25.4 标准化查询结果结构
|
||
|
||
适配器对外统一返回如下结构:
|
||
|
||
```json
|
||
{
|
||
"externalTaskId": "video_123",
|
||
"normalizedStatus": "running",
|
||
"progress": 50,
|
||
"resultUrl": "",
|
||
"resultExpiresAt": null,
|
||
"rawResponse": {}
|
||
}
|
||
```
|
||
|
||
### 25.5 供应商切换策略
|
||
|
||
首版建议按以下策略执行:
|
||
|
||
1. 根据 `videoModelId` 查出绑定的供应商模型列表
|
||
2. 按 `routingPriority` 升序排序
|
||
3. 优先使用 `isPrimary = 1` 的供应商模型
|
||
4. 若提交失败且属于可重试错误,则切到下一个供应商
|
||
5. 若已经拿到外部任务 ID,则后续只轮询该供应商,不再切换
|
||
|
||
### 25.6 不允许切换的场景
|
||
|
||
以下场景不能自动切换供应商:
|
||
|
||
- 已经成功提交到供应商并拿到任务 ID
|
||
- 供应商已进入 `running`
|
||
- 供应商已返回部分结果
|
||
|
||
### 25.7 建议保留的原始日志
|
||
|
||
建议新增供应商请求日志表或至少落文件日志,记录:
|
||
|
||
- 任务编号
|
||
- 供应商账号
|
||
- 供应商模型
|
||
- 请求 URL
|
||
- 请求方法
|
||
- 请求头脱敏版本
|
||
- 请求体脱敏版本
|
||
- 响应体
|
||
- HTTP 状态码
|
||
- 请求耗时
|
||
|
||
## 26. 任务执行链路详细说明
|
||
|
||
### 26.1 创建任务事务
|
||
|
||
用户提交任务时,后端需在一个事务内完成:
|
||
|
||
1. 校验用户状态
|
||
2. 校验平台视频模型状态
|
||
3. 查找当前生效的价格规则
|
||
4. 计算预估积分
|
||
5. 校验钱包可用积分
|
||
6. 创建视频任务记录
|
||
7. 冻结积分
|
||
8. 写入钱包流水
|
||
9. 提交事务
|
||
|
||
事务提交后再投递异步任务。
|
||
|
||
### 26.2 提交任务 Worker
|
||
|
||
Worker 执行顺序:
|
||
|
||
1. 根据 `taskNo` 读取任务
|
||
2. 判断状态是否允许提交
|
||
3. 根据 `videoModelId` 解析可用供应商绑定
|
||
4. 构建标准化请求 DTO
|
||
5. 调用供应商适配器提交任务
|
||
6. 保存 `externalTaskId`
|
||
7. 更新任务状态为 `submitted`
|
||
8. 写入任务事件
|
||
9. 投递轮询任务
|
||
|
||
### 26.3 轮询任务 Worker
|
||
|
||
Worker 执行顺序:
|
||
|
||
1. 读取本地任务
|
||
2. 若任务已结束,直接退出
|
||
3. 调用对应适配器查询状态
|
||
4. 写入原始响应
|
||
5. 若状态仍在处理中,更新 `nextPollAt`
|
||
6. 若状态成功,投递结果下载任务
|
||
7. 若状态失败,执行解冻与失败收尾
|
||
|
||
### 26.4 结果下载 Worker
|
||
|
||
Worker 执行顺序:
|
||
|
||
1. 使用适配器下载结果文件
|
||
2. 上传到对象存储
|
||
3. 创建 `media_assets` 记录
|
||
4. 回写 `resultAssetId`
|
||
5. 触发最终结算
|
||
|
||
### 26.5 最终结算 Worker
|
||
|
||
成功任务:
|
||
|
||
1. 将冻结积分转为实际消费
|
||
2. 写入消费流水
|
||
3. 更新任务为 `succeeded`
|
||
|
||
失败任务:
|
||
|
||
1. 解冻积分
|
||
2. 写入退回流水
|
||
3. 更新任务为 `failed`
|
||
|
||
### 26.6 注册赠送与邀请奖励触发
|
||
|
||
注册成功后:
|
||
|
||
1. 检查注册赠送规则是否开启
|
||
2. 检查用户是否已发放过注册赠送
|
||
3. 发放注册奖励积分
|
||
4. 写入钱包流水
|
||
|
||
任务消费成功后:
|
||
|
||
1. 检查用户是否存在邀请关系
|
||
2. 检查该邀请关系是否尚未奖励
|
||
3. 检查是否满足首次有效消费条件
|
||
4. 检查邀请奖励规则是否开启
|
||
5. 给邀请人发放积分奖励
|
||
6. 更新邀请关系状态为 `rewarded`
|
||
|
||
### 26.7 幂等要求
|
||
|
||
以下操作必须具备幂等性:
|
||
|
||
- 支付回调
|
||
- 任务冻结积分
|
||
- 任务最终扣费
|
||
- 任务失败退回积分
|
||
- 注册赠送发放
|
||
- 邀请奖励发放
|
||
- 兑换密钥使用
|
||
- 结果转存写库
|
||
- 供应商 webhook 处理
|
||
|
||
## 27. 环境变量与配置清单
|
||
|
||
### 27.1 后端环境变量
|
||
|
||
```env
|
||
APP_NAME=AIVideo
|
||
APP_ENV=development
|
||
APP_HOST=0.0.0.0
|
||
APP_PORT=8000
|
||
APP_DEBUG=true
|
||
|
||
MYSQL_HOST=127.0.0.1
|
||
MYSQL_PORT=3306
|
||
MYSQL_USER=root
|
||
MYSQL_PASSWORD=123456
|
||
MYSQL_DATABASE=aivideo
|
||
|
||
REDIS_HOST=127.0.0.1
|
||
REDIS_PORT=6379
|
||
REDIS_DB=0
|
||
|
||
JWT_SECRET=replace_me
|
||
JWT_REFRESH_SECRET=replace_me_too
|
||
JWT_ACCESS_EXPIRE_MINUTES=120
|
||
JWT_REFRESH_EXPIRE_DAYS=30
|
||
|
||
STORAGE_PROVIDER=minio
|
||
STORAGE_ENDPOINT=127.0.0.1:9000
|
||
STORAGE_BUCKET=ai-video
|
||
STORAGE_ACCESS_KEY=minioadmin
|
||
STORAGE_SECRET_KEY=minioadmin
|
||
STORAGE_PUBLIC_BASE_URL=https://cdn.example.com
|
||
|
||
POINT_EXCHANGE_RATIO=100
|
||
REDEEM_CODE_FAIL_LIMIT_PER_HOUR=20
|
||
INVITE_REWARD_MIN_CONSUME_POINTS=100
|
||
|
||
PAYMENT_NOTIFY_BASE_URL=https://api.example.com
|
||
VIDEO_NOTIFY_BASE_URL=https://api.example.com
|
||
|
||
DATA_ENCRYPTION_KEY=replace_32_length_key
|
||
SENTRY_DSN=
|
||
```
|
||
|
||
### 27.2 前端环境变量
|
||
|
||
前台:
|
||
|
||
```env
|
||
NEXT_PUBLIC_API_BASE_URL=https://api.example.com
|
||
NEXT_PUBLIC_APP_NAME=AIVideo
|
||
```
|
||
|
||
后台:
|
||
|
||
```env
|
||
NEXT_PUBLIC_ADMIN_API_BASE_URL=https://api.example.com
|
||
NEXT_PUBLIC_ADMIN_APP_NAME=AIVideo Admin
|
||
```
|
||
|
||
### 27.3 系统配置表建议维护的键
|
||
|
||
建议把以下配置放入 `system_configs`:
|
||
|
||
- `site.title`
|
||
- `site.notice`
|
||
- `wallet.point_exchange_ratio`
|
||
- `reward.signup.enabled`
|
||
- `reward.signup.points`
|
||
- `reward.invite.enabled`
|
||
- `reward.invite.points`
|
||
- `reward.invite.trigger`
|
||
- `reward.invite.min_consume_points`
|
||
- `invite.code.enabled`
|
||
- `upload.max_image_size_mb`
|
||
- `upload.max_video_size_mb`
|
||
- `upload.max_audio_size_mb`
|
||
- `task.default_poll_interval_seconds`
|
||
- `task.max_poll_minutes`
|
||
- `task.daily_create_limit`
|
||
|
||
## 28. 本地开发流程
|
||
|
||
### 28.1 后端初始化步骤
|
||
|
||
```text
|
||
1. 创建 Python 虚拟环境
|
||
2. 安装依赖
|
||
3. 准备 .env
|
||
4. 初始化 MySQL 数据库
|
||
5. 执行 Alembic migrate
|
||
6. 启动 FastAPI
|
||
7. 启动 Celery Worker
|
||
8. 启动 Celery Beat 或定时轮询服务
|
||
```
|
||
|
||
### 28.2 前台初始化步骤
|
||
|
||
```text
|
||
1. 安装 Node.js 依赖
|
||
2. 配置 .env.local
|
||
3. 启动 Next.js dev server
|
||
4. 连接后端调试登录、充值、创建任务
|
||
```
|
||
|
||
### 28.3 后台初始化步骤
|
||
|
||
```text
|
||
1. 安装 Node.js 依赖
|
||
2. 配置 .env.local
|
||
3. 创建管理员种子账号
|
||
4. 启动后台项目
|
||
5. 先录入增长奖励规则
|
||
6. 再录入兑换密钥批次
|
||
7. 再录入供应商账号
|
||
8. 再录入供应商模型
|
||
9. 再创建平台视频模型
|
||
10. 再创建绑定关系和价格规则
|
||
```
|
||
|
||
### 28.4 数据初始化顺序
|
||
|
||
建议种子数据按以下顺序初始化:
|
||
|
||
1. 管理员角色与权限
|
||
2. 管理员账号
|
||
3. 增长奖励规则
|
||
4. 支付渠道
|
||
5. 兑换密钥批次
|
||
6. 供应商账号
|
||
7. 供应商模型
|
||
8. 平台视频模型
|
||
9. 平台模型绑定关系
|
||
10. 价格规则
|
||
11. 系统配置
|
||
|
||
## 29. 错误码规范
|
||
|
||
### 29.1 错误码分段
|
||
|
||
建议按模块划分错误码:
|
||
|
||
- `10000-19999`:认证与用户
|
||
- `20000-29999`:钱包与积分
|
||
- `30000-39999`:充值与支付
|
||
- `40000-49999`:素材与上传
|
||
- `50000-59999`:视频任务
|
||
- `60000-69999`:供应商与模型
|
||
- `70000-74999`:邀请、兑换与增长奖励
|
||
- `75000-79999`:后台权限与系统配置
|
||
|
||
### 29.2 常用错误码示例
|
||
|
||
```text
|
||
10001 未登录
|
||
10002 Token 无效
|
||
10003 用户被禁用
|
||
|
||
20001 积分不足
|
||
20002 钱包不存在
|
||
20003 冻结积分失败
|
||
20004 兑换密钥不存在
|
||
20005 兑换密钥已使用
|
||
20006 兑换密钥已过期
|
||
|
||
30001 充值订单不存在
|
||
30002 支付回调验签失败
|
||
30003 订单已处理
|
||
|
||
40001 上传文件类型不支持
|
||
40002 文件大小超限
|
||
40003 素材不存在
|
||
|
||
50001 平台视频模型不存在
|
||
50002 平台视频模型已下架
|
||
50003 没有可用供应商
|
||
50004 任务状态不允许当前操作
|
||
50005 任务创建失败
|
||
50006 任务记录不存在或无权限访问
|
||
|
||
60001 供应商账号不可用
|
||
60002 供应商模型不可用
|
||
60003 供应商接口超时
|
||
60004 供应商接口限流
|
||
60005 供应商返回格式异常
|
||
|
||
70001 邀请码不存在
|
||
70002 邀请码不可用
|
||
70003 邀请关系已绑定
|
||
70004 邀请奖励已发放
|
||
```
|
||
|
||
## 30. 开发任务拆分建议
|
||
|
||
### 30.1 后端任务拆分
|
||
|
||
后端至少拆成以下开发任务:
|
||
|
||
1. 认证模块
|
||
2. 用户与钱包模块
|
||
3. 兑换密钥模块
|
||
4. 邀请与奖励模块
|
||
5. 充值订单与支付回调模块
|
||
6. 素材上传模块
|
||
7. 供应商账号与模型管理模块
|
||
8. 平台视频模型与绑定模块
|
||
9. 价格规则模块
|
||
10. 视频任务模块
|
||
11. OpenAI 适配器
|
||
12. Seedance 适配器
|
||
13. 异步任务模块
|
||
14. 日志与监控模块
|
||
|
||
### 30.2 前台任务拆分
|
||
|
||
前台至少拆成以下开发任务:
|
||
|
||
1. 登录注册
|
||
2. 钱包与充值
|
||
3. 兑换密钥
|
||
4. 邀请中心
|
||
5. 素材管理
|
||
6. 创建视频任务
|
||
7. 任务列表
|
||
8. 任务详情
|
||
9. 个人中心
|
||
|
||
### 30.3 后台任务拆分
|
||
|
||
后台至少拆成以下开发任务:
|
||
|
||
1. 管理员登录
|
||
2. 仪表盘
|
||
3. 用户管理
|
||
4. 充值订单管理
|
||
5. 兑换密钥管理
|
||
6. 增长奖励规则管理
|
||
7. 邀请关系管理
|
||
8. 供应商账号管理
|
||
9. 供应商模型管理
|
||
10. 平台视频模型管理
|
||
11. 绑定关系管理
|
||
12. 价格规则管理
|
||
13. 视频任务管理
|
||
14. 回调日志和操作日志
|
||
|
||
## 31. 开发验收清单
|
||
|
||
### 31.1 用户端验收
|
||
|
||
- 用户可正常登录退出
|
||
- 用户可看到平台视频模型与价格
|
||
- 用户可修改用户名和头像
|
||
- 用户可上传素材
|
||
- 用户可通过兑换密钥获得积分
|
||
- 用户可看到邀请码和邀请链接
|
||
- 用户可创建任务
|
||
- 用户可轮询看到任务变化
|
||
- 用户可看到结果视频
|
||
- 用户可删除自己的任务记录
|
||
- 用户可查看积分流水
|
||
|
||
### 31.2 后台验收
|
||
|
||
- 可新增多个供应商账号
|
||
- 可新增多个供应商模型
|
||
- 可新增平台视频模型
|
||
- 可绑定多个供应商模型到同一个平台视频模型
|
||
- 可配置每秒积分价格
|
||
- 可配置注册赠送积分是否开启及积分数
|
||
- 可配置邀请奖励是否开启及积分数
|
||
- 可批量生成或导入兑换密钥
|
||
- 可查看任务命中的实际供应商
|
||
- 可查看邀请关系与奖励状态
|
||
- 可查看回调日志与操作日志
|
||
|
||
### 31.3 技术验收
|
||
|
||
- OpenAI 官方格式能成功提交、查询和下载结果
|
||
- Seedance 格式能成功提交、查询和下载结果
|
||
- 支付回调幂等
|
||
- 任务积分冻结与扣减幂等
|
||
- 任务失败积分退回正确
|
||
- 兑换密钥并发兑换时只成功一次
|
||
- 注册赠送积分只发放一次
|
||
- 邀请奖励只发放一次
|
||
- 供应商切换策略符合预期
|
||
- 日志、监控、错误追踪已接入
|
||
|
||
### 31.4 上线前人工回归项
|
||
|
||
- 创建 1 个 OpenAI 平台模型并完成生成
|
||
- 创建 1 个 Seedance 平台模型并完成生成
|
||
- 构造供应商主路由失败并验证自动切换
|
||
- 构造支付重复回调并验证只到账一次
|
||
- 构造任务失败并验证积分退回
|
||
- 构造同一个兑换密钥重复兑换并验证只成功一次
|
||
- 构造邀请注册和首次消费并验证奖励只发放一次
|