feat(review): 重构项目级单方案验收协作
This commit is contained in:
@@ -2,83 +2,72 @@
|
||||
|
||||
## 系统边界
|
||||
|
||||
Delivery Desk 是单体 Web 应用:React 前端调用 Express API,前后端共享 `shared/types.ts` 类型。开发环境使用 SQLite 和本地上传目录;正式环境使用 PostgreSQL 和腾讯云 COS。
|
||||
Delivery Desk 是 React + Express 单体应用,前后端共享 `shared/types.ts`。开发环境使用 SQLite 和本地上传目录,正式环境使用 PostgreSQL 和腾讯云 COS。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
browser["浏览器"] --> app["Express / React 应用"]
|
||||
app --> database["SQLite 或 PostgreSQL"]
|
||||
app --> local["本地 uploads(开发)"]
|
||||
app --> cos["腾讯云 COS(正式)"]
|
||||
customer["客户验收链接"] --> app
|
||||
client["外部 API 客户端"] --> app
|
||||
browser["工作台 / 客户浏览器"] --> app["Express + React"]
|
||||
api["外部 API 客户端"] --> app
|
||||
app --> db["SQLite / PostgreSQL"]
|
||||
app --> storage["本地 uploads / 腾讯云 COS"]
|
||||
```
|
||||
|
||||
## 业务层级
|
||||
## 产品层级
|
||||
|
||||
```text
|
||||
运营组
|
||||
└── 项目
|
||||
└── 作品交付集
|
||||
└── 作品
|
||||
└── 验收轮次
|
||||
└── 候选稿(1–5 个)
|
||||
└── 作品
|
||||
└── 验收轮次(每轮一个方案)
|
||||
```
|
||||
|
||||
- 一个运营组只能有一位组管理员,可以有多位光影叙事。
|
||||
- 平台管理员可以有多位,不属于固定运营组。
|
||||
- 普通工作台账号只能读写所属运营组的数据;平台管理员可跨组管理。
|
||||
- 客户会话只绑定一个项目,不能跨项目浏览。
|
||||
- 平台级 API Key 可创建项目;项目级 API Key 只能操作指定项目。
|
||||
|
||||
## 运行结构
|
||||
|
||||
- `src/`:React 页面、组件、状态和 API 客户端。
|
||||
- `api/routes/`:HTTP 路由与输入校验。
|
||||
- `api/services/`:作品、存储等业务编排。
|
||||
- `api/repositories/`:查询封装。
|
||||
- `api/database.ts`:SQLite/PostgreSQL 统一查询接口和事务。
|
||||
- `api/db.ts`:SQLite 初始化及增量迁移。
|
||||
- `db/postgres/schema.sql`:PostgreSQL 当前完整 schema。
|
||||
- `shared/types.ts`:前后端共享领域类型。
|
||||
|
||||
`DATABASE_URL` 存在时使用 PostgreSQL,否则使用 SQLite。两套数据库必须保持相同业务约束;涉及表或字段的修改必须同时更新 `api/db.ts`、`db/postgres/schema.sql` 及迁移验证脚本。
|
||||
- 客户会话绑定项目,不能跨项目访问。
|
||||
- 项目级 API Key 只能访问绑定项目;平台级 Key 可跨组管理项目。
|
||||
- 历史作品交付集不再是产品层级。`collections` 表仅作为旧数据和旧 URL 的迁移兼容容器。
|
||||
- `work_versions` 继续保存每轮内容快照,但与 `review_rounds` 强制一对一。
|
||||
- 升级时如检测到旧的一轮多方案数据,会把额外方案拆成只读的独立历史轮次,保留图片、批注、验收事件和当前活动方案,再建立一轮一方案唯一约束。
|
||||
|
||||
## 主要数据表
|
||||
|
||||
| 表 | 用途 |
|
||||
|---|---|
|
||||
| `operation_groups` | 运营组及启停状态 |
|
||||
| `users` / `sessions` | 工作台账号、角色和登录会话 |
|
||||
| `customer_sessions` | 客户项目级验收会话 |
|
||||
| `projects` | 项目、客户访问密码和访问期限 |
|
||||
| `collections` | 项目下的作品交付集 |
|
||||
| `notes` | 作品当前状态、活动轮次和选中稿 |
|
||||
| `review_rounds` | 验收轮次、完成状态和选中候选稿 |
|
||||
| `work_versions` | 各候选稿的标题、正文、标签和验收状态快照 |
|
||||
| `images` | 候选稿图片、顺序、存储提供方和对象 Key |
|
||||
| `operation_groups` | 运营组及状态 |
|
||||
| `users` / `sessions` | 工作台账号、角色和会话 |
|
||||
| `customer_sessions` | 项目级客户会话 |
|
||||
| `projects` | 项目、客户访问配置和自动验收状态 |
|
||||
| `collections` | 迁移期内部兼容容器,不属于产品层级 |
|
||||
| `notes` | 作品当前状态、活动轮次和项目归属 |
|
||||
| `review_rounds` | 验收轮次与完成原因 |
|
||||
| `work_versions` | 单轮内容快照;每轮恰好一条 |
|
||||
| `images` | 轮次图片、顺序和存储信息 |
|
||||
| `annotations` | 图片坐标批注 |
|
||||
| `text_annotations` | 标题或正文的版本级批注 |
|
||||
| `work_comments` | 作品总体反馈与回复 |
|
||||
| `review_events` | 提交、修改、通过、重新打开等验收记录 |
|
||||
| `api_keys` | 平台级或项目级 API Key 的哈希与状态 |
|
||||
| `storage_configs` | 加密后的 COS 配置及启用状态 |
|
||||
| `audit_logs` | 管理和业务操作审计 |
|
||||
| `text_annotations` | 标题、正文和 Tag 选区批注与文本上下文 |
|
||||
| `work_comments` | 作品总体反馈 |
|
||||
| `review_events` | 提交、退修、通过和重新打开记录 |
|
||||
| `api_keys` | 平台级/项目级 API Key 哈希 |
|
||||
| `storage_configs` | 加密后的 COS 配置 |
|
||||
| `audit_logs` | 管理与业务审计 |
|
||||
|
||||
## 存储流程
|
||||
## 状态计算
|
||||
|
||||
平台管理员在管理页新增 COS 配置。SecretId 和 SecretKey 使用 `COS_CONFIG_ENCRYPTION_KEY` 派生的 AES-256-GCM 密钥加密后写入数据库,读取配置的接口不会返回明文。
|
||||
作品状态为 `draft`、`pending`、`changes_requested`、`approved`。只有活动轮次可新增批注和作出验收决定;新轮次会锁定旧轮次。客户通过活动轮次后作品为已通过,退修后运营通过新轮次提交修改。
|
||||
|
||||
启用配置前会在目标桶的 `.delivery-desk-check/` 路径依次上传、读取并删除一个临时对象。启用后,新上传文件写入:
|
||||
项目验收状态自动计算:
|
||||
|
||||
```text
|
||||
<path-prefix>/originals/YYYY/MM/<uuid>.<ext>
|
||||
```
|
||||
- 没有非草稿作品:`draft`
|
||||
- 存在未通过作品:`reviewing`
|
||||
- 所有非草稿作品通过:`completed`
|
||||
- 人工归档:`archived`
|
||||
|
||||
未启用 COS 时,上传文件保存在本地 `uploads/`。图片 URL 按产品约定为公开随机地址,不提供对象级访问鉴权。
|
||||
完成项目为只读。新增作品、创建新轮次或由管理员重新打开作品时,项目恢复为验收中;已关闭或归档项目始终只读。开放反馈不会阻止通过;通过时仍为开放的反馈会标记为随该轮验收关闭,历史内容保留。
|
||||
|
||||
## 验收状态
|
||||
## 批注模型
|
||||
|
||||
作品状态为 `draft`、`pending`、`changes_requested`、`approved`。一个验收轮次可包含 1–5 个候选稿;单稿退修时,其他待验收稿仍可继续验收。客户选中并通过任意一稿后,作品即通过,同轮其他稿标记为未选用,历史轮次只读。已通过作品只能由平台管理员或所属组管理员填写原因后重新打开,历史事件保留。
|
||||
- 作品缩略图只展示现有坐标标记,不能新增坐标批注;点击标记会联动打开验收协作面板中的对应反馈。
|
||||
- 点击图片打开悬浮图片窗格;只有该窗格可以新增坐标批注,并支持原图查看、缩放和前后切换。点击窗格外会同时关闭图片窗格和验收协作面板。
|
||||
- 标题、正文和 Tag 批注保存 `start_offset`、`end_offset`、`selected_text` 及前后文,提交时校验选区仍与轮次快照一致。
|
||||
- `GET /api/works/:workId/annotations` 按轮次返回图片批注、文字批注、总体反馈和验收事件。
|
||||
|
||||
作品交付集状态由其中非草稿作品自动计算:没有已提交作品时为 `draft`,存在未通过作品时为 `reviewing`,全部已提交作品通过时为 `completed`。`archived` 是人工状态,自动计算不会覆盖。完成后客户页面只读;新增作品、新验收轮次或重新打开作品会自动恢复为验收中。
|
||||
## 存储
|
||||
|
||||
平台管理员可在管理页保存和测试 COS 配置。SecretId/SecretKey 使用 `COS_CONFIG_ENCRYPTION_KEY` 派生的 AES-256-GCM 密钥加密,读取接口不返回明文。连接测试会上传、读取并删除临时对象。外部 API 提供的公开图片 URL 只保存地址,不下载、不转存 COS。
|
||||
|
||||
@@ -3,34 +3,33 @@
|
||||
## 已完成
|
||||
|
||||
- 三类工作台角色、运营组隔离、账号管理和 7 天会话
|
||||
- 项目、作品交付集、作品、多候选稿验收轮次和验收状态
|
||||
- 手动多图上传、封面、上传前拖拽排序及新验收轮次
|
||||
- 图片坐标批注、标题/正文批注、总体反馈和验收记录
|
||||
- 客户项目链接、密码、姓名、期限和验收决定
|
||||
- 项目 → 作品 → 单方案验收轮次,以及项目级自动验收状态
|
||||
- 手动多图上传、公开 URL API、封面与上传前拖拽排序
|
||||
- 缩略图只读标记、悬浮图片窗格、原图缩放与坐标批注
|
||||
- 标题、正文和 Tag 选区批注、总体反馈、按作品聚合反馈和验收记录
|
||||
- 批注回复线程、只能撤回本人反馈并保留撤回记录
|
||||
- 客户项目链接、密码、姓名、访问期限和验收决定
|
||||
- API Key、审计日志、COS 前端配置及连接测试
|
||||
- SQLite/PostgreSQL 双运行时、迁移验证和 Docker 部署
|
||||
- 桌面端与移动端响应式页面
|
||||
|
||||
## 初版上线前仍需完成
|
||||
|
||||
以下需求尚未在代码中完整落地,不应在交付时宣称可用:
|
||||
以下范围尚未完整落地,不应在交付时宣称可用:
|
||||
|
||||
- ZIP + CSV 批量导入和最多 100 个作品的异步批量 API
|
||||
- `externalId` 幂等创建作品(项目和作品交付集暂未支持)
|
||||
- webhook 与站内未读通知
|
||||
- PDF 验收报告和最终原图 ZIP 导出
|
||||
- 批注/回复的参考图片附件
|
||||
- 项目、作品交付集、作品的回收站、归档恢复和永久删除规则
|
||||
- 批注/回复中的参考图片附件
|
||||
- 项目与作品的回收站、归档恢复和永久删除流程
|
||||
- 已上传作品在所有阶段的图片重新排序
|
||||
- 在线人员状态、实时变更通知和并发版本冲突保护
|
||||
- HEIC/HEIF 转换、缩略图流水线和 EXIF 定位信息清理
|
||||
- 自动化端到端浏览器测试及真实腾讯云、PostgreSQL 部署演练
|
||||
- 在线人员状态、实时变更通知和并发冲突保护
|
||||
- HEIC/HEIF 转换、多尺寸缩略图和 EXIF 定位信息清理
|
||||
- 真实腾讯云、生产 PostgreSQL、HTTPS 和备份恢复演练
|
||||
|
||||
## 上线门槛
|
||||
|
||||
初版正式发布至少应满足:
|
||||
|
||||
1. 使用 PostgreSQL 和独立生产 COS 桶,完成一次备份恢复演练。
|
||||
2. 轮换所有在聊天、截图或开发数据库中出现过的云密钥和临时密码。
|
||||
1. 使用 PostgreSQL 和独立生产 COS 桶,完成备份恢复演练。
|
||||
2. 轮换所有在聊天、截图或开发数据中出现过的云密钥和临时密码。
|
||||
3. 在 HTTPS 域名下验证平台管理员、组管理员、光影叙事和客户四条核心流程。
|
||||
4. 根据真实交付承诺,从上方未完成清单中选定必须进入初版的项目。
|
||||
4. 根据真实交付承诺,从未完成清单中选定必须进入初版的项目。
|
||||
|
||||
@@ -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