# API Questions & Answers ## Question ``` what is v4_documents.py? ``` ## Response v4_documents.py is the new additive V4 API router I added in Phase 4. What it does: - Defines V4 endpoints under /api/v4 for registry-driven document/relationship workflows. - Exposes read endpoints for catalogs: - GET /api/v4/document-types - GET /api/v4/person-roles - Exposes write endpoints for code-or-id updates: - PUT /api/v4/documents/{document_id}/type - POST /api/v4/documents/{document_id}/people - PATCH /api/v4/document-people/{document_person_id} - DELETE /api/v4/document-people/{document_person_id} - Uses DocumentService methods as the backend (no direct DB access in the route layer). - Returns typed request/response models for backward-compatible, additive API evolution. It is registered in app.py, so it is live when the app starts. If you want, I can walk endpoint-by-endpoint with examples of request/response payloads. --- ## Question ``` Please do ``` ## Response Absolutely. Here is a quick endpoint-by-endpoint walkthrough of v4_documents.py, with practical request/response examples. **What This Router Is** - Prefix: /api/v4 - Purpose: additive V4 contract for: 1. Registry catalogs (document types, person roles) 2. Role-aware document-person linking 3. Code-or-id document type assignment - It delegates to DocumentService and does not access DB sessions directly in route handlers. **Dependency Wiring** - Route dependency: get_document_service in v4_documents.py - Behavior: 1. Uses app.state.services.documents when running in the app lifecycle 2. Falls back to a direct DocumentService() instance if needed (useful in isolated tests) **1) List Document Types** - Endpoint: GET /api/v4/document-types - Query param: active_only=true by default - Backing service call: list_document_types(active_only=...) - Response shape: [ { "id": "uuid", "code": "letter", "label": "Letter", "is_active": true, "sort_order": 0 } ] **2) List Person Roles** - Endpoint: GET /api/v4/person-roles - Query param: active_only=true by default - Backing service call: list_person_roles(active_only=...) - Response shape: [ { "id": "uuid", "code": "author", "label": "Author", "is_active": true } ] **3) Set Document Type (By Id Or Code)** - Endpoint: PUT /api/v4/documents/{document_id}/type - Body options: 1. document_type_id 2. document_type_code - Rule: provide one selector, not both - Example request: { "document_type_code": "record" } - Example response: { "document_id": "uuid", "document_type_id": "uuid", "document_type_code": "record" } **4) List Document-Person Links For A Document** - Endpoint: GET /api/v4/documents/{document_id}/people - Backing service call: list_document_people(document_id=...) - Example response: { "document_id": "uuid", "links": [ { "id": "uuid", "document_id": "uuid", "person_id": "uuid", "role_id": "uuid", "role_code": "author", "person_name": "Zenna Cochran" } ] } **5) Add A Document-Person Link** - Endpoint: POST /api/v4/documents/{document_id}/people - Body fields: 1. person_id required 2. role_id optional 3. role_code optional - If duplicate document/person/role link is attempted, returns conflict envelope via shared error handlers. - Example request: { "person_id": "uuid", "role_code": "mentioned" } - Example success response: { "id": "uuid", "document_id": "uuid", "person_id": "uuid", "role_id": "uuid", "role_code": "mentioned", "person_name": "Ada Lovelace" } **6) Update Link Role** - Endpoint: PATCH /api/v4/document-people/{document_person_id} - Body options: 1. role_id 2. role_code - Rule: provide one selector, not both - Example request: { "role_code": "recipient" } - Example response: { "id": "uuid", "document_id": "uuid", "person_id": "uuid", "role_id": "uuid", "role_code": "recipient", "person_name": "Ada Lovelace" } **7) Delete Link** - Endpoint: DELETE /api/v4/document-people/{document_person_id} - Response: HTTP 204 No Content **Error Behavior** - Uses shared registration in errors.py - So AppError categories map to consistent envelope + status codes: 1. validation_error -> 400 2. not_found_error -> 404 3. conflict_error -> 409 4. internal_unexpected_error -> 500 **Where It Gets Mounted** - Included in app factory at app.py - That makes all /api/v4 endpoints available during normal app startup. If you want, next I can generate a compact curl-style smoke checklist for all 7 endpoints so you can test them in under 2 minutes. --- ## Question ``` Should there be one of these for people, jobs, and sources too? ``` ## Response Short answer: yes, but not all at once. Given your V4 scope, the strongest split is: 1. Keep v4_documents.py for document-centric workflows This file already owns: - document type catalog/use - document-person role links - document-level relationship mutations 2. Add a V4 people router next Recommended new file: - src/transcription/api/v4_people.py Why: - You likely need person-centric queries and updates that are not naturally document-scoped - It keeps API boundaries clearer as UI grows 3. Do not rush a separate jobs/sources V4 router unless contracts are diverging For now, jobs and sources are still tightly tied to the existing transcription pipeline behavior. A new v4_jobs or v4_sources router is useful only when you need genuinely new contract shape, such as: - job lifecycle contract changes - source revision/audit contract changes - new pagination/filtering semantics incompatible with current endpoints Practical rule of thumb: 1. New router if the domain has new V4 semantics and independent lifecycle 2. Keep existing router if only additive fields are needed Suggested target structure: 1. v4_documents.py 2. src/transcription/api/v4_people.py 3. optional later: src/transcription/api/v4_jobs.py 4. optional later: src/transcription/api/v4_sources.py If you want, I can scaffold v4_people next with additive endpoints that mirror your current service capabilities and keep error envelope behavior consistent.