# Umsetzung Pressemitteilung bearbeiten: Titelbild, Rechte, Veröffentlichung Stand: 11.06.2026 Diese Notiz dokumentiert die zuletzt umgesetzten Anpassungen an der Bearbeitung von Pressemitteilungen im User Panel und an den parallel genutzten Admin-Formularen. ## Betroffener Bereich - Customer Create/Edit: `resources/views/livewire/customer/press-releases/create.blade.php` - Customer Edit: `resources/views/livewire/customer/press-releases/edit.blade.php` - Admin Create/Edit: `resources/views/livewire/admin/press-releases/create.blade.php`, `resources/views/livewire/admin/press-releases/edit.blade.php` - Show/Index (Customer + Admin) für die Termin-Anzeige: `resources/views/livewire/customer/press-releases/{show,index}.blade.php`, `resources/views/livewire/admin/press-releases/{show,index}.blade.php` - Model (Zeitzonen-Konstante + Accessoren): `app/Models/PressRelease.php` - Titelbild-Manager: `resources/views/livewire/components/press-release-images-manager.blade.php` - Platzhalter-Auswahl: `resources/views/livewire/components/press-release-placeholder-picker.blade.php` - Platzhalter-Dateien: `public/images/press-release-placeholders` - Layout-CSS: `resources/css/shared/hub-components.css` ## Titelbild-Platzhalter Die Platzhalter für Pressemitteilungs-Titelbilder wurden erweitert. - Die Varianten werden über `App\Enums\PressReleasePlaceholder` verwaltet. - Die SVG-Dateien liegen lokal unter `public/images/press-release-placeholders`. - Der Picker lädt die lokalen Varianten in `resources/views/livewire/components/press-release-placeholder-picker.blade.php`. - Das Modal wurde für mehr Varianten verbreitert und mit einer scrollbaren Grid-Darstellung versehen. Ziel: Wenn noch kein eigenes Titelbild vorhanden ist, kann ein optisch passender Platzhalter gewählt werden. ## Titelbild-Upload Der Upload wurde auf ein einzelnes Titelbild begrenzt. - Es kann vorerst nur ein Titelbild pro Pressemitteilung hochgeladen werden. - Wenn ein Titelbild vorhanden ist, wird die Platzhalter-Card ausgeblendet. - Das Upload-Formular wird ebenfalls ausgeblendet, solange ein Titelbild existiert. - Das vorhandene Titelbild wird in einer eigenen Bild-Card angezeigt. - In der Bild-Card werden Titel, Größe und Bildnachweis/Copyright angezeigt. - Das Titelbild kann gelöscht werden; danach erscheinen Platzhalter und Upload-Formular wieder. Das Upload-Formular ist einklappbar: - Im Ausgangszustand erscheint nur der Hinweis, dass ein Titelbild fehlt. - Über „Eigenes Titelbild hochladen" wird das Formular geöffnet. - Über „Abbrechen" wird das Formular wieder geschlossen und zurückgesetzt. ## Bildverarbeitung und Speicherverhalten Die Bildverarbeitung wurde auf die Titelbild-Nutzung optimiert. - Erlaubte Formate: JPG, PNG, WebP. - Maximale Dateigröße: 16 MB. - Nicht previewfähige Dateien wie TIFF lösen keine Livewire-Preview-Exception mehr aus; sie werden über die Validierung abgefangen. - Für Pressemitteilungsbilder wird eine Cover-Variante erzeugt: 1280 x 580 px. - Der kanonische Bildpfad zeigt auf die Cover-Variante. - Das Original wird nach der Variantenerzeugung gelöscht, um Speicherplatz zu sparen. - Breite und Höhe in der Oberfläche beziehen sich auf die gespeicherte Cover-Version, nicht auf das Original. Relevante Datei: `app/Services/Image/ImageService.php`. ## Lizenz- und Rechteformular Das Formular wurde an die Vorgaben aus `docs/user-admin/Lizenztyp Bildupload.md` angepasst. Erfasste Felder: - Titel / Alt-Text über das bestehende `title`-Feld. - Öffentlicher Bildnachweis über das bestehende `copyright`-Feld. - Urheber / Fotograf / Rechteinhaber über `author`. - Lizenztyp über `license_type`. - Lizenzdetails über `license_detail`. - Lizenz-URL über `license_url`. - Quelle / Fundstelle über `source_url`. - Personenrechte über `people_rights_status`. - Marken, Kunstwerke, geschützte Werke oder private Orte über `property_rights_status`. - Interne Notizen über `rights_notes`. - Rechtebestätigung über `rights_confirmed_at`. Lizenztypen: - Eigene Aufnahme - Creative-Commons-Lizenz - Agentur-/Stockbild-Lizenz - Vom Urheber / Fotografen freigegeben - Presse-/PR-Bild mit Nutzungsfreigabe - Gemeinfrei / Public Domain / CC0 - Sonstige Lizenz / Sondervereinbarung Wichtige Regeln: - „Bitte wählen" ist der Ausgangszustand. - „Unsicher" wurde aus den Auswahlmöglichkeiten entfernt. - Am Ende muss der Uploadende die Verantwortung für die Rechte bestätigen. - Creative-Commons-Lizenzen erfassen zusätzlich die konkrete CC-Variante. - CC-, Stock-/Agentur- und Presse-/PR-Lizenzen verlangen eine Lizenz- oder Nachweis-URL. - „Sonstige Lizenz / Sondervereinbarung" verlangt einen Pflicht-Freitext. - Risikohinweise werden bei eingeschränkten oder unklaren Lizenzfällen angezeigt. Relevante Dateien: - `app/Enums/ImageLicenseType.php` - `app/Models/PressReleaseImage.php` - `database/migrations/2026_06_10_154249_add_rights_detail_fields_to_press_release_images_table.php` - `resources/views/livewire/components/press-release-images-manager.blade.php` ## Veröffentlichung Die Veröffentlichungs-Box wurde vereinfacht. Sichtbar sind nur noch: - Sofort nach Freigabe - Geplanter Termin Embargo / Sperrfrist wurde in den Formularen aus der Oberfläche entfernt, weil es aktuell noch keine sinnvolle Anwendung im User-Flow gibt. Technisches Verhalten: - `scheduled_at` bleibt erhalten und wird weiterhin gespeichert. - `embargo_at` wird in den betroffenen Formularen nicht mehr gesetzt und beim Speichern auf `null` geführt. - Für den geplanten Termin wird `flux:date-picker` für das Datum verwendet. - Für die Uhrzeit wird `flux:time-picker` verwendet. - Intern werden Datum und Uhrzeit wieder zu `scheduledAt` kombiniert. - Der geplante Termin muss mindestens 5 Minuten in der Zukunft liegen. - Bei zu frühem Termin wird direkt ein Fehler gesetzt; beim Speichern greift die Validierung ebenfalls. Betroffene Properties: - `scheduledDate` - `scheduledTime` - `scheduledAt` ## Zeitzonen-Handling für geplante Veröffentlichung Stand: 11.06.2026 (nachgezogen) Die Anwendung läuft serverseitig in UTC (`config/app.php` → `timezone = 'UTC'`). Geplante Termine werden aber von Redaktion und Kunden in **deutscher Zeit** gedacht. Vorher wurde die im Formular eingegebene Uhrzeit naiv als UTC interpretiert, wodurch die Veröffentlichung um den Berlin-Offset (im Sommer +2 h) verschoben stattfand. Das ist behoben. Grundprinzip: - Eingabe und Anzeige erfolgen in **Europe/Berlin**. - Gespeichert wird weiterhin **UTC**. - Wichtig: Laravel konvertiert beim Speichern **nicht** automatisch nach UTC. Deshalb wird der eingegebene Wert beim Parsen explizit als Berlin interpretiert und mit `->utc()` umgewandelt; beim Laden wird umgekehrt von UTC nach Berlin gewandelt. Zentrale Stelle: - `App\Models\PressRelease::DISPLAY_TIMEZONE` (`'Europe/Berlin'`) ist die Single Source of Truth. - `PressRelease::scheduledAtLocal()` und `PressRelease::embargoAtLocal()` liefern die Termine in der Anzeige-Zeitzone für alle Views. Verhalten in den Formularen (Customer **und** Admin, Create **und** Edit): - Helper `scheduledAtUtc()`: parst die naiven Eingabefelder als Berlin und gibt den UTC-Zeitpunkt für die Speicherung zurück. - Die „mind. 5 Minuten in der Zukunft"-Prüfung läuft jetzt über eine zeitzonenbewusste Closure-Regel statt über die naive `after:`-Regel. - Beim Bearbeiten (`mount`) wird `scheduled_at` von UTC nach Berlin gewandelt, bevor Datum/Uhrzeit in die Eingabefelder gefüllt werden. Anzeige (lokalisiert auf Berlin): - Customer-Show/-Index und Admin-Show/-Index: geplanter Termin und Embargo werden über `scheduledAtLocal()` / `embargoAtLocal()` ausgegeben. Bewusst (noch) nicht umgestellt: - `published_at`, `created_at` und die Status-Log-Zeitstempel werden weiterhin in UTC angezeigt. Eine vollständige Anzeige-Lokalisierung dieser Felder ist als Folgeschritt vorgesehen. ## Aufräumung: Scheduling-Logik und Queries Im Zuge der Zeitzonen-Umstellung wurden zwei Altlasten in allen vier PM-Formularen bereinigt: - **Doppelte Termin-Synchronisierung entfernt:** Die Termin-Logik lief vorher sowohl im generischen `updated()`-Hook als auch in den spezifischen `updated{PublishMode,ScheduledDate,ScheduledTime}`-Hooks – also doppelt. `updated()` enthält jetzt nur noch die generische Re-Validierung bereits fehlerhafter Felder; die Synchronisierung liegt ausschließlich in den spezifischen Hooks. - **Redundante Queries reduziert:** Im Customer-Edit wird die geladene Pressemitteilung pro Request memoisiert (`mount()`, `with()` und `save()` greifen sonst jeweils mit einer eigenen Query auf dieselbe PM zu). ## Responsive Layout Das Layout der Pressemitteilungsformulare wurde entkoppelt von der globalen Sidebar-Logik. Die globale Flux-Sidebar bleibt im stabilen Standardzustand: - `flux:sidebar sticky stashable` - Header- und Toggle-Sichtbarkeit weiter über `lg:hidden` Das eigentliche Formularlayout wird über eigene Klassen gesteuert: - `.pr-editor-layout` - `.pr-editor-side` Regel in `resources/css/shared/hub-components.css`: ```css @media (min-width: 1180px) { .pr-editor-layout { grid-template-columns: minmax(0, 1fr) 360px; } .pr-editor-side { position: sticky; top: 1rem; } } ``` Verhalten: - Unter 1180 px steht die rechte Formularbox unterhalb des Hauptinhalts. - Ab 1180 px steht die rechte Formularbox wieder rechts. - Die rechte Box wird ab 1180 px sticky. - Die globale linke Navigation bleibt davon unberührt. ## Button-Varianten Sekundäre `variant="ghost"`-Buttons in Blade-Views wurden breit auf `variant="filled"` umgestellt, weil die Ghost-Buttons optisch zu wenig als Buttons erkennbar waren. Umfang: - Alle Blade-Views unter `resources/views` wurden auf verbleibende `variant="ghost"` geprüft. - Markdown-Dokumentation wurde dabei nicht als UI geändert. ## Tests und Verifikation Ergänzte bzw. angepasste Tests: - `tests/Feature/PressReleasePlaceholderTest.php` - `tests/Feature/PressReleaseImageLicenseTest.php` - `tests/Feature/CustomerPressReleaseSchedulingFormTest.php` - `tests/Feature/Admin/AdminPressReleaseSchedulingTest.php` Für die Zeitzonen-Umstellung zusätzlich angepasst (Assertions auf Berlin-Werte umgestellt): - `tests/Feature/PressReleaseShowPhase8aTest.php` - `tests/Feature/Admin/AdminPressReleaseShowTest.php` Zuletzt erfolgreich ausgeführte Checks: - `php artisan test --compact tests/Feature/CustomerPressReleaseSchedulingFormTest.php tests/Feature/Admin/AdminPressReleaseSchedulingTest.php tests/Feature/Admin/AdminPressReleaseShowTest.php tests/Feature/PressReleaseShowPhase8aTest.php tests/Feature/PressReleaseIndexPhase8bTest.php` - `vendor/bin/pint --dirty --format agent` - Volle Suite: 400 passed (die zwei roten Tests `PressReleaseImageApiTest` und `CustomerPressReleaseCreatePhase7Test` sind vorbestehende, unabhängige WIP- Failures – per Stash-Test verifiziert, dass sie auch ohne diese Änderungen scheitern). Vorher zusätzlich grün gelaufen: - `php artisan test --compact tests/Feature/PressReleasePlaceholderTest.php tests/Feature/PressReleaseImageLicenseTest.php tests/Feature/CustomerPressReleaseEditPhase7Test.php` - Phase-8-nahe Show-/Index-/Attachment-/Admin-Tests. ## Bewusst noch nicht umgesetzt - Optionaler Upload von Lizenznachweisen oder Freigabe-Dokumenten. - Reaktivierung des separaten Anhang-Managers. - Manuelle redaktionelle Prüf-Workflows für riskante Lizenzfälle. - Vollständige Medienbibliothek statt einzelnes Titelbild. - Frontend-Ausgabe des Bildnachweises außerhalb der Bearbeitungsoberfläche, sofern noch nicht separat angebunden. - Anzeige-Lokalisierung von `published_at`, `created_at` und Status-Log-Zeitstempeln (aktuell weiterhin UTC). - Klärung/Anpassung der Auto-Publish-Policy: geplante PMs (Status `review` + fälliger `scheduled_at`) werden vom Scheduler-Command automatisch veröffentlicht – ohne separate redaktionelle Freigabe. Wird in einem eigenen Schritt geprüft.