Add database schema, ERD, and repository layer

This commit is contained in:
Alexander
2026-05-08 10:03:28 +02:00
parent 84a6fe8ec7
commit 66264e1314
8 changed files with 749 additions and 208 deletions
+114 -208
View File
@@ -16,259 +16,165 @@ skinparam package {
title Music Aggregator - Database Structure
' ══════════════════════════════════════════════════════════════
' CORE MUSIC ENTITIES
' ══════════════════════════════════════════════════════════════
package "Core Music Entities" #E3F2FD {
entity "artist_metadata" {
package "Music Metadata" #E3F2FD {
entity "artists" {
* id : UUID <<PK>>
--
foreign_artist_id : TEXT <<UNIQUE>>
name : TEXT
sort_name : TEXT
disambiguation : TEXT
artist_type : TEXT
status : TEXT
overview : TEXT
images : JSONB
links : JSONB
genres : JSONB
external_id : VARCHAR(255) <<UNIQUE>>
name : VARCHAR(500)
artist_type : VARCHAR(50)
country : VARCHAR(10)
genres : TEXT[]
image_url : TEXT
--
created_at : TIMESTAMPTZ
updated_at : TIMESTAMPTZ
}
entity "artists" {
* id : UUID <<PK>>
--
metadata_id : UUID <<FK>>
quality_profile_id : UUID <<FK>>
metadata_profile_id : UUID <<FK>>
root_folder_id : UUID <<FK>>
--
path : TEXT
monitored : BOOLEAN
monitor_new_items : TEXT
--
last_info_sync : TIMESTAMPTZ
added_at : TIMESTAMPTZ
}
entity "albums" {
* id : UUID <<PK>>
--
artist_metadata_id : UUID <<FK>>
external_id : VARCHAR(255) <<UNIQUE>>
artist_id : UUID <<FK>>
--
foreign_album_id : TEXT <<UNIQUE>>
title : TEXT
clean_title : TEXT
disambiguation : TEXT
overview : TEXT
album_type : TEXT
title : VARCHAR(500)
album_type : VARCHAR(50)
release_date : DATE
images : JSONB
genres : JSONB
total_tracks : INT
total_discs : INT
label : VARCHAR(255)
genres : TEXT[]
cover_url : TEXT
is_monitored : BOOLEAN
--
monitored : BOOLEAN
added_at : TIMESTAMPTZ
}
entity "album_releases" {
* id : UUID <<PK>>
--
album_id : UUID <<FK>>
--
foreign_release_id : TEXT <<UNIQUE>>
title : TEXT
status : TEXT
duration_ms : INT
release_date : DATE
country : TEXT[]
label : TEXT[]
format : TEXT
track_count : INT
--
monitored : BOOLEAN
created_at : TIMESTAMPTZ
updated_at : TIMESTAMPTZ
}
entity "tracks" {
* id : UUID <<PK>>
--
album_release_id : UUID <<FK>>
artist_metadata_id : UUID <<FK>>
track_file_id : UUID <<FK NULL>>
external_id : VARCHAR(255) <<UNIQUE>>
album_id : UUID <<FK>>
--
foreign_track_id : TEXT <<UNIQUE>>
title : TEXT
track_number : INT
disc_number : INT
title : VARCHAR(500)
duration_ms : INT
explicit : BOOLEAN
}
entity "track_files" {
* id : UUID <<PK>>
isrc : VARCHAR(20)
disc_number : INT
track_number : INT
--
album_id : UUID <<FK>>
--
path : TEXT
relative_path : TEXT
size : BIGINT
--
file_hash : TEXT
audio_hash : TEXT
--
quality : JSONB
media_info : JSONB
--
scene_name : TEXT
release_group : TEXT
--
date_added : TIMESTAMPTZ
created_at : TIMESTAMPTZ
}
}
' ══════════════════════════════════════════════════════════════
' CONFIGURATION
' ══════════════════════════════════════════════════════════════
package "Configuration" #FFF3E0 {
entity "quality_profiles" {
package "Torrent Catalog" #FFF3E0 {
entity "torrents" {
* id : UUID <<PK>>
--
name : TEXT <<UNIQUE>>
cutoff : INT
items : JSONB
upgrade_allowed : BOOLEAN
}
entity "metadata_profiles" {
* id : UUID <<PK>>
--
name : TEXT <<UNIQUE>>
primary_album_types : JSONB
secondary_album_types : JSONB
release_statuses : JSONB
}
entity "root_folders" {
* id : UUID <<PK>>
--
name : TEXT
path : TEXT <<UNIQUE>>
default_quality_profile_id : UUID <<FK>>
default_metadata_profile_id : UUID <<FK>>
}
entity "indexers" {
* id : UUID <<PK>>
--
name : TEXT
implementation : TEXT
settings : JSONB
enable_rss : BOOLEAN
enable_search : BOOLEAN
priority : INT
}
entity "download_clients" {
* id : UUID <<PK>>
--
name : TEXT
implementation : TEXT
settings : JSONB
protocol : TEXT
priority : INT
enabled : BOOLEAN
}
}
' ══════════════════════════════════════════════════════════════
' DOWNLOAD TRACKING
' ══════════════════════════════════════════════════════════════
package "Download Tracking" #E8F5E9 {
entity "wanted_albums" {
* id : UUID <<PK>>
--
album_id : UUID <<FK>> <<UNIQUE>>
--
priority : INT
search_count : INT
last_searched_at : TIMESTAMPTZ
added_at : TIMESTAMPTZ
}
entity "download_queue" {
* id : UUID <<PK>>
--
artist_id : UUID <<FK>>
album_id : UUID <<FK>>
info_hash : VARCHAR(40) <<UNIQUE>>
--
download_id : TEXT
tracker : VARCHAR(100)
title : TEXT
format : VARCHAR(20)
quality : VARCHAR(20)
source : VARCHAR(20)
bit_depth : INT
sample_rate : INT
seeders : INT
peers : INT
size : BIGINT
size_left : BIGINT
track_count : INT
has_cover_art : BOOLEAN
has_cue_sheet : BOOLEAN
has_rip_log : BOOLEAN
download_link : TEXT
torrent_file : BYTEA
--
status : TEXT
progress : REAL
created_at : TIMESTAMPTZ
updated_at : TIMESTAMPTZ
}
}
package "Download Management" #E8F5E9 {
entity "downloads" {
* id : UUID <<PK>>
--
torrent_id : UUID <<FK>>
album_id : UUID
format : VARCHAR(20)
quality : VARCHAR(20)
--
state : download_state
qbit_hash : VARCHAR(64)
save_path : TEXT
error_message : TEXT
--
protocol : TEXT
indexer : TEXT
download_client : TEXT
torrent_hash : TEXT
output_path : TEXT
--
added_at : TIMESTAMPTZ
queued_at : TIMESTAMPTZ
started_at : TIMESTAMPTZ
completed_at : TIMESTAMPTZ
created_at : TIMESTAMPTZ
updated_at : TIMESTAMPTZ
}
entity "blocklist" {
entity "download_files" {
* id : UUID <<PK>>
--
artist_id : UUID <<FK>>
album_id : UUID <<FK>>
download_id : UUID <<FK>>
track_id : UUID <<FK NULL>>
--
source_title : TEXT
quality : JSONB
size : BIGINT
protocol : TEXT
indexer : TEXT
message : TEXT
torrent_hash : TEXT
file_path : TEXT
file_size : BIGINT
file_type : VARCHAR(20)
sha256_hash : VARCHAR(64)
--
date : TIMESTAMPTZ
verified_at : TIMESTAMPTZ
created_at : TIMESTAMPTZ
}
}
' ══════════════════════════════════════════════════════════════
' RELATIONSHIPS
' ══════════════════════════════════════════════════════════════
package "Caching & Queue (River)" #F3E5F5 {
entity "river_job" {
* id : BIGSERIAL <<PK>>
--
kind : TEXT
state : river_job_state
queue : TEXT
args : JSONB
metadata : JSONB
--
attempt : SMALLINT
max_attempts : SMALLINT
priority : SMALLINT
--
scheduled_at : TIMESTAMPTZ
attempted_at : TIMESTAMPTZ
created_at : TIMESTAMPTZ
finalized_at : TIMESTAMPTZ
}
' Core music relationships
artist_metadata ||--|| artists : "has config"
artist_metadata ||--o{ albums : "released"
albums ||--o{ album_releases : "has releases"
album_releases ||--o{ tracks : "contains"
tracks }o--o| track_files : "stored in"
track_files }o--|| albums : "belongs to"
entity "river_queue" {
* name : TEXT <<PK>>
--
metadata : JSONB
paused_at : TIMESTAMPTZ
created_at : TIMESTAMPTZ
updated_at : TIMESTAMPTZ
}
}
' Artist config relationships
artists }o--|| quality_profiles : "uses"
artists }o--o| metadata_profiles : "uses"
artists }o--o| root_folders : "stored in"
note right of river_job
Cache refresh jobs:
kind = "indexer_cache_refresh"
args = {key, url, ttl_expires, refresh_interval}
scheduled_at = next refresh time
end note
' Root folder defaults
root_folders }o--o| quality_profiles : "default"
root_folders }o--o| metadata_profiles : "default"
' Download tracking relationships
wanted_albums ||--|| albums : "targets"
download_queue }o--o| artists : "for"
download_queue }o--o| albums : "for"
blocklist }o--|| artists : "for"
blocklist }o--o| albums : "for"
artists ||--o{ albums : "released"
albums ||--o{ tracks : "contains"
albums ||--o{ torrents : "available on"
torrents ||--o| downloads : "downloaded as"
downloads ||--o{ download_files : "consists of"
tracks ||--o| download_files : "matched to"
@enduml