generated from john/python-template
102 lines
4.1 KiB
SQL
102 lines
4.1 KiB
SQL
## PostgreSQL DDL Specification (Version 2)
|
|
|
|
```sql
|
|
-- Enable pgcrypto for UUID generation if on PostgreSQL < 13
|
|
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
|
|
|
-- 1. PERSON TABLE
|
|
CREATE TABLE person (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
full_name TEXT NOT NULL,
|
|
display_name TEXT,
|
|
maiden_name TEXT,
|
|
birth_date DATE,
|
|
birth_date_raw TEXT,
|
|
birth_place TEXT,
|
|
death_date DATE,
|
|
death_date_raw TEXT,
|
|
death_place TEXT,
|
|
biography TEXT,
|
|
portrait_path TEXT,
|
|
metadata JSONB DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- 2. DOCUMENT TABLE
|
|
CREATE TABLE document (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL,
|
|
document_type TEXT,
|
|
document_date DATE,
|
|
document_date_raw TEXT,
|
|
location_created TEXT,
|
|
notes TEXT,
|
|
archive_identifier TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- 3. DOCUMENT_PERSON (Junction Table for Multi-Author / Multi-Recipient)
|
|
CREATE TABLE document_person (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
document_id UUID NOT NULL REFERENCES document(id) ON DELETE CASCADE,
|
|
person_id UUID NOT NULL REFERENCES person(id) ON DELETE CASCADE,
|
|
role VARCHAR(20) NOT NULL, -- 'author' or 'recipient'
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
CONSTRAINT unique_document_person_role UNIQUE (document_id, person_id, role)
|
|
);
|
|
|
|
-- 4. JOB TABLE (Batch-level orchestrator)
|
|
CREATE TABLE job (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
document_id UUID NOT NULL REFERENCES document(id) ON DELETE CASCADE,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'queued', -- 'queued', 'processing', 'completed', 'partial_success', 'failed'
|
|
retry_count INTEGER NOT NULL DEFAULT 0,
|
|
provider TEXT NOT NULL, -- e.g., 'openai', 'anthropic'
|
|
model TEXT NOT NULL, -- e.g., 'gpt-4o', 'claude-3-5-sonnet'
|
|
prompt_name TEXT,
|
|
date_created TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
date_updated TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- 5. SOURCE TABLE (Physical image files & active state)
|
|
CREATE TABLE source (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
document_id UUID NOT NULL REFERENCES document(id) ON DELETE CASCADE,
|
|
page_number INTEGER NOT NULL DEFAULT 1,
|
|
upload_name TEXT NOT NULL,
|
|
filename TEXT NOT NULL,
|
|
file_path TEXT NOT NULL,
|
|
raw_transcription TEXT, -- Cached active AI text output
|
|
revised_text TEXT, -- Active human edited text
|
|
date_uploaded TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
date_revised TIMESTAMPTZ
|
|
);
|
|
|
|
-- 6. JOB_SOURCE (Junction Table: Per-Image Execution Record)
|
|
CREATE TABLE job_source (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
job_id UUID NOT NULL REFERENCES job(id) ON DELETE CASCADE,
|
|
source_id UUID NOT NULL REFERENCES source(id) ON DELETE CASCADE,
|
|
status VARCHAR(50) NOT NULL DEFAULT 'pending', -- 'pending', 'transcribed', 'failed'
|
|
raw_transcription TEXT, -- Point-in-time raw AI text output
|
|
ai_metadata JSONB, -- Page-level bounding boxes, tokens, confidence
|
|
raw_api_response JSONB, -- Complete REST response envelope
|
|
error_detail TEXT,
|
|
executed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
CONSTRAINT unique_job_source UNIQUE (job_id, source_id)
|
|
);
|
|
|
|
-- INDEXES FOR FAST LOOKUPS & QUERY PERFORMANCE
|
|
CREATE INDEX idx_person_full_name ON person(full_name);
|
|
CREATE INDEX idx_document_date ON document(document_date);
|
|
CREATE INDEX idx_document_person_doc ON document_person(document_id);
|
|
CREATE INDEX idx_document_person_per ON document_person(person_id);
|
|
CREATE INDEX idx_source_document ON source(document_id);
|
|
CREATE INDEX idx_source_page_order ON source(document_id, page_number);
|
|
CREATE INDEX idx_job_document ON job(document_id);
|
|
CREATE INDEX idx_job_source_job ON job_source(job_id);
|
|
CREATE INDEX idx_job_source_source ON job_source(source_id);
|
|
CREATE INDEX idx_job_source_ai_metadata ON job_source USING GIN (ai_metadata);
|
|
``` |