b2in/dev/displays-11-05-2026/01-status.md
Kevin Adametz 6c6d683b9a Display CMS Optimierungen 29-05-2026
- Mediathek: Video-Vorschaubilder statt Icons (FFmpeg-Thumbnails + Backfill-Command), Kategorie "Sonstiges"
- B2in Media-Picker zeigt alle Medientypen, Typ wird automatisch erkannt; Thumbnail-Preview vor allen Medien-URL-Feldern
- B2in Marke/Footer: Footer ein/aus, Logo+Claim frei positionierbar (Ecken) mit Constraints, separate Anzeige-Schalter
- Angebote-Modul dynamisch: kein Slide-Typ mehr, einheitliches Detail-Layout mit ein-/ausblendbaren Bloecken, Logo/Brand pro Slide, Streichpreis-Option
- Player: leere Module stoppen Endlosschleife, dynamische Layout-Anpassung bei verstecktem Footer/Header
- Fix: Script-Ladereihenfolge (Livewire vor Flux), entfernte stale public/flux/flux.js, Modal-Crash beim Aktualisieren behoben

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 15:57:33 +00:00

23 KiB
Raw Blame History

Cabinet Displays Implementierungs-Status

Konzept: siehe 00-entwicklungskonzept.md. Diese Datei wird je Phase fortgeschrieben.

Übersicht

Phase Inhalt Status
0 Konzept-Freigabe 11.05.2026
1 Datenmodell + Daten-Migration 11.05.2026
2 API & Player (config + preview + module preview) 12.05.2026
3 Admin-UI: Displays-Liste mit Live/Entwurf 12.05.2026
4 Admin-UI: Entwurf-Editor (Iframe-Vorschau) 12.05.2026
5 Modul-Editor: 3-stufige Vorschau 12.05.2026
6 Umbenennung Versionen → Module + Onboarding 12.05.2026
7 Aufräumen + alte Pivot-Tabelle entfernen 13.05.2026
8 Review: Fehler / Optimierungen / Erweiterungen 🟡 29.05.2026 (Befundaufnahme)

Legende: fertig · 🟡 in Arbeit · offen · blockiert


Defaults aus §10 (Konzept-Freigabe vom 11.05.2026)

Der User hat das Konzept freigegeben. Da keine abweichende Wahl getroffen wurde, gelten die im Konzept empfohlenen Defaults:

  1. Test-Display: genau 1 Datensatz per Seeder angelegt, weitere können bei Bedarf erstellt werden.
  2. Entwurf verwerfen: löscht die Draft-Playlist. Beim erneuten Anlegen wird die Reihenfolge aus Live kopiert.
  3. Module bleiben shared: Modul-Änderungen wirken sofort auf alle Displays, die das Modul live einsetzen. Modul-eigene Versionierung ist out of scope.
  4. Polling-Mechanismus der Player (alle 60 s) reicht; kein Push-Refresh.

Live-Roll-out Hinweise

Auf dem Live-Server reicht für jede Phase:

git pull
composer install --no-dev --optimize-autoloader   # falls neue Composer-Deps
php artisan migrate --force                       # bringt neue Migrations ein
php artisan config:cache                          # Caches frisch
php artisan view:clear

Alle strukturellen Änderungen liegen ausschließlich in database/migrations/ als datierte Dateien vor auf der Live-DB reicht php artisan migrate --force. Datenverlust gibt es nicht: bestehende Pivot-Daten aus display_display_version werden in die neue Struktur überführt.


Phase 1 Datenmodell

Ziel: neue Tabellen display_playlists + display_playlist_items, erweiterte displays-Spalten (is_test, preview_token), vollständige verlustfreie Migration der heutigen Pivot-Daten.

Dateien:

  • database/migrations/2026_05_11_*_create_display_playlists_table.php
  • database/migrations/2026_05_11_*_create_display_playlist_items_table.php
  • database/migrations/2026_05_11_*_add_test_flag_and_preview_token_to_displays_table.php
  • database/migrations/2026_05_11_*_migrate_pivot_to_display_playlists.php
  • app/Models/DisplayPlaylist.php
  • app/Models/DisplayPlaylistItem.php
  • app/Models/Display.php (neue Relations, alte versions() bleibt kompatibel)
  • database/factories/DisplayPlaylistFactory.php
  • database/factories/DisplayPlaylistItemFactory.php
  • tests/Feature/DisplayPlaylistMigrationTest.php

Wichtig: Die alte Tabelle display_display_version und die Relation Display::versions() bleiben in dieser Phase erhalten (Removal erst in Phase 7), damit keine bestehenden Funktionen brechen.

Stand 11.05.2026 abgeschlossen

Gelieferte Migrationen (Live-Reihenfolge)

Reihenfolge Datei Zweck
1 2026_05_11_113300_add_test_flag_and_preview_token_to_displays_table.php displays.is_test + displays.preview_token (unique)
2 2026_05_11_113310_create_display_playlists_table.php Neue Tabelle für Live/Entwurfs-Bespielung pro Display
3 2026_05_11_113320_create_display_playlist_items_table.php Geordnete Module pro Bespielung
4 2026_05_11_113330_migrate_pivot_to_display_playlists.php Übernimmt bestehende Pivot-Daten als Published-Playlists (idempotent)

Die Daten-Migration ist idempotent wenn pro Display bereits eine Published-Playlist existiert, wird sie übersprungen. Die alte Pivot-Tabelle display_display_version bleibt erhalten.

Neue Modelle & Relations

  • App\Models\DisplayPlaylist mit Scopes published()/draft(), Relation modules() (geordnet)
  • App\Models\DisplayPlaylistItem
  • App\Models\Display erweitert um playlists(), livePlaylist(), draftPlaylist(), liveModules(), ensurePreviewToken()
  • Display::versions() ist als @deprecated markiert, bleibt aber funktional

Tests

tests/Feature/DisplayPlaylistMigrationTest.php   11 passed
tests/Feature/DisplayListTest.php                ok
tests/Feature/DisplayVersionTest.php             ok
tests/Feature/DisplayVersionApiTest.php          ok
tests/Feature/DisplayMediaTest.php               ok

Insgesamt 67 grüne Tests rund um Displays (11 neu + 56 bestand). Keine Linter-Warnungen, Pint clean.

Roll-out auf Live

git pull
php artisan migrate --force

Reihenfolge stimmt durch die Timestamps automatisch. Daten-Migration ist idempotent, kann beliebig oft laufen.


Phase 2 API & Player

Ziel: bestehende Player-Konfiguration liest künftig aus der Published-Playlist. Zusätzlich gibt es öffentliche Vorschau-Endpunkte für Display-Entwürfe per Token und einzelne Module. Das JSON-Schema bleibt rückwärtskompatibel (playlist[], updated_at).

Stand 12.05.2026 abgeschlossen

Geplante/aktuelle Dateien:

  • app/Services/DisplayPlaylistConfigBuilder.php
  • app/Http/Controllers/Api/DisplayVersionApiController.php
  • app/Http/Controllers/Api/DisplayPreviewController.php
  • app/Http/Controllers/Api/ModulePreviewController.php
  • routes/domains.php
  • public/_cabinet/display/index.html
  • tests/Feature/DisplayVersionApiTest.php

Umsetzung:

  • Live-Config: GET /api/display/{display}/config liest livePlaylist
  • Live-Check: GET /api/display/{display}/check bezieht sich auf die Published-Playlist
  • Draft-Preview: GET /api/display/preview/{token} liefert die Draft-Playlist
  • Modul-Preview: GET /api/display/module/{module}/preview liefert ein Einzelmodul im Player-Schema
  • Player-Preview-Seiten: /preview/{token} und /preview/module/{module}

Tests

tests/Feature/DisplayVersionApiTest.php          13 passed
tests/Feature/DisplayPlaylistMigrationTest.php   ok

Insgesamt 24 grüne Tests für Phase 2 und die Playlist-Grundlage. Pint clean.

Hinweis

In der lokalen Umgebung musste der alte Route-Cache einmal mit php artisan route:clear geleert werden, damit die neuen Preview-Routen sichtbar wurden. Für Live bleibt beim Roll-out php artisan config:cache bzw. ein frischer Route-/Config-Cache relevant.


Phase 3 Admin-UI: Displays-Liste mit Live/Entwurf

Ziel: Die Display-Liste zeigt pro physischem Display den Live-Stand und optionalen Entwurf nebeneinander. Entwürfe können aus Live angelegt, verworfen und veröffentlicht werden. Das Test-Display ist sichtbar hervorgehoben.

Stand 12.05.2026 abgeschlossen

Dateien:

  • app/Livewire/Admin/Cms/DisplayList.php
  • resources/views/livewire/admin/cms/display-list.blade.php
  • tests/Feature/DisplayListTest.php

Umsetzung:

  • Display-Karten zeigen Live und Entwurf als zwei getrennte Spalten
  • Der globale Bearbeiten-Button im Display-Kopf wurde entfernt; Live und Entwurf haben jeweils eigene Bearbeiten-Buttons
  • Die Live-Card zeigt die Player-URL direkt als kopierbares Feld; der API-Link ist weniger prominent unten rechts platziert
  • Live-Spalte nutzt livePlaylist.modules
  • Entwurf-Spalte nutzt draftPlaylist.modules
  • Live-Bearbeitung speichert nur die Published-Playlist
  • Entwurfs-Bearbeitung speichert nur die Draft-Playlist und erzeugt bei Bedarf den Preview-Token
  • Die Modul-Auswahl im Bearbeiten-Dialog zeigt nur noch Module, die in der aktuell bearbeiteten Bespielung noch nicht enthalten sind
  • Der Plus-Button fügt auch dann das erste verfügbare Modul hinzu, wenn der Select-Wert wegen des Platzhalters noch nicht explizit gesetzt wurde
  • Aktion Entwurf anlegen kopiert den aktuellen Live-Stand und erzeugt bei Bedarf den Preview-Token
  • Aktion Veröffentlichen ersetzt die Published-Playlist durch den Draft und synchronisiert die alte Pivot-Tabelle weiterhin kompatibel
  • Aktion Verwerfen löscht die Draft-Playlist
  • Test-Displays (is_test) werden in der Liste hervorgehoben
  • Der bestehende Bearbeiten-Dialog pflegt die Live-Bespielung weiter und synchronisiert bis Phase 7 zusätzlich display_display_version

Tests

tests/Feature/DisplayListTest.php   14 passed

Die neuen Tests decken Draft anlegen, verwerfen, veröffentlichen, getrennte Live-/Entwurfs-Bearbeitung, gefilterte Modul-Auswahl sowie die Darstellung von Live-/Entwurf-Modulen ab.


Phase 4 Admin-UI: Entwurf-Editor mit Iframe-Vorschau

Ziel: Beim Bearbeiten eines Entwurfs ist die Player-Vorschau direkt sichtbar. Moduländerungen im Entwurf werden sofort in die Draft-Playlist geschrieben und laden die Vorschau neu.

Stand 12.05.2026 abgeschlossen

Dateien:

  • app/Livewire/Admin/Cms/DisplayList.php
  • resources/views/livewire/admin/cms/display-list.blade.php
  • tests/Feature/DisplayListTest.php

Umsetzung:

  • Der Entwurfs-Editor zeigt rechts eine 9:16-Iframe-Vorschau
  • Die Iframe-Vorschau sitzt dauerhaft unterhalb der Aktualisieren-Aktion, damit sie im Desktop-Modal nicht mit dem Formular überlappt
  • Die Vorschau lädt /preview/{token} mit Cache-Bust-Parameter
  • Hinzufügen, Entfernen und Sortieren von Modulen persistiert bei Draft-Bearbeitung sofort in display_playlist_items
  • Nach jeder Moduländerung wird die Iframe-Vorschau per wire:key neu aufgebaut
  • Vollbild-Vorschau ist aus dem Editor heraus verlinkt

Tests

tests/Feature/DisplayListTest.php   21 passed

Die Tests decken das Rendern der Vorschau-URL und das sofortige Persistieren von Draft-Änderungen für Preview-Reloads ab.


Phase 5 Modul-Editor: 3-stufige Vorschau

Ziel: Module können beim Bearbeiten visuell geprüft werden: kleine Vorschau je Item, eingebettete Player-Vorschau und Vollbild-Vorschau.

Stand 12.05.2026 abgeschlossen

Dateien:

  • app/Livewire/Admin/Cms/DisplayVersionEditor.php
  • resources/views/livewire/admin/cms/display-version-editor.blade.php
  • resources/views/livewire/admin/cms/partials/version-editor-video.blade.php
  • resources/views/livewire/admin/cms/partials/version-editor-b2in.blade.php
  • resources/views/livewire/admin/cms/partials/version-editor-offers.blade.php
  • tests/Feature/DisplayVersionTest.php

Umsetzung:

  • Modul-Editor zeigt eine 9:16-Iframe-Vorschau über /preview/module/{module}
  • Vollbild-Vorschau ist direkt aus dem Editor verlinkt
  • Das Item-Bearbeiten-Modal ist breiter und zeigt unterhalb der Aktualisieren-Aktion ebenfalls eine 9:16-Iframe-Vorschau
  • Aktualisieren im Item-Bearbeiten-Modal schließt das Modal nicht mehr, sondern speichert den Inhalt und lädt die Iframe-Vorschau neu
  • Die Modal-Aktionen stehen unterhalb der Iframe-Vorschau und bieten Aktualisieren, Abbrechen und Schließen
  • Die Vorschau im Item-Bearbeiten-Modal nutzt eine eigene Item-Preview und zeigt nur den aktuell bearbeiteten Slide statt das komplette Modul
  • Der Display-Player rendert seinen Viewport strikt als 9:16-Fläche und skaliert Slide-, Footer- und QR-Elemente proportional zur Player-Fläche
  • Harte Player-Elemente wie B2in-Headerlogo/Claim/Footer/QR, Offers-Logo/Brandtext/QR-Labels und Video-Footer-QR-Label sind jetzt als Modul-Einstellungen im CMS pflegbar
  • Die Modul-Meta-Einstellungen sind als sichtbarer Block unterhalb der Media-/Slide-Liste editierbar; Angebote vererben Footer-Claim und Web/QR-URL automatisch an alle Slides
  • Logo-Alt-Text-Felder wurden aus den Modul-Meta-Einstellungen entfernt; Player nutzen weiterhin feste Fallback-Alt-Texte
  • Video-Display unterstützt Mediathek-Upload-URLs wie /storage/... ohne Legacy-assets/-Prefix
  • Die Display-Mediathek und der schnelle Media-Picker akzeptieren SVG-Dateien als Bild-Uploads
  • Änderungen an Name, Einstellungen, Items, Reihenfolge und Aktiv-Status laden die Modul-Vorschau neu
  • Video/Footer/Media/Slide-Listen zeigen Inline-Mini-Previews je Item; Slide-Previews sind größer dargestellt
  • Einzelmodul-Vorschau nutzt weiterhin den Player aus Phase 2

Phase 6 Umbenennung Versionen → Module + Onboarding

Ziel: Die Admin-UI verwendet den fachlich korrekten Begriff „Module“. Alte URLs wurden während der Übergangsphase per 301 weitergeleitet und in Phase 7 entfernt.

Stand 12.05.2026 abgeschlossen

Dateien:

  • routes/admin.php
  • app/Livewire/Admin/Cms/DisplayVersionList.php
  • resources/views/livewire/admin/cms/display-version-list.blade.php
  • resources/views/livewire/admin/cms/display-version-editor.blade.php
  • resources/views/livewire/admin/cms/display-dashboard.blade.php
  • resources/views/components/layouts/app/sidebar.blade.php
  • tests/Feature/DisplayVersionTest.php

Umsetzung:

  • Neue Routen: admin/cms/display-modules und admin/cms/display-modules/{displayVersion}/edit
  • Neue Routennamen: admin.cms.display-modules und admin.cms.display-module-edit
  • Alte display-versions-Routen waren während der Übergangsphase als 301-Redirects aktiv und wurden in Phase 7 entfernt
  • Sidebar, Dashboard, Listen- und Editor-Texte verwenden „Module“
  • Technische Modell-/Klassennamen bleiben bei DisplayVersion, da sie fachlich weiterhin die wiederverwendbaren Module abbilden

Tests

tests/Feature/DisplayVersionTest.php          ok
tests/Feature/DisplayVersionApiTest.php       ok
tests/Feature/DisplayListTest.php             ok
tests/Feature/DisplayPlaylistMigrationTest.php  ok

Insgesamt 64 grüne Tests für Phasen 5/6 und die angrenzenden Display-Flows. Pint clean.


Phase 7 Technisches Aufräumen & Optimierung

Ziel: Nach Stabilisierung des neuen Playlist-Flows wird die alte Pivot-Kompatibilität entfernt und der Modul-Editor weiter vereinheitlicht.

Stand 13.05.2026 umgesetzt

Dateien:

  • app/Models/Display.php
  • app/Models/DisplayVersion.php
  • app/Livewire/Admin/Cms/DisplayList.php
  • app/Console/Commands/MigrateLegacyDisplays.php
  • app/Support/DisplayModuleSettings.php
  • app/Services/DisplayPlaylistConfigBuilder.php
  • app/Livewire/Admin/Cms/DisplayVersionEditor.php
  • app/Livewire/Admin/Cms/DisplayVersionList.php
  • routes/admin.php
  • database/migrations/2026_05_13_103600_drop_display_display_version_table.php
  • resources/views/livewire/admin/cms/display-list.blade.php
  • resources/views/livewire/admin/cms/display-version-editor.blade.php
  • resources/views/livewire/admin/cms/partials/version-editor-video.blade.php

Umsetzung:

  • Alte Pivot-Tabelle display_display_version wird per Migration entfernt
  • Legacy-Relationen Display::versions() und DisplayVersion::displays() wurden entfernt
  • Display-Bearbeitung, Draft-Veröffentlichung und Legacy-Migrations-Command schreiben ausschließlich in display_playlists und display_playlist_items
  • Alte display-versions-Redirect-Routen wurden entfernt; die Admin-UI nutzt nur noch display-modules
  • Modul-Settings-Defaults liegen zentral in App\Support\DisplayModuleSettings und werden von Editor, Listen-Erstellung und API-Config-Builder gemeinsam genutzt
  • Admin-Iframes laden per loading="lazy" verzögert, um die parallelen Player-Vorschauen leichter zu halten
  • Video-Display-Items zeigen im Editor sichtbar an, ob die Quelle aus der Mediathek oder aus einem Legacy-Dateinamen kommt

Phase 8 Review 29.05.2026 (Befundaufnahme)

Geprüft wurden die drei Navigationspunkte:

  • admin/cms/display-media → Volt admin.cms.display-media-library
  • admin/cms/display-modulesApp\Livewire\Admin\Cms\DisplayVersionList (+ Editor DisplayVersionEditor)
  • admin/cms/displaysApp\Livewire\Admin\Cms\DisplayList

Vorgehen: Code-Review der Komponenten/Views/Services/Player + Laravel-Logs + DB-Stand. Eine Browser-Sichtprüfung war in dieser Session nicht möglich (Browser-MCP nicht verfügbar). Alle Befunde (#1#11) wurden inzwischen umgesetzt (Details je Punkt unten).

Aktueller Datenstand (DB): 5 Displays (davon 0 Test-Displays), 6 Module, 7 Playlists (5 Live + 2 Entwürfe), 13 Medien.

Tests: DisplayListTest, DisplayMediaTest, DisplayVersionTest, DisplayVersionApiTest, DisplayPlaylistMigrationTest95 passed (276 Assertions). Keine CMS-Fehler in storage/logs (vorhandene Log-Fehler betreffen unrelated immobilien-azizi-Routen).

🔴 Fehler (sollten behoben werden)

  1. Mediathek-Suche hebelt alle Filter aus. behoben 29.05.2026 In display-media-library.blade.php ($media-Computed) und in DisplayMediaPicker::resolveMediaItems() wurde die Suche als ->where('filename','like',…)->orWhere('title','like',…) ohne Gruppierung an die vorherigen when()-Filter gehängt. Durch SQL-Präzedenz (AND bindet stärker als OR) wurde die Query zu … AND filename LIKE … OR title LIKE …. Sobald gesucht wurde, wurden Typ-, Quelle-, Sammlungs- und (beim Picker) der active()-Filter ignoriert, sobald ein Treffer über title zustande kam. Behebung: Neuer gekapselter Scope DisplayMedia::scopeSearch() (Closure um filename/title), den Library und Picker gemeinsam nutzen. Tests: keeps preceding filters when combined with the search scope, search scope respects the active filter on the media picker in DisplayMediaTest.php.

  2. Inhalt-Bearbeiten reaktiviert deaktivierte Items. behoben 29.05.2026 In DisplayVersionEditor übergab loadItemContent() nur das content-Array an loadVideoContent()/loadFooterContent()/loadMediaContent()/loadSlideContent(). Alle vier setzten …IsActive = true fest das tatsächliche is_active des Items wurde nie geladen. Wer ein zuvor per Auge-Icon deaktiviertes Item öffnete und „Aktualisieren" klickte, hat es über getActiveFlag() ungewollt wieder aktiviert. Behebung: loadItemContent() reicht (bool) $item->is_active an die Loader durch, die es in die jeweilige …IsActive-Property schreiben. Test: editing an inactive item keeps it inactive in DisplayVersionTest.php.

🟡 Optimierungen / Aufräumen

  1. Toter Code im Video-Editor. behoben 29.05.2026 DisplayVersionEditor::loadAvailableVideos(), Property $availableVideos, der mount()-Aufruf und der ungenutzte Illuminate\Support\Facades\File-Import wurden entfernt (im aktiven Editor-Blade ungenutzt; das einzige Blade mit availableVideos gehört zur Legacy-CabinetDisplay). Spart den Dateisystem-Scan von public/_cabinet/assets bei jedem Editor-Aufruf.

  2. Modul-Löschen ohne Schutz. behoben 29.05.2026 DisplayVersionList::deleteVersion() ermittelt jetzt den displays_count (distinct Displays über Playlists) und blockiert das Löschen, solange das Modul in irgendeiner Bespielung (Live oder Entwurf) genutzt wird; es erscheint ein roter Flash-Hinweis mit Anzahl. Module ohne Nutzung lassen sich weiterhin löschen. Test: cannot delete a display version that is used by a playlist in DisplayVersionTest.php.

  3. Doppelte Such-Logik zwischen Library und Picker (siehe #1) → ein gemeinsamer Query-Scope DisplayMedia::scopeSearch(string $term) verhindert künftige Divergenz. erledigt 29.05.2026 (im Zuge von #1).

  4. Preview-Token bleibt nach Veröffentlichen bestehen. behoben 29.05.2026 DisplayList::publishDraft()/discardDraft() ließen displays.preview_token gesetzt, obwohl /preview/{token} danach 404 lieferte (kein Draft mehr); ein Rotations-Button fehlte ganz. Behebung: Neue Model-Methoden Display::rotatePreviewToken() und Display::clearPreviewToken(). publishDraft() und discardDraft() setzen den Token jetzt zurück (alter Link wird ungültig). Im Entwurf gibt es einen „Link erneuern"-Button (rotatePreviewToken() mit wire:confirm), der bei offenem Entwurf zugleich die Iframe-Vorschau aktualisiert. Tests: publishing a draft clears the preview token, can discard a draft playlist (erweitert) und can rotate the preview token of a draft in DisplayListTest.php.

🟠 Konfiguration / Dev-Umgebung

  1. Live-Vorschau zeigt im lokalen Dev auf die Produktion. behoben 29.05.2026 config/display.php player_url defaultete auf https://cabinet.b2in.eu/display, und DISPLAY_PLAYER_URL war in .env nicht gesetzt. In display-list.blade.php nutzten „Vorschau", „Live-URL zum Kopieren" und „Display-Übersicht öffnen" diese Produktions-URL, während die Entwurfs-„Test-URL" über url('/preview/…') lokal lief. Lokal sah man Live also den Produktionsstand, Entwurf aber lokale Daten inkonsistent und irreführend. Behebung: Player-Seite (public/_cabinet/display/) und die Display-API liegen auf der Portal-Domain, daher ist der Player lokal unter https://portal.b2in.test/_cabinet/display erreichbar (der Player ermittelt BASE_URL aus window.location.origin und ruft die API auf derselben Domain auf).
    • .env: DISPLAY_PLAYER_URL=https://portal.b2in.test/_cabinet/display gesetzt (Config-Cache geleert).
    • .env.example: dokumentiert (Live-Wert als Kommentar).
    • phpunit.xml: DISPLAY_PLAYER_URL=https://cabinet.b2in.eu/display gepinnt, damit die bestehenden URL-Tests (DisplayListTest, DisplayVersionApiTest) deterministisch gegen den Produktionswert prüfen, unabhängig von der lokalen .env.
    • Der Produktions-Fallback in config/display.php (und damit das Live-Verhalten) bleibt unverändert.

🟢 Erweiterungen / Verbesserungen (UX)

  1. Test-Display existiert nicht. behoben 29.05.2026 Neuer idempotenter Database\Seeders\TestDisplaySeeder legt genau ein Test-Display an (überspringt, falls schon vorhanden) und ist im DatabaseSeeder registriert. In der Dev-DB wurde das Test-Display angelegt. Tests: seeds exactly one test display, is idempotent and does not create a second test display in TestDisplaySeederTest.php.

  2. Externe Bilder ohne Thumbnail. behoben 29.05.2026 Grid, Listenansicht und Detail-Sidebar (display-media-library.blade.php) rendern externe Bilder jetzt direkt via <img src="{{ external_url }}"> (gemeinsame $thumbSrc-Logik: Upload-Thumbnail → sonst external_url). Nicht-Bild-Externe behalten das Link-Icon. Test: renders external image media with an inline thumbnail in DisplayMediaTest.php.

  3. Mediathek-Pagination ohne resetPage. behoben 29.05.2026 Die Volt-Komponente nutzt jetzt WithPagination und Update-Hooks (updatedSearch/updatedFilterType/updatedFilterSource/updatedFilterCollection), die bei jeder Filter-/Suchänderung resetPage() aufrufen. Test: resets pagination to page one when a filter changes in DisplayMediaTest.php.

  4. Modul-Hinzufügen nur einzeln. behoben 29.05.2026 Der Bespielungs-Dialog (display-list.blade.php) nutzt jetzt einen durchsuchbaren Flux-Listbox-Multi-Select (versionsToAdd) plus „Hinzufügen"-Button (addSelectedVersions()), der alle ausgewählten Module auf einmal übernimmt (Duplikate werden übersprungen). Die programmatische addVersion()-Methode bleibt für Einzel-Adds/Tests erhalten. Test: can add multiple modules to a playlist at once in DisplayListTest.php.

Empfohlene Reihenfolge

  1. #1 + #2 (echte Fehler, klein, mit Tests) → 2. #7 (Dev-Konfiguration, blockiert lokales Testen) → 3. #3/#4/#5/#6 (Aufräumen/Robustheit) → 4. #8#11 (UX-Erweiterungen). Jeder Punkt wird gemäß Projekt-Regeln mit Test abgesichert und mit Pint formatiert.

Stand 29.05.2026: Alle Befunde (#1#11) sind umgesetzt, getestet und mit Pint formatiert.