AirShelf/core/ARCHITECTURE.md

703 lines
15 KiB
Markdown
Raw 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.

# AirShelf 技术架构方案
> 版本v1.0
> 日期2026-05-29
> 定位:从原型走向真实可运营产品的顶层技术架构决策文档
> 适用范围Django 后端、前端产品化、火山 ARK AI 接入、额度账本、运营后台、60s 多段视频生产
---
## 1. 架构结论
AirShelf 不应该先横向补齐所有页面,而应该先打穿一条真实生产闭环:
商品创建 -> 项目创建 -> AI 脚本 -> 基础资产 -> 可选故事板 -> 4 段视频生成 -> FFmpeg 拼接导出 -> 额度确认扣费 -> 资产入库 -> 运营后台可观测
第一阶段采用“模块化单体 + 异步任务”的架构:
- 后端Django + Django REST Framework
- 数据库MySQL
- 缓存/队列/锁Redis
- 异步任务Celery Worker + Celery Beat
- 文件存储:火山 TOS
- AI 模型:火山 ARK统一 Provider 抽象
- 运营后台:先用 Django Admin + 少量自定义后台页
- 前端React + Vite 单页应用。以 `v1/*.html` 为核心视觉规格,`电商AI平台/*.html` 作为未迁移页面和原版能力补充,重建为真实前端应用
- 路由:正式业务入口使用 React History URL例如 `/products``/projects/new``/pipeline/:id``/exact/*.html` 只作为像素级设计稿镜像和视觉回归基线,不作为产品业务路由
暂不采用微服务。当前阶段最大风险不是服务边界不够细而是任务状态、扣费账本、AI 失败恢复、资产流转没有被一套一致的数据模型兜住。模块化单体更容易保证事务一致性,也更适合快速把 PRD 全量能力落地。
---
## 2. 核心原则
### 2.1 账本优先
额度系统不能后补。所有 AI 任务、导出任务、重跑任务都必须先经过额度预检,并由账本记录冻结、确认扣费、失败释放、人工调整。
关键原则:
- 失败不扣费
- 用户确认采用后扣费
- 预估消耗需要额度预检
- 扣费必须幂等
- 所有账务变更必须有流水
### 2.2 任务异步化
火山生图、生视频、视频拼接都不能放在同步 HTTP 请求里执行。API 只负责创建任务、返回 task_idWorker 负责执行、轮询、重试、写状态。
### 2.3 资产对象化
图片、视频、成片不直接存数据库。数据库只存 TOS object key、元数据、归属、状态、引用关系。所有中间产物都应成为可追踪 Asset。
### 2.4 状态机先行
项目、阶段、AI 任务、视频片段、导出任务都必须有清晰状态机。不要只靠布尔字段拼状态,否则 60s 多段生产会很快失控。
### 2.5 单项目多段并发
60s 视频按 4 段 x 15s 生产。每段是独立 VideoSegment 和独立 AIJob可并发、可单段失败、可单段重跑、可回选历史版本。
---
## 3. 系统拓扑
```text
Browser
|
| HTTPS
v
Frontend Web
|
| REST / SSE or WebSocket
v
Django API
|
| ORM
v
MySQL
Django API
|
| enqueue task
v
Redis broker
|
v
Celery Workers
| | |
| | +--> FFmpeg export
| +----------> TOS upload/download
+------------------> Volcano ARK
Celery Workers
|
| status / ledger / asset metadata
v
MySQL
Django Admin / Ops
|
v
MySQL + task logs + billing ledger
```
部署形态:
- `airshelf-web`:前端静态资源或 SSR 前端服务
- `airshelf-api`Django API
- `airshelf-worker-default`:通用任务
- `airshelf-worker-ai`AI 文本/图片/视频任务
- `airshelf-worker-media`FFmpeg 拼接、转码、缩略图
- `airshelf-beat`定时任务、超时扫描、TOS 临时文件清理
---
## 4. 应用模块划分
建议 Django apps
```text
apps/
accounts/ 用户、登录、JWT、团队成员
teams/ 团队、角色、邀请、权限
products/ 商品库、卖点、商品图
projects/ 项目、阶段、脚本、分镜
assets/ 资产库、TOS 文件、引用关系
ai/ 火山 Provider、AIJob、模型配置
pipeline/ 5 阶段编排、视频片段、故事板
billing/ 额度账户、冻结、扣费、流水、套餐
media/ FFmpeg 拼接、字幕、BGM、导出
ops/ 运营后台扩展、任务监控、财务对账
common/ 审计字段、软删除、幂等、锁、工具
```
模块边界:
- `ai` 不直接扣费,只上报任务结果和预估成本。
- `billing` 不调用火山,只处理额度、冻结、确认扣费和流水。
- `assets` 不理解业务阶段,只管理文件、资产类型、引用和权限。
- `pipeline` 负责把 PRD 的 5 个 Stage 串起来。
- `ops` 只读为主,人工调整必须写审计日志。
---
## 5. 关键数据模型
### 5.1 账户与团队
- `User`
- `Team`
- `TeamMember`
- `Invitation`
- `Role`
V1 决策:
- 一个用户默认属于一个团队。
- 注册自动创建团队,注册者为超管。
- 预留多团队字段,但 V1 不开放切换多团队。
### 5.2 商品与项目
- `Product`
- `ProductImage`
- `ProductSellingPoint`
- `Project`
- `ProjectStageState`
- `Script`
- `ScriptShot`
Project 关键字段:
- `team_id`
- `product_id`
- `creator_id`
- `target_duration_seconds`30 / 45 / 60
- `segment_count`2 / 3 / 4
- `current_stage`
- `status`
### 5.3 资产
- `Asset`
- `AssetVersion`
- `AssetReference`
资产类型:
- product_image
- product_triptych
- character_portrait
- character_triptych
- scene_image
- storyboard
- video_clip
- final_video
- bgm
- subtitle
关键字段:
- `team_id`
- `project_id`
- `owner_id`
- `tos_key`
- `mime_type`
- `duration_seconds`
- `width`
- `height`
- `source`
- `status`
- `is_shared`
### 5.4 AI 任务
- `AIJob`
- `AIJobAttempt`
- `ModelConfig`
AIJob 关键字段:
- `job_type`text / image / video
- `provider`volcengine
- `model_name`
- `request_payload`
- `response_payload`
- `external_task_id`
- `status`
- `progress`
- `error_code`
- `error_message`
- `estimated_cost`
- `actual_cost`
- `idempotency_key`
任务状态:
```text
created -> quota_checked -> queued -> submitted -> polling -> succeeded
-> failed
-> timeout
-> cancelled
```
### 5.5 视频片段与导出
- `VideoSegment`
- `VideoSegmentVersion`
- `ExportJob`
- `TimelineItem`
- `SubtitleCue`
VideoSegment
- `project_id`
- `segment_index`
- `start_second`
- `end_second`
- `prompt`
- `use_storyboard`
- `adopted_version_id`
- `status`
60s 项目生成 4 个 VideoSegment
- 0-15s
- 15-30s
- 30-45s
- 45-60s
### 5.6 额度与财务
- `Wallet`
- `QuotaPolicy`
- `QuotaUsage`
- `BillingTransaction`
- `BillingHold`
- `PricingRule`
- `RechargeOrder`
四层额度:
- 用户日额度
- 用户月额度
- 团队月额度
- 团队总额度池
账务动作:
- estimate
- hold
- release
- charge
- refund
- manual_adjust
所有扣费以 `BillingTransaction` 为准,不从任务表反推财务结果。
---
## 6. Redis 设计
Redis DB index
- DB 0Django cache
- DB 1Celery broker
- DB 2Celery result backend
- DB 3分布式锁、幂等锁、防重复扣费锁
- DB 4限流、验证码计数、短期风控
- DB 5任务进度 pubsub / WebSocket 预留
锁设计:
- `lock:billing:confirm:{job_id}`
- `lock:project:generate:{project_id}`
- `lock:segment:generate:{segment_id}`
- `lock:export:{project_id}`
锁必须有 TTL且所有关键写入仍要依赖数据库唯一约束保证最终幂等。
---
## 7. 火山 ARK Provider 设计
所有模型通过统一 Provider 调用:
```text
AIProvider
generate_text()
generate_image()
create_video_task()
get_video_task()
```
当前模型决策来自 `account.md`,代码只读取环境变量:
- 文本主模型DeepSeek-V3-2
- 文本备用模型Doubao Seed 2.0 Pro / Lite
- 图片模型Seedream 5.0 Lite / 5.0 / 4.5
- 视频模型Seedance 2.0 / 2.0 Fast / 1.5 Pro
接口策略:
- 文本OpenAI-compatible chat
- 图片:同步或短异步,统一落成 AIJob
- 视频:异步任务,提交后轮询
- 所有外部响应原文进入 `response_payload`,便于排障
模型配置不硬编码在业务流程中。业务流程只声明用途:
- script_generation
- asset_prompt_generation
- product_image_optimize
- storyboard_generation
- video_segment_generation
由 ModelConfig 决定具体模型。
---
## 8. 60s 多段生产流程
### 8.1 Stage 1 脚本
输入:
- 商品信息
- 卖点
- 目标时长
- 用户指令
输出:
- Script
- ScriptShot
- 自动切段结果
60s 输出要求:
- `segment_count = 4`
- 每段约 15s
- 每个镜头必须归属 segment_index
### 8.2 Stage 2 基础资产
生成:
- 商品三视图
- 人物立绘
- 人物三视图
- 场景图
资产候选规则:
- 创意选择型一次 4 张
- 结构转换型一次 1 张
- 采用后才进入当前项目引用
### 8.3 Stage 3 故事板
故事板是可选项,不是硬前置。
如果生成:
- 每段 1 张故事板图
- 60s 项目最多 4 张
- 每张可独立重跑
### 8.4 Stage 4 视频片段
每个 VideoSegment 独立生成:
- 输入:脚本分段、基础资产、可选故事板、视频提示词
- 输出VideoSegmentVersion
- 用户采用某一版后,才进入可拼接素材
并发策略:
- 单项目最多 4 段并发
- 全局并发由 Worker 数和 Redis 队列控制
- 外部配额不足时降级到每项目 2 段并发
### 8.5 Stage 5 拼接导出
输入:
- 已采用的视频片段
- 时间线配置
- 字幕
- BGM
- 转场
输出:
- final_video Asset
- ExportJob
第一版导出能力:
- 单主轨
- 排序
- 裁剪
- 字幕烧录
- BGM 混音
- 9:16
- 1080P MP4
---
## 9. API 设计原则
API 应按资源和动作拆分,不把复杂动作塞进一个“大生成接口”。
示例:
```text
POST /api/products/
GET /api/products/
POST /api/projects/
GET /api/projects/{id}/
POST /api/projects/{id}/script/generate/
POST /api/projects/{id}/script/confirm/
POST /api/projects/{id}/assets/generate/
POST /api/assets/{id}/adopt/
POST /api/projects/{id}/storyboards/generate/
POST /api/storyboards/{id}/adopt/
POST /api/video-segments/{id}/generate/
POST /api/video-segment-versions/{id}/adopt/
POST /api/projects/{id}/exports/
GET /api/exports/{id}/
GET /api/ai-jobs/{id}/
POST /api/billing/estimate/
GET /api/billing/transactions/
```
前端轮询策略:
- AIJob 详情接口提供统一进度。
- Stage 页面不直接轮询火山。
- 后续可用 SSE/WebSocket 替代轮询。
---
## 10. 运营后台
第一版用 Django Admin 承担运营后台,不另起复杂后台前端。
必须有:
- 用户管理
- 团队管理
- 额度账户
- 消费流水
- AIJob 任务监控
- 视频片段与导出任务
- 模型配置
- PricingRule
- 人工补偿/退款/额度调整
人工操作要求:
- 必须写审计日志
- 财务调整必须写 BillingTransaction
- 禁止直接改余额字段绕过账本
---
## 11. 部署与环境
环境:
- local
- test
- production
敏感配置:
- 本地测试凭据记录在 `account.md`
- 代码与架构文档不保存真实密钥
- K8s 使用 Secret 注入环境变量
K8s 工作负载:
```text
Deployment airshelf-web
Deployment airshelf-api
Deployment airshelf-worker-default
Deployment airshelf-worker-ai
Deployment airshelf-worker-media
Deployment airshelf-beat
Service airshelf-web
Service airshelf-api
Ingress airshelf
Secret airshelf-env
ConfigMap airshelf-config
```
CI/CD 需要从当前纯静态部署升级为多镜像构建:
- web image
- api image
- worker image 可复用 api image启动命令不同
---
## 12. 可观测性
日志:
- API request log
- AI provider request/response summary
- Celery task log
- billing ledger log
- export job log
指标:
- AI 任务成功率
- AI 平均耗时
- 视频段失败率
- 导出失败率
- 队列长度
- Worker 并发
- TOS 上传失败率
- 额度冻结未释放数量
告警:
- AI 任务连续失败
- 队列堆积
- 导出任务超时
- Billing hold 超时未释放
- Redis / MySQL 不可用
---
## 13. 安全与权限
权限模型:
- 超管:团队所有权限、充值、额度划拨、财务查看
- 团管:成员管理、成员额度分配、团队资产管理
- 成员:创建项目、使用额度、管理自己的项目
安全要求:
- 所有 API 必须按 team_id 做数据隔离
- 资产下载使用签名 URL
- 上传文件做类型、大小、时长校验
- 后台人工操作写审计
- ARK/TOS/Redis/MySQL 密钥只走环境变量
- JWT refresh token 需要轮换和黑名单
---
## 14. 关键风险与架构应对
| 风险 | 应对 |
| --- | --- |
| PRD 60s 与页面流程 15s 口径冲突 | 以 60s 多段为工程目标,页面文案后续统一 |
| AI 任务失败或超时 | AIJob 状态机 + Attempt + 重试 + 单段重跑 |
| 重复扣费 | BillingHold + 幂等 key + Redis lock + DB 唯一约束 |
| 外部模型并发不足 | 队列限流,单项目并发可降级 |
| TOS 文件失控增长 | tmp 前缀清理任务,资产软删除,引用检查 |
| 视频导出耗时长 | media worker 独立队列,任务进度入库 |
| 运营后台需求膨胀 | V1 先 Django Admin后续再独立后台 |
---
## 15. 开发路线
### Phase 0工程初始化
- 创建 Django 项目
- 配置 MySQL / Redis / Celery / TOS
- Dockerfile 与 K8s 基础部署
- 健康检查与环境变量管理
验收:
- API 可启动
- Worker 可启动
- 能连接 MySQL / Redis
- 能上传测试文件到 TOS
### Phase 1业务地基
- 用户、团队、角色
- 商品库
- 项目
- 资产模型
- AIJob
- Billing 账本
验收:
- 注册自动建团队
- 商品 CRUD
- 项目创建
- 额度预检、冻结、释放、确认扣费可跑通
### Phase 2AI 纵向闭环
- 脚本生成
- 基础资产生成
- 故事板生成
- 4 段视频生成
- 结果入 TOS 和资产库
验收:
- 一个 60s 项目可生成 4 个视频片段
- 单段失败可重跑
- 用户采用后扣费
### Phase 3导出与前端联调
- FFmpeg 拼接
- 字幕
- BGM
- 1080P MP4 导出
- 前端接真实 API
验收:
- 4 段视频可导出成 60s 成片
- 成片入库
- 可下载、可预览
### Phase 4运营后台与上线硬化
- Django Admin 增强
- 任务监控
- 财务对账
- 模型配置
- 日志告警
- 并发压测
验收:
- 运营能查任务、查用户、查流水、人工调整额度
- 失败任务可定位
- 队列堆积可观测
---
## 16. 最终判断
AirShelf 的架构核心不是“页面数量”而是“AI 生产系统 + 账本系统 + 资产系统”的一致性。
正确的第一目标是:
> 用 Django + Celery + TOS + 火山 ARK 打穿真实 60s 多段视频生产闭环,并保证失败恢复和扣费一致性。
页面可以逐步接入,运营后台可以先用 Django Admin但账本、任务状态机、资产引用和 AI Provider 必须从第一天按真实产品设计。