7.2 KiB
Database Schema (Version 4)
This document defines the selected schema direction for V4 document-person relationship expansion.
V4 goals are:
- extensible role taxonomy,
- extensible document type taxonomy,
- explicit assertion state (
asserted,suggested), - policy-driven exclusivity,
- deterministic migration from V3 links.
Scope
This specification focuses on relationship and document-type governance persistence changes. Existing Person, Source, Job, and JobSource core structures remain as in V3 unless explicitly noted.
New/Expanded Concepts
- Relationship role: semantic label such as
author,recipient,mentioned. - Assertion state: whether the link is canonical (
asserted) or pending review (suggested). - Exclusivity matrix: configurable role-pair conflicts for same
(document_id, person_id). - Suggestion provenance: evidence fields enabling review decisions.
- Document type registry: controlled taxonomy for
Documentclassification with stable code identity.
Selected Model: Role Registry + Separate Suggestion Table
This option cleanly separates canonical links from pending suggestions and enables fully data-driven role expansion.
Tables
person_role
| Column | Type | Notes |
|---|---|---|
id |
UUID PK | Stable key |
code |
TEXT UNIQUE | Canonical role code, for example author, recipient, mentioned |
label |
TEXT | UI label |
is_active |
BOOLEAN | Soft-enable/disable role |
created_at |
TIMESTAMPTZ | Audit timestamp |
updated_at |
TIMESTAMPTZ | Audit timestamp |
document_person (asserted links only)
| Column | Type | Notes |
|---|---|---|
id |
UUID PK | Stable key |
document_id |
UUID FK | -> document.id |
person_id |
UUID FK | -> person.id |
role_id |
UUID FK | -> person_role.id |
created_at |
TIMESTAMPTZ | Audit timestamp |
updated_at |
TIMESTAMPTZ | Audit timestamp |
Constraints:
UNIQUE(document_id, person_id, role_id)
document_person_suggestion
| Column | Type | Notes |
|---|---|---|
id |
UUID PK | Stable key |
document_id |
UUID FK | -> document.id |
person_id |
UUID FK | -> person.id |
role_id |
UUID FK | -> person_role.id |
status |
TEXT | pending, accepted, rejected |
confidence |
FLOAT NULL | Optional score |
source_mechanism |
TEXT NULL | For example rule, llm |
evidence_ref |
TEXT NULL | Pointer or excerpt ID |
evidence_span |
JSON NULL | Optional text span payload |
note |
TEXT NULL | Reviewer note |
created_at |
TIMESTAMPTZ | Suggestion creation time |
reviewed_at |
TIMESTAMPTZ NULL | Decision time |
reviewed_by |
TEXT NULL | Operator identifier |
Constraints:
UNIQUE(document_id, person_id, role_id, status)with policy for multiple pending rows defined in service layer.- Optional stricter rule: one active pending suggestion per
(document_id, person_id, role_id).
role_exclusivity
| Column | Type | Notes |
|---|---|---|
id |
UUID PK | Stable key |
left_role_id |
UUID FK | -> person_role.id |
right_role_id |
UUID FK | -> person_role.id |
created_at |
TIMESTAMPTZ | Audit timestamp |
Constraints:
- Canonical ordering rule to avoid duplicate pairs (
left_role_id < right_role_idenforced in service/DB). UNIQUE(left_role_id, right_role_id)
Initial seed:
- Exclusivity pair: (
author,recipient)
Deferred Alternative (Not Selected for V4)
An enum-based shared table model was considered but is intentionally not selected for V4 because it couples canonical and provisional states in one table and increases invariant complexity.
Assertion-State Semantics
asserted: canonical relationship used for document/person metadata and business logic.suggested: non-canonical proposal requiring explicit review.- Accept action:
- creates asserted link (or confirms existing),
- marks suggestion
accepted.
- Reject action:
- marks suggestion
rejected.
- marks suggestion
Exclusivity Enforcement
Policy target:
- For a single
(document_id, person_id), disallow coexistence of role pairs configured as exclusive.
Enforcement layers:
- Service-level pre-check for clear API errors.
- Database-level guard where feasible (constraints/triggers or deterministic write path).
Initial configured rule:
authorandrecipientare exclusive.
Enforcement semantics:
- Exclusivity is enforced for asserted links.
- Pending suggestions may exist even if they would conflict when asserted.
- Accepting a suggestion must run exclusivity checks and fail deterministically on conflict.
Migration From V3
Data Mapping
- Existing V3
document_personrows map to V4assertedsemantics. - Existing V3 role values:
author-> roleauthorrecipient-> rolerecipient
Backfill Steps
- Seed role rows (
author,recipient,mentioned) if using Option A. - Migrate current links into asserted table/state.
- Run conflict scan for exclusivity violations.
- Apply deterministic conflict policy for any violations.
- Enable hard enforcement after data passes validation.
Indexing Guidance
Recommended indexes:
document_person(document_id)document_person(person_id)document_person(role_id)(Option A) ordocument_person(role)(Option B)document_person_suggestion(document_id, status)(Option A)document_person_suggestion(person_id, status)(Option A)
Selection Rationale
V4 selects role registry plus separate suggestion storage for clearer provenance boundaries, cleaner lifecycle transitions, and long-term extensibility.
Document Type Registry Model (Selected for V4)
V4 applies the same registry governance pattern to document classification.
Tables
document_type
| Column | Type | Notes |
|---|---|---|
id |
UUID PK | Stable key |
code |
TEXT UNIQUE | Canonical type code, for example letter, diary, book, postcard |
label |
TEXT | UI display label |
is_active |
BOOLEAN | Soft-enable/disable type |
sort_order |
INTEGER NULL | Optional UI ordering |
created_at |
TIMESTAMPTZ | Audit timestamp |
updated_at |
TIMESTAMPTZ | Audit timestamp |
document update
| Column | Type | Notes |
|---|---|---|
document_type_id |
UUID FK NULL | -> document_type.id |
Constraints and Governance
document_type.codemust be stable and unique.document_type.labelmay change without changing canonical type identity.- Inactive types remain valid for historical records but are excluded from default create/edit selectors.
Initial Seeds
- Seed baseline type codes from current V3 usage set (for example
letter,diary,book,postcard,record,memo) and refine labels as needed.
Migration and Normalization (Small Corpus)
- Seed canonical
document_typerows. - Manually assign each existing document (10 total) to a canonical type via
document_type_id. - Resolve any outlier values directly during this one-time pass.
- Enforce registry-backed write validation after manual assignment is complete.
Indexing Guidance (Document Type)
document_type(code)unique index.document(document_type_id)index.