feat(review): 重构项目级单方案验收协作
This commit is contained in:
@@ -1,60 +1,32 @@
|
||||
# API 接入指南
|
||||
|
||||
## 认证方式
|
||||
## 认证
|
||||
|
||||
工作台网页使用 HttpOnly Cookie 会话。外部客户端使用:
|
||||
工作台使用 HttpOnly Cookie;外部客户端使用:
|
||||
|
||||
```http
|
||||
Authorization: Bearer dd_live_xxx
|
||||
```
|
||||
|
||||
API Key 明文只在创建时返回一次,数据库仅保存 SHA-256 哈希。平台管理员创建平台级 Key;组管理员创建本组项目级 Key。失效或越权请求会返回 `401` 或 `403`。
|
||||
平台级 Key 可跨组创建和查询项目。项目级 Key 只能操作绑定项目,包括在该项目中新建作品和验收轮次。密钥明文只在创建时返回一次。
|
||||
|
||||
## 主要路由
|
||||
|
||||
| 路由组 | 用途 |
|
||||
|---|---|
|
||||
| `/api/auth/*` | 登录、退出、当前账号、修改密码 |
|
||||
| `/api/management/groups` | 运营组创建、改名、启停和管理员更换 |
|
||||
| `/api/management/users` | 账号创建、改名、启停和重置密码 |
|
||||
| `/api/management/api-keys` | API Key 创建、查询和吊销 |
|
||||
| `/api/management/audit-logs` | 审计日志查询 |
|
||||
| `/api/management/storage-configs` | COS 配置、连接测试和启用 |
|
||||
| `/api/projects` | 项目创建、查询和编辑 |
|
||||
| `/api/projects/:projectId/collections` | 作品交付集创建、查询和编辑 |
|
||||
| `/api/notes` | 作品查询与创建 |
|
||||
| `/api/notes/:noteId/review-rounds` | 创建包含 1–5 个候选稿的验收轮次 |
|
||||
| `/api/notes/:noteId/versions` | 兼容接口:创建单候选稿验收轮次 |
|
||||
| `/api/notes/:noteId/status` | 草稿与待验收状态切换 |
|
||||
| `/api/notes/:noteId/text-annotations` | 标题/正文批注 |
|
||||
| `/api/images/:imageId/annotations` | 图片坐标批注 |
|
||||
| `/api/review/:slug/*` | 客户登录、浏览和反馈 |
|
||||
| `/api/review/:slug/works/:noteId/decision` | 客户对指定候选稿作出验收决定 |
|
||||
| `/api/health` | 数据库就绪检查 |
|
||||
|
||||
## 查询运营组、项目、作品交付集和作品
|
||||
|
||||
调用方不需要预先知道数据库 ID。使用 API Key 按顺序查询:
|
||||
## 发现资源
|
||||
|
||||
```bash
|
||||
# 返回 Key 有权访问的项目,响应包含 group_id、group_name 和项目 id
|
||||
# 查询 Key 可访问的项目,响应包含 group_id、group_name 和项目 id
|
||||
curl http://localhost:3010/api/projects \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY"
|
||||
|
||||
# 查询项目中的作品交付集
|
||||
curl http://localhost:3010/api/projects/1/collections \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY"
|
||||
|
||||
# 查询交付集中的作品,响应包含作品 id、external_id 和 version_number
|
||||
curl "http://localhost:3010/api/notes?collectionId=1" \
|
||||
# 查询项目作品
|
||||
curl http://localhost:3010/api/projects/1/works \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY"
|
||||
```
|
||||
|
||||
项目级 Key 的项目列表只会返回绑定项目;平台级 Key 可以查询全部运营组的项目。创建作品时只传 `collectionId`,服务会据此确定项目和运营组并校验权限,不需要重复传递 `projectId` 或 `groupId`。
|
||||
调用方不再需要作品交付集 ID。`externalId` 在项目内唯一,可用于安全重试和找回作品。
|
||||
|
||||
## 创建项目
|
||||
|
||||
平台级 API Key 可以指定目标运营组。项目级 Key 不能创建项目。
|
||||
只有平台级 Key 可以创建项目。
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3010/api/projects \
|
||||
@@ -63,120 +35,94 @@ curl -X POST http://localhost:3010/api/projects \
|
||||
-d '{"name":"7 月内容计划","slug":"july-content","groupId":1,"client_description":"客户可见说明"}'
|
||||
```
|
||||
|
||||
`slug` 仅支持小写字母、数字和连字符,并作为客户验收链接的一部分。
|
||||
## 创建作品
|
||||
|
||||
## 创建作品交付集
|
||||
JSON 请求中的 `images` 为 1–30 个公开 HTTP/HTTPS URL。服务只保存 URL,不下载也不转存 COS;数组顺序就是展示顺序,第一张为封面。
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3010/api/projects/1/collections \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"2026 年 7 月交付","client_description":"本月交付内容"}'
|
||||
```
|
||||
|
||||
新建作品交付集的 `status` 为 `draft`。上传首件作品后自动变为 `reviewing`;全部非草稿作品通过后自动变为 `completed`。响应中的 `work_count`、`approved_count` 和 `completed_at` 分别表示已提交作品数、已通过作品数和本次完成时间。调用方不应直接维护作品交付集状态;创建作品、新验收轮次、修改验收状态和删除作品都会触发服务端重算。
|
||||
|
||||
## 上传作品
|
||||
|
||||
外部客户端使用 JSON 创建作品,`images` 直接传入 1–30 个公开可读的 HTTP/HTTPS 图片 URL。服务只保存 URL,不会下载图片或再次上传到 COS。数组顺序就是展示顺序,第一张为封面。
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3010/api/notes \
|
||||
curl -X POST http://localhost:3010/api/projects/1/works \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"collectionId": 1,
|
||||
"externalId": "client-work-20260721-001",
|
||||
"title": "作品标题",
|
||||
"description": "正文内容",
|
||||
"tags": ["用户填写的标签原文"],
|
||||
"images": [
|
||||
"https://cdn.example.com/works/01.jpg",
|
||||
"https://cdn.example.com/works/02.jpg"
|
||||
]
|
||||
"externalId":"client-work-20260722-001",
|
||||
"title":"作品标题",
|
||||
"description":"正文内容",
|
||||
"tags":["#夏日","用户原文"],
|
||||
"images":["https://cdn.example.com/01.jpg","https://cdn.example.com/02.jpg"]
|
||||
}'
|
||||
```
|
||||
|
||||
`externalId` 是调用方在当前作品交付集内的作品唯一标识,支持字母、数字、点、下划线、冒号和横线,最长 128 位。相同 `collectionId + externalId` 的重复请求不会重复创建作品,而会以 `200` 返回原作品并包含 `"idempotent": true`。创建成功响应中的 `id` 是后续上传版本所需的 `workId`;如果调用方丢失了该 ID,可以通过 `GET /api/notes?collectionId=1&externalId=client-work-20260721-001` 找回。
|
||||
相同 `projectId + externalId` 的重试不会重复创建,响应包含 `idempotent: true`。调用方负责保证外部图片 URL 长期公开可用。
|
||||
|
||||
URL 图片不会进入当前配置的 COS,也不会由服务检查其内容或长期可用性,因此调用方需要保证链接公开、稳定且确实指向图片。工作台手动上传仍接受 JPEG、PNG、GIF、WebP 和 AVIF。标签按原文保存和展示,不会自动添加 `#` 或拆分为标签库。
|
||||
## 创建新验收轮次
|
||||
|
||||
## 创建单候选稿验收轮次(兼容接口)
|
||||
每轮只能提交一个方案。标题、正文、标签和图片会形成不可修改的轮次快照;新轮次自动锁定上一轮。
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3010/api/notes/12/versions \
|
||||
curl -X POST http://localhost:3010/api/works/12/rounds \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"title": "修改后的标题",
|
||||
"description": "修改后的正文",
|
||||
"tags": ["修改后的标签原文"],
|
||||
"images": [
|
||||
"https://cdn.example.com/works/v2-01.jpg",
|
||||
"https://cdn.example.com/works/v2-02.jpg"
|
||||
]
|
||||
"title":"修改后的标题",
|
||||
"description":"修改后的正文",
|
||||
"tags":["#第二轮"],
|
||||
"images":["https://cdn.example.com/round-2.jpg"]
|
||||
}'
|
||||
```
|
||||
|
||||
该接口保留给只提交一个方案的现有调用方。批注绑定候选稿或具体图片,不会被新验收轮次覆盖。
|
||||
## 查询作品与全部反馈
|
||||
|
||||
## 提交多候选稿验收轮次
|
||||
```bash
|
||||
# 当前轮或指定轮
|
||||
curl "http://localhost:3010/api/works/12?round=2" \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY"
|
||||
|
||||
`POST /api/notes/:noteId/review-rounds` 可在同一轮中提交 1–5 个候选稿。JSON 请求中每个候选稿使用公开图片 URL:
|
||||
# 按轮返回该作品全部反馈和验收事件
|
||||
curl http://localhost:3010/api/works/12/annotations \
|
||||
-H "Authorization: Bearer $DELIVERY_DESK_API_KEY"
|
||||
```
|
||||
|
||||
标题、正文和 Tag 选区批注使用:
|
||||
|
||||
```json
|
||||
{
|
||||
"candidates": [
|
||||
{
|
||||
"candidate_name": "暖色方案",
|
||||
"title": "夏日新品",
|
||||
"description": "暖色调正文",
|
||||
"tags": ["#夏日", "#新品"],
|
||||
"images": ["https://cdn.example.com/warm-01.jpg"]
|
||||
},
|
||||
{
|
||||
"candidate_name": "冷色方案",
|
||||
"title": "夏日新品",
|
||||
"description": "冷色调正文",
|
||||
"tags": ["#夏日", "#新品"],
|
||||
"images": ["https://cdn.example.com/cool-01.jpg"]
|
||||
}
|
||||
]
|
||||
"round_number": 2,
|
||||
"target": "description",
|
||||
"start_offset": 4,
|
||||
"end_offset": 8,
|
||||
"selected_text": "选中文字",
|
||||
"content": "这里需要调整"
|
||||
}
|
||||
```
|
||||
|
||||
客户验收决定必须带上候选稿的 `version_number`。选中并通过某稿后,同轮其他稿自动标记为 `not_selected`,历史轮次变为只读。提交新轮次时,尚未结束的上一轮会自动关闭,其中仍在等待验收的候选稿会标记为 `not_selected`。旧的 `/versions` 接口继续可用,等价于创建只有一个候选稿的新轮次。决定接口使用客户登录后获得的 Cookie,不能使用工作台 API Key 代替。
|
||||
服务会校验偏移量和所选文字是否匹配当前轮次快照。历史轮次或已完成项目返回 `409`。
|
||||
|
||||
批注、文字批注和总体反馈都可回复,类型分别为 `image_annotation`、`text_annotation`、`comment`:
|
||||
|
||||
```http
|
||||
POST /api/works/:workId/feedback/:type/:feedbackId/replies
|
||||
POST /api/works/:workId/feedback/:type/:feedbackId/withdraw
|
||||
```
|
||||
|
||||
撤回只允许原作者执行,不会删除数据库记录。客户入口在路径前增加 `/api/review/:slug`,并执行相同的项目归属与身份校验。
|
||||
|
||||
## 客户验收
|
||||
|
||||
客户输入项目密码和姓名后使用 Cookie 调用:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3010/api/review/july-content/works/12/decision \
|
||||
-b cookies.txt \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"version_number": 5,
|
||||
"decision": "approved"
|
||||
}'
|
||||
-d '{"round_number":2,"decision":"approved"}'
|
||||
```
|
||||
|
||||
## Python 冒烟脚本
|
||||
`decision` 为 `approved` 或 `changes_requested`;退修必须填写 `reason`。只允许决定活动轮次。
|
||||
|
||||
项目自带 `tests/api_create_work.py`,只使用 Python 标准库。推荐通过环境变量提供项目级 API Key:
|
||||
客户侧全部反馈接口为 `/api/review/:slug/works/:workId/annotations`,仍会校验客户会话绑定的项目。
|
||||
|
||||
```powershell
|
||||
$env:DELIVERY_DESK_API_KEY = 'dd_live_xxx'
|
||||
python tests/api_create_work.py --project-id 1 --collection-id 1
|
||||
## 兼容接口
|
||||
|
||||
# 为已有作品创建单候选稿验收轮次
|
||||
python tests/api_create_work.py --project-id 1 --collection-id 1 --work-id 12
|
||||
```
|
||||
旧的 `/api/notes`、`/api/notes/:id/versions`、`/api/notes/:id/review-rounds` 与 `/api/projects/:id/collections` 暂保留一个兼容周期。旧交付集 URL 会跳转到项目页;旧多候选稿请求会返回 `400`,不会再创建多方案轮次。新接入必须使用项目、作品和轮次接口。
|
||||
|
||||
如果项目级 Key 只能访问一个项目,并且项目下只有一个作品交付集,可以省略两个 ID。脚本也支持不传 Key、改用 `--username` 后交互输入密码。
|
||||
|
||||
## 错误响应
|
||||
|
||||
错误统一以 JSON 返回:
|
||||
|
||||
```json
|
||||
{ "error": "错误说明" }
|
||||
```
|
||||
|
||||
常见状态码:`400` 输入无效、`401` 未认证、`403` 越权、`404` 资源不存在、`409` 唯一性或状态冲突、`500` 服务端错误。
|
||||
错误统一为 `{ "error": "错误说明" }`。常见状态码:`400` 输入无效、`401` 未认证、`403` 越权、`404` 不存在、`409` 状态冲突。
|
||||
|
||||
Reference in New Issue
Block a user