forked from 77media/video-flow
626 lines
15 KiB
Markdown
626 lines
15 KiB
Markdown
# 🎬 Video Edit API 完整规范文档
|
||
|
||
## 📋 概述
|
||
|
||
本文档为Video-Flow视频编辑功能的后端API提供完整的实现规范,包括RESTful API设计、数据结构定义、认证机制、数据库设计等,为后端开发团队提供详细的实现指南。
|
||
|
||
## 🏗️ 系统架构
|
||
|
||
### 技术栈建议
|
||
- **后端框架**: FastAPI (Python) / Express.js (Node.js) / Spring Boot (Java)
|
||
- **数据库**: PostgreSQL (主数据库) + Redis (缓存)
|
||
- **认证**: JWT Token
|
||
- **文件存储**: AWS S3 / 阿里云OSS
|
||
- **消息队列**: Redis / RabbitMQ (用于异步处理)
|
||
|
||
### 服务架构
|
||
```
|
||
Frontend (React)
|
||
↓ HTTP/HTTPS
|
||
API Gateway
|
||
↓
|
||
Video Edit Service
|
||
↓
|
||
Database (PostgreSQL) + Cache (Redis)
|
||
```
|
||
|
||
## 🗄️ 数据库设计
|
||
|
||
### 1. 编辑点表 (edit_points)
|
||
|
||
```sql
|
||
CREATE TABLE edit_points (
|
||
id VARCHAR(50) PRIMARY KEY,
|
||
video_id VARCHAR(100) NOT NULL,
|
||
project_id VARCHAR(100) NOT NULL,
|
||
user_id INTEGER NOT NULL,
|
||
position_x FLOAT NOT NULL CHECK (position_x >= 0 AND position_x <= 100),
|
||
position_y FLOAT NOT NULL CHECK (position_y >= 0 AND position_y <= 100),
|
||
timestamp FLOAT NOT NULL CHECK (timestamp >= 0),
|
||
description TEXT DEFAULT '',
|
||
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'edited', 'processing', 'completed', 'failed')),
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
-- 索引
|
||
INDEX idx_edit_points_video_project (video_id, project_id),
|
||
INDEX idx_edit_points_user (user_id),
|
||
INDEX idx_edit_points_status (status),
|
||
INDEX idx_edit_points_created (created_at DESC),
|
||
|
||
-- 外键约束
|
||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
|
||
);
|
||
```
|
||
|
||
### 2. 编辑历史表 (edit_point_history)
|
||
|
||
```sql
|
||
CREATE TABLE edit_point_history (
|
||
id SERIAL PRIMARY KEY,
|
||
edit_point_id VARCHAR(50) NOT NULL,
|
||
action VARCHAR(20) NOT NULL CHECK (action IN ('created', 'updated', 'deleted', 'submitted')),
|
||
old_data JSONB,
|
||
new_data JSONB,
|
||
user_id INTEGER NOT NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
-- 索引
|
||
INDEX idx_history_edit_point (edit_point_id),
|
||
INDEX idx_history_user (user_id),
|
||
INDEX idx_history_created (created_at DESC),
|
||
|
||
-- 外键约束
|
||
FOREIGN KEY (edit_point_id) REFERENCES edit_points(id) ON DELETE CASCADE,
|
||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||
);
|
||
```
|
||
|
||
### 3. 编辑任务队列表 (edit_tasks)
|
||
|
||
```sql
|
||
CREATE TABLE edit_tasks (
|
||
id SERIAL PRIMARY KEY,
|
||
edit_point_id VARCHAR(50) NOT NULL,
|
||
task_type VARCHAR(20) NOT NULL DEFAULT 'edit_request',
|
||
priority INTEGER DEFAULT 0,
|
||
status VARCHAR(20) DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'completed', 'failed')),
|
||
payload JSONB NOT NULL,
|
||
result JSONB,
|
||
error_message TEXT,
|
||
retry_count INTEGER DEFAULT 0,
|
||
max_retries INTEGER DEFAULT 3,
|
||
scheduled_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
started_at TIMESTAMP,
|
||
completed_at TIMESTAMP,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
|
||
-- 索引
|
||
INDEX idx_tasks_status (status),
|
||
INDEX idx_tasks_scheduled (scheduled_at),
|
||
INDEX idx_tasks_edit_point (edit_point_id),
|
||
|
||
-- 外键约束
|
||
FOREIGN KEY (edit_point_id) REFERENCES edit_points(id) ON DELETE CASCADE
|
||
);
|
||
```
|
||
|
||
## 🔌 API 端点规范
|
||
|
||
### 基础配置
|
||
- **Base URL**: `https://api.smartvideo.py.qikongjian.com/v1`
|
||
- **Content-Type**: `application/json`
|
||
- **认证方式**: Bearer Token (JWT)
|
||
|
||
### 1. 获取编辑点列表
|
||
|
||
```http
|
||
GET /video-edit/edit-points
|
||
```
|
||
|
||
**查询参数:**
|
||
```typescript
|
||
interface GetEditPointsQuery {
|
||
video_id: string; // 必需:视频ID
|
||
project_id: string; // 必需:项目ID
|
||
offset?: number; // 可选:偏移量,默认0
|
||
limit?: number; // 可选:限制数量,默认50,最大100
|
||
status?: EditPointStatus; // 可选:状态筛选
|
||
sort?: 'created_at' | 'updated_at' | 'timestamp'; // 可选:排序字段
|
||
order?: 'asc' | 'desc'; // 可选:排序方向,默认desc
|
||
}
|
||
```
|
||
|
||
**响应格式:**
|
||
```typescript
|
||
interface GetEditPointsResponse {
|
||
code: number; // 状态码,0表示成功
|
||
successful: boolean; // 是否成功
|
||
message: string; // 响应消息
|
||
data: {
|
||
edit_points: EditPoint[];
|
||
total_count: number;
|
||
has_more: boolean;
|
||
pagination: {
|
||
offset: number;
|
||
limit: number;
|
||
total: number;
|
||
};
|
||
};
|
||
}
|
||
```
|
||
|
||
**示例请求:**
|
||
```bash
|
||
curl -X GET "https://api.smartvideo.py.qikongjian.com/v1/video-edit/edit-points?video_id=video123&project_id=proj456&limit=20" \
|
||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||
-H "Content-Type: application/json"
|
||
```
|
||
|
||
### 2. 创建编辑点
|
||
|
||
```http
|
||
POST /video-edit/edit-points
|
||
```
|
||
|
||
**请求体:**
|
||
```typescript
|
||
interface CreateEditPointRequest {
|
||
video_id: string; // 必需:视频ID
|
||
project_id: string; // 必需:项目ID
|
||
position_x: number; // 必需:X坐标百分比 (0-100)
|
||
position_y: number; // 必需:Y坐标百分比 (0-100)
|
||
timestamp: number; // 必需:时间戳(秒)
|
||
description?: string; // 可选:编辑描述
|
||
status?: EditPointStatus; // 可选:初始状态,默认pending
|
||
}
|
||
```
|
||
|
||
**响应格式:**
|
||
```typescript
|
||
interface CreateEditPointResponse {
|
||
code: number;
|
||
successful: boolean;
|
||
message: string;
|
||
data: EditPoint;
|
||
}
|
||
```
|
||
|
||
**示例请求:**
|
||
```bash
|
||
curl -X POST "https://api.smartvideo.py.qikongjian.com/v1/video-edit/edit-points" \
|
||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"video_id": "video123",
|
||
"project_id": "proj456",
|
||
"position_x": 50.5,
|
||
"position_y": 30.2,
|
||
"timestamp": 15.5,
|
||
"description": "需要在这里添加特效"
|
||
}'
|
||
```
|
||
|
||
### 3. 更新编辑点
|
||
|
||
```http
|
||
PUT /video-edit/edit-points/{edit_point_id}
|
||
```
|
||
|
||
**路径参数:**
|
||
- `edit_point_id`: 编辑点ID
|
||
|
||
**请求体:**
|
||
```typescript
|
||
interface UpdateEditPointRequest {
|
||
description?: string; // 可选:编辑描述
|
||
status?: EditPointStatus; // 可选:状态
|
||
position_x?: number; // 可选:X坐标百分比
|
||
position_y?: number; // 可选:Y坐标百分比
|
||
}
|
||
```
|
||
|
||
**响应格式:**
|
||
```typescript
|
||
interface UpdateEditPointResponse {
|
||
code: number;
|
||
successful: boolean;
|
||
message: string;
|
||
data: EditPoint;
|
||
}
|
||
```
|
||
|
||
### 4. 删除编辑点
|
||
|
||
```http
|
||
DELETE /video-edit/edit-points/{edit_point_id}
|
||
```
|
||
|
||
**路径参数:**
|
||
- `edit_point_id`: 编辑点ID
|
||
|
||
**响应格式:**
|
||
```typescript
|
||
interface DeleteEditPointResponse {
|
||
code: number;
|
||
successful: boolean;
|
||
message: string;
|
||
data: null;
|
||
}
|
||
```
|
||
|
||
### 5. 批量删除编辑点
|
||
|
||
```http
|
||
POST /video-edit/edit-points/batch-delete
|
||
```
|
||
|
||
**请求体:**
|
||
```typescript
|
||
interface BatchDeleteRequest {
|
||
edit_point_ids: string[]; // 必需:要删除的编辑点ID列表
|
||
}
|
||
```
|
||
|
||
### 6. 提交编辑请求
|
||
|
||
```http
|
||
POST /video-edit/edit-points/{edit_point_id}/submit
|
||
```
|
||
|
||
**路径参数:**
|
||
- `edit_point_id`: 编辑点ID
|
||
|
||
**响应格式:**
|
||
```typescript
|
||
interface SubmitEditResponse {
|
||
code: number;
|
||
successful: boolean;
|
||
message: string;
|
||
data: {
|
||
task_id: string; // 任务ID,用于跟踪处理状态
|
||
estimated_duration: number; // 预估处理时间(秒)
|
||
};
|
||
}
|
||
```
|
||
|
||
### 7. 获取编辑统计
|
||
|
||
```http
|
||
GET /video-edit/stats
|
||
```
|
||
|
||
**查询参数:**
|
||
```typescript
|
||
interface GetStatsQuery {
|
||
project_id?: string; // 可选:项目ID筛选
|
||
video_id?: string; // 可选:视频ID筛选
|
||
date_from?: string; // 可选:开始日期 (ISO 8601)
|
||
date_to?: string; // 可选:结束日期 (ISO 8601)
|
||
}
|
||
```
|
||
|
||
**响应格式:**
|
||
```typescript
|
||
interface GetStatsResponse {
|
||
code: number;
|
||
successful: boolean;
|
||
message: string;
|
||
data: {
|
||
total_edit_points: number;
|
||
status_breakdown: {
|
||
pending: number;
|
||
edited: number;
|
||
processing: number;
|
||
completed: number;
|
||
failed: number;
|
||
};
|
||
daily_stats: Array<{
|
||
date: string;
|
||
count: number;
|
||
}>;
|
||
};
|
||
}
|
||
```
|
||
|
||
## 🔐 认证和权限控制
|
||
|
||
### JWT Token 结构
|
||
```typescript
|
||
interface JWTPayload {
|
||
user_id: number;
|
||
username: string;
|
||
email: string;
|
||
role: 'admin' | 'user' | 'viewer';
|
||
permissions: string[];
|
||
exp: number; // 过期时间戳
|
||
iat: number; // 签发时间戳
|
||
}
|
||
```
|
||
|
||
### 权限级别
|
||
- **admin**: 所有操作权限
|
||
- **user**: 可以创建、编辑、删除自己的编辑点
|
||
- **viewer**: 只能查看编辑点
|
||
|
||
### 权限检查中间件
|
||
```python
|
||
# FastAPI 示例
|
||
from fastapi import Depends, HTTPException, status
|
||
from fastapi.security import HTTPBearer
|
||
|
||
security = HTTPBearer()
|
||
|
||
async def verify_token(token: str = Depends(security)):
|
||
try:
|
||
payload = jwt.decode(token.credentials, SECRET_KEY, algorithms=["HS256"])
|
||
return payload
|
||
except jwt.ExpiredSignatureError:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||
detail="Token has expired"
|
||
)
|
||
except jwt.JWTError:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||
detail="Invalid token"
|
||
)
|
||
|
||
async def check_edit_permission(
|
||
edit_point_id: str,
|
||
current_user: dict = Depends(verify_token)
|
||
):
|
||
# 检查用户是否有权限编辑该编辑点
|
||
edit_point = await get_edit_point(edit_point_id)
|
||
if not edit_point:
|
||
raise HTTPException(status_code=404, detail="Edit point not found")
|
||
|
||
if current_user["role"] != "admin" and edit_point.user_id != current_user["user_id"]:
|
||
raise HTTPException(status_code=403, detail="Permission denied")
|
||
|
||
return edit_point
|
||
```
|
||
|
||
## 📊 数据类型定义
|
||
|
||
### TypeScript 接口定义
|
||
|
||
```typescript
|
||
// 编辑点状态枚举
|
||
enum EditPointStatus {
|
||
PENDING = 'pending',
|
||
EDITED = 'edited',
|
||
PROCESSING = 'processing',
|
||
COMPLETED = 'completed',
|
||
FAILED = 'failed'
|
||
}
|
||
|
||
// 编辑点位置
|
||
interface EditPointPosition {
|
||
x: number; // X坐标百分比 (0-100)
|
||
y: number; // Y坐标百分比 (0-100)
|
||
}
|
||
|
||
// 编辑点主数据结构
|
||
interface EditPoint {
|
||
id: string; // 编辑点唯一ID
|
||
video_id: string; // 视频ID
|
||
project_id: string; // 项目ID
|
||
user_id: number; // 用户ID
|
||
position_x: number; // X坐标百分比
|
||
position_y: number; // Y坐标百分比
|
||
timestamp: number; // 视频时间戳(秒)
|
||
description: string; // 编辑描述
|
||
status: EditPointStatus; // 状态
|
||
created_at: string; // 创建时间 (ISO 8601)
|
||
updated_at: string; // 更新时间 (ISO 8601)
|
||
}
|
||
|
||
// API 通用响应格式
|
||
interface ApiResponse<T = any> {
|
||
code: number; // 状态码,0表示成功
|
||
successful: boolean; // 是否成功
|
||
message: string; // 响应消息
|
||
data: T; // 响应数据
|
||
timestamp?: string; // 响应时间戳
|
||
request_id?: string; // 请求ID(用于追踪)
|
||
}
|
||
|
||
// 分页信息
|
||
interface PaginationInfo {
|
||
offset: number; // 偏移量
|
||
limit: number; // 限制数量
|
||
total: number; // 总数量
|
||
has_more: boolean; // 是否有更多数据
|
||
}
|
||
|
||
// 错误详情
|
||
interface ErrorDetail {
|
||
field?: string; // 错误字段
|
||
code: string; // 错误代码
|
||
message: string; // 错误消息
|
||
}
|
||
```
|
||
|
||
## ⚠️ 错误码定义
|
||
|
||
### HTTP 状态码
|
||
- `200`: 成功
|
||
- `201`: 创建成功
|
||
- `400`: 请求参数错误
|
||
- `401`: 未认证
|
||
- `403`: 权限不足
|
||
- `404`: 资源不存在
|
||
- `409`: 资源冲突
|
||
- `422`: 数据验证失败
|
||
- `429`: 请求过于频繁
|
||
- `500`: 服务器内部错误
|
||
- `503`: 服务不可用
|
||
|
||
### 业务错误码
|
||
```typescript
|
||
enum BusinessErrorCode {
|
||
// 通用错误 (1000-1099)
|
||
INVALID_PARAMETER = 1001,
|
||
MISSING_PARAMETER = 1002,
|
||
INVALID_FORMAT = 1003,
|
||
|
||
// 认证错误 (1100-1199)
|
||
TOKEN_EXPIRED = 1101,
|
||
TOKEN_INVALID = 1102,
|
||
PERMISSION_DENIED = 1103,
|
||
|
||
// 编辑点错误 (1200-1299)
|
||
EDIT_POINT_NOT_FOUND = 1201,
|
||
EDIT_POINT_LIMIT_EXCEEDED = 1202,
|
||
INVALID_POSITION = 1203,
|
||
INVALID_TIMESTAMP = 1204,
|
||
|
||
// 视频错误 (1300-1399)
|
||
VIDEO_NOT_FOUND = 1301,
|
||
VIDEO_NOT_ACCESSIBLE = 1302,
|
||
|
||
// 项目错误 (1400-1499)
|
||
PROJECT_NOT_FOUND = 1401,
|
||
PROJECT_NOT_ACCESSIBLE = 1402,
|
||
|
||
// 系统错误 (1500-1599)
|
||
DATABASE_ERROR = 1501,
|
||
EXTERNAL_SERVICE_ERROR = 1502,
|
||
RATE_LIMIT_EXCEEDED = 1503
|
||
}
|
||
```
|
||
|
||
## 🚀 部署和运维
|
||
|
||
### 环境变量配置
|
||
```bash
|
||
# 数据库配置
|
||
DATABASE_URL=postgresql://user:password@localhost:5432/video_flow
|
||
REDIS_URL=redis://localhost:6379/0
|
||
|
||
# JWT配置
|
||
JWT_SECRET_KEY=your-super-secret-key
|
||
JWT_ALGORITHM=HS256
|
||
JWT_EXPIRE_HOURS=24
|
||
|
||
# 服务配置
|
||
API_HOST=0.0.0.0
|
||
API_PORT=8000
|
||
DEBUG=false
|
||
LOG_LEVEL=INFO
|
||
|
||
# 外部服务
|
||
S3_BUCKET=video-edit-storage
|
||
S3_ACCESS_KEY=your-access-key
|
||
S3_SECRET_KEY=your-secret-key
|
||
|
||
# 限流配置
|
||
RATE_LIMIT_REQUESTS=100
|
||
RATE_LIMIT_WINDOW=60
|
||
```
|
||
|
||
### Docker 部署
|
||
```dockerfile
|
||
FROM python:3.11-slim
|
||
|
||
WORKDIR /app
|
||
|
||
COPY requirements.txt .
|
||
RUN pip install -r requirements.txt
|
||
|
||
COPY . .
|
||
|
||
EXPOSE 8000
|
||
|
||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||
```
|
||
|
||
### 监控和日志
|
||
- **健康检查**: `GET /health`
|
||
- **指标监控**: Prometheus + Grafana
|
||
- **日志收集**: ELK Stack
|
||
- **错误追踪**: Sentry
|
||
|
||
## 📈 性能优化建议
|
||
|
||
### 数据库优化
|
||
1. **索引策略**: 为常用查询字段创建复合索引
|
||
2. **分页优化**: 使用游标分页替代偏移分页
|
||
3. **连接池**: 配置合适的数据库连接池大小
|
||
4. **读写分离**: 读操作使用只读副本
|
||
|
||
### 缓存策略
|
||
1. **Redis缓存**: 缓存热点数据和查询结果
|
||
2. **CDN**: 静态资源使用CDN加速
|
||
3. **应用缓存**: 内存中缓存频繁访问的数据
|
||
|
||
### API优化
|
||
1. **批量操作**: 支持批量创建、更新、删除
|
||
2. **字段选择**: 支持指定返回字段减少数据传输
|
||
3. **压缩**: 启用gzip压缩
|
||
4. **限流**: 实现智能限流防止滥用
|
||
|
||
## 🧪 测试策略
|
||
|
||
### 单元测试
|
||
```python
|
||
import pytest
|
||
from fastapi.testclient import TestClient
|
||
|
||
def test_create_edit_point():
|
||
response = client.post("/video-edit/edit-points", json={
|
||
"video_id": "test-video",
|
||
"project_id": "test-project",
|
||
"position_x": 50.0,
|
||
"position_y": 30.0,
|
||
"timestamp": 15.5,
|
||
"description": "Test edit point"
|
||
})
|
||
assert response.status_code == 201
|
||
assert response.json()["successful"] == True
|
||
```
|
||
|
||
### 集成测试
|
||
- API端点完整性测试
|
||
- 数据库事务测试
|
||
- 认证授权测试
|
||
- 错误处理测试
|
||
|
||
### 性能测试
|
||
- 负载测试:模拟高并发请求
|
||
- 压力测试:测试系统极限
|
||
- 稳定性测试:长时间运行测试
|
||
|
||
## 📝 开发指南
|
||
|
||
### 开发环境搭建
|
||
1. 克隆代码仓库
|
||
2. 安装依赖:`pip install -r requirements.txt`
|
||
3. 配置环境变量
|
||
4. 初始化数据库:`alembic upgrade head`
|
||
5. 启动开发服务器:`uvicorn main:app --reload`
|
||
|
||
### 代码规范
|
||
- 使用 Black 进行代码格式化
|
||
- 使用 flake8 进行代码检查
|
||
- 使用 mypy 进行类型检查
|
||
- 遵循 PEP 8 编码规范
|
||
|
||
### Git 工作流
|
||
- 使用 Git Flow 分支模型
|
||
- 提交信息遵循 Conventional Commits
|
||
- 代码审查必须通过才能合并
|
||
- 自动化 CI/CD 流程
|
||
|
||
---
|
||
|
||
## 📞 技术支持
|
||
|
||
如有任何技术问题或需要进一步的实现指导,请联系开发团队。
|
||
|
||
**文档版本**: v1.0.0
|
||
**最后更新**: 2024-09-19
|
||
**维护者**: Video-Flow 开发团队
|