Überblick
#MusicVoting besteht aus einem Quarkus-Backend, einem Angular-Frontend (mit drei
Rollen-Ansichten), einer PostgreSQL-Datenbank und einer optionalen SwiftUI-iOS-App.
Die Musik wird über den Spotify Web Playback SDK im Browser des Monitors/TVs abgespielt.
Komponenten
#| Komponente | Technologie | Aufgabe |
|---|
| Backend | Quarkus (Java 21), JAX-RS, SSE | API, Party-Lebenszyklus, Provider-Anbindung |
| Frontend | Angular | Guest-, Host- und TV-Ansichten |
| Datenbank | PostgreSQL 16, Hibernate ORM Panache | Persistenz von Party, Queue, Votes |
| Mobile | SwiftUI (iOS) | Native Guest- und Admin-Ansicht (optional) |
| Provider | Spotify Web API + Web Playback SDK | Suche und Wiedergabe |
Wichtige Architekturentscheidungen
#- DB ist die Quelle der Wahrheit. Queue, aktueller Track und Fortschritt kommen aus der
Datenbank, nicht aus Spotify.
GET /track/current ruft die Spotify-„currently-playing“-API
nicht auf (siehe Datenbankschema und die Playback-Spec). Party vs. PartyEntity. Party ist die In-Memory-Repräsentation in der PartyRegistry,
PartyEntity die Panache-Entity der DB-Tabelle party. Sie sind bewusst getrennt und werden
nicht zusammengeführt.- Restart-fest. Endpunkte lösen eine Party bei Bedarf aus der DB auf, wenn sie nicht in der
In-Memory-Registry liegt – ein Backend-Neustart führt nicht zu 404. Auch der Spotify-Login
überlebt, weil der Refresh-Token in der DB liegt.
- Ein Provider pro Party. Über
ProviderKind (Spotify implementiert, YouTube vorgesehen),
abstrahiert durch das MusicProvider-Interface und die MusicProviderFactory. - Live-Updates über SSE, nicht über Polling (siehe Realtime / SSE).
- Die Musik geht nie aus. Würde die Queue leer, füllt das Backend automatisch einen Song nach
(Standard-Playlist → ähnliche Songs → Top-Charts → Suche). Gast-Songs haben immer Vorrang.
- Der Player treibt das Autoplay. Nur die Startpage kennt das echte Songende (Web Playback SDK)
und ruft
/track/next auf – über drei unabhängige Erkennungswege, pro Song genau einmal.
Datenfluss (Beispiel: Gast fügt einen Song hinzu)
#- Gast sucht (
GET /api/party/{id}/track/search?q=…) → Spotify-Treffer. - Gast tippt „+“ →
POST /api/party/{id}/track/addToPlaylist. - Backend schreibt eine
queue_entry-Zeile und sendet ein queue-updated-SSE-Event. - Alle verbundenen Clients (TV, Host, andere Gäste) laden die Queue neu.
Hintergrundprozesse
#PartyExpiryScheduler beendet Partys automatisch nach 2 Tagen und löscht beendete Partys
1 Monat nach endedAt (siehe Datenbankschema).
Betriebsvarianten
#| Variante | Wo | Beschreibung |
|---|
| Kubernetes | HTL-Cluster | Produktiv, per GitHub Actions (siehe CI/CD) |
deployment/server/ | eigener Server | Docker Compose + Caddy (HTTPS via Let’s Encrypt) |
deployment/compose/ | lokal | fertige GHCR-Images + PostgreSQL |
| Quellcode | lokal | quarkus:dev + npm start + DB aus musicvoting/docker-compose.yaml |