Add database schema, ERD, and repository layer
This commit is contained in:
+114
-208
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user