- Decision-Update Preisstruktur & Veroeffentlichungs-Flow aufgenommen (Launch-Tarife, Slot-Verbrauch bei Veroeffentlichung, Submit-Gate, Launch-Credits) inkl. Klarstellung 12.06.: Gelb geht direkt live, keine manuelle Pruef-Queue, nur Rot wird abgelehnt - Alle Status-Dokumente auf den Code-Stand gezogen: README-Index, STATUS-ABGLEICH (KI-Pipeline, Bilder/Lizenzen, Pricing), Checkliste (KI- und Titelbild-Bloecke, Launch-To-dos), Admin-User, user-zusammenhaenge (Datenmodell-Delta), Entwicklungsplan KI-Pruefung (Phase 0 abgehakt, Decision-Abgleich) - Ueberschriebene Tarif-Abschnitte in Konzept-Update 1/2 und Relaunch-Konzept mit Superseded-/IST-Hinweisen markiert - Neues Plan-Dokument PHASE-9-FLOW-UND-TARIFE-PLAN.md (9A-9J) - Phase-8-Roadmap-Doku (20-PHASE-8-USER-PANEL.md) + PROGRESS-Eintraege Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
277 lines
12 KiB
Markdown
277 lines
12 KiB
Markdown
# 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.
|
||
|