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.