Files
yingqing/AirShelf-完整交接文档-2026-08-12.md
T
2026-08-13 00:17:04 -05:00

1027 lines
43 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 完整交接文档
> 文档日期:2026-08-12
> 代码基线:`dev` 分支,`f2114bc36ec1e2b472164145cb8d40660af01969`
> 最新提交:`fix: 修正模型超时与结果未知重放`2026-07-21
> 文档性质:当前代码事实、历史资料、现场验证结果与待人工确认项的统一交接入口
> 安全声明:本文不包含真实密钥、密码、数据库连接值或用户数据
---
## 0. 如何使用这份文档
这份文档是 AirShelf 当前的主交接入口,用来替代对 2026-06-17 和 2026-06-24 旧交接报告的盲目依赖。旧报告仍有历史价值,但其后已新增 106 个提交和 23 个数据库迁移,“已完成/待办/默认模型/账号依赖”均可能过期。
事实优先级:
1. 当前运行代码、数据迁移和部署配置。
2. [后端架构](core/backend/ARCHITECTURE.md) 和 [前端架构](core/frontend/ARCHITECTURE.md)。
3. 本文的基线、验证和风险清单。
4. [PRD](PRD.md) 和 [顶层架构决策](core/ARCHITECTURE.md):用于理解目标,不自动等于已实现。
5. 历史交接、TODO、bug 和完成报告:用于追溯决策,不得单独当成当前状态。
本次不读取 `.env``account.md`、线上数据库和任何用户上传文件;运行时 Provider 开关、默认模型、余额和外部账号状态必须在管理后台和实际环境中二次确认。
---
## 1. 执行摘要
### 1.1 一句话定位
AirShelf 是一个面向中国电商卖家、运营团队和 MCN 的多租户 AI 内容生产平台:以商品为输入,通过脚本、基础资产、故事板、视频片段和导出五阶段流水线,生成可管理、可计费、可追溯的带货图片和短视频资产。
### 1.2 当前结论
- 项目已从静态设计稿进入真实 React + Django 产品化阶段。
- 商品、项目、脚本 Agent、资产、故事板、视频、自由创作、模特库、积分计费、通知和平台超管都有实作代码。
- 历史文档记录了商品到 Seedance 出片的真实端到端验证,但本次没有重跑线上 Provider 和生产数据。
- 当前代码可通过 Django system check、前端生产构建和最新模型路由核心测试,但后端全量测试尚未全绿。
- 当前最大的交接风险不是“没代码”,而是密钥管理、生产分支与 CI 不一致、测试环境仍依赖外部 Redis、缺少正式回滚/备份 Runbook,以及多个超大文件已进入高维护成本区。
### 1.3 基线数据
| 指标 | 当前值 |
| --- | ---: |
| Django 业务 app | 9 |
| 扫描到的核心模型类 | 51 |
| Celery 任务 | 11 |
| 前端调用的 API 路径 | 约 153 |
| 前端 `src` 文件 | 71 |
| 后端 app Python 文件 | 221 |
| 数据库迁移文件 | 64 |
| 后端测试文件 | 30 |
| Django 发现的测试数 | 545 |
| settings 读取的环境变量 | 66 |
| `.env.example` 未覆盖的已用变量 | 18 |
---
## 2. 产品范围与业务对象
### 2.1 用户与租户
- 一切业务数据以 `Team` 为租户边界。
- 登录/注册采用“用户名 + 密码”,不使用邮箱作为主登录标识。
- 注册是邀请制,邀请码分为加入已有团队和创建新团队两类。
- 团队角色:`owner` / `admin` / `member` / `viewer`
- 平台超管是用户维度,与团队角色分离。
- 后端使用 DRF Token Authentication,不是 JWT,也没有 refresh token 轮换链路。
### 2.2 核心业务对象
```text
Team
├─ User / TeamMember / Invitation
├─ CreditAccount / CreditLedger / CreditReservation / QuotaPolicy
├─ Product / ProductImage / ProductSellingPoint
├─ Model(模特库)
├─ Asset / AssetFile / AssetUsage / AssetReviewGroup
└─ Project
├─ ProjectStage
├─ ScriptVersion / ScriptSegment
├─ BaseAssetGroup
├─ StoryboardVersion / StoryboardShot / ShotVersion
├─ VideoSegment / VideoSegmentVersion
└─ Timeline / SubtitleTrack / BgmTrack / ExportJob
```
### 2.3 用户可见模块
| 模块 | 能力 | 主要代码 |
| --- | --- | --- |
| 登录/注册 | 邀请码校验、Token 登录、记住我 | `accounts``auth-screen.tsx` |
| 工作台 | 概览、最近项目、资产与余额摘要 | `dashboard.tsx` |
| 商品库 | 创建、图片、卖点、详情、关联项目、垃圾桶 | `products` |
| 模特库 | 模特录入、立绘、三视图、审核、引用 | `assets.Model``models.tsx` |
| 视频项目 | 新建项目、五阶段生产管线 | `projects``pipeline.tsx` |
| 图片创作 | 自由生图、模特上身图、平台套图、会话与批次 | `ai-tools.tsx` |
| 自由视频 | 文/图/首尾帧/音频参考、任务轮询、重生、下载 | `free-create.tsx` |
| 资产库 | 图片、视频、项目资产包、收藏/入库 | `library.tsx` |
| 垃圾桶 | 商品、项目、资产、任务的恢复与最终删除 | `trash.tsx` |
| 账户/团队 | 积分、流水、成员、限额、邀请、登录设备 | `billing``accounts` |
| 消息/设置 | 生成失败、余额、登录等通知和用户偏好 | `ops``settings.tsx` |
| 平台超管 | 团队、用户、邀请、模型、提示词、资产审核、任务、计费、完整性 | `adminpanel` |
### 2.4 明确未形成闭环的商业能力
- `/api/billing/recharge/` 会直接根据人民币金额和积分汇率入账,当前是手动/内部充值语义,没有微信、支付宝或第三方支付回调校验。
- 手机号注册和登录本期未实现。
- 没有完整的订单、发票、退款审批和支付对账子系统。
- 未发现 OpenAPI/Swagger 自动合同,前后端类型目前主要靠手工同步。
---
## 3. 代码仓库与资料地图
```text
AirShelf/
├─ core/
│ ├─ frontend/ React 19 + Vite 7 + TypeScript 真实业务前端
│ ├─ backend/ Django + DRF + Celery 后端
│ ├─ qa/ 视觉对比和功能审计工具
│ ├─ docs/ 专项技术资料
│ └─ ARCHITECTURE.md 早期顶层架构决策,不等于当前实现
├─ 电商AI平台/ HTML 设计稿与视觉规范,不是真站业务代码
├─ k8s/ K8s/K3s 部署清单
├─ .gitea/workflows/ Gitea Actions 构建与部署
├─ docs/todo/ 可用的专项完成说明
├─ docs/bug_todo/ 详细实施/问题过程记录,不代表当前待办
├─ docs/agents_todo/ Agent 协同实施方案
├─ tools/architecture-sync/ 架构文档差异扫描和验证
├─ PRD.md 产品目标与验收定义
├─ AGENTS.md / CLAUDE.md 工程约定、设计铁律、Git 流程
└─ 本文 当前统一交接入口
```
重要边界:
- 真实开发只改 `core/frontend``core/backend`
- `电商AI平台/*.html` 只是视觉标准答案,不在里面接 API 或开发新功能。
- 涉及页面和 CSS 的任务,必须先阅读 [设计规范](电商AI平台/design.md),并对照同名 HTML 设计稿。
- AI Skill 必须放在 `core/backend/skills/` 内,否则不在后端 Docker build context 中。
---
## 4. 系统架构
### 4.1 运行拓扑
```text
浏览器
→ Traefik / HTTPS Ingress
→ airshelf-core-webNginx
├─ /assets、/、SPA 路由 → React 静态资源
├─ /api/* → airshelf-core-api:8000
├─ /django-admin/* → airshelf-core-api:8000
└─ /static/* → airshelf-core-api:8000
airshelf-core-api
├─ MySQL:业务事实、任务、计费、资产元数据
├─ Redis DB0Django cache
├─ Redis DB1Celery broker
├─ Redis DB2Celery result backend
├─ Redis DB3:业务锁
├─ TOS:图片、视频、封面、导出文件
├─ 火山 ARK / Assets / TTS
└─ OpenAI-compatible 中转 Provider
airshelf-core-worker
└─ Celery 并发 4,复用 API 镜像和同一数据库/配置
```
### 4.2 技术栈
| 层 | 当前实现 |
| --- | --- |
| 前端 | React 19.2、TypeScript 5.9、Vite 7.2/7.3、Lucide React |
| 路由 | 自研 History API 路由,未使用 React Router |
| 前端状态 | React state/effect,无 Redux/Zustand/TanStack Query |
| 请求层 | 原生 `fetch` 封装为 `api` / `adminApi` |
| 后端 | Python 3.12 镜像、Django 5.05.1、DRF 3.15 |
| 异步任务 | Celery 5 + Redis |
| 数据库 | MySQL;测试数据库可切 SQLite |
| 对象存储 | 火山 TOS,通过 boto3/S3 协议适配 |
| AI | 火山 ARK 直连 + OpenAI-compatible Provider + 火山 TTS |
| 媒体 | FFmpeg + Pillow + Noto CJK |
| API 容器 | Gunicorn3 workers × 4 threads300s timeout |
| Web 容器 | Node 20 构建,Nginx Alpine 托管 |
| 集群 | K3s/Kubernetes + Traefik + cert-manager |
| CI/CD | Gitea Actions + 火山镜像仓库 |
### 4.3 当前 K8s 容量
| Deployment | 副本 | 资源 |
| --- | ---: | --- |
| `airshelf-core-api` | 1 | request 250m/512Milimit 1500m/2Gi |
| `airshelf-core-worker` | 1 | request 100m/512Milimit 1000m/2Gi |
| `airshelf-core-web` | 1 | request 20m/32Milimit 150m/128Mi |
当前 API、Worker、Web 都是单副本;Worker 没有按图片、视频、导出拆分队列,也没有独立 Celery Beat Deployment。
---
## 5. 后端架构
### 5.1 Django app 职责
| App | 职责 | 主要模型 |
| --- | --- | --- |
| `common` | UUID/时间/团队归属基类、分页、健康检查 | `UUIDModel``TimeStampedModel``TeamOwnedModel` |
| `accounts` | 用户、团队、成员、邀请码、偏好、会话、超管审计 | `User``Team``TeamMember``Invitation``LoginSession` |
| `products` | 商品、商品图、卖点、软删除 | `Product``ProductImage``ProductSellingPoint` |
| `assets` | 业务资产、TOS 文件、模特库、审核、标签、使用关系、自由资产 | `Asset``AssetFile``Model``AssetReviewGroup` |
| `projects` | 项目和五阶段业务状态 | 脚本、资产组、故事板、视频版本、时间线、导出 |
| `ai` | Provider、模型、生成任务、真实调用审计、Agent、生图/生视频/TTS | `ModelProvider``ModelConfig``AITask``AIModelAttempt` |
| `billing` | 积分账户、预留、扣费、释放、充值、限额、差异化定价 | `CreditAccount``CreditLedger``CreditReservation``BillingConfig` |
| `ops` | 站内通知和通知补齐 | `Notification` |
| `adminpanel` | 跨团队平台治理 API | 复用各业务模型 |
### 5.2 一级 API
```text
/api/health/ 浅层健康检查
/api/auth/ 注册、登录、个人、会话、团队、邀请
/api/products/ 商品 CRUD、图片、素材、垃圾桶
/api/assets/ 资产、批次、分面、审核、入库、垃圾桶
/api/models/ 模特库、立绘、三视图
/api/projects/ 项目 CRUD 和五阶段所有 action
/api/billing/ 积分摘要、流水、充值、趋势、计价配置
/api/ai/ 生图、自由视频、任务、模型、图片会话
/api/ops/ 消息列表、已读/未读、归档
/api/admin/ 平台超管治理 API
/django-admin/ Django 自带后台
```
前端平台后台使用 `/admin/*`Django Admin 已迁到 `/django-admin/`,不要改回 `/admin/`,否则会再次破坏 SPA 刷新。
### 5.3 项目流水线主要 action
- 脚本:`script-agent-stream``adopt-script``update/rerun/add/delete-script-segment`
- 实体:`extract-entities``extract-status`
- 基础资产:`generate-base-asset``pending-assets``adopt/attach/delete-base-asset``generate-triview`
- 审核:`poll-reviews``video-review-precheck`
- 故事板:`generate-storyboard``rerun-storyboard-shot``adopt-storyboard-shot-version``poll-storyboard``skip-storyboard`
- 视频:`submit/poll-video-segment``adopt-video-version``upload-video-segment`
- 后期:`generate-voiceover``upload-bgm``save-timeline``submit/poll-export`
- 生命周期:`trash``restore``purge`
### 5.4 Celery 任务
```text
ai:
submit_ai_task
poll_ai_task
extract_entities_task
generate_base_asset_task
generate_triview_task
generate_model_triview_task
generate_standalone_image_task
poll_free_video_task
projects:
poll_video_segment_task
run_export_job_task
ops:
ensure_team_notifications_task
```
任务最终事实以 MySQL 中的 `AITask`、项目版本和资产为准,不能仅依赖 Celery result backend。
---
## 6. 五阶段生产链路
### 6.1 Stage 1:脚本
```text
Product + 卖点 + 用户主题/改稿意图
→ 加载 core/backend/skills/ecommerce-video-script
→ 流式文本 Provider
→ 解析和归一化 ScriptDraft
→ ScriptVersion + ScriptSegment
→ 回填 project.metadata.script_entities
```
脚本 Agent 支持 `auto` / `theme` / `revise` 三种模式,也支持 `target_index` 精准只修某一镜。结构化脚本包含旁白、对白、说话人、画面、商品露出和实体引用。
SSE 事件会包含工具/进度、文本增量、草稿、保存结果、完成或错误。不同历史文档中对事件名的描述略有差异,前端和后端当前协议应以 `script_agent.py``projects/views.py``api.ts` 为准。
### 6.2 Stage 2:基础资产
- 实体提取将脚本中的角色、场景和商品转换为稳定 ID。
- 角色生成立绘和单张 16:9 三视图;商品和场景也可生成对应资产。
- 已采用基础资产通过 `BaseAssetGroup` 与实体关联,供故事板和视频复用。
- 模特库 `Model` 已与脚本角色解耦,模特是可跨项目复用的团队资产。
### 6.3 Stage 3:故事板
- 每个脚本镜头可生成多个 `StoryboardShotVersion`并选用一版。
- 参考图按 `entity_refs` 组合角色、场景和商品,提示词中的 `@图N` 必须与参考图数组顺序一致。
- Provider 支持图片编辑时优先走多图编辑,不支持时才回退纯文生图。
### 6.4 Stage 4:视频
- 每个 `VideoSegment` 可有多个版本,用户可重生和采用。
- 含真人参考的图片需先进入火山人像素材库,视频模型使用 `asset://` 引用来避免真人直链被拒。
- 素材库与 Seedance 调用必须属于可互相解析的同一火山账号体系。
- 已取得远程任务 ID 后,只轮询真正提交成功的 Provider/模型,禁止因为本地等待超时而重复提交高价任务。
### 6.5 Stage 5:后期与导出
- `Timeline` / `TimelineClip` 保存片段排列。
- 可配置字幕、BGM 和配音。
- `ExportJob` 交给 Celery,使用 FFmpeg 拼接并生成最终资产。
- 后端镜像已安装 FFmpeg 和 Noto CJK,避免线上导出缺二进制或中文字体。
---
## 7. AI Provider、重试、Fallback 与审计
### 7.1 Provider 适配层
```text
AIProvider Protocol
├─ VolcanoArkProvider 火山文本/图片/视频官方直连
├─ OpenAICompatibleProvider YunQi、TokenSSR 和其他 OpenAI-compatible 网关
├─ YunqiProvider 保留的 YunQi 特定适配
└─ VolcanoTtsProvider 火山配音
```
`ModelProvider` 保存供应商,`ModelConfig` 保存模型能力、价格、状态和路由元数据。业务代码不应假设某个固定模型永久默认;运行时结果以数据库和平台后台为准。
### 7.2 统一调用流程
```text
用户选择模型 / 系统默认模型
→ 创建一个 AITask
→ 预留一次积分
→ 调用主模型
├─ 明确失败:按策略重试,再按模型 metadata 决定是否 Fallback
└─ 远程结果未知:立即停止重放和 Fallback
→ 每次真实请求写一条 AIModelAttempt
→ 成功:保存资产/版本,最终扣费一次
→ 失败或结果未知:释放原预留
```
### 7.3 当前默认策略
| 能力 | 重试 | 单次超时 | 总时限 |
| --- | --- | ---: | ---: |
| 文本 | 等待 1s / 3s,最多重试 2 次 | 普通 120s,流式 300s | 480s |
| 图片 | 等待 3s,重试 1 次 | 300s | 900s |
| 配音 | 等待 2s,重试 1 次 | 60s | 180s |
| 视频提交 | 拿到任务 ID 之前等待 3s,重试 1 次 | 120s | 300s |
| 视频轮询 | 不重提交 | 60s/次 | 以 Provider 终态为准 |
单个逻辑任务默认最多尝试 3 个模型、5 次真实请求。修改策略后必须同时重启 API 和 Worker。
### 7.4 结果未知保护
ReadTimeout、发送后断线、HTTP 502/504 或响应丢失可能意味着上游已经创建任务。当系统无法确认上游未处理时,必须停止重试和 Fallback,避免重复出片和重复平台成本。
### 7.5 调用审计
`AIModelAttempt``AITask` 是多对一关系,记录:
- 调用顺序,首次/重试/Fallback。
- Provider 和真实模型快照。
- 操作、状态、耗时、错误分类和上游任务 ID。
- 用量、平台成本、脱敏请求/响应摘要。
管理员可在 `/admin/tasks` 查看调用链;普通用户只看标准化错误,不暴露内部供应商、真实候选模型和原始错误。
详细说明见 [模型调用与动态 Fallback 完成说明](docs/todo/模型调用与动态Fallback-完成说明.md)。
---
## 8. 资产、人像审核和删除生命周期
### 8.1 资产与文件分离
- `Asset` 保存团队归属、业务类型、审核和库状态。
- `AssetFile` 保存 TOS object key、bucket、content type、文件大小、checksum、宽高、时长和预览信息。
- `AssetUsage` 用于判断资产是否仍被商品、项目、模特或任务引用。
### 8.2 人像审核
需要审核的资产保存 `review_status``review_remote_id``review_error`。每个团队使用 `AssetReviewGroup` 关联火山资产组。
审核提交是 best-effort,但不允许将实际未提交成功的资产误标为 processing。前端会轮询状态并显示绿/红审核标记。
### 8.3 删除不等于删文件
删除链路需要区分:
1. 业务记录软删除。
2. 垃圾桶展示和恢复。
3. 项目、商品、会话和模特引用解绑。
4. ACTIVE 计费预留释放。
5. 任务和审计记录保留。
6. 确认无引用后才可最终删除 TOS 对象。
禁止为了“清理数据”直接删单表或单个 TOS 对象。
---
## 9. 积分、限额和计费
### 9.1 标准计费生命周期
```text
报价
→ 检查团队/成员/项目/单任务限额
→ reserve_credit
→ 执行 AITask
├─ 成功:charge_reserved_credit
└─ 失败:release_credit
→ CreditLedger 留下预留/扣费/释放/调整记录
```
一次用户操作只有一个 `AITask`、一次预留和一次最终扣费或释放。Fallback 的多次上游请求会记为平台成本,不转换成用户多笔扣费。
### 9.2 限额维度
- 团队自然月限额。
- 成员每日、每月和累计总限额。
- `QuotaPolicy` 的月限额、项目限额和单任务限额。
- 团队 `price_multiplier`:平台超管可为团队设置 0.10–10.00 价格系数。
### 9.3 平台计费配置
`BillingConfig` 当前提供:
- `points_per_yuan`:人民币与积分的换算。
- `video_margin_multiplier`:视频平台毛利系数。
- `video_reserve_buffer`:视频预留 buffer。
参数可在平台后台修改,文档不应将当前数据库值当成永久商业规则。
### 9.4 运维兜底
- `sweep_stale_reservations`:核对并处理超时预留。
- 超管任务页可对异常任务执行重试或回收退款。
- 删除仍为 ACTIVE 的计费任务时,信号会尝试释放预留。
---
## 10. 前端架构与页面
### 10.1 主要路由
```text
/login 登录
/register 注册
/dashboard 工作台
/products 商品库
/products/new 新建商品
/products/:id 商品详情
/models 模特库
/projects 视频项目
/projects/new 项目向导
/pipeline/:id 五阶段生产管线
/library 资产库
/asset-factory 图片创作
/image-optimize 模特上身图
/model-photo 模特图片模块
/platform-cover 平台套图
/free-create 自由视频
/account 账户与积分
/team 团队
/messages 消息中心
/settings 设置
/trash 垃圾桶
/admin/* 平台超管后台
```
### 10.2 全局状态和 API
- `App.tsx` 管理 Token 恢复、User/Team/Role、商品、项目、模型、余额、未读消息和页面分发。
- `api.ts` 统一处理基础 URL、Token、JSON/FormData 和 DRF 错误转换。
- `types.ts` 手工维护前后端数据契约。
- 无统一服务端状态/缓存层,轮询、去重、刷新恢复分散在各页面。
### 10.3 当前复杂度中心
| 文件 | 约行数 | 风险 |
| --- | ---: | --- |
| `routes/pipeline.tsx` | 4231 | 五阶段状态、轮询、交互和渲染集中 |
| `routes/ai-tools.tsx` | 2831 | 图片会话、批次、生成、删除、恢复集中 |
| `App.tsx` | 1111 | 全局状态和页面调度过重 |
| `api.ts` | 1044 | 153 左右 API 路径集中在单文件 |
| `ai/services.py` | 3614 | 多生成场景和计费/资产副作用集中 |
| `projects/views.py` | 1239 | 五阶段 action 集中 |
拆分建议顺序:先提取领域 hook/服务、再提取轮询和恢复逻辑、再按阶段拆容器,最后才拆纯展示组件。
### 10.4 设计规范
- 正式共享 token/组件位于 `core/frontend/src/design-restraint.css`
- 页面 CSS 全局生效,不是 CSS Modules;新类名必须有页面/组件前缀。
- 禁止在页面 CSS 重写 `.btn``.pill``.modal``.input` 等共享类。
- 禁止新造颜色和修改基础 token。
- `public/exact``电商AI平台` 只用于视觉对照。
---
## 11. 配置与环境变量
### 11.1 配置分类
| 分类 | 关键变量名(不含值) |
| --- | --- |
| Django | `DJANGO_SECRET_KEY``DJANGO_DEBUG``DJANGO_ALLOWED_HOSTS``DJANGO_CSRF_TRUSTED_ORIGINS``CORS_ALLOWED_ORIGINS` |
| MySQL | `DB_ENGINE``DB_NAME``DB_USER``DB_PASSWORD``DB_HOST``DB_PORT``DB_BIND_ADDRESS` |
| Redis/Celery | `REDIS_CACHE_URL``CELERY_BROKER_URL``CELERY_RESULT_BACKEND``REDIS_LOCK_URL``CELERY_TASK_ALWAYS_EAGER` |
| TOS | `TOS_ENDPOINT``TOS_BUCKET``TOS_ACCESS_KEY_ID``TOS_SECRET_ACCESS_KEY` |
| 火山 ARK | `VOLCANO_ARK_API_KEY``VOLCANO_ARK_BASE_URL``VIDEO_ARK_API_KEY` |
| 人像资产库 | `ASSETS_API_ENABLED``ASSETS_API_ACCESS_KEY``ASSETS_API_SECRET_KEY``ASSETS_API_PROJECT_NAME` |
| YunQi | `YUNQI_API_KEY``YUNQI_GPT_API_KEY``YUNQI_GEMINI_API_KEY``YUNQI_BASE_URL``YUNQI_API_VERSION` |
| TokenSSR | `TOKENSSR_API_KEY``TOKENSSR_BASE_URL` |
| 火山 TTS | `VOLC_TTS_APPID``VOLC_TTS_ACCESS_TOKEN``VOLC_TTS_CLUSTER``VOLC_TTS_BASE_URL` |
| AI 路由 | `MODEL_ROUTING_*` 共 19 项左右,控制重试、超时、候选和后处理 |
| 功能开关 | `MODEL_TRIVIEW_GENERATION_ENABLED``MODEL_TRYON_PROMPT_V2_ENABLED``MODEL_TRYON_PROMPT_V2_CANARY_TEAM_IDS` |
| 业务参数 | `DEFAULT_TRIAL_CREDITS``FREE_VIDEO_MAX_CONCURRENT` |
### 11.2 `.env.example` 当前缺口
settings 当前读取 66 个环境变量,[`.env.example`](core/backend/.env.example) 只覆盖其中一部分。未覆盖的 18 项为:
```text
ASSETS_API_ACCESS_KEY
ASSETS_API_ENABLED
ASSETS_API_PROJECT_NAME
ASSETS_API_SECRET_KEY
CELERY_TASK_ALWAYS_EAGER
CORS_ALLOWED_ORIGINS
DEFAULT_TRIAL_CREDITS
FREE_VIDEO_MAX_CONCURRENT
TOKENSSR_API_KEY
TOKENSSR_BASE_URL
VIDEO_ARK_API_KEY
VOLC_TTS_ACCESS_TOKEN
VOLC_TTS_APPID
VOLC_TTS_BASE_URL
VOLC_TTS_CLUSTER
YUNQI_API_VERSION
YUNQI_GEMINI_API_KEY
YUNQI_GPT_API_KEY
```
这意味着新人不能只复制 `.env.example` 就假设获得完整环境。应在不写入真实值的前提下补齐示例和用途。
### 11.3 密钥安全现状
- `core/backend/.env` 当前仍是 Git tracked 文件,并且历史上出现过真实供应商凭证。
- 后端 `.dockerignore` 会排除 `.env`,所以密钥不是由 Docker `COPY` 直接烘进镜像。
- 但 Gitea Actions 会从 tracked `.env` 构造 `/tmp/core.env`,再生成 K8s Secret `airshelf-core-env`
- 长期正确做法是将真实凭证从 Git 当前版本和历史移除,改为 Gitea Secret / K8s Secret / 专用密钥管理。
- 移除之前必须先盘点和轮换全部已暴露凭证,不能只做 `gitignore` 而不轮换。
---
## 12. 本地开发
### 12.1 前置依赖
- Python 3.12。
- Node.js 20+。
- MySQL(真实开发数据)或 SQLite(测试)。
- Redis:即使 Celery eager,当前 Django cache 仍是 Redis backend。
- FFmpeg:本地测试封面抽帧和导出时需要。
- 能够获取项目环境变量的安全渠道。
### 12.2 后端启动
Windows PowerShell
```powershell
cd core/backend
py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
Copy-Item .env.example .env
# 通过安全渠道补齐环境变量,不从聊天或 Git 复制真实密钥
python manage.py migrate
python manage.py runserver 127.0.0.1:8010
```
Linux/macOS
```bash
cd core/backend
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
cp .env.example .env
python manage.py migrate
python manage.py runserver 127.0.0.1:8010
```
当前仓库中的 `.venv` 可能绑定创建它的本机 Python 路径,换机后应重建,不要修补虚拟环境中的 launcher。
### 12.3 Celery Worker
Windows
```powershell
cd core/backend
.\.venv\Scripts\python.exe -m celery -A airshelf.celery:app worker -l info -P threads -c 4
```
Linux/macOS
```bash
cd core/backend
celery -A airshelf.celery:app worker -l info -c 4
```
Windows 不使用 prefork。`-P solo` 会将所有图片/视频任务串行化,仅适合特殊调试。
### 12.4 前端
```bash
cd core/frontend
npm install
npm run dev
```
Vite 开发端口默认是 5173`vite.config.ts``/api` 代理到本地 Django。
### 12.5 常用管理命令
```text
create_platform_admin 创建/更新平台超管
bootstrap_volcano_models 初始化火山模型
bootstrap_yunqi_models 初始化 YunQi 模型
seed_demo_models 生成演示模特
run_tryon_ab 模特上身图 A/B 验证
reconcile_video_timeouts 只读核对/可选恢复旧视频超时误判
sweep_stale_reservations 处理超时积分预留
audit_actor_model_migration 审计旧角色到模特的迁移
backfill_models 模特数据回填
migrate_saved_actors_to_models 将旧收藏角色迁移为模特
```
`--apply` 、回填、迁移或账务语义的命令不能在生产库盲跑;先用默认只读或帮助模式确认影响。
---
## 13. 测试与本次现场验证
### 13.1 推荐测试命令
```powershell
cd core/backend
$env:DB_ENGINE='sqlite'
python manage.py check --settings=airshelf.settings.test
python manage.py makemigrations --check --dry-run --settings=airshelf.settings.test
python manage.py test --settings=airshelf.settings.test
```
```bash
cd core/frontend
npm run build
```
QA 工具:
- [Visual Parity QA](core/qa/visual-parity/README.md)Playwright + pixelmatch 视觉差异。
- [Function Audit](core/qa/function-audit/README.md):遍历页面交互并发现死按钮。
### 13.2 2026-08-12 实际验证结果
| 检查 | 结果 |
| --- | --- |
| `manage.py check` + test settings + SQLite | 通过,0 issues |
| `makemigrations --check --dry-run` | 通过,No changes detected |
| 前端 `npm run build` | 通过 |
| 模型路由/重试/Fallback/错误分类 4 个测试模块 | 62/62 通过 |
| 后端全量测试 | 未全绿 |
前端构建产物:
- CSS 约 454.52 KBgzip 约 65.76 KB。
- JS 约 882.00 KBgzip 约 243.08 KB。
- Vite 警告主 chunk 超过 500 KB,应通过动态 import 或 manual chunks 渐进拆包。
### 13.3 当前测试红项
1. 全量运行发现 545 项测试。
2. `apps.projects.tests.ProjectApiTests.test_extract_entities_recovers_when_content_empty_uses_reasoning` 可稳定复现失败:期望 HTTP 200,实际 HTTP 400。
3. `airshelf.settings.test` 虽将数据库改为 SQLite 且 Celery eager,却没有将 Django cache 切换为 LocMem/Dummy cache;多个测试会尝试连接环境中的远程 Redis,导致大量环境性错误。
4. 这些 Redis 连接错误不等于同数量的业务缺陷,但说明当前“隔离测试”并未完全隔离。
优先修复顺序:先让 test settings 使用本地内存 cache,再处理实体提取 reasoning-only 回退测试,然后将 545 项全量测试跑到可重复全绿。
### 13.4 前端测试现状
- `core/frontend/package.json` 只有 `dev``build``preview`
- 没有 `test``lint` script,也没有前端 `*.test.*` / `*.spec.*` 单测文件。
- 视觉和交互自动化在 `core/qa` 中独立运行,尚未并入主 CI 质量门禁。
- `visual-parity/package.json` 的部分 script 仍包含旧 macOS 绝对路径,换机不可直接复用。
---
## 14. 构建、发布和环境
### 14.1 当前 CI/CD 行为
[Gitea Actions 工作流](.gitea/workflows/deploy.yaml) 当前会:
1. 拉取推送分支。
2. 构建三个镜像:设计稿静态站、真后端 API/Worker、真 React Web。
3. 推送到火山镜像仓库,同时写入日期+SHA tag 和 `latest`
4. 从配置构造 K8s Secret。
5. 替换镜像和域名占位符,apply K8s 清单。
6. 重启 Web/API/Worker Deployment。
7. 部署失败时向 Log Center 上报摘要。
### 14.2 环境与域名
| 上下文 | 当前工作流配置 |
| --- | --- |
| `dev` | 测试镜像组织;真 React 站点 `airshelf-web.test.airlabs.art` |
| `master` | 生产镜像组织;真 React 站点 `airshelf-web.airlabs.art` |
| 静态设计站 | 测试 `airshelf.test.airlabs.art`;生产 `airshelf.airlabs.art` |
本次未对上述 URL 执行线上可用性检查,表格只表示仓库当前配置。
### 14.3 生产分支严重不一致
- `AGENTS.md` / `CLAUDE.md` 明确写着:`dev` 是开发分支,`main` 是生产主分支。
- `origin/HEAD` 也指向 `origin/main`
- 但 Gitea 部署工作流只监听 `dev``master`,生产判断条件也是 `master`
在人工确定正确生产分支并修正文档或 CI 之前,不得假设合并到 `main` 会自动生产发布。这是 P0 交接项。
### 14.4 数据库迁移
- API 容器启动 Gunicorn 前执行 `migrate``collectstatic`
- Worker 复用同一镜像,但入口脚本明确跳过迁移。
- MySQL 迁移通过 `GET_LOCK('airshelf_migrate', 600)` 跨 Pod 串行化。
- 该锁是对 2026-07-07 多轮 rolling deployment 并发重放积分×10 数据迁移事故的修复。
- 数据变换迁移必须幂等,或在执行前有明确的一次性保护。
### 14.5 当前 CI 缺口
- 构建和部署之前没有 Django 测试门禁。
- 没有前端 lint/test 门禁,仅 Docker 构建间接执行 TypeScript + Vite build。
- 未看到明确的 `kubectl rollout status` 或部署后业务冒烟。
- 未看到自动 `rollout undo` 回滚。
- 当前工作流会同时构建静态设计站和真应用,接手人需明确两者域名,避免验收错站。
---
## 15. 运维与故障处理
### 15.1 当前可用的运维能力
- API liveness/readiness`GET /api/health/`
- Worker liveness`celery inspect ping`
- Gitea Actions 部署失败日志上报。
- 平台超管 `/admin/tasks`:查看任务、真实模型调用链、重试和回收。
- 站内消息:生成失败、余额和其他关键状态。
- 管理命令:视频超时恢复、超时预留处理、数据迁移审计。
### 15.2 健康检查局限
`/api/health/` 只返回静态 JSON,不检查 MySQL、Redis、TOS 和 AI Provider。因此 Pod Ready 不等于业务链路可用。
建议将健康分成:
- liveness:进程是否存活,保持当前轻量。
- readinessMySQL 和 Redis 的低成本检查。
- 独立运维探针:TOS/Provider 的限频、无扣费或最小成本校验。
### 15.3 尚未形成正式文档的 Runbook
未发现可直接交给值班人员的以下独立流程:
- MySQL 备份、恢复、RPO/RTO 和恢复演练。
- K8s 发布回滚和数据库迁移回退决策。
- Redis 不可用、Celery 队列积压和毒任务处理。
- TOS 访问失败、资产 URL 失效和误删恢复。
- Provider 大面积失败、欠费、模型下线和 Fallback 人工切换。
- 证书、域名、镜像仓库和第三方账号续期责任。
- 故障分级、值班人、联系方式和升级路径。
### 15.4 建议的最小发布检查
发布前:
- 确认目标分支、环境、镜像 tag 和变更范围。
- 运行 Django check、migration check、后端全量测试、前端 build。
- 审核所有数据迁移,对数据变换迁移准备备份与回滚策略。
- 确认 API 和 Worker 使用同版镜像和同一份模型路由策略。
发布后:
- 等待 Web/API/Worker rollout 完成。
- 检查浅层健康和日志。
- 冒烟登录、商品查询、图片上传和积分摘要。
- 至少冒烟文本、图片、配音、视频提交/轮询和 `/admin/tasks` 调用链。
- 检查一次预留到扣费/释放的完整流水。
- 确认新增资产能入 TOS、能预览、能进垃圾桶并恢复。
---
## 16. 安全、权限与合规
### 16.1 已有保护
- Django 密码校验器。
- DRF 默认需要登录。
- 团队数据通过 `TeamScopedViewSetMixin` 等服务端逻辑隔离。
- 平台超管和团队角色分离。
- 生产启用 secure cookie 和 forwarded HTTPS header。
- Nginx 设置 `X-Content-Type-Options``Referrer-Policy`
- 人像素材审核和 Seedance `asset://` 引用。
- AI 原始错误与普通用户提示分离。
### 16.2 优先安全风险
1. **P0:真实密钥进入 Git 历史。** 必须先轮换再清理。
2. **P0:凭证责任人和续期/吊销流程没有交接。**
3. **P1Basic Authentication 仍保留在 DRF 默认认证列表。** 如无真实需求,应评估移除。
4. **P1:前端“记住我 7 天”主要是本地存储策略,DRF Token 本身不是自带 7 天过期的 JWT。** 需确认后端会话撤销与 Token 失效语义是否符合产品要求。
5. **P1:无正式密钥扫描 CI 门禁。**
6. **P1:没有专门安全文档、事故响应流程和外部依赖清单。**
### 16.3 密钥治理建议
1. 盘点 Git 当前版本和历史中的所有供应商凭证。
2. 在各供应商后台创建新凭证,更新 Gitea/K8s Secret。
3. 重启 API/Worker,按能力冒烟验证。
4. 吊销旧凭证。
5. 从 Git 当前版本移除 `.env`,再评估是否需清洗历史。
6.`.env.example` 补齐为无密钥的变量契约。
7. CI 增加 secret scanning,并建立定期轮换表。
---
## 17. 当前风险和待办优先级
### P0:接手前必须确认
| 风险 | 影响 | 建议动作 |
| --- | --- | --- |
| `main` / `master` 生产分支矛盾 | 合并到 main 可能不部署,或团队误判生产流程 | 由仓库/部署负责人定调,统一 AGENTS、默认分支和 workflow |
| 真实 `.env` 被 Git 跟踪 | 供应商、TOS、数据库等凭证泄露 | 全量轮换,迁移到 Secret,清理当前版本与历史 |
| 缺少备份/恢复交接 | 数据迁移或人为误操后无法可控恢复 | 确认 MySQL/TOS 备份策略、RPO/RTO 和最近恢复演练 |
### P1:建议第一周完成
| 风险 | 建议 |
| --- | --- |
| 后端全量测试不全绿 | 隔离 Redis cache,修复 reasoning-only 实体提取回退,将 545 项测试纳入 CI |
| CI 无测试/发布后验证/自动回滚 | 增加质量门禁、rollout status、冒烟与人工回滚指南 |
| `.env.example` 缺 18 个配置 | 补齐变量、类型、必填性、默认值和重启影响 |
| 无 OpenAPI | 生成后端 schema,用于契约校验和前端类型生成 |
| 前端无 test/lint | 至少先补路由、API 错误、任务轮询和积分展示的测试 |
| 健康探针过浅 | 增加 readiness 的 MySQL/Redis 检查 |
### P2:中期技术债
| 风险 | 建议 |
| --- | --- |
| `pipeline.tsx` / `ai-tools.tsx` / `services.py` 过大 | 按领域边界渐进拆分,禁止一次性重写 |
| 单 API/Worker/Web 副本 | 对真实并发、可用性和成本做容量基线,再决定水平扩容 |
| 单 Worker 队列 | 视频/导出与图片任务可能互相饥饿,评估拆队列和资源限制 |
| 人工充值非真支付 | 若进入商用,需补支付单、签名回调、对账、退款和审计 |
| 缺少统一可观测平台 | 增加结构化日志、错误追踪、队列/任务/供应商指标和告警 |
### 已过期的旧交接项
- 旧报告中的 `/admin/*` 刷新 404 已修复,Django Admin 已迁到 `/django-admin/`
- 旧报告对默认模型的写死描述已不可靠,当前存在数据库动态默认、路由 metadata、Retry 和 Fallback。
- 2026-07-09 的提交表示火山账号曾进行迁移,但本次没有读取运行时凭证;旧报告的“借用 AirDrama 账号”不应继续当成当前事实,需账号负责人人工确认。
---
## 18. 架构文档同步状态
2026-08-12 运行项目自带的架构扫描器,结果:
```text
analysis_ready: true
requires_update: true
plan_id: arch-b47510754d10bb74309d
snapshot_id: f959a18ac43444340c4d
```
扫描发现两类影响:
1. `core/backend/airshelf/settings/base.py` 增加统一模型路由策略和类型化环境变量读取,影响后端架构的 `3.1 Settings``3.3 鉴权`
2. `core/backend/apps/ai/models.py` 增加 `AIModelAttempt`,影响 `4.6 ai`
当前 [后端架构](core/backend/ARCHITECTURE.md) 正文已包含部分最新内容,但文档同步标记仍落后于 HEAD;[前端架构](core/frontend/ARCHITECTURE.md) 本次没有被扫描器判定为必须更新。
本文没有修改两份 `ARCHITECTURE.md`。若后续要同步,必须按 `tools/architecture-sync/WORKFLOW.md` 重新生成计划、获得用户确认并验证。
---
## 19. 接手清单
### 19.1 第 0 天:权限与人员
- [ ] 确认仓库管理员、生产发布负责人和最终业务验收人。
- [ ] 确认 Gitea、火山镜像仓库、K3s/K8s、MySQL、Redis、TOS、ARK、Assets API、TTS、YunQi 和 TokenSSR 的账号归属。
- [ ] 确认生产分支到底是 `main` 还是 `master`
- [ ] 确认测试/生产数据库是否完全隔离。
- [ ] 获取备份策略、最近一次备份和最近一次恢复演练证据。
### 19.2 第 1 天:本地环境
- [ ] 重建 Python 3.12 `.venv`,不复用别人机器绑定的 launcher。
- [ ] 从安全渠道获得测试环境变量。
- [ ] 启动 MySQL/Redis/API/Worker/Web。
- [ ] 运行 Django check、migration check 和前端 build。
- [ ] 复现并记录当前后端测试红项。
### 19.3 第 23 天:业务冒烟
- [ ] 邀请码注册、登录、团队成员和角色。
- [ ] 商品创建、图片上传、详情、软删除和恢复。
- [ ] 新建项目,跑通脚本、实体、基础资产、故事板、视频和导出。
- [ ] 检查真人素材审核和 `asset://` 视频引用。
- [ ] 检查图片创作、模特上身图、平台套图和自由视频。
- [ ] 检查预留、成功扣费、失败释放、限额和超管调整。
- [ ] 检查 `/admin/tasks` 的 Retry/Fallback/AIModelAttempt 调用链。
### 19.4 第 1 周:工程收口
- [ ] 定调分支和发布流程。
- [ ] 轮换已入 Git 的全部真实凭证。
- [ ] 修复测试 Redis 隔离和实体提取回归。
- [ ] 将后端测试、前端 build 和基础 QA 加入 CI。
- [ ] 补全 `.env.example`
- [ ] 产出《发布/回滚 Runbook》和《备份/恢复 Runbook》。
- [ ] 将本文中的待人工确认项转化为已签字的责任表。
---
## 20. 人工待确认责任表
| 事项 | 当前代码可确认的事实 | 需人工填写 |
| --- | --- | --- |
| 产品负责人 | 仓库无可靠当前责任表 | 姓名、联系方式 |
| 技术负责人 | 仓库无可靠当前责任表 | 姓名、联系方式 |
| 生产发布 | workflow 目前按 `master` 处理生产 | 负责人、实际分支、审批人 |
| 数据库 | MySQL,迁移用 GET_LOCK 串行 | 管理员、备份位置、RPO/RTO |
| Redis | cache/broker/result/lock 四类用途 | 管理员、容量和告警 |
| TOS | 业务文件与导出存储 | 账号、bucket 负责人、生命周期规则 |
| 火山 ARK/Assets/TTS | 代码已集成 | 账号归属、额度、续费和吊销负责人 |
| YunQi/TokenSSR | OpenAI-compatible Provider | 账号归属、额度、备用策略 |
| 域名/证书 | Traefik + cert-manager | 负责人、续期/异常告警 |
| 故障值班 | 仓库未定义 | 值班表、P0/P1 升级路径 |
---
## 21. 资料索引
### 必读
- [AGENTS.md](AGENTS.md):项目工程约定、Git 流程、AI 链路和设计铁律。
- [PRD.md](PRD.md):产品目标、用户、五阶段、权限、边界和验收标准。
- [后端架构](core/backend/ARCHITECTURE.md)。
- [前端架构](core/frontend/ARCHITECTURE.md)。
- [设计规范](电商AI平台/design.md)。
### AI 与生成链路
- [AI 生成 Agent 化落地方案](AI生成-Agent化落地方案.md)。
- [AI Agent 历史交接](交接-AI生成Agent化-2026-06-17.md)。
- [脚本 Agent SSE 技术文档](core/docs/脚本Agent流式SSE技术文档.md)。
- [脚本 Agent 动态知识装配](core/docs/脚本Agent编排架构方案-动态知识装配.md)。
- [模型调用与动态 Fallback](docs/todo/模型调用与动态Fallback-完成说明.md)。
- [模特库与我的演员数据流](docs/todo/模特库与我的演员数据流说明.md)。
### QA 和审计
- [Visual Parity QA](core/qa/visual-parity/README.md)。
- [Function Audit](core/qa/function-audit/README.md)。
- [性能审计报告](性能审计报告-AirShelf-2026-06-19.md)。
- [UI 还原对比报告](UI还原对比报告-AirShelf-2026-06-19.md)。
### 历史资料(不能单独作为当前状态)
- [2026-06-24 项目移交报告](项目移交报告-2026-06-24.md)。
- [顶层技术架构方案](core/ARCHITECTURE.md)。
- `docs/bug_todo/`:专项问题和修复过程。
- `docs/agents_todo/`Agent 协同方案和 TODO 计划。
---
## 22. 文档维护规则
发生以下变化时,应更新本交接文档:
- 生产/开发分支或部署域名变化。
- Django app、一级 API、核心模型或鉴权变化。
- 五阶段顺序、任务执行模型或资产生命周期变化。
- Provider、Retry/Fallback、计费或人像审核边界变化。
- MySQL、Redis、TOS、K8s 或 CI/CD 架构变化。
- 交接责任人、备份策略、回滚流程或密钥归属变化。
- 全量测试基线或主要已知红项变化。
更新时必须在文首同时记录日期、分支、完整 HEAD SHA 和实际验证结果;不允许只改“已完成”文案而没有可复现证据。
---
## 23. 本次未验证的外部状态
以下项目需有相应权限的接手人在第 0–3 天完成:
- 测试和生产站点当前是否可访问。
- 实际默认模型、Provider 状态、Fallback metadata 和供应商余额。
- 火山 ARK、Assets API、TTS、YunQi、TokenSSR 当前凭证和账号归属。
- MySQL/Redis/TOS 实际容量、备份、监控和告警。
- 线上商品到最终视频导出的最新端到端通过情况。
- 生产发布应从 `main` 还是 `master` 触发。
- 所有已暴露凭证是否已经轮换或吊销。
---
_文档于 2026-08-12 基于当前 `dev` HEAD、架构扫描、配置和部署文件、代码结构、历史完成说明以及本地隔离验证整理。未修改业务代码、配置、数据库、既有架构文档、Git 暂存区或远端状态。_