9.7 KiB
System Architecture (Version 4)
This document describes the production architecture of the document transcription system.
Architecture Objectives
- Preserve original source material, per-execution machine output, and separate human revision.
- Support batching one or more images into ordered multi-page documents.
- Capture submission-time prompt provenance and a per-page OpenRouter SDK response snapshot.
- Execute page transcription concurrently with bounded
asyncioworkers. - Maintain relational portability across SQLite and PostgreSQL.
- Keep operator workflows cross-platform and Python-driven.
- Support one role-bearing link per Person and Document through an extensible role registry.
- Support registry-driven document classification with protected semantic built-ins.
Core Capabilities
- Ingest one or more images into sequential
Sourcepages under aDocument. - Execute asynchronous vision transcription with bounded worker concurrency.
- Preserve original source files with SHA-256 digests and byte sizes.
- Freeze prompt text, prompt hash, model, and explicitly configured sampling parameters on each
Job. - Preserve page-level machine output, normalized metadata, and an SDK-serialized OpenRouter response snapshot on
JobSource. - Organize historical
Personrecords through UUID-identified Document links and extensible roles. - Classify Documents through a UUID-identified registry with hidden semantic built-ins and unique labels.
- Maintain human revision separately from machine-generated text.
- Isolate page failures so multi-page jobs can complete with partial success.
- Operate across supported platforms through Python-based application and maintenance tooling.
V4.2 extends this baseline with immutable execution attempts, exact OpenRouter transport evidence, safe
versioned exports, and provider-neutral derived-artifact provenance. JobSource remains the mutable queue and
compatibility projection; ExecutionAttempt is the authoritative append-only processing history. See the
V4.2 Scope Boundary.
Technical Stack
- Runtime: Python 3.12 or later.
- Web application: FastAPI and NiceGUI.
- Persistence: SQLModel and SQLAlchemy, with SQLite and PostgreSQL support.
- Validation and settings: Pydantic V2 and pydantic-settings.
- Concurrency: Python
asyncioworkers. - Vision integration: OpenRouter through the application's provider adapter.
- Testing and quality: pytest, pytest-asyncio, Ruff, and ty.
Runtime Topology
The runtime operates as an asynchronous Python application:
- FastAPI + NiceGUI web application process.
- In-process
asyncioworker engine for transcription execution. - Relational persistence via SQLModel / SQLAlchemy.
- Pydantic V2 validation across API payloads, prompt configuration, and structured metadata.
^^^mermaid flowchart LR U[Browser User] --> A[FastAPI + NiceGUI App] A --> W[Asyncio Worker Engine] A --> DB[(Relational DB)] W --> P[Vision Provider APIs] W --> DB ^^^
Lifecycle Ownership
Application lifespan owns runtime setup and teardown:
- Initialize logging, settings, directories, and prompt configuration.
- Manage asynchronous database engine connection pools.
- Execute database bootstrap or migrations.
- Recover stale or interrupted jobs on startup.
- Manage graceful shutdown of active background tasks.
Layered Module Structure
Interface Layer
src/transcription/ui/**src/transcription/api/**
Responsibilities:
- Render document, source, person, job, and classification views.
- Accept user input for uploads, editing, linking, and revisions.
- Present structured validation and conflict feedback.
Application and Async Worker Layer
src/transcription/services/workflows.pysrc/transcription/worker.py
Responsibilities:
- Orchestrate uploads, job creation, and status transitions.
- Execute per-page provider calls through bounded concurrency.
- Persist page-level outcomes and update aggregate job state.
Domain and Service Layer
src/transcription/db/models.pysrc/transcription/services/documents.pysrc/transcription/services/sources.pysrc/transcription/services/jobs.pysrc/transcription/services/people.pysrc/transcription/services/workflows.py
Responsibilities:
- Keep one primary service boundary per aggregate: Documents, Sources, Jobs, and People.
- Documents own document records and the document-type registry.
- Sources own source records, revisions, source media formats, MIME resolution, and page execution evidence.
- Jobs own job lifecycle state and transitions.
- People own person records, relationship roles, document-person links, and portrait media.
- Apply deterministic conflict handling for relationship-role writes.
- Synchronize each Document's complete Person link set in the same transaction as Document fields.
- Resolve and validate registry records by UUID; use hidden semantic keys only for application-owned built-in behavior.
Source Media Policy
services/sources.pyis the single authority for accepted Source extensions and canonical MIME types.- Storage and provider payload loading must call the same Source validation functions.
- Supported Source formats are JPEG, PNG, TIFF, and PDF.
- Upload is an interface action, not a domain aggregate. Service names, errors, and workflow variables use
Sourceterminology; compatibility aliases may remain temporarily at old import boundaries.
Infrastructure Layer
src/transcription/db/**src/transcription/providers/**
Responsibilities:
- Provide async database sessions and engine configuration.
- Provide provider adapters for vision model execution.
Core Workflows
1. Multi-Page Transcription
- User uploads one or more images for a
Document. - System stores files, hashes them, creates ordered
Sourcerows, and creates aJob. - Worker claims the job, marks it
processing, and executes page calls concurrently. - Each provider call appends an
ExecutionAttemptwith its request manifest, transport evidence, SDK snapshot, normalized metadata, timing, and outcome. - The linked
JobSourceis updated as a compatibility projection, and a successful attempt updates theSource.raw_transcriptionlatest-success projection. - Aggregate status becomes
completed,partial_success, orfailed.
2. Document-Person Relationship Management
- User opens Document Create or Edit.
- UI loads one Linked People table containing Person and Role.
- Add, Edit, and Delete operations change staged UI state only.
- Service validates the complete desired set and computes deterministic add, update, and remove deltas.
- Document fields and links commit once in one transaction; any failure leaves both unchanged.
3. Document Type Management
- User selects a registry-backed document type for a document.
- Service resolves the Document Type UUID.
- Persistence stores the
document_type_idreference. - Inactive types remain valid for historical rows but are excluded from default selectors.
4. Document Printing
- User opens Print from persisted Document Detail.
- Service builds a safe projection containing archival metadata, semantic Author links, ordered Sources, current text, and oldest-to-newest Job metadata.
- The preview renders Facsimile or Text-only HTML without exposing local file paths.
- An explicit action opens the browser print dialog; browser Save as PDF remains available.
V4 Domain Rules
JobSource.raw_transcriptionpreserves page output for its Job execution.Source.raw_transcriptionis the latest-success machine-output projection for a page.- Human corrections occur only in
Source.revised_text. - Prompt and parameter provenance is frozen on
Jobat submission time. - The SDK-serialized OpenRouter response snapshot is stored on
JobSourcefor each successful page execution. - Every V4.2 provider call appends a distinct
ExecutionAttempt; retries never rewrite earlier attempts. - Exact response bytes identify the OpenRouter HTTP boundary and are not labeled as native upstream-provider JSON.
- Generic
ProcessingArtifactrecords use versioned schemas, digests, and one inline or external content location. DocumentPersonlinks are unique for(document_id, person_id)and require onerole_id.- Relationship mutations are deterministic, set-based, and atomic with Document writes.
DocumentType.idandPersonRole.idare canonical relationship identities; unique labels may evolve.- Nullable immutable
semantic_keyvalues identify protected application-defined built-ins and are never public selectors. - Current printable text uses non-null
Source.revised_text; otherwise it usesSource.raw_transcription.
Data Model Summary
Documenthas oneDocumentType, manySourcepages, manyJobruns, and manyPersonrecords throughDocumentPerson.Sourcebelongs to oneDocumentand may participate in manyJobSourceexecutions.Jobhas manyJobSourcerows.PersonRoledefines available relationship roles;DocumentTypeandPersonRolemay carry hidden semantic identity.
Test Strategy
- Unit tests for models, validation, hashing, and registry resolution.
- Service tests for registry protection, atomic link synchronization, uniqueness conflicts, and print projections.
- Async workflow tests for page isolation, partial failure handling, and stored evidence.
- UI integration tests for Linked People staging, registry selection, and safe print rendering.