29-05-2026 Optimierungen Fixes am Code
This commit is contained in:
parent
e8c47b7553
commit
4bb9094207
31 changed files with 5141 additions and 76 deletions
605
docs/PHASE-8-USER-PANEL-PLAN.md
Normal file
605
docs/PHASE-8-USER-PANEL-PLAN.md
Normal file
|
|
@ -0,0 +1,605 @@
|
|||
# Phase 8 · User-Panel-Konsolidierung & Pressemitteilungs-Lifecycle
|
||||
|
||||
Stand: 2026-05-21
|
||||
Vorgänger: Phase 7 (Press-Release-Form-Refactor — abgeschlossen)
|
||||
Abgleich-Doku: [`docs/STATUS-ABGLEICH-USER-PANEL.md`](./STATUS-ABGLEICH-USER-PANEL.md)
|
||||
|
||||
---
|
||||
|
||||
## 0. Worum es geht
|
||||
|
||||
Phase 8 bündelt drei thematisch zusammenhängende Bündel:
|
||||
|
||||
1. **User-Panel-Konsolidierung** — Lücken aus Phase 7 schließen, Firmen-Liste
|
||||
auf das Mockup-Niveau heben (`dev/frontend/tailwind_v3/User Firmen presseportale.html`).
|
||||
2. **Pressemitteilungs-Titelbild & SVG-Platzhalter** — jede PM bekommt ein
|
||||
sichtbares Hero-Bild, entweder eigener Upload oder ein farbiger
|
||||
SVG-Platzhalter aus einem definierten Set.
|
||||
3. **Veröffentlichungs-Modal mit rechtlichem Hinweis + Quota-Vorbereitung**
|
||||
— Pressemitteilungen werden nur über ein bewusstes Modal eingereicht;
|
||||
in dem Modal steht ein rechtlicher Hinweis und die Information, dass
|
||||
ein PM-Kontingent verbraucht wird.
|
||||
|
||||
Alle Änderungen, die das User-Panel betreffen, werden **konsistent ins
|
||||
Admin-Panel übertragen**, sobald sie inhaltlich passen (z. B.
|
||||
Show-Pages, Listen-Indikatoren, Bild-Manager-Wrapper).
|
||||
|
||||
---
|
||||
|
||||
## 1. Sub-Päckchen-Übersicht
|
||||
|
||||
| ID | Thema | Größe | Risiko |
|
||||
|---|---|---|---|
|
||||
| **8A** | Show-Page-Lücken schließen (subtitle, scheduling, embargo, boilerplate_override) — Customer + Admin | S | gering |
|
||||
| **8B** | Listen-Indikatoren für Scheduling/Embargo — Customer + Admin | S | gering |
|
||||
| **8C** | Pressekontakt-Warnung in Sidebar-Card (Customer + Admin) + Tests | XS | gering |
|
||||
| **8D** | Doku-Pflege: Phase-7-Schlussfeinheiten in `19-PHASE-7-…md` + Konzept-Anpassungen aus Abgleich | S | keine |
|
||||
| **8E** | Firmen-Liste auf Mockup-Niveau (Counter-Strip, Saved-Views, Filter-Chips, Card/List-Toggle, Rollen-Legende) | L | mittel |
|
||||
| **8F** | SVG-Platzhalter-Set extrahieren + auswählbar machen (Customer-Modal) | M | mittel |
|
||||
| **8G** | PressRelease-Titelbild — Schema, Default-Platzhalter, Vorschau im Form | M | mittel |
|
||||
| **8H** | FluxUI `flux:file-upload` im Image-Manager + Pflichtfelder Urheber/Lizenz/Rechte | M | mittel |
|
||||
| **8I** | Veröffentlichungs-Modal mit Rechts-Hinweisen + Quota-Anzeige (Customer) + Hook | M | mittel |
|
||||
| **8J** | Quota-Stub: Demo-Counter im Datenmodell + Decrement-Hook im PressReleaseService | M | hoch (Datenmodell) |
|
||||
| **8K** | Tests + Pint + Build + Roadmap-Update + Abschluss-Eintrag in `PROGRESS.md` | S | gering |
|
||||
|
||||
**Abkürzungen**: XS = < 1 h, S = 1–3 h, M = 3–8 h, L = 8–16 h.
|
||||
|
||||
Reihenfolge entspricht dem geplanten Ablauf. Nach jedem Päckchen ist ein
|
||||
Review-Stopp mit dem User vorgesehen, bevor das nächste startet.
|
||||
|
||||
---
|
||||
|
||||
## 2. Päckchen im Detail
|
||||
|
||||
### 8A · Show-Page-Lücken schließen
|
||||
|
||||
**Ziel**: Customer-Show und Admin-Show zeigen die Phase-7-Felder.
|
||||
|
||||
**Anpassungen**:
|
||||
|
||||
- `resources/views/livewire/customer/press-releases/show.blade.php`
|
||||
- Untertitel direkt unter H1 als kleinere Headline anzeigen
|
||||
- „Geplante Veröffentlichung"-Card mit `scheduled_at`, falls gesetzt
|
||||
- „Embargo bis"-Card mit `embargo_at`, falls gesetzt
|
||||
- „Boilerplate (Override)"-Card, falls `boilerplate_override` befüllt
|
||||
- `resources/views/livewire/admin/press-releases/show.blade.php`
|
||||
- Untertitel
|
||||
- Boilerplate-Override (Scheduling/Embargo sind bereits da)
|
||||
|
||||
**Tests**: bestehende Show-Tests erweitern um Assertions für die neuen
|
||||
Sichtbarkeiten.
|
||||
|
||||
**Akzeptanz**: Customer- und Admin-Show stellen exakt dieselben PM-Felder
|
||||
dar, die in den Forms gepflegt werden können (außer Anhänge — deaktiviert).
|
||||
|
||||
---
|
||||
|
||||
### 8B · Listen-Indikatoren für Scheduling/Embargo
|
||||
|
||||
**Ziel**: In beiden PM-Listen sieht man auf einen Blick, welche PMs
|
||||
geplant sind oder unter Embargo stehen.
|
||||
|
||||
**Anpassungen**:
|
||||
|
||||
- `customer/press-releases/index.blade.php`:
|
||||
- In der Datums-Spalte: zusätzliches Sub-Label „geplant · 21.05. 14:00"
|
||||
bzw. „Embargo bis 21.05."
|
||||
- `admin/press-releases/index.blade.php`:
|
||||
- Analog
|
||||
|
||||
**UI-Pattern**: Mono-Sub-Zeile unter dem Hauptdatum, wenn `status =
|
||||
review` UND `scheduled_at`/`embargo_at` gesetzt.
|
||||
|
||||
**Tests**: ein neuer Pest-Test pro Liste, der ein PM mit
|
||||
`scheduled_at`/`embargo_at` erstellt und die Sub-Zeile assertet.
|
||||
|
||||
---
|
||||
|
||||
### 8C · Pressekontakt-Warnung im Form-Sidebar
|
||||
|
||||
**Ziel**: Wenn keine Pressekontakt in einer PM gewählt ist, zeigt die
|
||||
Sidebar-Card eine dezente Warn-Box (analog zur „Telefonnummer fehlt"-
|
||||
Warnung), damit klar ist, dass die PM zwar speicherbar ist, aber
|
||||
einen Kontakt empfehlen sollte.
|
||||
|
||||
**Anpassungen**:
|
||||
|
||||
- `customer/press-releases/create.blade.php` + `edit.blade.php`:
|
||||
- Im Pressekontakt-Sidebar-Card:
|
||||
```blade
|
||||
@if (! $contactId)
|
||||
<div class="inline-callout warn">
|
||||
<flux:icon.exclamation-triangle class="size-4" />
|
||||
Es wurde noch kein Pressekontakt ausgewählt. Empfohlen, aber nicht zwingend.
|
||||
</div>
|
||||
@endif
|
||||
```
|
||||
- `admin/press-releases/create.blade.php` + `edit.blade.php`: identisch
|
||||
|
||||
**Tests**: Form-Render-Test mit ohne-Kontakt-Setup, das den Warn-String
|
||||
assertet.
|
||||
|
||||
---
|
||||
|
||||
### 8D · Doku-Pflege
|
||||
|
||||
**Ziel**: `19-PHASE-7-PRESS-RELEASE-FORM.md` und Konzept-Dokumente an
|
||||
den IST-Stand anpassen, damit zukünftige Phasen auf einer sauberen
|
||||
Basis aufsetzen.
|
||||
|
||||
**Konkret**:
|
||||
|
||||
- `dev/frontend/hub-flux/19-PHASE-7-PRESS-RELEASE-FORM.md`:
|
||||
- Block ergänzen: „Anhänge deaktiviert; Tests skipped; siehe Security-Review"
|
||||
- Block ergänzen: „Pressekontakt nullable; Warnung im Sidebar"
|
||||
- Block ergänzen: „Sidebar-Reihenfolge: Status → Kategorie → Portal
|
||||
(Pill) → Pressekontakt → Themen-Tags → Veröffentlichung → Weitere
|
||||
Felder → Phase-2-Footer"
|
||||
- `docs/user-admin/Admin-User.md`: Aktualisierungen aus
|
||||
[`STATUS-ABGLEICH-USER-PANEL.md` Abschnitt 6.1](./STATUS-ABGLEICH-USER-PANEL.md#61-sofort-ohne-risiko-machbar).
|
||||
- `docs/user-admin/checkliste-user-backend.md`: neuen Phase-7-Block
|
||||
hinzufügen.
|
||||
|
||||
**Akzeptanz**: Wer die `docs/`-Hauptdokumente liest, bekommt einen
|
||||
zutreffenden Eindruck vom IST-Stand.
|
||||
|
||||
---
|
||||
|
||||
### 8E · Firmen-Liste auf Mockup-Niveau
|
||||
|
||||
**Status**: ✅ abgeschlossen (21.05.2026)
|
||||
|
||||
**Was umgesetzt wurde**
|
||||
|
||||
- `resources/views/livewire/customer/press-kits/index.blade.php` komplett
|
||||
überarbeitet (Volt + Hub-Tokens).
|
||||
- Neue Hub-Tokens in `resources/css/shared/hub-components.css`: `.firm-card`,
|
||||
`.add-tile`, `.seg-toggle`, `.role-pill`, `.mini-logo`, `.lg-*`-Logo-Varianten,
|
||||
`.menu-trigger`, `.card-action`, `.page-btn`.
|
||||
- Counter-Strip mit `Firmen · aktiv · PMs gesamt · Pressekontakte hinterlegt`.
|
||||
- Saved-View-Tabs `Alle/Aktiv/In Anlage/Inaktiv/Mit mir geteilt`, mit
|
||||
Live-Counts. „In Anlage" ist bewusst noch leer (Phase-2-Heuristik).
|
||||
- Filter-Chips (Portal, Rolle) via FluxUI-Dropdown + URL-Sync (`?view=…&portal=…&role=…&mode=…`).
|
||||
- View-Toggle Karten / Liste, persistiert in der URL als `?mode=list`.
|
||||
- Karten- und Listen-Ansicht mit Hub-Look, deterministische Logo-Varianten,
|
||||
Status-Badge, Portal-Pills, Rolle-Pill, KPIs (PMs / Kontakte / letzte PM),
|
||||
Aktionen „Firma öffnen" und „Neue PM".
|
||||
- Add-Tile auf der letzten Seite (CTA: `Firma anlegen anfragen` → Profil).
|
||||
- Empty-States: 3-Schritt-Onboarding (keine Firmen) und Reset-CTA (Filter
|
||||
ohne Treffer).
|
||||
- Rollen-Legende als `panel-warm` mit Owner / Verantwortlich / Mitglied.
|
||||
- `tests/Feature/CustomerPressKitIndexPhase8eTest.php` mit 14 Tests
|
||||
(Counter, Saved-Views, Filter, View-Mode, Empty-States, Add-Tile,
|
||||
Rollen-Legende).
|
||||
|
||||
**Ziel**: `customer/press-kits/index.blade.php` entspricht dem Mockup
|
||||
`dev/frontend/tailwind_v3/User Firmen presseportale.html`.
|
||||
|
||||
**Mockup-Komponenten** (alle CSS-Klassen aus
|
||||
`resources/css/shared/hub-components.css` bereits vorhanden oder leicht
|
||||
ergänzbar):
|
||||
|
||||
- **Counter-Strip** (`.counter-strip`): `X Firmen · X aktiv · X PMs gesamt · X Pressekontakte`
|
||||
- **Saved-View-Tabs** (`.view-tabs`): `Alle / Aktiv / In Anlage / Inaktiv / Mit mir geteilt`
|
||||
- „In Anlage" = neue Firma, die noch keine Stammdaten hat (heuristisch: kein Logo + keine PMs)
|
||||
- „Mit mir geteilt" = `company_user.role IN (member, responsible)` ohne `owner_user_id = me`
|
||||
- **Filter-Chips** (`.filter-chip`):
|
||||
- Status (Aktiv/Inaktiv/Alle)
|
||||
- Portal (presseecho/businessportal24/Alle)
|
||||
- Rolle (Admin/Redakteur/Beobachter/Alle) — „Admin"-Begriff für Owner,
|
||||
„Redakteur" für `responsible`, „Beobachter" für `member`
|
||||
- Branche (Auswahl aus vorhandenen `Industry`-Werten)
|
||||
- **Seg-Toggle** (`.seg-toggle`): Karten- vs. Listen-Ansicht (Default Karten)
|
||||
- **Karten** (`.firm-card`):
|
||||
- Logo (Hub-Token-Box oder echtes Logo)
|
||||
- Status-Badge
|
||||
- Portal-Pills (eine oder zwei, je nach Firma-Portal)
|
||||
- Rolle-Pill (`.role-pill.admin` für Owner)
|
||||
- KPIs: PMs, Pressekontakte, Datum letzte PM
|
||||
- Aktionen: „Bearbeiten" (zur Firma) + „Neue PM" (Editor mit Firma vorgewählt)
|
||||
- `is-self`-Highlight für die aktive Firma aus dem Context-Switcher
|
||||
- **Add-Tile**: „Neue Firma anlegen" — derzeit nur Anfrage-Link auf Profil
|
||||
(Self-Service-Anlage ist Phase-2-Thema)
|
||||
- **Empty-States**:
|
||||
- Keine Firma: 3-Schritt-Onboarding (Stammdaten → Boilerplate → Pressekontakte) — derzeit nur Anfrage-CTA
|
||||
- Filter ohne Treffer: Reset-CTA
|
||||
- **Rollen-Legende** am Ende als `panel-warm`
|
||||
|
||||
**Volt-Anpassungen**:
|
||||
|
||||
- Computed Properties: `statusCounts`, `portalOptions`, `roleOptions`,
|
||||
`industryOptions`
|
||||
- Neue Properties: `$statusFilter`, `$portalFilter`, `$roleFilter`,
|
||||
`$industryFilter`, `$viewMode` (cards|list)
|
||||
- Methoden: `setView($status)`, `resetFilters()`, `toggleViewMode()`
|
||||
|
||||
**Was bewusst NICHT in 8E kommt**:
|
||||
|
||||
- Echte Self-Service-Firma-Anlage (Phase 2)
|
||||
- Statistik-Tab in Firmen-Detail (Phase 2)
|
||||
- Abrechnung pro Firma (Phase 2)
|
||||
|
||||
**Tests**:
|
||||
|
||||
- Komponente rendert mit 0/1/N Firmen
|
||||
- Filter-Kombinationen
|
||||
- View-Mode-Toggle
|
||||
- Counter-Strip-Zahlen stimmen mit den Filtern
|
||||
|
||||
**Admin-Spillover**: Die `admin/companies/index.blade.php` hat einen
|
||||
ähnlichen, älteren Mockup-Stand. Wenn Zeit übrig: Counter-Strip und
|
||||
Saved-Views auch dort einbauen (separater Patch im selben Päckchen,
|
||||
nur wenn ohne Mehraufwand machbar — sonst Phase 9).
|
||||
|
||||
---
|
||||
|
||||
### 8F · SVG-Platzhalter-Set
|
||||
|
||||
**Ziel**: Ein wiederverwendbares Set von Hero-Platzhaltern für PMs ohne
|
||||
echtes Titelbild.
|
||||
|
||||
**Quelle**: Bestehende inline SVGs in den Landing-Page-Komponenten:
|
||||
|
||||
- `resources/views/components/web/focus-hero.blade.php` (760×500, Punkt-Pattern + Kreise)
|
||||
- `resources/views/components/web/feed-top-item.blade.php` (240×160, Linien + Punkte)
|
||||
- ggf. weitere aus `industry-spotlight`, `quality-summary`, `live-ticker`
|
||||
|
||||
**Neue Struktur**:
|
||||
|
||||
```
|
||||
resources/views/components/portal/press-release-placeholder.blade.php
|
||||
public/images/press-release-placeholders/
|
||||
01-grid-blue.svg
|
||||
02-grid-green.svg
|
||||
03-grid-amber.svg
|
||||
04-lines-blue.svg
|
||||
05-lines-green.svg
|
||||
06-lines-amber.svg
|
||||
07-dots-blue.svg
|
||||
08-dots-green.svg
|
||||
09-dots-amber.svg
|
||||
```
|
||||
|
||||
Jede SVG ist 1600×900 (Hero-Aspect-Ratio 16:9), entspricht dem Bildformat
|
||||
des `large`-Variant aus `ImageService`.
|
||||
|
||||
**Komponente**:
|
||||
|
||||
```blade
|
||||
<x-portal.press-release-placeholder
|
||||
:variant="$pressRelease->placeholder_variant ?? '01-grid-blue'"
|
||||
:title="$pressRelease->title"
|
||||
class="aspect-[16/9] w-full" />
|
||||
```
|
||||
|
||||
**Modal-Auswahl** (Volt-Sub-Komponente):
|
||||
|
||||
```
|
||||
resources/views/livewire/components/press-release-placeholder-picker.blade.php
|
||||
```
|
||||
|
||||
- Grid 3×3 mit Vorschau aller Varianten
|
||||
- Wire-Event `placeholderSelected($variant)` → Parent setzt
|
||||
`placeholder_variant` und schließt das Modal
|
||||
|
||||
**Tests**: Komponente rendert mit jeder Variante; Picker emittiert
|
||||
korrektes Event.
|
||||
|
||||
---
|
||||
|
||||
### 8G · Titelbild-Schema & Default-Logik
|
||||
|
||||
**Ziel**: Jede PM hat **immer** ein Hero-Bild — entweder echtes Bild
|
||||
oder Platzhalter.
|
||||
|
||||
**Schema-Änderung**:
|
||||
|
||||
Migration: `add_placeholder_variant_to_press_releases.php`
|
||||
|
||||
```php
|
||||
$table->string('placeholder_variant', 32)->nullable()->after('boilerplate_override');
|
||||
```
|
||||
|
||||
**Default-Logik**:
|
||||
|
||||
- `PressRelease::booted` → bei `creating`: wenn `placeholder_variant`
|
||||
leer, würfle eine Variante aus dem Set
|
||||
- alternativ in `customer/press-releases/create.blade.php`: nach
|
||||
`mount()` Default setzen
|
||||
|
||||
**Cover-Image-Resolver** (Service):
|
||||
|
||||
```
|
||||
app/Services/PressRelease/PressReleaseCoverImage.php
|
||||
```
|
||||
|
||||
Public-Methoden:
|
||||
|
||||
- `coverUrl(PressRelease $pr, string $variant = 'large'): string`
|
||||
- wenn echtes Preview-Bild da → `variantUrl($variant)`
|
||||
- sonst → `asset('images/press-release-placeholders/'.$pr->placeholder_variant.'.svg')`
|
||||
- `coverIsPlaceholder(PressRelease $pr): bool`
|
||||
|
||||
**Verwendung**:
|
||||
|
||||
- Hero in Customer-Show, Admin-Show, Public-Detail-Page
|
||||
- Thumb in beiden Listen
|
||||
- Vorschau im Form
|
||||
|
||||
**Tests**: Resolver-Unit-Test für beide Fälle.
|
||||
|
||||
---
|
||||
|
||||
### 8H · FluxUI File-Upload + Lizenzfelder
|
||||
|
||||
**Ziel**: Image-Manager nutzt `flux:file-upload`, erfasst die rechtlich
|
||||
nötigen Felder, eckende UI passt zum Mockup.
|
||||
|
||||
**Anpassungen** in `resources/views/livewire/components/press-release-images-manager.blade.php`:
|
||||
|
||||
- `<flux:file-upload accept="image/jpeg,image/png,image/webp" wire:model="newImage" />`
|
||||
(Dropzone-Style aus FluxUI)
|
||||
- Zusätzliche Felder als FluxUI-Inputs:
|
||||
- **Urheber/Fotograf** (`flux:input` required)
|
||||
- **Lizenztyp** (`flux:select` mit Enum-Werten):
|
||||
- Eigene Aufnahme
|
||||
- CC-Lizenz (Lizenz-URL Pflicht)
|
||||
- Kommerzielle Lizenz erworben (Lizenz-URL Pflicht)
|
||||
- Einwilligung des Urhebers
|
||||
- Sonstiges
|
||||
- **Lizenz-URL** (`flux:input` conditional required)
|
||||
- **Personen-Einwilligung** (`flux:checkbox` optional)
|
||||
- **Rechte-Bestätigung** (`flux:checkbox` required, mit AGB-Text aus
|
||||
`Presseportal – Konzept für Relaunch.md` Abschnitt 2)
|
||||
|
||||
**Schema**:
|
||||
|
||||
Migration: `add_license_fields_to_press_release_images.php`
|
||||
|
||||
```php
|
||||
$table->string('author')->nullable();
|
||||
$table->string('license_type', 32)->nullable();
|
||||
$table->string('license_url')->nullable();
|
||||
$table->boolean('persons_consent')->default(false);
|
||||
$table->timestamp('rights_confirmed_at')->nullable();
|
||||
```
|
||||
|
||||
Enum: `App\Enums\ImageLicenseType` (PHP-Enum mit Labels).
|
||||
|
||||
**Tests**:
|
||||
|
||||
- Upload ohne Urheber → Validierungs-Fehler
|
||||
- Upload mit `license_type = cc` ohne `license_url` → Fehler
|
||||
- Upload mit allen Pflichtfeldern → erfolgreich, `rights_confirmed_at` gesetzt
|
||||
|
||||
**UI-Skizze** (Form-Reihenfolge):
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ [flux:file-upload Dropzone] │
|
||||
├─────────────────────────────────────┤
|
||||
│ Urheber: [input] * │
|
||||
│ Lizenztyp: [select] * │
|
||||
│ Lizenz-URL: [input] (*) │
|
||||
│ [ ] Personen-Einwilligung │
|
||||
│ [ ] Ich bestätige die Rechte * │
|
||||
│ │
|
||||
│ [Hochladen] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8I · Veröffentlichungs-Modal
|
||||
|
||||
**Ziel**: Customer kann eine PM nur über ein explizites Modal mit
|
||||
rechtlichem Hinweis und Quota-Information einreichen.
|
||||
|
||||
**Anpassungen** in `customer/press-releases/edit.blade.php`:
|
||||
|
||||
- „Zur Prüfung einreichen"-Button löst Modal-Open aus statt direkt
|
||||
`submitForReview` zu rufen
|
||||
- Modal-Inhalt:
|
||||
- Eyebrow „Veröffentlichung"
|
||||
- H3 „Pressemitteilung zur Prüfung einreichen"
|
||||
- Block „Rechtliche Hinweise" (aus Konzept-Abschnitt 5 zur
|
||||
DSGVO-Position + Abschnitt 2 zu Bildrechten, plus AGB-Verweis)
|
||||
- Block „Kontingent" — Anzeige `Ihre verbrauchten PMs in diesem Monat: X / Y`
|
||||
- Block „Bestätigungen":
|
||||
- [ ] Inhalt entspricht den AGB
|
||||
- [ ] Bildrechte sind geklärt
|
||||
- [ ] Pressekontakt-Daten korrekt
|
||||
- Footer: „Abbrechen" (sekundär) + „Veröffentlichung anfordern" (primär,
|
||||
disabled bis alle 3 Checkboxen gesetzt)
|
||||
- Confirm-Button ruft `submitForReview()` (existiert bereits)
|
||||
|
||||
**Schreibweise** (juristisch sicherer Ankertext):
|
||||
|
||||
```
|
||||
Mit dem Einreichen dieser Pressemitteilung versichern Sie:
|
||||
- Sie sind befugt, den Inhalt zu veröffentlichen.
|
||||
- Alle verwendeten Bilder, Logos und Zitate liegen in Ihrer Nutzungsbefugnis.
|
||||
- Personenbezogene Daten sind nur in dem für die Berichterstattung
|
||||
zwingend erforderlichen Umfang enthalten.
|
||||
- Aussagen entsprechen Ihrem Wissensstand und sind sachlich richtig.
|
||||
|
||||
Sie stellen [Plattform] von Ansprüchen Dritter frei, die aus einer
|
||||
unberechtigten Nutzung von Inhalten resultieren. Die endgültige
|
||||
Veröffentlichung erfolgt nach redaktioneller Prüfung.
|
||||
```
|
||||
|
||||
(Exakte Formulierung muss vor Go-Live durch einen Anwalt geprüft werden —
|
||||
für die Bauphase reicht der Platzhalter.)
|
||||
|
||||
**Quota-Anzeige**:
|
||||
|
||||
In Phase 8I noch ohne echte Tarif-Logik: Anzeige eines **Demo-Counters**,
|
||||
der aus einer einfachen Aggregation (`User::pressReleasesPublishedThisMonth()`)
|
||||
kommt — und einer hartcodierten Obergrenze (z. B. 3 als Starter-Default).
|
||||
Das echte Tarif-System kommt in einer späteren Phase.
|
||||
|
||||
**Tests**:
|
||||
|
||||
- Modal öffnet sich bei Klick
|
||||
- Submit-Button bleibt disabled bis alle 3 Checkboxen gesetzt
|
||||
- Nach Bestätigung: PM-Status ist `review`
|
||||
- Toast-Bestätigung wird angezeigt
|
||||
|
||||
**Admin-Spillover**: Im Admin-Editor reicht der Admin direkt ein
|
||||
(`publish`), kein Modal nötig — der Hinweis ist auf den Customer-Flow
|
||||
zugeschnitten.
|
||||
|
||||
---
|
||||
|
||||
### 8J · Quota-Stub
|
||||
|
||||
**Ziel**: Die UI-Anzeige in 8I hängt am echten Datenmodell, auch wenn
|
||||
das vollständige Tarif-/Credit-System erst später kommt.
|
||||
|
||||
**Datenmodell** (minimal):
|
||||
|
||||
Migration: `create_user_quota_table.php` oder als JSON in `profiles`?
|
||||
|
||||
> **Entscheidung**: Wir machen es als Migration-light auf `users`:
|
||||
>
|
||||
> ```php
|
||||
> $table->unsignedInteger('press_release_quota')->default(3)->after('settings');
|
||||
> $table->unsignedInteger('press_release_quota_used_this_month')->default(0)->after('press_release_quota');
|
||||
> ```
|
||||
>
|
||||
> Diese Spalten sind temporär, das echte Tarif-Modell überschreibt sie
|
||||
> oder ersetzt sie durch eigene Tabellen.
|
||||
|
||||
**Service** in `PressReleaseService::submitForReview`:
|
||||
|
||||
```php
|
||||
$user->increment('press_release_quota_used_this_month');
|
||||
```
|
||||
|
||||
(Reset des Counters per Scheduled-Command monatlich → eigener kleiner
|
||||
Befehl `ResetMonthlyPressReleaseQuota`.)
|
||||
|
||||
**API für die View** (z. B. via `User`-Method):
|
||||
|
||||
```php
|
||||
public function pressReleaseQuotaRemaining(): int
|
||||
{
|
||||
return max(0, $this->press_release_quota - $this->press_release_quota_used_this_month);
|
||||
}
|
||||
```
|
||||
|
||||
**Akzeptanz**: Veröffentlichungs-Modal zeigt sinnvolle Zahlen, der
|
||||
Counter erhöht sich nach Submit, der Scheduler-Command resettet ihn
|
||||
zum 1. des Monats. Tarif-Anbindung folgt später.
|
||||
|
||||
**Tests**:
|
||||
|
||||
- Counter inkrementiert bei `submitForReview`
|
||||
- Counter resettet via Scheduled-Command (Unit-Test)
|
||||
|
||||
---
|
||||
|
||||
### 8K · Tests, Pint, Build, Roadmap
|
||||
|
||||
**Ziel**: Saubere Übergabe.
|
||||
|
||||
- `vendor/bin/sail artisan test --compact` muss durchlaufen (außer
|
||||
pre-existing `ApiDocumentationTest`).
|
||||
- `vendor/bin/sail bin pint --dirty --format agent` clean.
|
||||
- `vendor/bin/sail npm run build:portal` clean.
|
||||
- `dev/frontend/hub-flux/20-PHASE-8-USER-PANEL.md` als neue
|
||||
Roadmap-Doku (analog zu `19-…`).
|
||||
- Eintrag in `dev/frontend/hub-flux/PROGRESS.md` mit allen Sub-Päckchen.
|
||||
- `docs/user-admin/checkliste-user-backend.md` um Phase-8-Block ergänzen.
|
||||
|
||||
---
|
||||
|
||||
## 3. Was außerhalb von Phase 8 bleibt
|
||||
|
||||
Bewusst nicht in Phase 8:
|
||||
|
||||
- **Magic-Link-Flow für Pressekontakte** → Phase 9 oder Phase 2 lt. Konzept
|
||||
- **Statistik-Tab in Firmen-Detail** → Phase 9
|
||||
- **Self-Service-Firmen-Anlage** → Phase 9
|
||||
- **Notice-and-Action für externe Meldungen** → Phase 2/3
|
||||
- **KI-Vorprüfung** → Phase 2/3
|
||||
- **Korrektur-/Update-Hinweis-System** → Phase 2/3
|
||||
- **Echtes Tarif-/Credit-System mit Stripe** → eigene Phase
|
||||
- **Trust-Score / Score-System** → Phase 3
|
||||
- **Anhänge-Reaktivierung** → eigener Sicherheits-Audit-Track
|
||||
|
||||
---
|
||||
|
||||
## 4. Reihenfolge & Review-Punkte
|
||||
|
||||
Vorgeschlagene Reihenfolge der Päckchen:
|
||||
|
||||
```
|
||||
8D (Doku zuerst — bewegt sich nichts am Code)
|
||||
→ 8A (Show-Page-Lücken)
|
||||
→ 8B (Listen-Indikatoren)
|
||||
→ 8C (Pressekontakt-Warnung)
|
||||
→ Review-Stopp mit User
|
||||
→ 8E (Firmen-Liste auf Mockup) — größtes Päckchen, Review davor
|
||||
→ Review-Stopp
|
||||
→ 8F (SVG-Platzhalter extrahieren)
|
||||
→ 8G (Titelbild-Schema + Default)
|
||||
→ 8H (FluxUI File-Upload + Lizenzfelder)
|
||||
→ Review-Stopp
|
||||
→ 8J (Quota-Stub im Datenmodell zuerst, damit 8I darauf aufsetzen kann)
|
||||
→ 8I (Veröffentlichungs-Modal)
|
||||
→ 8K (Abschluss)
|
||||
```
|
||||
|
||||
**Begründung**: Doku zuerst, weil der Abgleich sonst veraltet. Dann
|
||||
kleine UX-Lücken (8A–8C), die schnelle Wins sind. Anschließend die
|
||||
größere Firmen-Liste (8E), die ein eigenes Päckchen ist. Bild- und
|
||||
Veröffentlichungs-Block am Ende, weil sie thematisch zusammengehören
|
||||
und Schema-Änderungen mitbringen.
|
||||
|
||||
---
|
||||
|
||||
## 5. Risiken & Annahmen
|
||||
|
||||
- **Annahme**: FluxUI `flux:file-upload` ist in der aktuellen Version
|
||||
voll funktional und kompatibel mit `WithFileUploads` von Livewire.
|
||||
Fallback: bestehender Standard-Upload bleibt erhalten.
|
||||
- **Annahme**: SVG-Platzhalter (1600×900) sind klein genug, dass wir
|
||||
sie direkt aus `public/images/...` ausliefern — kein CDN-Setup nötig.
|
||||
- **Risiko**: Schema-Änderungen in 8G + 8H + 8J berühren produktive
|
||||
Tabellen (`press_releases`, `press_release_images`, `users`). Alle
|
||||
Migrations sind additive (nullable + default), Rollback-fähig.
|
||||
- **Risiko**: Quota-Stub in 8J wird vom echten Tarif-System abgelöst
|
||||
— Code-Schnittstelle (`pressReleaseQuotaRemaining()`) muss stabil bleiben,
|
||||
damit das Veröffentlichungs-Modal nicht neu gebaut werden muss.
|
||||
- **Risiko**: Rechtstext im Veröffentlichungs-Modal ist Platzhalter.
|
||||
Vor Go-Live durch Anwalt zu prüfen.
|
||||
|
||||
---
|
||||
|
||||
## 6. Akzeptanzkriterien Phase 8 gesamt
|
||||
|
||||
- [ ] Customer-Show + Admin-Show stellen alle Phase-7-Felder dar
|
||||
- [ ] PM-Listen markieren Scheduling und Embargo
|
||||
- [ ] Pressekontakt-Sidebar warnt bei leerer Auswahl
|
||||
- [ ] `docs/user-admin/*` ist mit dem Code synchron
|
||||
- [ ] Firmen-Liste entspricht dem Mockup zu ≥ 90 %
|
||||
- [ ] Jede PM hat ein sichtbares Hero-Bild (echtes oder Platzhalter)
|
||||
- [ ] Image-Upload erfasst Urheber + Lizenz-Typ + Rechte-Bestätigung
|
||||
- [ ] „Zur Prüfung einreichen" erfordert eine bewusste Modal-Bestätigung
|
||||
- [ ] Quota-Counter inkrementiert pro Einreichung, resettet monatlich
|
||||
- [ ] Tests grün (außer pre-existing `ApiDocumentationTest`)
|
||||
- [ ] Pint clean, Build clean
|
||||
- [ ] Roadmap-Eintrag und `PROGRESS.md`-Block geschrieben
|
||||
|
||||
---
|
||||
|
||||
## 7. Nächster Schritt
|
||||
|
||||
Mit **8D (Doku)** starten, weil das ohne Code-Änderungen funktioniert
|
||||
und den Boden für die folgenden Päckchen ebnet. Direkt im Anschluss
|
||||
**8A–8C** als Block, weil sie zusammen die Phase-7-Lücken schließen.
|
||||
|
||||
Danach Review-Stopp für Phase 8E (Firmen-Liste) — das ist das
|
||||
sichtbarste Päckchen für den User und sollte mit klarem Mockup-Vergleich
|
||||
abgenommen werden.
|
||||
Loading…
Add table
Add a link
Reference in a new issue