diff --git a/changelog/2026-04-17_switch-penpot-to-figma.md b/changelog/2026-04-17_switch-penpot-to-figma.md index e74e4f2..c16b8da 100644 --- a/changelog/2026-04-17_switch-penpot-to-figma.md +++ b/changelog/2026-04-17_switch-penpot-to-figma.md @@ -106,3 +106,17 @@ - `features/doc-service/app/routers/categories.py` — `POST /documents/categories` now finds similar categories by name (word overlap + SequenceMatcher) and triggers a background task to re-run AI extraction on affected documents, merging new `suggested_categories` into their `extracted_data` - `features/doc-service/STATUS.md` — updated endpoints table and filter params table - `frontend/STATUS.md` — updated sidebar and documents page sections + +--- + +# 2026-04-17 — Re-analyse button for documents + +**Timestamp:** 2026-04-17T00:00:00 + +**Summary:** Added a Re-analyse button to each document row that re-runs AI extraction on demand. The endpoint resets status to pending, clears any previous error, and enqueues the background processing task. The button is disabled while the document is already pending or processing. + +**Files Modified:** +- `features/doc-service/app/routers/documents.py` — added `POST /documents/{id}/reprocess` endpoint +- `frontend/src/api/client.ts` — added `reprocessDocument(id)` API function +- `frontend/src/pages/DocumentsPage.tsx` — added `reprocessMut` mutation and Re-analyse button in document row header +- `features/doc-service/STATUS.md` — marked reprocess as done, added endpoint to table diff --git a/features/doc-service/STATUS.md b/features/doc-service/STATUS.md index 167a53a..e6c5dee 100644 --- a/features/doc-service/STATUS.md +++ b/features/doc-service/STATUS.md @@ -33,6 +33,7 @@ Database: shared PostgreSQL instance, isolated via `alembic_version_doc_service` | `PATCH` | `/documents/{id}/title` | Update editable title | | `GET` | `/documents/categories` | List all categories for the user | | `POST` | `/documents/categories` | Create a category; triggers re-analysis of documents in similar categories | +| `POST` | `/documents/{id}/reprocess` | Reset status to pending and re-run AI extraction; 409 if already pending/processing | | `PATCH` | `/documents/categories/{id}` | Rename a category | | `DELETE` | `/documents/categories/{id}` | Delete a category | | `POST` | `/documents/{id}/categories/{cat_id}` | Assign category to document | @@ -138,7 +139,7 @@ backend (proxy) → doc-service:8001 ## Future work -- [ ] `POST /documents/{id}/reprocess` — re-run AI extraction +- [x] `POST /documents/{id}/reprocess` — re-run AI extraction - [ ] Advanced filter: query `extracted_data` JSON fields (vendor, due_date, amount) — requires PostgreSQL `jsonb` column or indexed virtual columns - [ ] Bulk operations endpoint - [ ] Document sharing via groups (blocked on groups/permissions system in backend) diff --git a/features/doc-service/app/routers/documents.py b/features/doc-service/app/routers/documents.py index 85d5972..5a1fd35 100644 --- a/features/doc-service/app/routers/documents.py +++ b/features/doc-service/app/routers/documents.py @@ -305,6 +305,24 @@ async def update_document_title( return _doc_with_categories(doc) +@router.post("/{doc_id}/reprocess", response_model=DocumentOut) +async def reprocess_document( + doc_id: str, + background_tasks: BackgroundTasks, + user_id: str = Depends(get_user_id), + db: AsyncSession = Depends(get_db), +) -> DocumentOut: + doc = await _get_user_doc(doc_id, user_id, db) + if doc.status in ("pending", "processing"): + raise HTTPException(status_code=409, detail="Document is already being processed") + doc.status = "pending" + doc.error_message = None + await db.commit() + background_tasks.add_task(process_document, doc_id) + doc = await _get_user_doc(doc_id, user_id, db) + return _doc_with_categories(doc) + + @router.delete("/{doc_id}", status_code=204) async def delete_document( doc_id: str, diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 0d08043..60bf326 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -170,6 +170,9 @@ export const updateDocumentTags = (id: string, tags: string[]) => export const updateDocumentTitle = (id: string, title: string) => api.patch(`/documents/${id}/title`, { title }).then((r) => r.data); +export const reprocessDocument = (id: string) => + api.post(`/documents/${id}/reprocess`).then((r) => r.data); + export const assignCategory = (docId: string, catId: string) => api.post(`/documents/${docId}/categories/${catId}`); diff --git a/frontend/src/pages/DocumentsPage.tsx b/frontend/src/pages/DocumentsPage.tsx index fa0e077..1443d27 100644 --- a/frontend/src/pages/DocumentsPage.tsx +++ b/frontend/src/pages/DocumentsPage.tsx @@ -13,6 +13,7 @@ import { assignCategory, removeCategory, updateDocumentTitle, + reprocessDocument, type DocumentOut, type CategoryOut, type DocumentListParams, @@ -225,6 +226,11 @@ function DocumentRow({ }, }); + const reprocessMut = useMutation({ + mutationFn: () => reprocessDocument(doc.id), + onSuccess: () => qc.invalidateQueries({ queryKey: ["documents"] }), + }); + const handleAcceptSuggestion = (name: string, existing: CategoryOut | undefined) => { if (existing) { assignMut.mutate({ catId: existing.id }); @@ -276,6 +282,22 @@ function DocumentRow({ > Download +