Files
familienarchiv/docs/architecture/db/db-relationships.puml
Marcel 663bb57334
All checks were successful
CI / fail2ban Regex (pull_request) Successful in 44s
CI / Semgrep Security Scan (pull_request) Successful in 23s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m8s
SDD Gate / RTM Check (pull_request) Successful in 18s
SDD Gate / Contract Validate (pull_request) Successful in 29s
SDD Gate / Constitution Impact (pull_request) Successful in 20s
CI / Unit & Component Tests (pull_request) Successful in 4m38s
CI / OCR Service Tests (pull_request) Successful in 25s
CI / Backend Unit Tests (pull_request) Successful in 5m58s
docs(relationship): ADR-044, DB diagrams, deploy runbook, RTM rows
- ADR-044 extends ADR-039 to the relationship edge: LocalDate+DatePrecision,
  update re-validation of create invariants, no @Version (last-write-wins),
  DELETE→404 anti-enumeration alignment, precise derived marriage date, and the
  relationshipDates.ts location reusing the existing person→shared boundary.
- db-orm.puml: person_relationships now carries from_date/from_date_precision/
  to_date/to_date_precision; db-relationships.puml gets a V78 columns-only note.
- DEPLOYMENT.md §5: V78 deploy note — no maintenance window, stop-old-then-start
  ordering (not rolling-deploy-safe), targeted pg_restore rollback.
- CLAUDE.md error-code list gains INVALID_RELATIONSHIP_DATES.
- rtm.md: REQ-001..REQ-019 for #837 mapped to impl + tests, all Done.

Refs #837
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 19:29:08 +02:00

157 lines
5.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@startuml db-relationships
' Schema source: Flyway V1V69 (excl. V37, V43 — intentionally removed)
' Schema as of: V69 (2026-05-27)
' ⚠ This is a versioned snapshot. Update when the schema changes significantly.
' Note: V69 adds columns only (persons.source_ref, tag.source_ref, document
' precision/attribution fields); no new FK relationships, so this diagram is unchanged.
' Note: V76 swaps persons.birth_year/death_year for birth_date/death_date +
' precision columns; columns only, no new FK relationships, diagram unchanged.
' Note: V77 adds the timeline_events table + two join tables (Timeline package below).
' Note: V78 swaps person_relationships.from_year/to_year for from_date/to_date +
' precision columns; columns only, no new FK relationships, diagram unchanged.
hide circle
skinparam linetype ortho
left to right direction
' ── Auth ──
package "Auth" {
entity app_users
entity user_groups
entity app_users_groups
entity group_permissions
entity password_reset_tokens
entity invite_tokens
entity invite_token_group_ids
}
' ── Documents ──
package "Documents" {
entity documents
entity document_receivers
entity document_tags
entity document_versions
entity document_annotations
entity document_comments
entity document_training_labels
entity comment_mentions
}
' ── Persons ──
package "Persons" {
entity persons
entity person_name_aliases
entity person_relationships
}
' ── Tags ──
package "Tags" {
entity tag
}
' ── Transcription ──
package "Transcription" {
entity transcription_blocks
entity transcription_block_versions
entity transcription_block_mentioned_persons
}
' ── OCR ──
package "OCR" {
entity ocr_jobs
entity ocr_job_documents
entity ocr_training_runs
entity sender_models
}
' ── Supporting ──
package "Supporting" {
entity notifications
entity audit_log
entity geschichten
entity geschichten_persons
entity journey_items
}
' ── Timeline (Zeitstrahl) ──
package "Timeline" {
entity timeline_events
entity timeline_event_persons
entity timeline_event_documents
}
' 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 (ON DELETE SET NULL)
document_receivers }o--|| documents : document_id
document_receivers }o--|| persons : person_id (ON DELETE CASCADE)
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
transcription_block_mentioned_persons }o--|| persons : person_id (ON DELETE CASCADE)
' 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
journey_items }o--|| geschichten : geschichte_id (ON DELETE CASCADE)
journey_items }o--o| documents : document_id (ON DELETE SET NULL)
note right of journey_items : partial UNIQUE (geschichte_id, document_id)\nWHERE document_id IS NOT NULL (V74)
note right of geschichten : CHECK length(body) <= 4000\nfor type = JOURNEY (V75)
' Timeline relationships (V77)
timeline_event_persons }o--|| timeline_events : timeline_event_id (ON DELETE CASCADE)
timeline_event_persons }o--|| persons : person_id (ON DELETE CASCADE)
timeline_event_documents }o--|| timeline_events : timeline_event_id (ON DELETE CASCADE)
timeline_event_documents }o--|| documents : document_id (ON DELETE CASCADE)
note right of timeline_events : CHECK event_date_end non-null IFF RANGE\nCHECK date_precision <> 'UNKNOWN' (V77)
@enduml