# 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_id；Worker 负责执行、轮询、重试、写状态。

### 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 0：Django cache
- DB 1：Celery broker
- DB 2：Celery 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 2：AI 纵向闭环

- 脚本生成
- 基础资产生成
- 故事板生成
- 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 必须从第一天按真实产品设计。
