# AI 短视频创作平台 — 工程骨架方案 > 本方案由 WorkBuddy 产出,交付给 Trae 执行。 > 定位:toC 产品,Python 后端 + React 前端,独立部署。 --- ## 一、技术栈总览 | 层 | 技术 | 版本 | 角色 | |---|---|---|---| | **前端框架** | React | 19.x | UI 层 | | **构建工具** | Vite | 6.x | 开发/打包 | | **语言** | TypeScript | 5.x | 前端类型安全 | | **UI 组件** | shadcn/ui | latest | 原子组件库 | | **样式** | Tailwind CSS | 4.x | 原子化样式 | | **拖拽** | @dnd-kit | latest | 时间轴/素材拖拽 | | **画布** | react-konva | latest | 预览画布/文字贴纸 | | **状态管理** | zustand | 5.x | 编辑器状态 + 撤销重做 | | **数据请求** | @tanstack/react-query | 5.x | 服务端状态/缓存 | | **动画** | framer-motion | 11.x | 过渡动效 | | **路由** | react-router | 7.x | 页面路由 | | **表单** | react-hook-form + zod | latest | 表单校验 | | **后端框架** | FastAPI | 0.115+ | REST API + WebSocket | | **ASGI 服务器** | uvicorn | latest | 生产级运行 | | **数据库** | PostgreSQL + Redis | 16 / 7 | 持久化 + 缓存/队列 | | **ORM** | SQLAlchemy 2.0 | 2.x | 数据库映射 | | **任务队列** | Celery + Redis | 5.x | AI 异步生成 | | **文件存储** | MinIO / S3 | — | 视频/素材存储 | | **AI 集成** | OpenAI SDK / 本地模型 | — | 脚本生成/视频处理 | --- ## 二、目录结构 ``` ai-video-platform/ ├── frontend/ # React 前端 │ ├── index.html │ ├── package.json │ ├── tsconfig.json │ ├── vite.config.ts │ ├── tailwind.config.ts │ ├── components.json # shadcn/ui 配置 │ ├── public/ │ │ └── favicon.svg │ └── src/ │ ├── main.tsx # 入口 │ ├── App.tsx # 根组件 + 路由 │ ├── index.css # Tailwind 入口 │ ├── lib/ │ │ └── utils.ts # cn() 工具函数 │ ├── components/ │ │ ├── ui/ # shadcn/ui 组件(自动生成) │ │ │ ├── button.tsx │ │ │ ├── card.tsx │ │ │ ├── dialog.tsx │ │ │ ├── slider.tsx │ │ │ ├── tabs.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├─�� input.tsx │ │ │ ├── textarea.tsx │ │ │ ├── select.tsx │ │ │ ├── toast.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── sheet.tsx # 侧边栏 │ │ │ └── skeleton.tsx # 加载骨架 │ │ ├── layout/ │ │ │ ├── AppShell.tsx # 整体布局壳 │ │ │ ├── Sidebar.tsx # 左侧导航 │ │ │ └── Header.tsx # 顶部栏 │ │ ├── editor/ # 🔥 视频编辑器核心 │ │ │ ├── Timeline/ │ │ │ │ ├── Timeline.tsx # 时间轴容器 │ │ │ │ ├── Track.tsx # 单条轨道 │ �� │ │ ├── TrackItem.tsx # 轨道上的片段 │ │ │ │ ├── TimelineRuler.tsx # 时间标尺 │ │ │ │ └── TimelineControls.tsx # 缩放/播放控制 │ │ │ ├── Canvas/ │ │ │ │ ├── PreviewCanvas.tsx # 预览画布(react-konva) │ │ │ │ ├── TextOverlay.tsx # 文字叠层 │ │ │ │ ├── StickerLayer.tsx # 贴纸层 │ │ │ │ └── VideoLayer.tsx # 视频画面层 │ │ │ ├── Toolbar/ │ │ │ │ ├── EditorToolbar.tsx # 编辑工具栏 │ │ │ │ ├── CropTool.tsx # 裁剪工具 │ │ │ │ └── TextTool.tsx # 文字工具 │ │ │ └── AssetPanel/ │ │ │ ├── AssetLibrary.tsx # 素材库面板 │ │ │ ├── MediaUploader.tsx # 上传组件 │ │ │ └── AIGenerator.tsx # AI 生成入口 │ │ ├── ai/ # AI 功能面板 │ │ │ ├── ScriptGenerator.tsx # 脚本生成 │ │ │ ├── VoiceGenerator.tsx # AI 配音 │ │ │ ├── SubtitleGenerator.tsx # 字幕生成 │ │ │ └── GenerationProgress.tsx # 生成进度(WebSocket) │ │ └── common/ │ │ ├── LoadingSpinner.tsx │ │ ├── ErrorBoundary.tsx │ │ ├── EmptyState.tsx │ │ └── ConfirmDialog.tsx │ ├── pages/ │ │ ├── Home.tsx # 首页/项目列表 │ │ ├── Editor.tsx # 🔥 编辑器主页面 │ │ ├── Projects.tsx # 我的项目 │ │ ├── Templates.tsx # 模板市场 │ │ ├── Assets.tsx # 素材管理 │ │ └── Settings.tsx # 用户设置 │ ├── stores/ # zustand 状态 │ │ ├── editorStore.ts # 🔥 编辑器核心状态 + 撤销重做 │ │ ├── projectStore.ts # 项目元信息 │ │ ├── uiStore.ts # UI 状态(面板显隐等) │ │ └── authStore.ts # 用户认证 │ ├── hooks/ # 自定义 hooks │ │ ├── useEditor.ts # 编辑器逻辑入口 │ │ ├── useUndoRedo.ts # 撤销重做封装 │ │ ├── useWebSocket.ts # WebSocket 连接 │ │ ├── useMediaUpload.ts # 上传逻辑 │ �� └── useAIGeneration.ts # AI 生成调用 │ ├── api/ # API 层 │ │ ├── client.ts # axios/fetch 实例 │ │ ├── projects.ts # 项目 CRUD │ │ ├── media.ts # 素材上传/管理 │ │ ├── generation.ts # AI 生成接口 │ │ └── auth.ts # 认证接口 │ ├── types/ # TypeScript 类型 │ │ ├── project.ts │ │ ├── timeline.ts # 时间轴轨道类型 │ │ ├── media.ts │ │ └── api.ts # API 响应类型 │ └── utils/ │ ├── time.ts # 时间格式化 │ └── file.ts # 文件工具 │ ├── backend/ # Python 后端 │ ├── pyproject.toml # 项目管理(uv/poetry) │ ├── alembic.ini # 数据库迁移配置 │ ├── Dockerfile │ ├── docker-compose.yml # 本地开发环境 │ ├── app/ │ │ ├── __init__.py │ │ ├── main.py # FastAPI 入口 │ │ ├── config.py # 配置管理(pydantic-settings) │ │ ├── dependencies.py # 依赖注入 │ │ ├── api/ │ │ │ ├── __init__.py │ │ │ ├── v1/ │ │ │ │ ├── __init__.py │ │ │ │ ├── router.py # 路由聚合 │ │ │ │ ├── auth.py # 认证 │ │ │ │ ├── projects.py # 项目 CRUD │ │ │ │ ├── media.py # 素材上传 │ │ │ │ ├── generation.py # AI 生成 │ │ │ │ ├─�� templates.py # 模板 │ │ │ │ └── websocket.py # WebSocket 进度推送 │ │ ├── models/ │ │ │ ├── __init__.py │ │ │ ├── user.py │ │ │ ├── project.py │ │ │ ├── media.py │ │ │ └── template.py │ │ ├── schemas/ │ │ │ ├── __init__.py │ │ │ ├── user.py │ │ │ ├── project.py │ │ │ ├── media.py │ │ │ └── generation.py │ │ ├── services/ │ │ │ ├── __init__.py │ │ │ ├── project_service.py │ │ │ ├── media_service.py │ │ │ ├── script_generator.py # 🔥 AI 脚本生成 │ │ │ ├── voice_service.py # 🔥 AI 配音 │ │ │ ├── subtitle_service.py # 🔥 AI 字幕 │ │ │ ├── video_renderer.py # 🔥 视频合成 │ │ │ └── storage_service.py # 文件存储(MinIO/S3) │ │ ├── tasks/ # Celery 异步任务 │ │ │ ├── __init__.py │ │ │ ├── celery_app.py │ │ │ ├── generation_tasks.py # AI 生成任务 │ │ │ └── media_tasks.py # 媒体处理任务 │ │ ├── core/ │ │ │ ├── __init__.py │ │ │ ├── security.py # JWT / OAuth │ │ │ ├── database.py # SQLAlchemy 引擎 │ │ │ └── exceptions.py │ │ └── utils/ │ │ ├── __init__.py │ │ └── helpers.py │ ├── alembic/ │ │ ├── env.py │ │ └── versions/ │ ├── tests/ │ │ ├── conftest.py │ │ ├── test_projects.py │ │ └── test_generation.py │ └── requirements/ │ ├── base.txt │ ├── dev.txt │ └── prod.txt │ └── docs/ # 文档 ├── api-spec.md # API 接口说明 └── editor-architecture.md # 编辑器架构设计 ``` --- ## 三、前端核心依赖 ```jsonc // frontend/package.json (关键字段) { "name": "ai-video-platform", "private": true, "type": "module", "scripts": { "dev": "vite", "build": "tsc -b && vite build", "preview": "vite preview", "lint": "eslint ." }, "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.0.0", "@tanstack/react-query": "^5.0.0", "zustand": "^5.0.0", "@dnd-kit/core": "^6.1.0", "@dnd-kit/sortable": "^8.0.0", "@dnd-kit/utilities": "^3.2.0", "react-konva": "^18.2.0", "konva": "^9.3.0", "framer-motion": "^11.0.0", "react-hook-form": "^7.53.0", "@hookform/resolvers": "^3.9.0", "zod": "^3.23.0", "axios": "^1.7.0", "clsx": "^2.1.0", "tailwind-merge": "^2.5.0", "class-variance-authority": "^0.7.0", "lucide-react": "^0.460.0", "sonner": "^1.7.0" }, "devDependencies": { "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^4.3.0", "vite": "^6.0.0", "typescript": "^5.6.0", "tailwindcss": "^4.0.0", "@tailwindcss/vite": "^4.0.0", "eslint": "^9.0.0" } } ``` --- ## 四、后端核心依赖 ``` # backend/requirements/base.txt # Web 框架 fastapi>=0.115,<1.0 uvicorn[standard]>=0.32,<1.0 python-multipart>=0.0.18 # 文件上传 # 数据库 sqlalchemy>=2.0,<3.0 asyncpg>=0.30,<1.0 # PostgreSQL 异步驱动 alembic>=1.14,<2.0 # 数据库迁移 pydantic>=2.10,<3.0 pydantic-settings>=2.6,<3.0 # 缓存 & 队列 redis>=5.2,<6.0 celery>=5.4,<6.0 # 认证 python-jose[cryptography]>=3.3,<4.0 passlib[bcrypt]>=1.7,<2.0 # 文件存储 boto3>=1.35,<2.0 # S3/MinIO minio>=7.2,<8.0 # AI SDK openai>=1.55,<2.0 # 工具 httpx>=0.28,<1.0 loguru>=0.7,<1.0 ``` --- ## 五、初始化步骤(逐条命令) ### 5.1 创建项目目录 ```bash mkdir ai-video-platform && cd ai-video-platform ``` ### 5.2 前端初始化 ```bash # 1. Vite + React + TypeScript npm create vite@latest frontend -- --template react-ts cd frontend npm install # 2. 安装运行时依赖 npm install react-router @tanstack/react-query zustand @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities react-konva konva framer-motion react-hook-form @hookform/resolvers zod axios clsx tailwind-merge class-variance-authority lucide-react sonner # 3. 安装开发依赖 npm install -D tailwindcss @tailwindcss/vite # 4. 初始化 shadcn/ui npx shadcn@latest init # 选择:TypeScript / Neutral / CSS variables / Yes to all # 5. 添加 shadcn 组件 npx shadcn@latest add button card dialog slider tabs dropdown-menu input textarea select toast tooltip sheet skeleton ``` ### 5.3 Tailwind CSS v4 配置 ```ts // frontend/vite.config.ts import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' import path from 'path' export default defineConfig({ plugins: [react(), tailwindcss()], resolve: { alias: { '@': path.resolve(__dirname, './src'), }, }, server: { port: 3000, proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true, }, '/ws': { target: 'ws://localhost:8000', ws: true, }, }, }, }) ``` ```css /* frontend/src/index.css */ @import "tailwindcss"; @import "tw-animate-css"; @custom-variant dark (&:is(.dark *)); :root { --radius: 0.625rem; --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); --card-foreground: oklch(0.145 0 0); --popover: oklch(1 0 0); --popover-foreground: oklch(0.145 0 0); --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.97 0 0); --secondary-foreground: oklch(0.205 0 0); --muted: oklch(0.97 0 0); --muted-foreground: oklch(0.556 0 0); --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); --chart-3: oklch(0.398 0.07 227.392); --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); } .dark { --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); /* ... 暗色主题变量 ... */ } @theme inline { --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); --color-chart-1: var(--chart-1); --color-chart-2: var(--chart-2); --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); } @layer base { * { @apply border-border; } body { @apply bg-background text-foreground; } } ``` ### 5.4 后端初始化 ```bash cd backend # 1. 创建虚拟环境 python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate # 2. 安装依赖 pip install -r requirements/base.txt # 3. 初始化 Alembic alembic init alembic # 修改 alembic/env.py 指向你的数据库 # 4. 创建初始迁移 alembic revision --autogenerate -m "init" alembic upgrade head # 5. 启动开发服务器 uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` ### 5.5 本地基础设施 ```bash # docker-compose.yml — 一键启动 PostgreSQL + Redis + MinIO docker compose up -d ``` ```yaml # backend/docker-compose.yml services: postgres: image: postgres:16-alpine environment: POSTGRES_USER: video_dev POSTGRES_PASSWORD: video_dev POSTGRES_DB: ai_video_platform ports: - "5432:5432" volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:7-alpine ports: - "6379:6379" minio: image: minio/minio:latest command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin ports: - "9000:9000" - "9001:9001" volumes: - miniodata:/data volumes: pgdata: miniodata: ``` --- ## 六、编辑器核心状态设计(zustand store) 这是整个前端的灵魂。交给 Trae 后,它是编码优先级最高的模块。 ```ts // frontend/src/stores/editorStore.ts import { create } from 'zustand'; import { temporal } from 'zundo'; // zustand 撤销重做中间件 interface TrackItem { id: string; type: 'video' | 'image' | 'audio' | 'text' | 'sticker'; trackId: string; startTime: number; // 毫秒 duration: number; // 毫秒 properties: { x?: number; y?: number; width?: number; height?: number; rotation?: number; opacity?: number; text?: string; fontSize?: number; fontColor?: string; // ... 其他属性 }; source: { url?: string; // 媒体文件 URL fileId?: string; // 后端文件 ID }; } interface EditorState { // 项目元信息 projectId: string | null; projectName: string; // 轨道数据 tracks: TrackItem[]; // 播放状态 currentTime: number; isPlaying: boolean; duration: number; // 选中状态 selectedItemIds: string[]; // 缩放 zoom: number; // 0.25 ~ 4.0 // 操作 addTrackItem: (item: TrackItem) => void; removeTrackItem: (id: string) => void; updateTrackItem: (id: string, updates: Partial) => void; moveTrackItem: (id: string, newStartTime: number, newTrackId?: string) => void; setCurrentTime: (time: number) => void; togglePlay: () => void; selectItems: (ids: string[]) => void; setZoom: (zoom: number) => void; } export const useEditorStore = create()( temporal( (set) => ({ projectId: null, projectName: '未命名项目', tracks: [], currentTime: 0, isPlaying: false, duration: 60000, selectedItemIds: [], zoom: 1, addTrackItem: (item) => set((s) => ({ tracks: [...s.tracks, item] })), removeTrackItem: (id) => set((s) => ({ tracks: s.tracks.filter((t) => t.id !== id), selectedItemIds: s.selectedItemIds.filter((sid) => sid !== id), })), updateTrackItem: (id, updates) => set((s) => ({ tracks: s.tracks.map((t) => t.id === id ? { ...t, ...updates } : t ), })), moveTrackItem: (id, newStartTime, newTrackId) => set((s) => ({ tracks: s.tracks.map((t) => t.id === id ? { ...t, startTime: newStartTime, trackId: newTrackId ?? t.trackId } : t ), })), setCurrentTime: (time) => set({ currentTime: time }), togglePlay: () => set((s) => ({ isPlaying: !s.isPlaying })), selectItems: (ids) => set({ selectedItemIds: ids }), setZoom: (zoom) => set({ zoom }), }), { limit: 50 } // 保留 50 步撤销历史 ) ); ``` --- ## 七、后端 FastAPI 入口骨架 ```python # backend/app/main.py from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.api.v1.router import api_router from app.core.database import engine, Base from app.config import settings @asynccontextmanager async def lifespan(app: FastAPI): # 启动时:创建表(开发环境) # async with engine.begin() as conn: # await conn.run_sync(Base.metadata.create_all) yield # 关闭时清理 await engine.dispose() app = FastAPI( title="AI 短视频创作平台", version="0.1.0", lifespan=lifespan, ) # CORS app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 注册路由 app.include_router(api_router, prefix="/api/v1") @app.get("/health") async def health_check(): return {"status": "ok"} ``` ### WebSocket 进度推送 ```python # backend/app/api/v1/websocket.py from fastapi import APIRouter, WebSocket, WebSocketDisconnect router = APIRouter() class ConnectionManager: def __init__(self): self.active_connections: dict[str, WebSocket] = {} async def connect(self, task_id: str, websocket: WebSocket): await websocket.accept() self.active_connections[task_id] = websocket def disconnect(self, task_id: str): self.active_connections.pop(task_id, None) async def send_progress(self, task_id: str, data: dict): ws = self.active_connections.get(task_id) if ws: await ws.send_json(data) manager = ConnectionManager() @router.websocket("/ws/generation/{task_id}") async def generation_progress(websocket: WebSocket, task_id: str): await manager.connect(task_id, websocket) try: while True: # 保持连接,等待 Celery 任务推送进度 await websocket.receive_text() except WebSocketDisconnect: manager.disconnect(task_id) ``` --- ## 八、前后端联调约定 ### API 规范 | 事项 | 约定 | |---|---| | 接口前缀 | `/api/v1/` | | 请求格式 | `application/json`,上传用 `multipart/form-data` | | 响应格式 | `{ "code": 0, "data": {...}, "message": "ok" }` | | 分页格式 | `{ "code": 0, "data": { "items": [...], "total": 100, "page": 1, "page_size": 20 } }` | | 错误码 | 0=成功,4xxx=客户端错误,5xxx=服务端错误 | | WebSocket | `/ws/generation/{task_id}` — AI 生成进度实时推送 | | 认证 | Bearer Token(JWT),Header: `Authorization: Bearer ` | ### 统一响应模型 ```python # backend/app/schemas/common.py from pydantic import BaseModel from typing import Generic, TypeVar T = TypeVar("T") class ApiResponse(BaseModel, Generic[T]): code: int = 0 message: str = "ok" data: T | None = None class PageResponse(BaseModel, Generic[T]): items: list[T] total: int page: int page_size: int ``` ### 前端请求封装 ```ts // frontend/src/api/client.ts import axios from 'axios'; const client = axios.create({ baseURL: '/api/v1', timeout: 30000, }); // 请求拦截:自动带 Token client.interceptors.request.use((config) => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // 响应拦截:统一错误处理 client.interceptors.response.use( (res) => res.data, (err) => { if (err.response?.status === 401) { // 跳转登录 } return Promise.reject(err); } ); export default client; ``` --- ## 九、AI 生成核心功能拆解 按优先级排列,建议 Trae 按此顺序实现: | 优先级 | 功能 | 前端关键组件 | 后端关键服务 | 复杂度 | |---|---|---|---|---| | P0 | **AI 脚本生成** | `ScriptGenerator.tsx`(输入主题/关键词 → 流式显示脚本) | `script_generator.py`(调用 LLM API,SSE 流式返回) | ⭐⭐ | | P0 | **视频编辑器基础** | `Timeline/` + `Canvas/` + `editorStore` | 项目 CRUD、素材上传 | ⭐⭐⭐⭐⭐ | | P1 | **AI 配音** | `VoiceGenerator.tsx`(选择音色 → 试听 → 插入时间轴) | `voice_service.py`(TTS API) | ⭐⭐⭐ | | P1 | **AI 字幕** | `SubtitleGenerator.tsx`(语音识别 → 字幕轨道展示) | `subtitle_service.py`(ASR) | ⭐⭐⭐ | | P2 | **模板市场** | `Templates.tsx`(模板浏览 → 一键套用) | `templates.py`(模板 CRUD) | ⭐⭐ | | P2 | **视频合成导出** | 导出进度条 | `video_renderer.py`(FFmpeg 合成 + Celery 异步) | ⭐⭐⭐⭐ | --- ## 十、开发工作流 ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ WorkBuddy │────▶│ Trae │────▶│ Git Commit │ │ 方案 & 架构 │ │ 编码 & 调试 │ │ 版本管理 │ └──────────────┘ └──────────────┘ └──────────────┘ ▲ │ └────────────────────────────────────────┘ 遇到架构问题回 WorkBuddy 讨论 ``` 1. WorkBuddy 产出本方案 → Trae 读者直接执行 2. Trae 按 P0 → P1 → P2 顺序编码 3. 每完成一个模块,前端 `npm run dev` 即时验证 4. 后端 `pytest` + `uvicorn --reload` 同步验证 5. 遇到技术选型/架构疑问 → 回 WorkBuddy 讨论 6. 确定方案后继续在 Trae 编码 --- ## 十一、交付清单 给 Trae 的第一阶段任务(建议一次不要超过 5 个文件): - [ ] `frontend/package.json` — 按第四节配置 - [ ] `frontend/vite.config.ts` — 按 5.3 节配置 - [ ] `frontend/tailwind.config.ts` — 按 5.3 节配置 - [ ] `frontend/src/index.css` — 按 5.3 节配置 - [ ] `frontend/src/main.tsx` — React 入口 - [ ] `frontend/src/App.tsx` — 路由 + 布局壳 - [ ] `frontend/src/components/layout/AppShell.tsx` — shadcn/ui 侧边栏 + 顶栏 - [ ] `frontend/src/stores/editorStore.ts` — 编辑器核心状态(第六节) - [ ] `frontend/src/pages/Home.tsx` — 首页占位 - [ ] `frontend/src/pages/Editor.tsx` — 编辑器主��面占位 - [ ] `backend/pyproject.toml` — 项目配置 - [ ] `backend/requirements/base.txt` — 按第四节配置 - [ ] `backend/app/main.py` — 第七节完整代码 - [ ] `backend/app/config.py` — pydantic-settings 配置 - [ ] `backend/app/core/database.py` — SQLAlchemy 引擎 - [ ] `backend/app/api/v1/router.py` — 路由聚合 - [ ] `backend/app/api/v1/websocket.py` — WebSocket 进度推送 - [ ] `backend/app/schemas/common.py` — 统一响应模型 - [ ] `backend/docker-compose.yml` — 本地基础设施 ``` --- _方案版本:v1.0 | 产出日期:2026-07-31 | 产出工具:WorkBuddy | 执行工具:Trae_