feat: add manual revision and dashboard list apis

This commit is contained in:
afei A
2026-03-27 23:38:50 +08:00
parent d02fc8565f
commit eeaff269eb
24 changed files with 1950 additions and 64 deletions

View File

@@ -0,0 +1,401 @@
# Manual Revision Backend Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add backend support for the mid-end manual revision flow: export current asset, register offline-edited revision assets as a single version chain, and require an explicit confirm action before the waiting workflow continues.
**Architecture:** Reuse the existing `waiting_review` Temporal pause in `MidEndPipelineWorkflow` instead of inventing a second workflow state machine. Model manual revisions as first-class asset versions plus a richer review-task status, then implement dedicated HTTP endpoints for revision registration, revision-chain queries, and confirm-continue. The final confirm endpoint will bridge back into the existing review signal by approving the latest revision asset explicitly.
**Tech Stack:** FastAPI, Pydantic, SQLAlchemy async ORM, SQLite, Temporal Python SDK, pytest
---
### Task 1: Lock the desired backend behavior with failing integration tests
**Files:**
- Modify: `tests/test_api.py`
- [ ] **Step 1: Add a failing test for registering a manual revision asset while the order is waiting for review**
Add a new integration test next to the existing mid-end review tests that:
- creates a `semi_pro` order
- waits for `waiting_review`
- calls the new revision registration endpoint
- asserts the response returns a new asset id, version number, parent asset id, and review task state `revision_uploaded`
- [ ] **Step 2: Add a failing test for confirming the revision and letting the existing workflow finish**
Add a second integration test that:
- creates a `semi_pro` order
- waits for `waiting_review`
- registers a revision asset
- calls the new confirm endpoint
- waits for the workflow result
- asserts the workflow succeeds and the order final asset is derived from the revision asset rather than the original QC candidate
- [ ] **Step 3: Add a failing test for listing the single-line revision chain**
Add an integration test that:
- creates a `semi_pro` order
- waits for `waiting_review`
- registers two manual revisions in sequence
- calls the revision chain query endpoint
- asserts the chain order is `v1 -> v2 -> v3` with correct parent-child relationships
- [ ] **Step 4: Run the three new tests and verify they fail for missing routes and schema**
Run:
```bash
pytest tests/test_api.py -k "manual_revision or revision_chain or confirm_revision" -v
```
Expected:
- FastAPI returns `404` or `422`
- no revision assets are created
- current codebase does not satisfy the new flow yet
- [ ] **Step 5: Commit the failing tests**
```bash
git add tests/test_api.py
git commit -m "test: cover manual revision review flow"
```
### Task 2: Add persistence for revision assets and review-task substate
**Files:**
- Modify: `app/domain/enums.py`
- Modify: `app/infra/db/models/asset.py`
- Modify: `app/infra/db/models/review_task.py`
- Modify: `app/infra/db/models/order.py`
- Modify: `app/infra/db/session.py`
- [ ] **Step 1: Extend enums for manual revision support**
Update `app/domain/enums.py` with:
- a new asset type such as `MANUAL_REVISION`
- a new review-task status such as `REVISION_UPLOADED`
Keep `OrderStatus.WAITING_REVIEW` unchanged so the workflow can stay paused in the same state.
- [ ] **Step 2: Add version-chain columns to `AssetORM`**
Update `app/infra/db/models/asset.py` to add:
- `parent_asset_id: int | None`
- `root_asset_id: int | None`
- `version_no: int`
- `is_current_version: bool`
Add a self-referential relationship only if it stays simple; otherwise keep reads explicit in services to avoid ORM complexity.
- [ ] **Step 3: Add review-task fields for the current revision under review**
Update `app/infra/db/models/review_task.py` to add:
- `latest_revision_asset_id: int | None`
- `resume_asset_id: int | None`
The open review task should remain the single source of truth for:
- whether the order is still in `waiting_review`
- whether a revision was uploaded but not yet confirmed
- which asset should be used on confirm
- [ ] **Step 4: Keep the model changes compatible with the current bootstrapping approach**
Update `app/infra/db/session.py` only if imports need to change. Do not introduce Alembic in this MVP plan; this repo currently uses `Base.metadata.create_all`, so keep the first implementation aligned with the existing bootstrap model.
- [ ] **Step 5: Run the focused tests again and verify failure has moved from schema absence to route/service absence**
Run:
```bash
pytest tests/test_api.py -k "manual_revision or revision_chain or confirm_revision" -v
```
Expected:
- tables boot successfully in test setup
- failures now point at missing service logic or missing endpoints
- [ ] **Step 6: Commit the persistence changes**
```bash
git add app/domain/enums.py app/infra/db/models/asset.py app/infra/db/models/review_task.py app/infra/db/models/order.py app/infra/db/session.py
git commit -m "feat: add persistence for manual revision state"
```
### Task 3: Add revision registration and revision-chain query APIs
**Files:**
- Create: `app/api/schemas/revision.py`
- Create: `app/application/services/revision_service.py`
- Create: `app/api/routers/revisions.py`
- Modify: `app/main.py`
- Modify: `app/api/schemas/asset.py`
- Modify: `app/application/services/asset_service.py`
- [ ] **Step 1: Define revision request and response schemas**
Create `app/api/schemas/revision.py` with:
- `RegisterRevisionRequest`
- `RegisterRevisionResponse`
- `RevisionChainItem`
- `RevisionChainResponse`
- `ConfirmRevisionResponse`
For the MVP, use JSON fields instead of multipart upload:
- `parent_asset_id`
- `uploaded_uri`
- `reviewer_id`
- `comment`
This keeps the current mock-backed architecture coherent. Real object storage upload can be a later phase.
- [ ] **Step 2: Implement `RevisionService.register_revision`**
Create `app/application/services/revision_service.py` with logic that:
- loads the order and verifies it is `waiting_review`
- loads the active pending review task
- validates `parent_asset_id` belongs to the order
- creates a new `AssetORM` row with `asset_type=MANUAL_REVISION`
- computes `root_asset_id` and `version_no`
- marks previous revision asset as `is_current_version=False`
- updates the active review task to `REVISION_UPLOADED`
- sets `latest_revision_asset_id` and `resume_asset_id` to the new asset
- [ ] **Step 3: Implement `RevisionService.list_revision_chain`**
Query all order assets that belong to the same root chain, ordered by `version_no ASC`, and serialize them for the UI.
- [ ] **Step 4: Expose the revision routes**
Create `app/api/routers/revisions.py` with:
- `POST /api/v1/orders/{order_id}/revisions`
- `GET /api/v1/orders/{order_id}/revisions`
Wire the router in `app/main.py`.
- [ ] **Step 5: Extend asset serialization for the UI**
Update `app/api/schemas/asset.py` to expose:
- `parent_asset_id`
- `root_asset_id`
- `version_no`
- `is_current_version`
Update `app/application/services/asset_service.py` if ordering needs to prefer `version_no` over raw `created_at`.
- [ ] **Step 6: Run the revision registration and chain tests**
Run:
```bash
pytest tests/test_api.py -k "manual_revision or revision_chain" -v
```
Expected:
- registration test passes
- chain test passes
- confirm test still fails because continue logic is not implemented yet
- [ ] **Step 7: Commit the revision API work**
```bash
git add app/api/schemas/revision.py app/application/services/revision_service.py app/api/routers/revisions.py app/main.py app/api/schemas/asset.py app/application/services/asset_service.py tests/test_api.py
git commit -m "feat: add manual revision registration and chain queries"
```
### Task 4: Add explicit confirm-continue that reuses the existing review signal
**Files:**
- Modify: `app/api/schemas/review.py`
- Modify: `app/api/routers/reviews.py`
- Modify: `app/application/services/review_service.py`
- Modify: `app/workers/workflows/types.py`
- [ ] **Step 1: Add confirm request and response models**
Extend `app/api/schemas/review.py` with:
- `ConfirmRevisionRequest`
- `ConfirmRevisionResponse`
Fields should include:
- `reviewer_id`
- `comment`
Do not ask the caller for `selected_asset_id`; the backend should derive that from the active review tasks `resume_asset_id`.
- [ ] **Step 2: Implement `confirm_revision_continue` in `ReviewService`**
Add a new service method that:
- verifies the order is still `waiting_review`
- loads the active review task
- rejects the call unless task status is `REVISION_UPLOADED`
- verifies `resume_asset_id` is present
- marks the task as `SUBMITTED`
- reuses `WorkflowService.signal_review(...)` with:
- `decision=APPROVE`
- `selected_asset_id=resume_asset_id`
- `comment` prefixed or structured to indicate manual revision confirmation
This is the key MVP simplification: the workflow does not need a new signal type because it already knows how to export an explicitly selected asset.
- [ ] **Step 3: Expose a dedicated confirm route**
Add a route such as:
```text
POST /api/v1/reviews/{order_id}/confirm-revision
```
Keep it separate from `/submit` so the API remains clear and the front-end does not need to fake a normal approve call.
- [ ] **Step 4: Normalize the Temporal payload type if needed**
Update `app/workers/workflows/types.py` only if the review payload needs an optional metadata field such as `source="manual_revision_confirm"`. Skip this if current payload is already sufficient.
- [ ] **Step 5: Run the confirm-flow test**
Run:
```bash
pytest tests/test_api.py -k "confirm_revision" -v
```
Expected:
- workflow resumes from the existing `waiting_review`
- export uses the revision asset id
- order finishes as `succeeded`
- [ ] **Step 6: Commit the confirm flow**
```bash
git add app/api/schemas/review.py app/api/routers/reviews.py app/application/services/review_service.py app/workers/workflows/types.py tests/test_api.py
git commit -m "feat: confirm manual revision and resume workflow"
```
### Task 5: Surface revision state in order, queue, and workflow responses
**Files:**
- Modify: `app/api/schemas/order.py`
- Modify: `app/api/schemas/review.py`
- Modify: `app/api/schemas/workflow.py`
- Modify: `app/application/services/order_service.py`
- Modify: `app/application/services/review_service.py`
- Modify: `app/application/services/workflow_service.py`
- [ ] **Step 1: Extend order detail response**
Update `OrderDetailResponse` to include:
- `current_revision_asset_id`
- `current_revision_version`
- `revision_count`
- `review_task_status`
- [ ] **Step 2: Extend pending review response**
Update `PendingReviewResponse` to include:
- `review_status`
- `latest_revision_asset_id`
- `revision_count`
This is what the new queue UI needs for labels like `可人工介入` and `待确认回流`.
- [ ] **Step 3: Extend workflow/status response only with revision summary, not duplicated chain detail**
Update `WorkflowStatusResponse` or add a nested summary object with:
- `latest_revision_asset_id`
- `latest_revision_version`
- `pending_manual_confirm: bool`
Do not duplicate the full revision chain here; the dedicated revision-chain endpoint already covers that.
- [ ] **Step 4: Implement the response assembly in services**
Update:
- `OrderService.get_order`
- `ReviewService.list_pending_reviews`
- `WorkflowService.get_workflow_status`
Use the current open review task plus current-version asset rows to compute the response fields.
- [ ] **Step 5: Add or update tests for enriched responses**
Extend `tests/test_api.py` assertions so the new endpoints and existing endpoints expose the fields required by the designed UI.
- [ ] **Step 6: Run the full API test module**
Run:
```bash
pytest tests/test_api.py -v
```
Expected:
- existing approve/rerun tests still pass
- new manual revision tests pass
- no regression in low-end flow
- [ ] **Step 7: Commit the response-shape changes**
```bash
git add app/api/schemas/order.py app/api/schemas/review.py app/api/schemas/workflow.py app/application/services/order_service.py app/application/services/review_service.py app/application/services/workflow_service.py tests/test_api.py
git commit -m "feat: expose manual revision state in API responses"
```
### Task 6: Documentation and final verification
**Files:**
- Modify: `README.md`
- Modify: `docs/superpowers/specs/2026-03-27-review-workbench-design.md`
- [ ] **Step 1: Document the manual revision API flow**
Update `README.md` with:
- revision registration endpoint
- revision chain endpoint
- confirm-revision endpoint
- the fact that current MVP uses URI registration instead of real binary upload
- [ ] **Step 2: Sync the spec wording with the implemented API names**
Update the design spec only where route names or payload names need to match the code.
- [ ] **Step 3: Run the complete test suite**
Run:
```bash
pytest -q
```
Expected:
- all existing tests pass
- new manual revision flow is covered
- [ ] **Step 4: Do a quick endpoint smoke pass**
Run:
```bash
pytest tests/test_api.py::test_mid_end_order_waits_review_then_approves -v
pytest tests/test_api.py -k "manual_revision or confirm_revision" -v
```
Expected:
- baseline approve flow still works
- manual revision register/confirm flow works
- [ ] **Step 5: Commit docs and verification updates**
```bash
git add README.md docs/superpowers/specs/2026-03-27-review-workbench-design.md
git commit -m "docs: describe manual revision backend flow"
```
## Notes for the Implementer
- Keep the first implementation scoped to `semi_pro` and the existing single review pause.
- Do not add a second Temporal workflow or a second review wait state in this MVP.
- Do not implement real file storage upload in this pass; register an uploaded URI or mock URI first.
- Keep the version chain single-line. Reject requests that try to branch from a non-current version.
- If a persistent SQLite database already exists locally, schema changes may require deleting the dev DB before rerunning because this repo currently has no migration system.

View File

@@ -0,0 +1,312 @@
# 审核优先运营台设计文档
日期2026-03-27
## 1. 背景
当前项目是一个 `FastAPI + Temporal + SQLite + SQLAlchemy` 的图片流水线 MVP支持
- 低端自动流程 `auto_basic`
- 中端半自动流程 `semi_pro`
- 订单创建、订单详情、资产查询、待审核列表、审核提交、workflow 状态查询
- `approve / rerun_scene / rerun_face / rerun_fusion` 审核信号
- 面向人工审核节点的扩展设计:人工导出、离线修订、上传新副本并确认回流
本次目标不是实现完整前端系统,而是为当前后端能力设计一个可落地的桌面端运营页面原型,服务内部审核人员。
## 2. 设计目标
- 优先支持审核员处理 `waiting_review` 订单
- 让审核员先看图,再结合流程信息做决策
- 在单页内完成:选单、看图、流程判断、提交审核
- 在人工审核节点支持“导出原图 -> 离线修改 -> 上传新副本 -> 确认继续流水线”
- 保留新建订单入口,但不干扰审核主任务
## 3. 用户与使用场景
目标用户是内部运营/审核人员,主要在桌面端使用。
核心任务链路:
1. 从待审核队列中找到当前需要处理的订单
2. 查看候选图、最终图和历史版本
3. 结合 workflow 当前步骤、历史步骤与异常信息判断结果
4. 提交 `approve``rerun_*`
5. 进入下一单继续审核
扩展任务链路:
1. 在人工审核节点导出当前候选图
2. 线下修订后上传为新的副本版本
3. 在页面内检查新副本是否正确
4. 手动点击“确认继续流水线”,从审核后的下一段继续
5. 如需再次修订,则基于最新副本继续形成单线版本链
## 4. 信息架构
页面采用三栏结构,强调“详情审核”而不是“总览监控”。
### 左侧:待审核队列
- 搜索
- 快速筛选:全部、待审核、超时、高优先级、最近更新
- 订单卡片列表
每条卡片至少展示:
- `order_id`
- `service_mode`
- 当前步骤
- 等待时长
- 异常标记
- 人工介入标签:`可人工介入``待确认回流``修订中`
左侧只负责选单,不直接执行审核动作。
### 中央:大图审核区
中央是页面视觉核心,采用看图优先布局。
包括:
- 顶部状态条
- 主图预览区
- 版本链带:`原候选 -> 修订 v2 -> 修订 v3 -> 当前版本`
- 候选图 / 最终图 / 历史版本切换
- 缩略图带
- 局部放大检查
这个区域必须拿到页面最大面积,用于判断面部、纹理、融合边缘等细节。
### 右侧:审核与流程侧栏
右侧分为两块:
- 上半区:审核动作面板
- 下半区:压缩版流程时间线
审核动作包括:
- `approve`
- `rerun_scene`
- `rerun_face`
- `rerun_fusion`
- 审核备注
- `导出原图`
- `上传修订稿`
- `确认继续流水线`
流程侧栏展示:
- 当前步骤
- 关键 step 历史
- 最近重跑节点
- 错误信息 / 异常状态
- 人工修订记录:版本号、备注、上传时间、确认继续时间
### 顶部:订单状态条
顶部只保留最关键的信息:
- 订单号
- 客户层级
- 服务模式
- 当前步骤
- 状态
- SLA / 异常提醒
- 当前版本号
- 人工修订链次数
### 新建订单入口
保留在页面右上角,以按钮进入弹窗或二级页,不占据首页主区域。
## 5. 交互设计
### 主交互节奏
`左侧选单 -> 中央看图 -> 右侧做决定 -> 队列进入下一单或返回列表`
### 队列交互
- 点击订单卡片后,中央与右侧联动刷新
- 不打开新页面,不跳转
- 当前选中卡片需要强视觉高亮
### 图片查看交互
- 默认展示主图 + 缩略图带
- 主图和版本链联动,支持查看原候选、最新修订版、历史修订版
- 支持在候选图、最终图、历史版本之间切换
- 支持局部放大检查
- 每张图需要有状态标签,例如:`QC 候选``历史版本``当前选中`
### 人工修订交互
- 仅在中高端流程的人工审核节点展示
- 点击 `导出原图` 后导出当前选中版本用于线下修订
- 点击 `上传修订稿` 后创建一个新的副本版本,而不是覆盖原候选
- 上传成功后不自动开跑,订单进入 `待确认回流`
- 审核员确认新副本无误后,点击 `确认继续流水线`
- 回流从人工审核后的下一段继续,不再让审核员选择 `rerun_*`
- 多轮人工修订采用单线版本链,只保留一个继续流转的最新版本
### 审核动作交互
- `approve` 是唯一主 CTA
- `rerun_*` 是次级动作,与通过操作明显区分
- 执行 `rerun_*` 时要求填写备注
- 如果存在多张候选图,`approve` 前必须明确选中提交对象
### 流程查看交互
- 右侧默认展示摘要版时间线
- 重点体现:当前节点、失败节点、重跑来源
- 在人工修订模式下补充“修订记录”摘要
- 需要时可展开完整 step 历史
### 新建订单交互
- 从顶部按钮打开
- 不抢首页视觉焦点
- 表单字段直接对应当前后端 `CreateOrderRequest`
## 6. 视觉方向
页面风格应为:`专业、冷静、偏高密度` 的内部工作台。
### 视觉原则
- 中央主图区优先级最高
- 使用中性色为主,搭配单一强调色和语义状态色
- 通过分区背景、边框和留白建立左右区域层次
- 不使用花哨装饰和重营销化语言
### 状态表达
- `approve` 使用唯一主强调色
- `rerun_*` 使用次级语义动作样式
- 异常、超时、失败步骤在队列和顶部状态条中直接标红提示
- step 时间线使用统一状态编码:已完成、处理中、等待审核、失败、重跑来源
### 动效原则
- 仅保留短过渡反馈
- 不使用重动画
- 重点反馈:切换订单、切换图片、审核提交状态变化
- 在人工修订链中,版本切换和“待确认回流”需要有显式状态反馈
## 7. 数据映射
页面建立在当前已有 API 能力之上。
### 左侧队列
来源:
- 待审核列表接口
### 顶部状态条
来源组合:
- 订单详情
- workflow 当前状态
- 最新副本版本元数据
### 中央图片区
来源:
- 订单资产接口
- 人工修订版本链接口 / 版本元数据
### 右侧流程区
来源:
- workflow 状态接口
### 审核动作
来源:
- 审核提交接口
- 导出资产接口
- 修订稿上传接口
- 人工确认继续接口
`approve``rerun_*` 复用同一提交接口,仅决策参数不同。
人工修订能力需要把“资产版本”和“流程推进”拆成两类操作:
- 资产操作:导出、上传新副本、查看版本链
- 流程操作:确认继续流水线
## 8. 异常与边界处理
- 资产为空时,显示“暂无候选图 / 等待流程产出”
- workflow 拉取失败时,右侧流程区单独报错,不阻塞中央图片区
- 审核提交失败时,在右侧动作区就近展示错误
- 订单异常或失败时,队列卡片与顶部状态条同步显式标记
- 切换订单时,如果备注已编辑未提交,需要提示是否放弃
- 触发 `rerun_*` 后,页面进入“已发起重跑,等待流程推进”的过渡状态
- 导出失败时,仅动作区报错,不影响当前订单浏览
- 上传失败时,不创建新版本节点,仍停留在当前版本
- 上传成功但未确认继续时,队列中明确标记 `待确认回流`
- 确认继续失败时,保留最新副本版本,允许重试,不回退版本链
- 同一订单支持多轮人工修订,但只保留一条线性继续链,不允许并行分支
## 9. 本次原型范围
本次原型只覆盖一个桌面端单页:
- 待审核队列
- 详情审核区
- 流程时间线
- 资产预览
- 新建订单入口
- 人工修订回流模式下的版本链与动作区
不包含:
- 登录
- 多页后台结构
- 真实前端联调
- 响应式移动端适配
## 10. 原型验收标准
原型应回答以下问题:
1. 审核员能否快速找到待处理订单
2. 进入详情后能否高效看图并做决策
3. 流程与异常信息是否足够支持审核判断
4. 页面主视觉是否明确体现“看图优先、审核优先”
5. 人工修订后能否清楚看见版本链、待确认状态和继续入口
## 11. 推荐原型结构
推荐使用单页桌面运营台结构:
- 左 280px队列栏
- 中 1.25x 主区:大图审核区
- 右 280-320px审核动作 + 压缩流程区
这是当前最匹配项目能力与用户偏好的结构。
## 12. 人工修订状态机
建议将人工介入抽象成 4 个显式状态:
- `可人工介入`
- `修订上传完成`
- `待确认回流`
- `已回流继续`
状态规则:
- `可人工介入` 时允许导出原图和上传修订稿
- `修订上传完成 / 待确认回流` 时不允许再上传并行版本
- `待确认回流` 时右侧主按钮固定为 `确认继续流水线`
- `已回流继续` 后保留完整版本链供回看,后续若再次进入人工审核,则从最新版本继续生成下一版