Backend published auf signage/screen/{slug}/playlist-changed nach
Playlist-Mutationen (2s Debounce). Agent subscribed und fetcht
Playlist sofort (3s Debounce). 60s-Polling bleibt als Fallback.
Neue Packages: mqttnotifier (Backend), mqttsubscriber (Agent)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Die Transition-Logik in displayItem() setzte element.style.display = '',
wodurch die CSS-Klassen-Regel display:none wieder griff und alle
Content-Elemente (iframe, img, video) unsichtbar blieben.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Upload-Fortschrittsbalken per XHR mit Progress-Event
- Checkbox-Toggle statt Ja/Nein-Select für Enabled-Feld
- vars.yml Download-Button im Provisioning-Workflow
- Alle UX-Aufgaben in TODO.md abgehakt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Flash-Messages nach allen Manage-Aktionen (Upload, Löschen, Speichern, Hinzufügen)
- Screen-Online/Offline-Status als farbiger Punkt in Admin-Tabelle
- overflow-x Wrapper für alle Tabellen (Admin, Playlist, Medienbibliothek)
- Navbar-Burger für mobile Viewports in Admin und Manage
- UX-Gestaltungsplan als Sektion in TODO.md eingetragen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Player-UI: Content-Type-Handling (image/video/web statt alles-iframe),
Fast-Retry-Polling beim Start, Splash wird korrekt ausgeblendet,
Fallback-Anzeige bei X-Frame-Options-Blockade
- Dev-Display: Backend-URL auf 192.168.64.1 für Multipass-Netz korrigiert
- Media-Upload: Typ wird aus MIME-Type abgeleitet statt blind aus Formular
- TODO: Daten-Bug dokumentiert
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
README, DEVELOPMENT und TODO spiegelten noch den Stand vor Ebene 1+2 wider.
Checkboxen in TODO von ~18 auf ~70 aktualisiert, drei neue API-Dokumentationsdateien ergänzt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- POST /admin/screens/provision: legt Screen in DB an (Upsert) und zeigt
eine 5-Schritt-Seite mit kopierbaren Code-Blöcken:
1. inventory.yml Eintrag
2. host_vars/{slug}/vars.yml Inhalt
3. ssh-copy-id Befehl
4. ansible-playbook Befehl (mit Vault-Passwort-Hinweis)
5. Link zur Playlist-Verwaltung
- Admin-Formular: IP-Adresse + SSH-User Felder ergänzt
- Altes "nur anlegen"-Formular als aufklappbaren Details-Block versteckt
- Clipboard-Copy-Buttons für jeden Code-Block
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend-Container mit Dockerfile aus server/backend/
- Postgres healthcheck damit Backend erst startet wenn DB bereit ist
- uploads-Volume für hochgeladene Dateien
- MORZ_INFOBOARD_DATABASE_URL zeigt auf postgres-Service
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Agent loggt im Normalfall nichts mehr (kein heartbeat_tick, kein
mqtt_heartbeat_sent, kein status_report_sent)
- nur noch Fehler und Zustandsaenderungen werden geloggt
- Ansible: journald auf Storage=volatile + RuntimeMaxUse=20M (RAM-only,
automatisches Verdraengen alter Eintraege bei vollem Puffer)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rolle signage_player: baut Binary lokal (linux/arm64), deployt es,
schreibt config.json per Template, installiert und aktiviert systemd-Unit
- inventory.yml mit Host info10 (10.0.0.200)
- group_vars/signage_players: getrennte vars.yml (oeffentlich) und
vault.yml (Secrets, gitignored) fuer MQTT-Credentials
- host_vars/info10: ansible_host, ansible_user, screen_id
- site.yml zeigt auf signage_players-Gruppe und signage_player-Rolle
- Binaries und vault.yml in .gitignore
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- DELETE /api/v1/screens/{screenId}/status loescht einzelne Screen-Eintraege
- /api/v1/meta listet jetzt 5 Tools inkl. screen-status-delete und diagnostic_ui-Pfade
- filePlayerStatusStore persistiert den Status-Store atomar in einer JSON-Datei
- MORZ_INFOBOARD_STATUS_STORE_PATH aktiviert die Datei-Persistenz (leer = In-Memory)
- Integration-Test deckt den vollstaendigen Lifecycle: POST -> list -> HTML -> JSON -> DELETE -> 404 ab
- DEVELOPMENT.md beschreibt End-to-End-Entwicklungstest und neue Env-Variable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /api/v1/screens/status und GET /status akzeptieren jetzt
derived_state=online|degraded|offline zum direkten Filtern nach der
serverseitig abgeleiteten Diagnoseeinschaetzung. Erlaubte Werte sind
online, degraded und offline; unknown ist explizit nicht erlaubt, da
derived_state immer auf einen der drei Werte abgebildet wird.
Abgrenzung zu server_connectivity: derived_state filtert nach dem
zusammengefassten Zustand (stale + connectivity + status), waehrend
server_connectivity nur den gemeldeten Connectivity-Wert betrifft.
Beide Filter koennen kombiniert werden.
Tests: FiltersByDerivedState, RejectsInvalidDerivedState
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /api/v1/screens/status und GET /status akzeptieren jetzt q=<substring>
zum Filtern der Ergebnisliste nach ScreenID. Der Vergleich ist case-
insensitiv. Leerer Wert bedeutet kein Filter; jeder andere String ist gueltig
(keine Validierung noetig). Die Summary-Counts bleiben unveraendert und
beschreiben weiterhin den gesamten Store-Bestand.
Die Quick-Filter auf /status behalten den aktuellen q-Wert beim Klick, damit
der Textfilter nicht verloren geht wenn man z.B. von "All screens" auf
"Stale reports" wechselt.
Tests: FiltersByScreenIDSubstring, ScreenIDFilterIsCaseInsensitive
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-Refresh auf GET /status/{screenId}:
screenDetailPageData bekommt RefreshSeconds (wie statusPageData). Das
Detail-Template rendert das Meta-Tag analog zur Uebersichtsseite mit
denselben 15 Sekunden, damit ein Screen seinen Zustand (z.B. fresh ->
stale, connectivity-Wechsel) auch ohne manuellen Reload sichtbar macht.
Test: meta-refresh-Tag jetzt in TestRouterScreenDetailPageRoute geprueft.
DRY-Refactor: Fehlermeldungen vereinheitlicht:
overviewQueryErrorMessage und overviewQueryErrorCode sind jetzt in
playerstatus.go definiert -- dort wo auch die Validierungslogik lebt.
writeOverviewQueryError delegiert vollstaendig an beide Helper statt
die Meldungen selbst zu duplizieren. Die vorherige Kopie in statuspage.go
mit abweichenden Satzendezeichen und Grossschreibung wurde entfernt.
Beide Fehlerpfade (JSON und HTML) nutzen jetzt exakt dieselben
Meldungstexte.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drei eng zusammenhaengende Aenderungen in einem Commit, da sie dieselbe
Template-Infrastruktur teilen und gemeinsam die HTML-Diagnoseansicht
abrunden:
1. CSS-Extraktion (Verbesserung, kein Verhalten geaendert)
Das bisherige Inline-CSS wurde in die Konstante statusPageCSS
ausgelagert. statusPageCSSBlock injiziert es per String-Konkatenation
in alle Templates, sodass kein Template-Inheritance-Mechanismus
benoetigt wird und jede Seite eigenstaendig ausfuehrbar bleibt.
2. GET /status/{screenId} -- neue HTML-Detailseite
Zeigt den letzten bekannten Datensatz eines einzelnen Screens:
Derived State, Player-Status, Connectivity und Frische als
Summary-Cards; Timing- und Endpoints-Details in aufgeraeuemten
Key-Value-Tabellen. Verlinkung zurueck auf /status und auf den
bestehenden JSON-Endpunkt. Bei unbekanntem Screen: 404 mit HTML-
Fehlerseite und Rueck-Link.
Route: GET /status/{screenId}
3. HTML-Fehlerseite fuer /status bei ungueltigen Query-Parametern
Bisher lieferte handleStatusPage einen rohen JSON-Fehler, wenn
z.B. ?stale=banana uebergeben wurde -- inkongruent fuer einen
HTML-Endpunkt. writeStatusPageQueryError rendert jetzt dasselbe
statusPageErrorTemplate wie der Not-Found-Fall der Detailseite
und gibt text/html mit 400 zurueck.
Neue Tests (router_test.go):
- ScreenDetailPageRoute: prueft Inhalt, Links, Content-Type
- ScreenDetailPageNotFound: prueft 404 + HTML + Rueck-Link
- StatusPageRejectsInvalidQueryParams: prueft jetzt auch text/html
fuer alle Fehlerfaelle
Docs (PLAYER-STATUS-HTTP.md):
- Query-Parameter-Validierung mit erlaubten Werten und Fehlercodes
- Neue /status/{screenId}-Seite und HTML-Fehlerseiten dokumentiert
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bisher wurden ungueltige Werte fuer server_connectivity und stale im
Listing-Endpunkt und auf der Statusseite stillschweigend ignoriert bzw.
fuehrten zu leeren Ergebnissen ohne Fehlermeldung. Beide Parameter werden
jetzt explizit auf erlaubte Werte geprueft und liefern bei ungueltiger
Eingabe einen 400-Fehler mit beschreibendem error_code – konsistent mit
der bestehenden Validierung fuer updated_since und limit.
Neue Tests (playerstatus_test.go):
- RejectsInvalidServerConnectivity
- RejectsInvalidStale
- RejectsInvalidUpdatedSince
- RejectsInvalidLimit
Neue Tests (router_test.go):
- StatusPageRejectsInvalidQueryParams (table-driven, alle 4 Faelle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>