PostgreSQL 16. Das Schema wird beim ersten Start aus
musicvoting/backend/setup.sql initialisiert (Hibernate generiert es nicht).
Tabellen#
party#
Eine Party (Top-Level-Aggregat).
| Spalte | Typ | Hinweise |
|---|---|---|
id | VARCHAR PK | Party-ID |
provider_kind | VARCHAR NOT NULL | spotify / youtube |
created_at | TIMESTAMPTZ | Default NOW() |
pin | VARCHAR(5) | Gast-PIN |
host_pin | VARCHAR(5) | Host-PIN |
ended_at | TIMESTAMPTZ | NULL = aktiv |
currently_playing_entry_id | UUID → queue_entry(id) | aktueller Song; ON DELETE SET NULL |
playback_started_at | TIMESTAMPTZ | Basis für DB-berechneten Fortschritt |
paused_position_ms | BIGINT | Position bei Pause |
queue_entry#
Ein Song in der Warteschlange einer Party.
| Spalte | Typ | Hinweise |
|---|---|---|
id | UUID PK | Default gen_random_uuid() |
party_id | VARCHAR → party(id) | ON DELETE CASCADE |
track_uri | VARCHAR NOT NULL | Spotify-URI |
track_name | VARCHAR NOT NULL | |
artist_name | VARCHAR NOT NULL | |
album_name | VARCHAR | |
image_url | TEXT | Cover |
duration_ms | INTEGER | |
added_at | TIMESTAMPTZ | Default NOW() – FIFO-Tiebreak |
UNIQUE (party_id, track_uri) → keine Duplikate |
vote#
Ein Like eines Geräts für einen Queue-Eintrag.
| Spalte | Typ | Hinweise |
|---|---|---|
id | UUID PK | |
queue_entry_id | UUID → queue_entry(id) | ON DELETE CASCADE |
device_id | VARCHAR NOT NULL | anonyme Geräte-Identität |
voted_at | TIMESTAMPTZ | Default NOW() |
UNIQUE (queue_entry_id, device_id) → ein Like pro Gerät/Song |
Beziehungen#
party → queue_entry:ON DELETE CASCADE(Party beenden leert die Queue).queue_entry → vote:ON DELETE CASCADE.party.currently_playing_entry_id → queue_entry:ON DELETE SET NULL(zirkuläre Referenz, wird insetup.sqlperALTER TABLEnach Anlegen vonqueue_entryergänzt).
Eindeutige PINs nur für aktive Partys#
CREATE UNIQUE INDEX party_pin_active_idx ON party (pin) WHERE ended_at IS NULL;
CREATE UNIQUE INDEX party_host_pin_active_idx ON party (host_pin) WHERE ended_at IS NULL;
Partielle Unique-Indizes: PINs müssen nur unter aktiven Partys eindeutig sein; eine beendete Party gibt ihren PIN-Slot wieder frei.
Sortierung der Queue#
Nicht im Schema, sondern beim Lesen berechnet: Likes desc, bei Gleichstand added_at
aufsteigend (FIFO). Mit ?deviceId= liefert GET /track/queue zusätzlich hasVoted pro Eintrag.
Aufräum-Lebenszyklus#
Über den PartyExpiryScheduler:
- Auto-Ende nach 2 Tagen: Queue leeren, Tokens löschen,
ended_atsetzen,party-ended-Event. - Purge nach 1 Monat (
ended_at):party-Zeile löschen →queue_entry/votekaskadieren.