# Data Model Specification This document defines the data schema across PostgreSQL (Primary), Typesense (Search), and Redis (Caching/Queueing). ## 1. Relational Schema (PostgreSQL) ### **Core Tables** #### `tracks` * `id` (UUID, PK) * `path` (TEXT, UNIQUE) - Physical disk path. * `hash` (TEXT, INDEX) - BLOB/MD5 hash for deduplication. * `title`, `artist`, `album` (TEXT) * `duration` (REAL) - In seconds. * `state` (ENUM) - `[LIBRARY, RECOMMENDED, HIDDEN, MISSING, DELETED]` * `play_count`, `skip_count`, `dislike_count` (INTEGER) * `last_played_at` (TIMESTAMP) * `mtime` (REAL) - File mtime at last index. * `source_type` (ENUM) - `[MANUAL, RECOMMENDATION]` #### `artists` & `albums` * `artists`: `id`, `name`, `mbid`, `discogs_id`, `image_path`. * `albums`: `id`, `artist_id`, `title`, `year`, `artwork_id`. #### `genre` & `track_genre` * `genre`: `id`, `name`, `parent_id` (Self-join for hierarchy). * `track_genre`: `track_id`, `genre_id`, `weight` (Decimal). ### **Recommendation & Lifecycle Tables** #### `recommendation_batch` * `id` (UUID, PK) * `user_id` (UUID) * `status` (ENUM) - `[ACTIVE, RESOLVED, FAILED]` * `last_interaction_at` (TIMESTAMP) * `seed_track_id` (UUID, FK) #### `dislikes` * `track_id` (UUID, FK) * `disliked_at` (TIMESTAMP) * `warned_at` (TIMESTAMP, NULLABLE) * `state` (ENUM) - `[HIDDEN, WARNED, DELETED]` ### **Metadata & Enrichment** * `track_audio_features`: `track_id`, `bpm`, `key`, `energy`, `danceability`, etc. * `track_lyrics`: `track_id`, `lyrics_text`, `provider`. * `mb_cache` / `lastfm_cache`: Key-Value stores for external API responses. ## 2. Search Schema (Typesense) Typesense is used for ultra-fast, fuzzy search. Indices are rebuilt from PostgreSQL. **Index: `tracks`** * `title` (string, facet) * `artist` (string, facet) * `album` (string, facet) * `genres` (string, facet) * `state` (string, filterable) ## 3. Cache & Queue (Redis) * **BullMQ:** Stores job payloads and processing states. * **Session Cache:** Stores ephemeral playback metadata and current "rolling window" track IDs.