presseportale/dev/frontend/hub-flux/04-PHASE-2-CUSTOMER-DASHBOARD.md
Kevin Adametz 0a3e52d603 19-05-2026 Rebrand Pressekonto, Hub-Flux UI und Legacy-Media-Migration
Umbenennung presseportale → pressekonto in Domains, Themes und Dokumentation.
Design-Tokens, Portal-Shell, Customer-Dashboard, Auth- und Admin-PM-Views.
Artisan-Befehl migrate:legacy-media mit Tests und Hub-Flux-Entwicklungsdocs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 16:36:13 +00:00

177 lines
7.5 KiB
Markdown

# Phase 2 — Customer-Dashboard auf Mockup-Stil
> Detail-Plan analog zu `01-PHASE-0-TOKENS.md` und
> `02-PHASE-1-PORTAL-SHELL.md`. Wird beim Abschluss auf Status `✅ abgeschlossen`
> gesetzt; Lessons learned wandern in `PROGRESS.md`.
**Status**: ✅ abgeschlossen · **Aufwand**: ~½ Tag · **Risiko**: niedrig
---
## Ziel
`resources/views/livewire/customer/dashboard.blade.php` matched das Mockup
`dev/frontend/tailwind_v3/User Dashboard presseportale.html` zu ≥ 90 %.
Sichtbarer Wow-Moment für den Kunden, ohne neue Business-Logik.
## Was sich ändert
### Visuell
| Bereich | Heute | Mockup |
| ----------------- | ------------------------------------------------ | --------------------------------------------------------------------- |
| Page-Header | `<flux:card>` mit `<flux:heading>` „Willkommen“ | Hub-Badge + Eyebrow + großes H1 + Untertitel + rechts Status-Pille |
| KPI-Reihe | 4 schmale `<flux:card>` mit `<flux:text>`-Zahl | 4 `stat-card`s mit Strip links, Mono-Zahl groß, Sub-Info, Sparkline |
| Pressemitteilungen-Block | `<flux:card>` mit Liste / Empty-State | `panel` mit `section-eyebrow`, Empty-State mit Schritt-Karten 01/02/03 |
| Datenqualität | Grid aus `<flux:badge>`-Karten | `panel` rechts mit 2 `hint-card`s (Progress-Bar + Action-Link) |
| Firmen-Slot | `<flux:card>` mit Firmen-Liste | `panel` mit gestrichelten Empty-Slot-Karten + Hinweis-Box |
| Brand-Bridge | (nicht vorhanden) | `panel-dark` rechts: presseecho + businessportal24 Status |
| Footer | (nicht vorhanden) | Subtle-Footer mit Tastenkürzel / Changelog / Status / Support |
### Datenmodell
Heute liefert das Volt-`with()`:
- `stats.total | published | review | draft`
- `qualityHints[]`
- `recent` (PressRelease-Collection, max. 5)
- `companies`
Mockup verlangt **zusätzlich**:
- `stats.deltaMonth` — Veränderung ggü. Vormonat (Total)
- `profileCompleteness` — Prozentwert für Profil-Progress-Bar
- `billingCompleteness` — Prozentwert für Rechnungsadresse
- `bridgeStatus``['presseecho' => 'connected'|'pending', 'businessportal24' => …]`
(vorerst `connected` fest verdrahtet, später aus echtem Sync-Status)
## Was NICHT geändert wird
- Logik / Volt-Methoden — Layout-only.
- Statistik-Backend (`PressRelease::where(...)`) bleibt 1:1.
- `qualityHints`-Logik bleibt — wird nur anders gerendert.
- Topbar (eigene Phase, später).
---
## Implementierungs-Schritte
### 1. Shared Hub-Components-CSS
Klassen wandern in **`resources/css/shared/hub-components.css`** (neue Datei).
Importiert in:
- `resources/css/portal.css` (nach `flux.css`)
- `resources/css/web/shared-styles.css` (nach `design-tokens.css`)
Damit haben **Portal-Build und Web-Build** dieselbe Hub-Komponenten-Sprache —
DRY für späteres Wiederverwenden (z. B. Admin-Dashboard in Phase 3).
Folgende Klassen kommen rein (alle mit `var(--color-*)`-Tokens, keine Hex-Literale):
- `.panel`, `.panel-warm`, `.panel-dark`, `.panel-head`
- `.stat-card` + `.stat-strip` + `.stat-label` + `.stat-num`
+ Varianten: `.is-primary`, `.is-ok`, `.is-warn`, `.is-muted`
- `.hint-card` + `.hint-card .hint-ico`
- `.badge` + `.badge.warn` + `.badge.ok` + `.badge.hub` + `.badge.dot`
- `.bridge-row`, `.dot-pe`, `.dot-bp`
### 2. Blade-Components in `resources/views/components/portal/`
#### `stat-card.blade.php`
```blade
<x-portal.stat-card variant="primary|ok|warn|muted" label="Gesamt" :value="$stats['total']">
<x-slot:meta>2026</x-slot:meta> {{-- rechts oben --}}
<x-slot:trend>0 ggü. Vormonat</x-slot:trend> {{-- unten --}}
</x-portal.stat-card>
```
Render: `<article class="stat-card is-{variant}">` + Strip + Label + Mono-Zahl
+ Meta-Slot oben rechts + Trend-Slot unten. Sparkline (SVG) erstmal weggelassen
— optionales Detail; lässt sich nachschieben, wenn Daten dafür da sind.
#### `hint-card.blade.php`
```blade
<x-portal.hint-card :icon="$hint['icon']" :title="$hint['title']" :percent="60" :href="$hint['href']">
{{ $hint['description'] }}
<x-slot:action>Profil öffnen</x-slot:action>
</x-portal.hint-card>
```
Render: `.hint-card`-Grid mit Icon-Square + Progress-Bar + Text + Action-Link
in `text-accent-deep`.
#### `bridge-card.blade.php` (optional, Phase 2 minimal)
Bleibt erstmal **inline** im Dashboard (sehr spezifisch, eine Stelle).
Wird in Phase 3/4 extrahiert, wenn klar ist wie weit der Brand-Bridge-Pattern
sich verbreitet.
### 3. `customer/dashboard.blade.php` umbauen
Layout-Skelett (alles im `<div class="space-y-8">`-Container):
1. **Page-Header**`<header>` mit Grid `1fr auto`:
- Links: Hub-Badge `User Backend` + Eyebrow + `<h1>Mein Dashboard</h1>`
+ Subtitle (Name + Reichweiten-Hinweis)
- Rechts: Status-Pille
- Wenn `$selectedCompany`: Hub-Badge mit Firma-Name (grün/ok-Stil)
- Wenn nicht: Warn-Pille „Keine Firma zugeordnet → zuordnen“
2. **KPI-Reihe** — 4 `<x-portal.stat-card>` (Gesamt/Veröffentlicht/Prüfung/Entwürfe)
3. **Zweispalten-Grid** (`2fr 1fr`):
- Links: `<article class="panel">` mit Pressemitteilungen — Liste **oder**
Empty-State (3 Schritt-Karten)
- Rechts: `<article class="panel">` mit `<x-portal.hint-card>`s
4. **Unteres Grid** (`2fr 1fr`):
- Links: `<article class="panel">` Firmen — Liste **oder** Empty-Slot-Karten
- Rechts: `<article class="panel-dark">` Brand-Bridge (inline)
5. **Footer** — kleine Link-Reihe in `text-ink-3`
### 4. Volt `with()` ergänzen
- `stats.deltaMonth` via zweiter Query (Vormonats-Counts vs. Aktuell)
- `profileCompleteness` als simpler Heuristik-Wert (firstname/lastname/phone/etc.)
- `billingCompleteness` analog (Vorhanden = 100, sonst 0; oder Ist-Felder/Soll-Felder)
- `bridgeStatus` vorerst hardcoded `['presseecho' => 'connected', 'businessportal24' => 'connected']`
→ später aus echtem Sync-Service
### 5. Tests
`tests/Feature/Customer/DashboardTest.php` (oder bestehender Test, falls vorhanden):
- Rendert ohne Fehler bei eingeloggtem Customer
- Stat-Zahlen werden korrekt ausgegeben
- Empty-State wird angezeigt, wenn keine PRs existieren
- Quality-Hints werden angezeigt, wenn `profile()` fehlt
---
## Akzeptanzkriterien
- [x] Phase-2-Plan-Dokument geschrieben
- [x] `shared/hub-components.css` existiert, importiert in beiden Builds
- [x] `<x-portal.stat-card>` und `<x-portal.hint-card>` rendern wie Mockup
- [x] `/admin/me` zeigt das neue Dashboard ohne Console-Errors
- [x] Empty-State für Pressemitteilungen ist sichtbar, wenn keine vorhanden
- [x] Quality-Hints rendern mit Progress-Bar
- [x] Brand-Bridge-Dark-Card unten rechts zeigt presseecho + businessportal24
- [x] Neuer Smoke-Test `tests/Feature/Customer/DashboardTest.php` mit 5 Cases
(Core-Sections, Empty-State, PR-Liste, Profil-Hint, vollständiges Profil
blendet Hints aus). Cross-Check: alle 18 verwandten Tests bleiben grün.
- [x] Pint clean
- [x] `PROGRESS.md`-Eintrag
---
## Risiken & Mitigation
- **FluxUI-Klassen vs. Custom-CSS-Kollisionen** — wir mischen `<flux:badge>`
weiterhin **nicht** im Dashboard (für Status-Pillen nehmen wir
`.badge.hub|.warn|.ok|.dot`). Auf den Detail-Seiten (Phase 4) bleibt
FluxUI dominant.
- **Sparklines weggelassen** — minimaler Stilverlust, wird in Phase 4 mit
echten Trend-Daten nachgereicht. Mockup-Match weiterhin ≥ 90 %.
- **`stats.deltaMonth`-Performance** — zweite Query auf gleicher Tabelle;
bei wachsendem Datensatz später cachen. Heute irrelevant.