docs(db): add full ORM diagram (db-orm.puml)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
432
docs/architecture/db/db-orm.puml
Normal file
432
docs/architecture/db/db-orm.puml
Normal file
@@ -0,0 +1,432 @@
|
||||
@startuml db-orm
|
||||
' Schema source: Flyway V1–V60 (excl. V37, V43 — intentionally removed)
|
||||
' Schema as of: V60 (2026-05-06)
|
||||
' ⚠ This is a versioned snapshot. Update when the schema changes significantly.
|
||||
|
||||
hide circle
|
||||
skinparam linetype ortho
|
||||
|
||||
' ── Auth ──
|
||||
package "Auth" {
|
||||
|
||||
entity app_users {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
email : VARCHAR(255) NOT NULL UNIQUE
|
||||
password : VARCHAR(255) NOT NULL
|
||||
first_name : VARCHAR(100)
|
||||
last_name : VARCHAR(100)
|
||||
birth_date : DATE
|
||||
contact : TEXT
|
||||
enabled : BOOLEAN NOT NULL
|
||||
color : VARCHAR(20) NOT NULL
|
||||
notify_on_reply : BOOLEAN NOT NULL
|
||||
notify_on_mention : BOOLEAN NOT NULL
|
||||
created_at : TIMESTAMP
|
||||
}
|
||||
|
||||
entity user_groups {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
name : VARCHAR(255) NOT NULL UNIQUE
|
||||
}
|
||||
|
||||
entity app_users_groups {
|
||||
app_user_id : UUID <<FK>>
|
||||
group_id : UUID <<FK>>
|
||||
}
|
||||
|
||||
entity group_permissions {
|
||||
group_id : UUID <<FK>>
|
||||
--
|
||||
permission : VARCHAR(255)
|
||||
}
|
||||
|
||||
entity password_reset_tokens {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
app_user_id : UUID <<FK>>
|
||||
token : VARCHAR(64) NOT NULL UNIQUE
|
||||
expires_at : TIMESTAMP NOT NULL
|
||||
used : BOOLEAN NOT NULL
|
||||
created_at : TIMESTAMP NOT NULL
|
||||
}
|
||||
|
||||
entity invite_tokens {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
code : VARCHAR(10) NOT NULL UNIQUE
|
||||
label : VARCHAR(255)
|
||||
max_uses : INTEGER
|
||||
use_count : INTEGER NOT NULL
|
||||
prefill_first_name : VARCHAR(255)
|
||||
prefill_last_name : VARCHAR(255)
|
||||
prefill_email : VARCHAR(255)
|
||||
expires_at : TIMESTAMP
|
||||
created_by : UUID <<FK>>
|
||||
created_at : TIMESTAMP NOT NULL
|
||||
revoked : BOOLEAN NOT NULL
|
||||
}
|
||||
|
||||
entity invite_token_group_ids {
|
||||
invite_token_id : UUID <<FK>>
|
||||
group_id : UUID <<FK>>
|
||||
}
|
||||
}
|
||||
|
||||
' ── Documents ──
|
||||
package "Documents" {
|
||||
|
||||
entity documents {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
title : VARCHAR(255) NOT NULL
|
||||
original_filename : VARCHAR(255) NOT NULL
|
||||
status : VARCHAR(255) NOT NULL
|
||||
file_path : VARCHAR(255)
|
||||
file_hash : VARCHAR(64)
|
||||
summary : TEXT
|
||||
transcription : TEXT
|
||||
meta_date : DATE
|
||||
meta_location : VARCHAR(255)
|
||||
meta_document_location : VARCHAR(255)
|
||||
archive_box : VARCHAR(255)
|
||||
archive_folder : VARCHAR(255)
|
||||
sender_id : UUID <<FK>>
|
||||
metadata_complete : BOOLEAN NOT NULL
|
||||
script_type : VARCHAR(30) NOT NULL
|
||||
thumbnail_key : VARCHAR(255)
|
||||
thumbnail_generated_at : TIMESTAMP
|
||||
thumbnail_aspect : VARCHAR(16)
|
||||
page_count : INTEGER
|
||||
search_vector : tsvector <<computed>>
|
||||
created_at : TIMESTAMP
|
||||
updated_at : TIMESTAMP
|
||||
}
|
||||
|
||||
entity document_receivers {
|
||||
document_id : UUID <<FK>>
|
||||
person_id : UUID <<FK>>
|
||||
}
|
||||
|
||||
entity document_tags {
|
||||
document_id : UUID <<FK>>
|
||||
tag_id : UUID <<FK>>
|
||||
}
|
||||
|
||||
entity document_versions {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
document_id : UUID <<FK>>
|
||||
editor_id : UUID <<FK>>
|
||||
editor_name : VARCHAR(200) NOT NULL
|
||||
saved_at : TIMESTAMP NOT NULL
|
||||
snapshot : JSONB NOT NULL
|
||||
changed_fields : JSONB NOT NULL
|
||||
}
|
||||
|
||||
entity document_annotations {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
document_id : UUID <<FK>>
|
||||
page_number : INTEGER NOT NULL
|
||||
x : DOUBLE PRECISION NOT NULL
|
||||
y : DOUBLE PRECISION NOT NULL
|
||||
width : DOUBLE PRECISION NOT NULL
|
||||
height : DOUBLE PRECISION NOT NULL
|
||||
color : VARCHAR(20) NOT NULL
|
||||
polygon : JSONB
|
||||
file_hash : VARCHAR(64)
|
||||
created_by : UUID <<FK>>
|
||||
created_at : TIMESTAMP NOT NULL
|
||||
}
|
||||
|
||||
entity document_comments {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
document_id : UUID <<FK>>
|
||||
annotation_id : UUID <<FK>>
|
||||
block_id : UUID <<FK>>
|
||||
parent_id : UUID <<FK>>
|
||||
author_id : UUID <<FK>>
|
||||
author_name : VARCHAR(200) NOT NULL
|
||||
content : TEXT NOT NULL
|
||||
created_at : TIMESTAMP NOT NULL
|
||||
updated_at : TIMESTAMP NOT NULL
|
||||
}
|
||||
|
||||
entity document_training_labels {
|
||||
document_id : UUID <<FK>>
|
||||
--
|
||||
label : VARCHAR(50) NOT NULL
|
||||
}
|
||||
|
||||
entity comment_mentions {
|
||||
comment_id : UUID <<FK>>
|
||||
app_user_id : UUID <<FK>>
|
||||
}
|
||||
}
|
||||
|
||||
' ── Persons ──
|
||||
package "Persons" {
|
||||
|
||||
entity persons {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
first_name : VARCHAR(255)
|
||||
last_name : VARCHAR(255) NOT NULL
|
||||
alias : VARCHAR(255)
|
||||
title : VARCHAR(50)
|
||||
person_type : VARCHAR(20) NOT NULL
|
||||
notes : TEXT
|
||||
birth_year : INTEGER
|
||||
death_year : INTEGER
|
||||
family_member : BOOLEAN NOT NULL
|
||||
}
|
||||
|
||||
entity person_name_aliases {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
person_id : UUID <<FK>>
|
||||
last_name : VARCHAR(255) NOT NULL
|
||||
first_name : VARCHAR(255)
|
||||
type : VARCHAR(50) NOT NULL
|
||||
sort_order : INTEGER NOT NULL
|
||||
created_at : TIMESTAMPTZ
|
||||
}
|
||||
|
||||
entity person_relationships {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
person_id : UUID <<FK>>
|
||||
related_person_id : UUID <<FK>>
|
||||
relation_type : VARCHAR(30) NOT NULL
|
||||
from_year : INTEGER
|
||||
to_year : INTEGER
|
||||
notes : VARCHAR(2000)
|
||||
created_at : TIMESTAMPTZ NOT NULL
|
||||
}
|
||||
}
|
||||
|
||||
' ── Tags ──
|
||||
package "Tags" {
|
||||
|
||||
entity tag {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
name : VARCHAR(255) NOT NULL UNIQUE
|
||||
parent_id : UUID <<FK>>
|
||||
color : VARCHAR(20)
|
||||
}
|
||||
}
|
||||
|
||||
' ── Transcription ──
|
||||
package "Transcription" {
|
||||
|
||||
entity transcription_blocks {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
annotation_id : UUID <<FK>>
|
||||
document_id : UUID <<FK>>
|
||||
text : TEXT
|
||||
label : VARCHAR(200)
|
||||
sort_order : INTEGER NOT NULL
|
||||
version : INTEGER NOT NULL
|
||||
source : VARCHAR(10) NOT NULL
|
||||
reviewed : BOOLEAN NOT NULL
|
||||
created_by : UUID <<FK>>
|
||||
updated_by : UUID <<FK>>
|
||||
created_at : TIMESTAMP NOT NULL
|
||||
updated_at : TIMESTAMP NOT NULL
|
||||
}
|
||||
|
||||
entity transcription_block_versions {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
block_id : UUID <<FK>>
|
||||
text : TEXT NOT NULL
|
||||
changed_by : UUID <<FK>>
|
||||
changed_at : TIMESTAMP NOT NULL
|
||||
}
|
||||
|
||||
entity transcription_block_mentioned_persons {
|
||||
block_id : UUID <<FK>>
|
||||
person_id : UUID NOT NULL
|
||||
--
|
||||
display_name : VARCHAR(200) NOT NULL
|
||||
}
|
||||
}
|
||||
|
||||
' ── OCR ──
|
||||
package "OCR" {
|
||||
|
||||
entity ocr_jobs {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
status : VARCHAR(20) NOT NULL
|
||||
total_documents : INT NOT NULL
|
||||
processed_documents : INT NOT NULL
|
||||
error_count : INT NOT NULL
|
||||
skipped_count : INT NOT NULL
|
||||
created_by : UUID
|
||||
progress_message : TEXT
|
||||
created_at : TIMESTAMPTZ NOT NULL
|
||||
updated_at : TIMESTAMPTZ NOT NULL
|
||||
}
|
||||
|
||||
entity ocr_job_documents {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
job_id : UUID <<FK>>
|
||||
document_id : UUID <<FK>>
|
||||
status : VARCHAR(20) NOT NULL
|
||||
error_message : TEXT
|
||||
current_page : INT
|
||||
total_pages : INT
|
||||
created_at : TIMESTAMPTZ NOT NULL
|
||||
updated_at : TIMESTAMPTZ NOT NULL
|
||||
}
|
||||
|
||||
entity ocr_training_runs {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
status : VARCHAR(20) NOT NULL
|
||||
block_count : INT NOT NULL
|
||||
document_count : INT NOT NULL
|
||||
model_name : VARCHAR(100) NOT NULL
|
||||
error_message : TEXT
|
||||
triggered_by : UUID <<FK>>
|
||||
person_id : UUID <<FK>>
|
||||
cer : DOUBLE PRECISION
|
||||
loss : DOUBLE PRECISION
|
||||
accuracy : DOUBLE PRECISION
|
||||
epochs : INT
|
||||
created_at : TIMESTAMPTZ NOT NULL
|
||||
completed_at : TIMESTAMPTZ
|
||||
}
|
||||
|
||||
entity sender_models {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
person_id : UUID <<FK>> UNIQUE
|
||||
model_path : TEXT NOT NULL
|
||||
accuracy : DOUBLE PRECISION
|
||||
cer : DOUBLE PRECISION
|
||||
corrected_lines_at_training : INT NOT NULL
|
||||
created_at : TIMESTAMPTZ NOT NULL
|
||||
updated_at : TIMESTAMPTZ NOT NULL
|
||||
}
|
||||
}
|
||||
|
||||
' ── Supporting ──
|
||||
package "Supporting" {
|
||||
|
||||
entity notifications {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
recipient_id : UUID <<FK>>
|
||||
type : VARCHAR(32) NOT NULL
|
||||
document_id : UUID
|
||||
reference_id : UUID
|
||||
annotation_id : UUID
|
||||
actor_name : VARCHAR(255)
|
||||
read : BOOLEAN NOT NULL
|
||||
created_at : TIMESTAMP NOT NULL
|
||||
}
|
||||
|
||||
entity audit_log {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
happened_at : TIMESTAMPTZ NOT NULL
|
||||
actor_id : UUID <<FK>>
|
||||
kind : VARCHAR(50) NOT NULL
|
||||
document_id : UUID <<FK>>
|
||||
payload : JSONB
|
||||
}
|
||||
|
||||
entity geschichten {
|
||||
id : UUID <<PK>>
|
||||
--
|
||||
title : VARCHAR(255) NOT NULL
|
||||
body : TEXT
|
||||
status : VARCHAR(32) NOT NULL
|
||||
author_id : UUID <<FK>>
|
||||
created_at : TIMESTAMP NOT NULL
|
||||
updated_at : TIMESTAMP NOT NULL
|
||||
published_at : TIMESTAMP
|
||||
}
|
||||
|
||||
entity geschichten_persons {
|
||||
geschichte_id : UUID <<FK>>
|
||||
person_id : UUID <<FK>>
|
||||
}
|
||||
|
||||
entity geschichten_documents {
|
||||
geschichte_id : UUID <<FK>>
|
||||
document_id : UUID <<FK>>
|
||||
}
|
||||
}
|
||||
|
||||
' Auth relationships
|
||||
app_users_groups }o--|| app_users : app_user_id
|
||||
app_users_groups }o--|| user_groups : group_id
|
||||
group_permissions }o--|| user_groups : group_id
|
||||
password_reset_tokens }o--|| app_users : app_user_id
|
||||
invite_tokens }o--|| app_users : created_by
|
||||
invite_token_group_ids }o--|| invite_tokens : invite_token_id
|
||||
invite_token_group_ids }o--|| user_groups : group_id
|
||||
|
||||
' Document relationships
|
||||
documents }o--o| persons : sender_id
|
||||
document_receivers }o--|| documents : document_id
|
||||
document_receivers }o--|| persons : person_id
|
||||
document_tags }o--|| documents : document_id
|
||||
document_tags }o--|| tag : tag_id
|
||||
document_versions }o--|| documents : document_id
|
||||
document_versions }o--o| app_users : editor_id
|
||||
document_annotations }o--|| documents : document_id
|
||||
document_annotations }o--o| app_users : created_by
|
||||
document_comments }o--|| documents : document_id
|
||||
document_comments }o--o| document_annotations : annotation_id
|
||||
document_comments }o--o| transcription_blocks : block_id
|
||||
document_comments }o--o| app_users : author_id
|
||||
document_comments }o--o| document_comments : parent_id
|
||||
document_training_labels }o--|| documents : document_id
|
||||
comment_mentions }o--|| document_comments : comment_id
|
||||
comment_mentions }o--|| app_users : app_user_id
|
||||
|
||||
' Person relationships
|
||||
person_name_aliases }o--|| persons : person_id
|
||||
person_relationships }o--|| persons : person_id
|
||||
person_relationships }o--|| persons : related_person_id
|
||||
|
||||
' Tag self-reference
|
||||
tag }o--o| tag : parent_id
|
||||
|
||||
' Transcription relationships
|
||||
transcription_blocks }o--|| document_annotations : annotation_id
|
||||
transcription_blocks }o--|| documents : document_id
|
||||
transcription_blocks }o--o| app_users : created_by
|
||||
transcription_blocks }o--o| app_users : updated_by
|
||||
transcription_block_versions }o--|| transcription_blocks : block_id
|
||||
transcription_block_versions }o--o| app_users : changed_by
|
||||
transcription_block_mentioned_persons }o--|| transcription_blocks : block_id
|
||||
|
||||
' OCR relationships
|
||||
ocr_job_documents }o--|| ocr_jobs : job_id
|
||||
ocr_job_documents }o--|| documents : document_id
|
||||
ocr_training_runs }o--o| app_users : triggered_by
|
||||
ocr_training_runs }o--o| persons : person_id
|
||||
sender_models ||--|| persons : person_id
|
||||
|
||||
' Supporting relationships
|
||||
notifications }o--|| app_users : recipient_id
|
||||
audit_log }o--o| app_users : actor_id
|
||||
audit_log }o--o| documents : document_id
|
||||
geschichten }o--o| app_users : author_id
|
||||
geschichten_persons }o--|| geschichten : geschichte_id
|
||||
geschichten_persons }o--|| persons : person_id
|
||||
geschichten_documents }o--|| geschichten : geschichte_id
|
||||
geschichten_documents }o--|| documents : document_id
|
||||
|
||||
@enduml
|
||||
Reference in New Issue
Block a user