# System Architecture (Version 2) This document describes the V2 production architecture of the personal historical-document transcription system. ## Architecture Objectives * Preserve source material as immutable transcribed text alongside page-level spatial AI metadata. * Support batching multi-image and folder uploads cleanly into sequential pages (`page_number`). * Leverage asynchronous worker pools (`asyncio`) for parallel single-image API execution bounded by rate limiters (`asyncio.Semaphore`). * Migrate persistence to PostgreSQL using native `UUID`, `TIMESTAMPTZ`, and `JSONB` document storage. * Standardize all data validation, API parsing, and database models on **Pydantic V2**. * Support rich historical attribution (multi-author and multi-recipient relationships). ## Runtime Topology The V2 runtime operates as an asynchronous Python application: * FastAPI + NiceGUI web application process. * In-process `asyncio` background task orchestrator for parallel API execution. * Relational persistence via PostgreSQL (using `asyncpg` or `psycopg3`). * Pydantic V2 validation layer wrapping API payloads and PostgreSQL `JSONB` schemas. ```mermaid flowchart LR U[Browser User] --> A[FastAPI + NiceGUI App] A --> W[Asyncio Worker Engine] A --> DB[(PostgreSQL Database)] W --> P[Vision Provider APIs\nOpenAI / Claude] W --> DB ``` ## Lifecycle Ownership Application lifespan owns runtime setup/teardown: * Initialize environment logging and Pydantic configuration. * Manage asynchronous PostgreSQL connection pools (`asyncpg` / `psycopg3`). * Execute database migrations and index initialization. * Recover stale processing jobs on startup. * Manage graceful shutdown of active `asyncio` worker pools. ## Layered Module Structure ### Interface Layer * `src/transcription/ui/**` (NiceGUI pages, multi-page renderers, person cards) * `src/transcription/api/**` (FastAPI routes and JSON error handlers) ### Application & Async Worker Layer * `src/transcription/services/workflows.py` * `src/transcription/worker.py` Responsibilities: * Batch orchestration and status transitions (`queued` -> `processing` -> `completed` | `partial_success` | `failed`). * Parallel single-image API execution using `asyncio.gather` bounded by `asyncio.Semaphore`. * Pydantic schema parsing (`PageAIMetadata`) and validation prior to database storage. ### Domain & Service Layer * `src/transcription/db/models.py` (SQLModel/Pydantic V2 schema definitions for the current implementation) * `src/transcription/services/*.py` (Transactional operations for `Document`, `Person`, `Source`, `Job`, and `JobSource`) ### Infrastructure Layer * `src/transcription/db/**` (PostgreSQL connection pooling and raw parameterized SQL execution) * `src/transcription/providers/**` (OpenAI & Anthropic Vision SDK adapters) ## Processing Workflow 1. User uploads a folder or batch of images for a `Document`. 2. System creates `Document`, `Job(status='queued')`, and ordered `Source` pages (`page_number = 1..N`). 3. Worker claims job, sets `Job.status = 'processing'`, and spawns parallel `asyncio` tasks bounded by semaphore. 4. Each task calls Vision API for a **single** `Source` image. 5. On task completion: * Writes a `JobSource` record containing `status='transcribed'`, `raw_transcription`, `ai_metadata` (bounding boxes/confidence), and `raw_api_response`. * Caches active text to `Source.raw_transcription`. 6. On page failure: * Writes `JobSource` record with `status='failed'` and `error_detail`. 7. Once all page tasks resolve: * Marks `Job.status` as `completed` (100% success), `partial_success` (at least 1 success, 1 failure), or `failed` (all failed). ## Domain Ownership & Invariants * **Immutable AI Outputs:** `source.raw_transcription` and `job_source.raw_transcription` store original, point-in-time machine output and are immutable. * **Inlined Revisions:** Human corrections occur on `source.revised_text`. UI renders `COALESCE(revised_text, raw_transcription)`. * **Sequential Integrity:** Multi-page documents are strictly ordered by `source.page_number ASC`. * **Page Execution Isolation:** A failure on one page image does not invalidate successful transcriptions on sister pages in the same batch job. ## Data Model Summary * `Document` has many `Source` pages, many `Job` runs, and many `Person` records via `DocumentPerson` junction (`author` or `recipient`). * `Source` belongs to one `Document` and can be processed across many `JobSource` executions. * `Job` has many `JobSource` execution records. ## Test Strategy * Unit tests for Pydantic V2 schemas, custom validators, and JSONB serialization. * Integration tests for async PostgreSQL connection handling and parameterized queries. * Async workflow tests using mock AI providers to verify `partial_success` and retry logic. * UI integration tests for multi-page rendering and person management. --- ## Technology References - [FastAPI documentation](https://fastapi.tiangolo.com/) - [NiceGUI documentation](https://nicegui.io/documentation) - [PostgreSQL documentation](https://www.postgresql.org/docs/) - [Python asyncio](https://docs.python.org/3/library/asyncio.html#module-asyncio) - [Pydantic Validation](https://pydantic.dev/docs/validation/latest/get-started/) - [Pydantic AI](https://pydantic.dev/docs/ai/overview/) ## Related Local References - [System Overview](index_v2.md) - [System Design Intent](invariant/intent.md) - [Transcription Methodology](invariant/transcription_methodology.md) - System Architecture (this document) - [System Requirements](requirements_v2.md) - [Data model](schema_v2.md) - [Error Handling Policy](error_handling_v2.md) - [Implementation Plan](implementation_plan_v2.md)