# 07 · API 接口规范

## 1. 通用约定

- **BaseURL**: `https://api.yaoai.com/v1`
- **格式**: JSON(UTF-8),时间 ISO-8601
- **鉴权**: `Authorization: Bearer <jwt>`,租户从 JWT claims 解析
- **请求 ID**: 每个响应带 `X-Request-Id`
- **分页**: `?page=1&size=20`,响应 `{items[], total, page, size}`
- **错误**: 统一结构
  ```json
  {"error":{"code":"INVALID_PARAM","message":"...","requestId":"..."}}
  ```
- **幂等**: 写操作支持 `Idempotency-Key` 头
- **限流**: 返回 `Retry-After`

## 2. 认证

| Method | Path | 说明 |
|--------|------|------|
| POST | `/auth/register` | 注册(email/username + password) |
| POST | `/auth/login` | 登录 → {accessToken, refreshToken, user} |
| POST | `/auth/logout` | 注销 |
| POST | `/auth/refresh` | 刷新 token |
| GET  | `/auth/me` | 当前用户信息 |
| POST | `/auth/oauth/{provider}/callback` | 第三方登录 |
| POST | `/auth/password/reset-request` | 发送重置邮件 |
| POST | `/auth/password/reset` | 用 token 重置 |

## 3. 租户与成员

| Method | Path | 说明 |
|--------|------|------|
| GET | `/tenants/current` | 当前租户 |
| PATCH | `/tenants/current` | 更新名称/Logo |
| GET | `/tenants/members` | 成员列表 |
| POST | `/tenants/invitations` | 邀请成员 |

## 4. 项目

| Method | Path | 说明 |
|--------|------|------|
| GET | `/projects?page=&search=&status=&from=&to=&members=` | 列表 |
| GET | `/projects/stats` | Dashboard 统计 |
| POST | `/projects` | 创建(multipart: file + meta) |
| GET | `/projects/{id}` | 详情 |
| GET | `/projects/{id}/full-data` | 含大纲/人物/分集聚合 |
| PATCH | `/projects/{id}` | 更新字段 |
| DELETE | `/projects/{id}` | 删除 |
| POST | `/projects/{id}:archive` | 归档 |

### 项目成员

| Method | Path |
|--------|------|
| GET | `/projects/{id}/members` |
| POST | `/projects/{id}/invitations` |
| PATCH | `/projects/{id}/members/{mid}` |
| DELETE | `/projects/{id}/members/{mid}` |

## 5. 剧本解析 (四步导入)

| Method | Path | 说明 |
|--------|------|------|
| POST | `/projects/{id}/import/step1-extract` | 文本抽取 |
| POST | `/projects/{id}/import/step2-characters` | AI 角色提取 |
| GET/PATCH/DELETE | `/projects/{id}/characters/{cid}` | 用户修改角色 |
| POST | `/projects/{id}/import/step3-episodes` | 智能分集 |
| POST | `/projects/{id}/import/step4-confirm` | 一键创建 |

## 6. 风格与大纲

| Method | Path |
|--------|------|
| GET | `/styles` |
| POST | `/projects/{id}:set-style` |
| POST | `/projects/{id}/outline:generate`  → `taskId` |
| GET | `/projects/{id}/outline` |
| PUT | `/projects/{id}/outline` |

## 7. 分集

| Method | Path |
|--------|------|
| GET | `/projects/{id}/episodes` |
| POST | `/projects/{id}/episodes:generate` |
| PATCH | `/projects/{id}/episodes/{eid}` |
| DELETE | `/projects/{id}/episodes/{eid}` |

## 8. 角色/场景/道具

每种资源一套相同风格:

```
GET    /projects/{id}/characters
POST   /projects/{id}/characters
GET    /projects/{id}/characters/{cid}
PATCH  /projects/{id}/characters/{cid}
DELETE /projects/{id}/characters/{cid}
POST   /projects/{id}/characters/{cid}:generate-turnaround   # 四视图
POST   /projects/{id}/characters/{cid}:upload-reference      # 参考图
POST   /projects/{id}/characters/{cid}/appearances           # 新增变体
GET    /projects/{id}/characters/{cid}/appearances
```

scenes / props 同构。

## 9. 分镜

| Method | Path | 说明 |
|--------|------|------|
| GET | `/projects/{id}/episodes/{eid}/storyboards` | 列表 |
| POST | `/projects/{id}/episodes/{eid}/storyboards:generate` | AI 批量生成分镜 |
| POST | `/projects/{id}/storyboards` | 手动创建 |
| GET | `/projects/{id}/storyboards/{sid}` | 详情 |
| PATCH | `/projects/{id}/storyboards/{sid}` | 更新 |
| DELETE | `/projects/{id}/storyboards/{sid}` | 删除 |
| POST | `/projects/{id}/storyboards/{sid}:duplicate` | 复制 |
| PUT | `/projects/{id}/episodes/{eid}/storyboards:reorder` | 拖拽重排序 |
| POST | `/projects/{id}/storyboards/{sid}:ai-check` | AI 合规检查 |

### 分镜资产

| Method | Path |
|--------|------|
| GET | `/projects/{id}/storyboards/{sid}/assets?type=FIRST_FRAME&active=true` |
| POST | `/projects/{id}/storyboards/{sid}/assets/first-frame:generate` |
| POST | `/projects/{id}/storyboards/{sid}/assets/last-frame:generate` |
| POST | `/projects/{id}/storyboards/{sid}/assets/video:generate` |
| POST | `/projects/{id}/storyboards/{sid}/assets/audio:generate` |
| PATCH | `/projects/{id}/storyboards/{sid}/assets/{aid}:activate` | 回滚版本 |

### 批量

| Method | Path |
|--------|------|
| POST | `/projects/{id}/episodes/{eid}/storyboards:batch-generate` body={storyboardIds[], targets:[first_frame,last_frame,video]} |

## 10. 视频合成

| Method | Path |
|--------|------|
| POST | `/projects/{id}/episodes/{eid}:assemble` | 合成最终视频(FFmpeg) |
| GET | `/projects/{id}/episodes/{eid}/segments` | 分镜段状态 |
| GET | `/projects/{id}/episodes/{eid}/final` | 最终 MP4 下载 URL |

## 11. 任务与进度

| Method | Path |
|--------|------|
| GET | `/tasks/{taskId}` | 单任务详情 |
| GET | `/tasks?type=&status=&projectId=` | 列表 |
| POST | `/tasks/{taskId}:cancel` | 取消 |
| GET | `/tasks/{taskId}/events` (**SSE**) | 进度事件流 |
| GET | `/projects/{id}/events` (**SSE**) | 项目级事件聚合 |

**SSE 事件格式**:
```
event: task.progress
data: {"taskId":"01HX...","type":"VIDEO_GEN","progress":42,"stage":"polling","message":"Shot 12/50"}

event: task.completed
data: {"taskId":"...","result":{...}}

event: task.failed
data: {"taskId":"...","error":{"code":"...","message":"..."}}

event: credit.consumed
data: {"amount":50,"balance":2340}
```

## 12. 计费

| Method | Path |
|--------|------|
| GET | `/billing/balance` | 当前余额+冻结+已消费 |
| GET | `/billing/transactions?page=&type=` | 流水 |
| POST | `/billing/recharge` body={amount, paymentMethod} → 支付链接 |
| POST | `/billing/subscription` body={plan} → 升级 |
| GET | `/billing/subscription` | 当前订阅 |
| POST | `/billing/subscription:cancel` |
| GET | `/usage/stats?from=&to=` | 积分统计 |
| GET | `/usage/daily?from=&to=` | 30 天趋势 |
| GET | `/usage/records?...` | 明细 |

## 13. 资产库

| Method | Path |
|--------|------|
| GET | `/assets?library=personal&type=character&tags=&search=` |
| POST | `/assets` | 上传 |
| GET | `/assets/{aid}` |
| PATCH | `/assets/{aid}` |
| DELETE | `/assets/{aid}` |
| POST | `/assets/{aid}:favorite` |
| POST | `/assets/{aid}:clone-to-project` body={projectId} |

## 14. 设置与提示词

| Method | Path |
|--------|------|
| GET/PUT | `/settings/watermark` |
| GET | `/prompt-templates?scope=&key=` |
| POST | `/prompt-templates` |
| PATCH | `/prompt-templates/{id}` |
| GET | `/prompt-templates/{id}/versions` |
| POST | `/prompt-templates/{id}:rollback?version=` |
| GET/POST | `/prompt-presets` |

## 15. 企业管理(`/admin/*`)

需要 `ADMIN` 或 `OWNER` 角色:

| Method | Path |
|--------|------|
| GET | `/admin/employees?search=&status=` |
| POST | `/admin/employees` |
| PATCH | `/admin/employees/{id}` |
| DELETE | `/admin/employees/{id}` |
| POST | `/admin/employees:bulk-import` (CSV) |
| GET | `/admin/groups` |
| POST | `/admin/groups` |
| PATCH | `/admin/groups/{id}` |
| GET | `/admin/audit-logs?...` |

## 16. 系统

| Method | Path |
|--------|------|
| GET | `/system/boot-id` | 健康检查 |
| GET | `/system/version` | 版本 |
| GET | `/system/notifications` | 全局公告 |

## 17. OpenAPI 规范

- 使用 `springdoc-openapi` 自动生成 `/v3/api-docs` 和 Swagger UI
- 所有 DTO 用 Bean Validation 注解(`@NotNull`/`@Size`/`@Email`)
- Controller 强制使用 `ResponseEntity<ApiResponse<T>>` 统一包装
- 错误码集中维护在 `ErrorCode` 枚举
