CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE TABLE artists ( id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL UNIQUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE albums ( id BIGSERIAL PRIMARY KEY, artist_id BIGINT NOT NULL REFERENCES artists(id) ON DELETE CASCADE, name TEXT NOT NULL, year INT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (artist_id, name) ); CREATE TABLE tracks ( id BIGSERIAL PRIMARY KEY, artist_id BIGINT NOT NULL REFERENCES artists(id) ON DELETE CASCADE, album_id BIGINT REFERENCES albums(id) ON DELETE SET NULL, title TEXT NOT NULL, track_number INT, genre TEXT, duration_secs DOUBLE PRECISION, codec TEXT, bitrate INT, sample_rate INT, file_hash TEXT NOT NULL UNIQUE, file_size BIGINT NOT NULL, storage_path TEXT NOT NULL, manual_override BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE pending_tracks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), status TEXT NOT NULL DEFAULT 'pending', inbox_path TEXT NOT NULL, file_hash TEXT NOT NULL, file_size BIGINT NOT NULL, raw_title TEXT, raw_artist TEXT, raw_album TEXT, raw_year INT, raw_track_number INT, raw_genre TEXT, duration_secs DOUBLE PRECISION, path_title TEXT, path_artist TEXT, path_album TEXT, path_year INT, path_track_number INT, norm_title TEXT, norm_artist TEXT, norm_album TEXT, norm_year INT, norm_track_number INT, norm_genre TEXT, norm_featured_artists TEXT, confidence DOUBLE PRECISION, llm_notes TEXT, error_message TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE TABLE track_artists ( id BIGSERIAL PRIMARY KEY, track_id BIGINT NOT NULL REFERENCES tracks(id) ON DELETE CASCADE, artist_id BIGINT NOT NULL REFERENCES artists(id) ON DELETE CASCADE, role TEXT NOT NULL DEFAULT 'featured', UNIQUE (track_id, artist_id, role) ); -- Indexes CREATE INDEX idx_artists_name_trgm ON artists USING gin (name gin_trgm_ops); CREATE INDEX idx_albums_name_trgm ON albums USING gin (name gin_trgm_ops); CREATE INDEX idx_tracks_file_hash ON tracks (file_hash); CREATE INDEX idx_pending_status ON pending_tracks (status); CREATE INDEX idx_pending_file_hash ON pending_tracks (file_hash); CREATE INDEX idx_track_artists_track ON track_artists (track_id); CREATE INDEX idx_track_artists_artist ON track_artists (artist_id);