presseportale/dev/frontend/hub-flux/PROGRESS.md
Kevin Adametz ad741331ee
Some checks failed
tests / ci (push) Has been cancelled
linter / quality (push) Has been cancelled
Doku-Abschluss 12.06.: README-Stand, weiteres/-Index, Next Steps (Phase-2/Magic-Link, Duplicate-Content)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:24:28 +00:00

2237 lines
104 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Fortschritts-Log — Hub × FluxUI
> Tagebuch der Umsetzung. Neue Einträge **oben** anfügen.
> Format pro Eintrag: Datum · Phase · Was wurde gemacht · Wer · Notizen
---
## 2026-06-12 · Tagesabschluss · PM-Vorschau-Feinschliff + Next Steps ✅
- **Was**: Letzte Review-Runde auf der PM-Vorschauseite: Sprache-Kachel
entfernt (Kürzel jetzt als Badge am Portal-Namen), Panel „Zugeordnete
Pressekontakte" zu **„Firma & Pressekontakt"** zusammengeführt — oben
die Firma als vollwertige `firm-card` wie in der Firmenübersicht
(Logo/Initialen, Name + Meta-Zeile, Portal-Pills, Aktiv-Badge,
PM-/Kontakt-KPIs, „Firma öffnen"), direkt darunter der zugeordnete
Pressekontakt bzw. der Leerhinweis.
- **Dateien**: `customer/press-releases/show.blade.php`,
`docs/README.md` (Stand + neuer `weiteres/`-Abschnitt).
- **Build/Test**: Suite 557 passed / 4 skipped, Pint clean.
- **Hinweis Doku**: Das umgesetzte Verlinkungs-Decision-Update wurde von
Kevin aus `docs/weiteres/` entfernt (Inhalt in §4 des
Preisstruktur-Decision-Updates integriert, Umsetzungsstand hier im Log).
- **Nächste Schritte (vereinbart 12.06.2026)**:
1. **Decision-Update „Phase-2-Funktionen & Magic-Link-Änderungsprozess"**
umsetzen (Boost + Veröffentlichungsnachweis für den Launch,
Magic-Link-Zugangs-/Änderungsprozess; überschneidet sich mit 9G
Tageslimit und 9I Launch-Credits).
2. **Decision-Update „Duplicate-Content & Duplicate-Checking"** umsetzen
(Cross-Portal-SEO vs. Duplikat-Erkennung eingereichter PMs).
3. Danach weiter laut Kevins Liste: Login-/Registrierungs-Flow
durchtesten (Zweig 3), Code-Optimierung (Zweig 4).
## 2026-06-12 · KI-generierte Bilder: Lizenztyp + Kennzeichnung ✅
- **Was**: Neuer Lizenztyp „KI-generiert" im Titelbild-Upload
(Entscheidung nach Kevins Frage): KI-Bilder haben keinen menschlichen
Urheber (§ 2 UrhG) — maßgeblich sind die Anbieter-Bedingungen, und ab
02.08.2026 greift die Kennzeichnungspflicht aus Art. 50 EU AI Act.
Formular-Schaltung bei Auswahl: Pflichtfeld „Verwendetes KI-Tool"
(statt CC-/Sonstiges-Detail), Urheber-Label wird „Verantwortlich für
die Erstellung", Hinweis-Box (kein Urheberrecht, Anbieter-Bedingungen,
öffentliche Kennzeichnung, keine realen Personen/Marken), zusätzlicher
Pflicht-Switch „Anbieter-Bedingungen geprüft". Der öffentliche
Bildnachweis wird automatisch vorgeschlagen („Bild: KI-generiert
(Tool)"), manuelle Eingaben werden nicht überschrieben. Neues Flag
`press_release_images.is_ai_generated` (Migration); Kennzeichnung
sichtbar als Badge im Upload-Manager und als Bildnachweis-Zeile unter
dem Titelbild auf Customer- und Admin-Detailseite — die öffentlichen
Portal-Seiten übernehmen das Label beim Web-Relaunch.
- **Dateien**: `app/Enums/ImageLicenseType.php` (AiGenerated),
`press-release-images-manager.blade.php`, `PressReleaseImage`-Model,
Migration, Customer-/Admin-Show (Bildnachweis-Zeile).
- **Build/Test**: 3 neue Tests (Pflichtfelder, Speichern inkl. Flag,
Nachweis-Vorschlag), Suite 557 passed / 4 skipped, Pint clean.
- **Offene Fragen**: Label-Ausspielung auf den öffentlichen Web-Seiten
beim Relaunch (Flag + copyright sind vorhanden).
## 2026-06-12 · Titelbild-Upload: Struktur + große Vorschau ✅
- **Was**: Das Bildrechte-Formular im Titelbild-Upload (gemeinsame
Komponente `press-release-images-manager`, Admin + Customer) war eine
lange flache Feldliste — jetzt fünf nummerierte Schritte mit
Trennlinien: 1 Bild auswählen, 2 Bildinformationen (öffentlich),
3 Herkunft & Lizenz (Pflicht-Badges, 2-Spalten-Grid), 4 Personen &
Rechte Dritter (Radio-Gruppen nebeneinander), 5 Bestätigung. Nach der
Bildauswahl erscheint statt des Mini-Thumbnails eine **große
16:9-Vorschau** im Titelbild-Format (mit Dateiname/Größe und „Anderes
Bild wählen"); die Dropzone weicht der Vorschau, bis das Bild
verworfen wird.
- **Dateien**: `resources/views/livewire/components/press-release-images-manager.blade.php`.
- **Build/Test**: PressReleaseImageLicenseTest 12 passed, Suite 552
passed / 4 skipped, Pint clean.
## 2026-06-12 · Verlinkung & Backlinks (Decision-Update 11.06.) ✅
- **Was**: Systemseitige `rel`-Auszeichnung für Links in PMs umgesetzt:
neue `PressReleaseLinkPolicy`, angewendet in
`PressReleaseHtmlSanitizer::render()` (wirkt rückwirkend auf alle
gespeicherten Inhalte). Externe Links → `sponsored nofollow noopener`
+ `target="_blank"`, portalinterne Links (drei Domains inkl. www,
relative Pfade) → follow, mailto/tel ohne rel/target. Autoren-`rel`
wird immer überschrieben — kein kundenseitiger follow/nofollow-Hebel.
Editor-Hinweis unter der Schreibfläche (Create/Edit). §9-Korrektur im
Preisstruktur-Decision-Update eingearbeitet, Umsetzungsstand im
Verlinkungs-Dokument ergänzt.
- **Dateien**: `app/Services/PressRelease/PressReleaseLinkPolicy.php`
(neu), `PressReleaseHtmlSanitizer.php`, Editor-Views (Create/Edit),
beide Decision-Dokumente.
- **Build/Test**: 6 neue Policy-Tests in `PressReleaseHtmlSanitizerTest`.
- **Offene Fragen**: CTA-Box/Darstellungs-Stufung → Boost-Konzept (9I);
Link-Obergrenze pro PM und Anchor-Text-Soft-Check → Phase 2.
## 2026-06-12 · PM-Vorschau-Umbau + Profil-Feinschliff ✅
- **Was**: (1) PM-Detailseite (Customer) nach Kevins Review umgebaut:
Status-Workflow direkt unter den Header, farblich abgehoben
(Soft-Hintergrund + 3px-Border je Status: Entwurf hub, Überarbeiten
err, In Prüfung warn, neu: Veröffentlicht ok); danach Pressekontakte +
Status & Verlauf, dann erst Titelbild und Inhalt. Metadaten ergänzt:
Portal, Kategorie, Sprache als Kacheln, Themen (Keywords) als Badges,
Backlink — alles im Verlaufs-Panel. (2) **Inhalts-Typografie**: Die
Detailseiten nutzten `prose`-Klassen, aber das Tailwind-Typography-
Plugin ist gar nicht installiert → Text erschien unformatiert (Diff
Editor vs. Vorschau). Neue Klasse `.pr-content` in hub-components.css
bildet die Editor-Typografie nach (Absätze, Listen, H2-H4, Links,
Blockquote); Customer- UND Admin-Detailseite umgestellt, Lesebreite
max 760px. (3) Profil: Pflicht-Badges an Pflichtfeldern, Fokus-Fix
nach dem Speichern (blur statt Autofokus auf „Anzeigename"),
Submit-Modal-Bestätigungen von rohen Checkboxen auf Flux-Switches
(Alpine-State via change-Event, Button-Freischaltung unverändert).
- **Dateien**: `customer/press-releases/show.blade.php` (Umbau),
`admin/press-releases/show.blade.php` (.pr-content),
`resources/css/shared/hub-components.css` (.pr-content),
`customer/profile.blade.php`, `components/press-release-submit-modal.blade.php`.
- **Build/Test**: Suite 546 passed / 4 skipped, Pint clean, npm run build ok.
- **Offene Fragen**: Web-Detailseiten (`web/release-detail` u. a.) nutzen
ebenfalls wirkungslose `prose`-Klassen — beim Web-Relaunch auf
`.pr-content` (oder Typography-Plugin) umstellen.
## 2026-06-12 · User-Panel-Restarbeiten (Kevins Liste) ✅
- **Was**: Alle Punkte aus `docs/user-admin/User-Panel-Restarbeiten.md`
(Status-Tabelle dort): (1) PM-Anlage ohne Firma zeigt eine Meldung mit
„Firma anlegen"-Button statt des leeren Editors. (2) Profil-Seite neu
gegliedert (Persönliche Daten / Konto / Rechnungsadresse / Einstellungen);
Rechnungsadresse vervollständigt um Anrede, Vorname, Nachname,
Firmenname (Migration `billing_addresses` + Snapshot-Spalte `company`
in `invoice_billing_addresses`, von MAN-Lauf und STR-Spiegelung
durchgereicht); „Persönliche Daten übernehmen"-Button gegen die
Doppel-Eingabe. (3) Doppelte Validierungsmeldung behoben: fehlende
Pflichtfelder melden einzeln unter dem Feld. (4) USt-ID-Validierung:
Formatprüfung sofort (hartes Speicher-Gate) + eVatR-Online-Bestätigung
(BZSt-REST-API, neuer `VatIdValidationService`, ENV `BILLING_OWN_VAT_ID`,
6h-Cache nur für definitive Ergebnisse, Ausfälle degradieren sanft).
(5) Rechnungsadresse ist Pflicht für jeden Checkout (Redirect aufs
Profil mit Hinweis); USt-ID wird als Stripe-Tax-ID übergeben.
(6) Firmenübersicht zeigt Logos auch für Legacy-Firmen (zentrale
logoUrl-Auflösung statt verkürzter Fast-Variante); „Letzte PM" mit
Jahreszahl. (7) Checkboxen → Flux-Switches (Boilerplate-Override,
Footer-Code); Token-Abilities bleiben Checkbox-Gruppe. Befund zu den
Profil-Schaltern: `show_stats`/`disable_footer_code` werden noch
nirgends ausgewertet (greifen mit Web-Relaunch) — steht jetzt in den
Beschreibungen.
- **Dateien**: `customer/profile.blade.php` (Neufassung),
`customer/press-releases/create.blade.php` (Guard),
`customer/press-kits/index.blade.php` (Logo/Datum),
`app/Services/Billing/VatIdValidationService.php` (neu) +
`VatIdCheckStatus`-Enum, `VatResolver` (isPlausibleVatId public),
`StripeCheckoutService` (Tax-ID-Sync), `CheckoutController` (Guard),
`User::hasCompleteBillingAddress()`, `BillingAddress::isComplete()`,
Migration, `config/billing.php` (`own_vat_id`).
- **Build/Test**: Suite 546 passed / 4 skipped, Pint clean; 14 neue Tests
(VatId-Service, PM-Guard, Profil-Validierung, Checkout-Guard).
- **Offene Fragen**: `BILLING_OWN_VAT_ID` in .env setzen (eigene USt-ID),
sonst bleibt die Online-Prüfung aus; Entscheidung zu den beiden
Profil-Schaltern (behalten vs. bis Relaunch ausblenden).
## 2026-06-12 · Responsive-Härtung (Block 3, Punkt 1) ✅
- **Was**: Systemische Responsive-Fehler behoben (Screenshots in
`dev/frontend/responsive/`): (1) Das starre Inline-Grid
`style="grid-template-columns:1fr auto"` der Seiten-Header (48 Seiten)
konnte nie umbrechen — die Aktions-Spalte quetschte die Titel-Spalte
(Buchstaben-Umbrüche im Firmennamen, Buttons liefen aus der Box).
Ersetzt durch die neue CSS-Klasse `.page-header` (hub-components.css):
unterhalb lg stapeln Titel und Aktionen, Aktions-Zeilen bekommen
flex-wrap. (2) Firmenkontext-Leiste im App-Layout stapelt jetzt erst
ab lg nebeneinander (vorher sm → Überlappung von „Firmenkontext"/
„Aktive Firma" zwischen 6401024px). (3) Stat-Cards: Label/Meta-Zeile
mit flex-wrap (keine Kollision mehr auf schmalen Karten), `.stat-num`
mit `overflow-wrap:anywhere` + 26px unter 480px (Text-Werte wie
„Businessportal24" sprengen die Karte nicht mehr). (4) KPI-Grids, die
schon ab sm auf 4 Spalten gingen (Customer-Dashboard, User-Show,
PM-Index), erst ab xl vierspaltig.
- **Dateien**: `resources/css/shared/hub-components.css` (.page-header,
.stat-num), `resources/views/components/portal/stat-card.blade.php`,
`resources/views/components/layouts/app.blade.php`, 48 Seiten-Views
(Header-Klasse per sed), 3 KPI-Grids.
- **Build/Test**: `npm run build` ok (beide Bundles), Suite 532 passed /
4 skipped.
- **Offene Fragen**: Weitere Stellen aus Kevins Klick-Durchgang folgen
(Liste Block 3).
## 2026-06-12 · Admin-Zahlungsmodul (P8-Rest) · Zahlungen + Tarif-Verwaltung ✅
- **Was**: Den Phase-8-Platzhalter `/admin/payments` durch das echte
Zahlungsmodul ersetzt: KPI-Reihe (aktive Abos, MRR netto, Umsatz
30 Tage brutto, offene Einzel-PMs), Tabellen für Stripe-Abos (mit
Tarif-Auflösung über die Price-IDs), Einmalkäufe (Typ/Status/PM-Link)
und den lokalen Rechnungsausgang (STR-/MAN-Badge), User-Suche über
alle drei Bereiche. Neu: `/admin/payments/plans` — Tarif-Verwaltung
mit Edit-Modal (Name, Netto-Preise, PM-Kontingent, Tageslimit,
aktiv/inaktiv, Sortierung) und **Sofort-Sync nach Stripe** über den
neuen `StripePlanSyncService`: Preisänderung legt ein neues
Price-Objekt an und deaktiviert das alte (Stripe-Preise sind
unveränderlich), Namensänderung aktualisiert das Produkt, unverknüpfte
Tarife werden komplett angelegt. Bestandsabos behalten ihren Preis
(Hinweis in UI und Speichermeldung). Buchungs-Seite zieht die Preise
ohnehin live aus `plans` → Änderungen wirken sofort überall.
Sidebar: eigener Eintrag „Tarife & Pakete" unter Billing.
- **Dateien**: `resources/views/livewire/admin/payments/index.blade.php`
(Neufassung), `resources/views/livewire/admin/payments/plans.blade.php`
(neu), `app/Services/Billing/StripePlanSyncService.php` (neu),
`routes/admin.php`, Sidebar.
- **Build/Test**: Suite 532 passed / 4 skipped, Pint clean; 13 neue Tests
(`AdminPlansPageTest`, `AdminPaymentsPageTest`), Stripe im Test gemockt.
- **Offene Fragen**: Refund-Workflow aus dem Admin (vorerst über das
Stripe-Dashboard); Einzel-PM-Preis bleibt Config/ENV-basiert.
- **Nächster Schritt**: User-Panel-Restarbeiten (Kevin sammelt Liste),
Login/Registrierungs-Flow durchtesten, 9G Tageslimit.
## 2026-06-12 · Phase 9F · Tarif-Seite + Checkout-UI ✅
- **Was**: „Buchungen & Add-ons" vom Credit-Konzept-Mock auf echte Daten
umgestellt: 4-Tier-Raster aus `plans` (Alpine Monat/Jahr-Toggle,
„2 Monate gratis"), Checkout-Buttons auf die 9E-Routen, Einzel-PM als
separater No-Abo-Block, Aktueller-Tarif-Panel (Abo / Bestandstarif
unbegrenzt / offene Einzelkäufe / leer) mit Kontingent-Kachel,
„Abo verwalten" → Stripe Billing Portal (neue Route
`me.checkout.billing-portal`), aktive Buchungen + Verlauf real.
Credit-Pakete/Marktplatz/Platzierungen entfernt (→ 9I bzw. Phase 2).
Stripe Tax im Dashboard aktiviert („SaaS business use", exklusiv).
**Feinschliff nach Review (Kevin)**: Aktueller-Tarif-Card nur bei
vorhandener Buchung (kein irreführendes „Unbegrenzt" vor dem Launch;
Kontingent-Kachel nur als echte Zahl), Tarif-Cards plakativer
(Icon je Tarif, größerer Preis, Trennlinie, mehr Abstand zum Button),
„Prüfung und Veröffentlichung inklusive" ohne „KI",
„Aktive Buchungen"-Panel entfernt (Info steht im Tarif-Panel),
Verlauf als eigene, klar abgegrenzte Sektion.
- **Dateien**: `resources/views/livewire/customer/bookings.blade.php`
(Neufassung), `app/Http/Controllers/CheckoutController.php` +
`app/Services/Billing/StripeCheckoutService.php` (Billing Portal),
`routes/customer.php`.
- **Build/Test**: Suite 519 passed / 4 skipped, Pint clean; 9 neue Tests
in `BookingsPageTest`, `PanelConsolidationTest` auf neue Seite angepasst.
- **Offene Fragen**: Stripe Tax + Produkt-Sync vor Relaunch im Live-Mode
wiederholen.
- **Nächster Schritt**: 9G Tageslimit (`plans.daily_limit` beim
Veröffentlichen), dann 9H Einzel-PM-Abo-Brücke, 9I Launch-Credits.
## 2026-06-12 · Phase 9E · Stripe-Anbindung komplett ✅
- **Was**: Produkt-Sync nach Stripe (Tarife + Einzel-PM, Netto-Preise,
Test-Mode), Webhook-Verarbeitung (STR-Spiegelung + Einmalkauf-Erfüllung;
Endpoint `pressekonto.com/stripe/webhook` registriert, Secret gesetzt),
Checkout-Flows als Backend (`me.checkout.subscription`,
`me.checkout.single-pm`; Stripe Tax via `Cashier::calculateTaxes()`),
Slot-Logik vom Stub auf Plan-Kontingent umgestellt: Abo → Tarif-Quote,
danach Einmalkauf-Verbrauch (consumed + PM-Verknüpfung),
**Grandfathered = unbegrenzt** (Entscheidung 12.06.2026, Bestandsschutz);
Stub-Spalte `users.press_release_quota` entfernt.
- **Dateien**: `app/Http/Controllers/CheckoutController.php`,
`app/Services/Billing/StripeCheckoutService.php`,
`app/Listeners/ProcessStripeWebhook.php`,
`app/Console/Commands/SyncStripePlans.php`, `app/Models/User.php`,
`app/Services/PressRelease/PressReleaseService.php`,
`routes/customer.php`, `config/billing.php`, Buchungs-Seite (Rückmeldung),
Submit-Modal/Views (Kontingent-Anzeige).
- **Build/Test**: Suite 510 passed / 4 skipped, Pint clean; Stripe-Sync
live gegen Test-Mode gelaufen (Einzel-PM: `STRIPE_PRICE_SINGLE_PM` in .env).
- **Offene Fragen**: Stripe Tax im Dashboard aktivieren (Ursprungsadresse),
sonst schlägt der Checkout fehl; Live-Mode-Sync vor Relaunch.
- **Nächster Schritt**: 9F Tarif-Seite/Buchungs-UI an die Checkout-Routen
anbinden (Mock ablösen), danach 9G Tageslimit.
## 2026-06-12 · Phase 9D · Tarif-Datenmodell, Rechnungskreise & USt ✅
Zentrale Doku: `docs/user-admin/Billing-und-Rechnungskreise.md`.
Plan: `docs/PHASE-9-FLOW-UND-TARIFE-PLAN.md` (9D ✅, 9E in Arbeit).
**Tarif-Datenmodell**
- Laravel Cashier ^16.5 (freigegeben), `User` ist Billable,
Cashier-Migrationen published + ausgeführt.
- `plans` (4 Tiers, Netto-Preise, Kontingente, Tageslimits, Seeder),
`single_purchases` (Einzel-PM, Extra-PM, Boost, PDF-Nachweis).
- `hasActiveBooking()` prüft hybrid: Cashier-Abo bezahlter
Einmalkauf aktive Legacy-Vereinbarung.
**Hybride Rechnungskreise (Entscheidung 12.06.)**
- `InvoiceNumberGenerator`: atomare fortlaufende Nummern, STR- (Stripe)
/ MAN- (manuell); Alt-Archiv `legacy_invoices` bleibt unverändert.
- MAN-Fälligkeitslauf `billing:generate-manual-invoices` (täglich
04:30): Periodenende → Rechnung mit Adress-Snapshot → Periode weiter.
**Legacy-Migration (P6.6, Runbook entsperrt)**
- `legacy:grandfather-subscriptions`: aktive jährliche Vereinbarungen
aus dem Rechnungsarchiv (22 im Test-Snapshot, 4 sofort fällig) als
`grandfathered` nach `user_payment_options` — Replay-fähig für den
Lauf kurz vor Relaunch.
**USt (Einwand 12.06.: alle neuen Preise netto; Legacy war brutto)**
- `VatResolver`: DE immer Steuer, EU nur mit USt-ID befreit (Reverse
Charge + Pflichthinweis `invoices.tax_note`), Drittland befreit.
- `vat_id` an Rechnungsadresse + Rechnungs-Snapshot; Netto-Ableitung
der Legacy-Beträge (199 € brutto → 167,23 € netto + 31,77 € USt —
Brutto bleibt für DE-Bestandskunden identisch).
- Offen: VIES-Validierung, PDF-Layout, Steuerberater-Abnahme.
**Verifikation**: Suite 490 passed / 4 skipped (39 neue Billing-Tests
über 4 Commits). Pint clean. Dry-Runs gegen Echtdaten validiert.
---
## 2026-06-12 · Phase 9 · Veröffentlichungs-Flow Block 1 (9A9C) ✅
Plan-Doc: `docs/PHASE-9-FLOW-UND-TARIFE-PLAN.md`. Grundlage:
`docs/Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`
(+ Entscheidung 12.06.: Gelb geht direkt live).
Vorab Block 0: Repo aufgeräumt (3 Artefakt-Dateien im Root entfernt),
der unkommittierte Stand vom 29.05.11.06. in drei Commits gesichert
(Vite/Multi-Domain-Infra, User-Panel/KI-Pipeline, Doku-Sync).
**9A — Gelb-Routing Direkt-Live**
- `routeByClassification()`: Gelb durchläuft denselben Auto-Publish-Pfad
wie Grün (`autoPublishApproved()`); nur Rot wird abgelehnt.
- Scheduler publiziert fällige gelbe + grüne PMs; unklassifizierte
bleiben als Fallback in der manuellen Queue.
**9B — Slot-Verbrauch bei Veröffentlichung**
- Increment aus `submitForReview()` entfernt; `publish()` und
`changeStatusFromAdmin()` zählen idempotent beim ersten
`published`-Übergang (Prüfung über Status-Logs). Rot kostet nichts.
- Submit-Guard: Einreichen erfordert freien Slot
(`QuotaExceededException`, API 422).
**9C — Submit-Gate + Funnel-Fix**
- `User::hasActiveBooking()`-Stub hinter `config/billing.php`
(`enforce_booking`, Default aus) — Tarif-Modul ersetzt nur den Rumpf.
- Einreichungs-Modal zeigt ohne Buchung einen Buchungs-Hinweis mit
CTA zur Buchungs-Seite; Server-Guard (`BookingRequiredException`),
API antwortet 402.
- **Befund + Fix**: Customer-Create legte PMs bei „Zur Prüfung senden"
direkt mit Status `review` an — vorbei an Blacklist, Quota, KI und
Status-Log. Jetzt: immer Draft anlegen, dann `submitForReview()`.
**Verifikation**: Suite 451 passed / 4 skipped (9 neue Tests:
Quota-Semantik, Gelb-Routing, Gate via Service/API/Modal). Pint clean.
Nächster Schritt: Review-Stopp, dann Block 2 (9D9J: Tarif-Datenmodell,
Stripe/Cashier — Dependency-Freigabe nötig, Tarif-UI, Tageslimit,
Einzel-PM, Launch-Credits).
---
## 2026-05-29 · Phase 8 · User-Panel-Konsolidierung abgeschlossen (8F8K) ✅
Abschluss von Phase 8. Die erste Hälfte (8A8E: Show-Page-Lücken,
Listen-Indikatoren, Pressekontakt-Warnung, Firmen-Liste auf Mockup-Niveau)
war bereits im Commit „Optimierung der User und Admin Panels" enthalten,
aber undokumentiert. Heute der zweite Block plus Doku-Sync.
Roadmap-Doc: `20-PHASE-8-USER-PANEL.md`. Plan: `docs/PHASE-8-USER-PANEL-PLAN.md`.
**8D — Doku-Sync**: `docs/user-admin/checkliste-user-backend.md`,
`docs/STATUS-ABGLEICH-USER-PANEL.md` und `Admin-User.md` auf den
echten IST-Stand gezogen (8A8E waren als „offen" markiert, sind
aber umgesetzt).
**8F — SVG-Titelbild-Platzhalter**
- 9 Varianten (3 Muster × 3 Hub-Farben) in
`public/images/press-release-placeholders/`.
- `App\Enums\PressReleasePlaceholder` (Default, Seed-deterministisch).
- `<x-portal.press-release-placeholder>` + Picker-Modal
(`components.press-release-placeholder-picker`, dispatcht
`placeholder-selected`).
**8G — Titelbild-Schema + Cover-Resolver**
- Migration `placeholder_variant` auf `press_releases` (nullable).
- Model-`creating`-Hook setzt deterministisch eine Variante.
- `App\Services\PressRelease\PressReleaseCoverImage`
(`coverUrl`/`coverIsPlaceholder`).
- Hero-Bild in Customer-/Admin-Show; Vorschau + Picker in Create/Edit.
**8H — Bild-Upload mit Lizenz-Pflichtfeldern**
- Migration: `author`, `license_type`, `license_url`,
`persons_consent`, `rights_confirmed_at` auf `press_release_images`.
- `App\Enums\ImageLicenseType` (CC/kommerziell erzwingen Lizenz-URL).
- Image-Manager: Urheber (Pflicht), Lizenztyp (Pflicht), Lizenz-URL
(bedingt), Personen-Einwilligung, Rechte-Bestätigung (Pflicht).
- Abweichung: Upload-Control bleibt `flux:input type=file` statt
`flux:file-upload` (Stabilität). Lizenzerfassung vollständig.
**8J — Quota-Stub (vor 8I, damit Modal darauf aufsetzt)**
- Migration: `users.press_release_quota` (3),
`..._used_this_month` (0).
- `User::pressReleaseQuotaRemaining()`,
Decrement in `PressReleaseService::submitForReview()`.
- Command `press-releases:reset-monthly-quota` + Scheduler
(`monthlyOn(1, '00:05')`).
**8I — Veröffentlichungs-Modal (Customer-Show)**
- „Zur Prüfung einreichen" öffnet jetzt ein FluxUI-Modal statt
`wire:confirm`: Rechtshinweis (Platzhalter, anwaltlich zu prüfen),
Kontingent-Badge, 3 Bestätigungs-Checkboxen (Submit via Alpine
disabled bis alle gesetzt) → ruft das bestehende `submitForReview()`.
**8K — Abschluss**
- Neue Tests: `PressReleasePlaceholderTest` (8),
`PressReleaseImageLicenseTest` (3), `PressReleaseQuotaTest` (3),
`PressReleasePublishModalPhase8iTest` (2).
- Suite: **375 passed, 4 skipped**. Pint clean.
`npm run build:portal` clean.
---
## 2026-05-29 · Wartung · Test-Regression-Fix + Phase-7-Doku nachgezogen
Review der Gesamt-Umsetzung. Zwei Befunde behoben:
### Fix — `ProfileUpdateTest > profile page is displayed`
Seit dem Customer-Portal-Umbau ist `/settings/profile` ein
**Redirect** auf `/admin/me/profile` (route `me.profile`), die
Profil-Pflege liegt jetzt in der Volt-Komponente
`customer.profile`. Der Starter-Kit-Test machte aber weiterhin
`GET /settings/profile``assertOk()` und lief deshalb auf 302
statt 200 (undokumentierte Regression aus dem Commit
„Optimierung der User und Admin Panels", 2026-05-22).
Test umgestellt auf `assertRedirect('/admin/me/profile')`. Das
Rendern der Zielseite ist bereits durch
`CustomerProfileSecurityTest` (Volt-Komponententest) abgedeckt,
also keine Doppelung. Die übrigen 4 Tests der Datei nutzen
weiterhin `Volt::test('settings.profile')` / `delete-user-form`
(Komponenten existieren und sind funktional).
### Doku-Sync
Phase 7 war im Code vollständig umgesetzt (siehe Eintrag unten),
aber im Log nicht erfasst und in den Status-Tabellen
widersprüchlich (`19-PHASE-7` „✅", `03-WEITERE-PHASEN` „🟡 in
Planung", `README` noch auf Stand Phase 2). Nachgezogen:
- Phase-7-Eintrag in diesem Log ergänzt.
- `README.md` Status-Tabelle auf Phase 07 aktualisiert.
- `03-WEITERE-PHASEN.md` Phase 7 von „🟡 In Planung" auf
„✅ abgeschlossen" + Gesamt-Status-Tabelle ergänzt.
**Validierung**:
- `php artisan test --compact` → 359 passed, 3 skipped,
1 failed (weiterhin nur der pre-existing `ApiDocumentationTest`,
fehlende `docs/api/v1.yml`)
- `vendor/bin/pint tests/Feature/Settings/ProfileUpdateTest.php`
→ fixed (EOF-Blankline)
- `npm run build:portal` → grün (436.51 KB CSS / 58.95 KB gzip)
---
## 2026-05-22 · Phase 7 · Press-Release-Form-Refactor ✅ (retroaktiv dokumentiert)
> Großes Modul-Refactor außerhalb der ursprünglichen hub-flux-
> Roadmap (06). Vorlage:
> `dev/frontend/tailwind_v3/User Neue Mitteilung presseportale.html`.
> Plan-Doc: `19-PHASE-7-PRESS-RELEASE-FORM.md`.
> Dieser Eintrag wurde am 2026-05-29 nachgetragen — die Arbeit
> selbst entstand am 21./22.05. (Commit „Optimierung der User und
> Admin Panels").
**7A — Migrations + Models**
- `add_phase7_fields_to_press_releases` (subtitle,
boilerplate_override, scheduled_at, embargo_at — alle nullable)
- `create_press_release_attachments_table` (analog
press_release_images, mit sort_order, soft-deletes)
- `add_boilerplate_to_companies` (companies.boilerplate)
- Models + Factory + Relationen + Casts.
**7B — Editor + Sanitizer**
- `composer require mews/purifier ^3.4` (approved)
- `App\Services\PressRelease\PressReleaseHtmlSanitizer`
(Allowlist p/br/h2/h3/strong/em/u/ul/ol/li/blockquote/a)
- `<flux:textarea>``<flux:editor>` mit reduzierter Toolbar.
- Test: `PressReleaseHtmlSanitizerTest`.
**7C/7D — Customer Create + Edit Form (UI)**
- 2-Spalter mit sticky Settings-Sidebar (Status & Absenden,
Portal read-only-Badge, Pressekontakt-Single-Select,
Themen-Tags, Veröffentlichung, SEO).
- Linke Spalte: Firma-Selector, Titel/Untertitel mit
Counter-Pillen (`.pr-meter`), `flux:editor`, Medien,
Anhänge, Boilerplate-Box mit Override-Toggle.
- Hub-Form-Bausteine in `hub-components.css` ergänzt
(`.pr-form-label`, `.pr-meter`, `.pr-bald-badge`,
`.pr-ai-hint`, `.pr-check-row`, `.pr-boiler`, `.pr-tag-chip`,
`.pr-pub-opt` …).
- Live-Re-Validation (`updated()` re-validiert Felder mit
bestehendem Error) + Sammel-Toast bei Validierungsfehler.
- Neues JS-Asset `portal-form-hooks` (Build).
- Tests: `CustomerPressReleaseCreatePhase7Test` (8),
`CustomerPressReleaseEditPhase7Test` (9).
**7E — Anhänge-Manager**
- `App\Services\PressRelease\PressReleaseAttachmentStorage`
- Komponente
`livewire/components/press-release-attachments-manager.blade.php`
(upload/remove/reorder, PDF/DOCX/XLSX/PPTX, Tile-Layout).
**7F — Scheduling + Embargo**
- UI: Radio „Geplanter Termin" + `datetime-local`,
Embargo-Switch + Date-Picker.
- Validation: scheduled_at min. 5 Min Zukunft, embargo_at
Zukunft (nur wenn Toggle aktiv).
- `PressReleaseService::publish()``resolvePublishedAt()`
(published_at > scheduled_at > embargo_at-Verschiebung > now).
- Command `press-releases:publish-scheduled`
(`App\Console\Commands\PublishScheduledPressReleases`,
`--dry-run`, `--limit=N`) + Scheduler-Eintrag in
`routes/console.php` (`everyFiveMinutes`, `withoutOverlapping`,
`runInBackground`).
- Tests: `PressReleaseSchedulingTest` (11),
`CustomerPressReleaseSchedulingFormTest` (5).
**Effekt auf die Suite**: von dokumentierten ~231 auf ~360 Tests
gewachsen. Admin-Create/Edit ziehen das Layout vorerst NUR
optisch mit; Scheduling/Embargo-UI bleibt Customer-seitig
(laut Plan-Doc Out-of-Scope für Admin in Phase 7).
---
## 2026-05-20 · Phase 6 · Auth-Cleanup ✅
Mit Phase 6 ist die hub-flux-Roadmap (Phase 06) **vollständig
abgeschlossen**. Schlanker Cleanup-Task ohne Risiko.
**Inventur** (Referenzen geprüft via `rg` über `resources/` + `routes/`):
| Datei | Status |
|---|---|
| `components/layouts/app/sidebar.blade.php` | aktiv (primäres Portal-Layout) |
| `components/layouts/auth/pressekonto.blade.php` | aktiv (6 Auth-Pages) |
| `components/layouts/auth.blade.php` | nur in `login-simple`/`test-simple` → weg |
| `components/layouts/auth/simple.blade.php` | Starter-Kit-Rest mit hardcoded `class="dark"` → weg |
| `components/layouts/auth/split.blade.php` | dito → weg |
| `components/layouts/auth/card.blade.php` | dito → weg |
| `components/layouts/app/header.blade.php` | nirgends referenziert → weg |
| `livewire/auth/login-simple.blade.php` | Debug-Page ohne Route → weg |
| `test-simple.blade.php` | Debug-Page ohne Route → weg |
**Gelöscht**: 7 Files, insgesamt ~17 KB Code
**Aktualisiert**: `_docs/FORTIFY-SANCTUM-SETUP.md` (Code-Beispiel
von `components.layouts.auth` auf `components.layouts.auth.pressekonto`).
**Side-Effect**: Portal-CSS-Bundle ist ~2.4 KB kleiner geworden
(422.62 KB statt 425.07 KB), weil weniger Klassen via Tailwind
JIT entdeckt werden.
**Validierung**:
- `php artisan view:clear && npm run build:portal` → grün
- `vendor/bin/pint --dirty --format agent` → passed
- Tests: 230/231 (nur der bekannte pre-existing
`ApiDocumentationTest`)
**Roadmap-Update**:
- `03-WEITERE-PHASEN.md` Phase 6 von „⚪ optional
(Auth-Konsolidierung)" auf „✅ abgeschlossen (Auth-Cleanup)"
umgestellt
- Status-Tabelle: Phase 6 ✅
- „Nächste Schritte" angepasst: kein hub-flux-Item mehr offen,
nur noch eigenständige Initiativen (Dark-Mode-Smoke-Test,
PM-Form-Wizard-Refactor, Web-Frontend-Block)
**Lesson**: Mit der Anti-Flash-Bridge aus Phase 5 wären die
hardcoded `class="dark"`-Layouts zu einer Stolperfalle für
Light-Mode-User geworden, sobald jemand sie reaktiviert hätte.
Cleanup zum richtigen Zeitpunkt.
Plan-Doc: `18-PHASE-6-AUTH-CLEANUP.md`
---
## 2026-05-20 · Phase 5 · Dark-Mode-Bugfixes (User-Findings)
Nach dem ersten visuellen Smoke-Test des Users zwei Folge-Fixes
geliefert, plus die Anti-Flash-Bridge:
### Fix 1 — Logo „presse" im Dark Mode
`components/web/brand-mark.blade.php`: Bei `variant="auto"` (Default)
wird die Name-Farbe jetzt über CSS-Custom-Property `--brand-mark-name-color`
mit Light-Mode-Fallback gesetzt. Im Portal-Dark-Mode setzt
`design-tokens.css` `.dark`-Block die Variable auf `#ffffff`. Hub-Frontend
ist Light-Only, dort bleibt die Variable undefiniert und der Marken-
Standardwert greift.
### Fix 2 — Navlist-Flackern beim Klick
`portal.css` Navlist-Item-Block:
- Hover im Dark Mode auf `var(--color-hub-soft)` (Light-Mode-Hover
`var(--color-bg)` ist dunkler als die Sidebar — wirkte als
„Eindrücken" statt Hervorheben)
- `:active`, `:focus` explizit auf `var(--color-hub-soft)` mit
`outline: none` → verhindert Browser-Default-Tap-Flash
- `-webkit-tap-highlight-color: transparent` für mobile Browser
- `:focus-visible` mit Hub-Ring für Tastatur-A11y bleibt erhalten
### Fix 3 — Anti-Flash-Bridge (FOLT bei `wire:navigate`)
Bei `wire:navigate` morpht Livewire das DOM, das neue HTML kommt
vom Server **ohne** `class="dark"` (Server kennt LocalStorage nicht).
Folge: kurzer weißer Theme-Flash, bis JS die Klasse wieder anhängt.
User hat das richtig diagnostiziert.
Lösung:
1. **JS-Bridge** in `partials/head.blade.php` +
`partials/admin-head.blade.php`: wrappt
`window.Flux.applyAppearance`, spiegelt den effektiv applizierten
Modus (bei `system` aus DOM-Klasse abgelesen → `dark`/`light`)
in ein `flux_appearance`-Cookie. Schreibt auch beim initialen
Page-Load.
2. **Server-Side Render**: `<html>`-Tag in
`components/layouts/app/sidebar.blade.php` und
`layouts/admin-master.blade.php` setzt `class="dark"`
direkt, basierend auf dem Cookie:
`@class(['dark' => request()->cookie('flux_appearance') === 'dark'])`
3. **Bonus**: hardcoded `class="dark"` aus `admin-master.blade.php`
raus (war Light-User-Bug-Falle).
Erstbesuch: einmaliger Flash (Cookie noch nicht gesetzt).
Alle weiteren Pageloads: kein Flash mehr.
### Latente Bug-Fixes nebenbei
- `customer/tokens.blade.php` Z. 137: `--color-ink-deep` Token war
nie definiert → durch `--color-panel-dark-2` ersetzt (konstant
dunkel in beiden Modi)
- `customer/security.blade.php` 2FA-QR: erklärender Kommentar für
`bg-white` (Scan-Tauglichkeit)
**Validierung**:
- Build, Pint, Tests: 230/231 (nur ApiDocumentationTest)
---
## 2026-05-20 · Phase 5 · Dark Mode ✅
Phase 5 (Dark Mode) ist abgeschlossen. Die meiste Arbeit war
faktisch schon in Phase 04 erledigt — die konsequente
Token-Disziplin zahlt sich jetzt voll aus.
**Was schon da war (Stand bei Phase-5-Start):**
- `shared/design-tokens.css` hat einen kompletten
`.dark { … }`-Block (Z. 182248) mit allen Surfaces,
Hub-Blau (heller), Bernstein (heller, mit konstantem
`--color-accent-warm`), Ink-Skala (invertiert),
Status-Farben, Bridge-Dots, Schatten und `color-scheme: dark`
- `portal.css` hat `@custom-variant dark (&:where(.dark, .dark *))`
+ Dark-Mode-Shadow-Overrides für Primary-Buttons
- `hub-components.css` ist 100 % token-basiert
- `panel-dark` nutzt `--color-panel-dark*` (konstant)
- `@fluxAppearance` in beiden Head-Partials integriert
- Switcher in Sidebar (Desktop + Mobile) +
`settings/appearance.blade.php`
**Was im Rahmen von Phase 5 gefixt wurde:**
1. **`customer/tokens.blade.php` Z. 137** — Token-Anzeige
nutzte ein nicht existentes `--color-ink-deep`. Damit war
der Code-Block bisher transparent (im Dark Mode wäre
`--color-ink` hell → weißer Text unlesbar). Umgestellt auf
`--color-panel-dark-2` (konstant dunkel, weißer Text in
beiden Modi korrekt).
2. **`customer/security.blade.php` Z. 270** — 2FA-QR-Code in
`bg-white`. Bewusst belassen (QR-Codes brauchen
schwarz-auf-weiß für Scan-Tauglichkeit), erklärender
Kommentar ergänzt.
**Was unkritisch ist (kein Fix):**
- Alle weiteren `bg-white` / `text-white`-Treffer in
`customer/dashboard.blade.php` sind im `panel-dark` Block
(konstant dunkel) oder auf `--color-accent` (Bernstein in
beiden Modi) — passt
- `admin/dashboard.blade.php` Quick-Action Hover
(`group-hover:bg-hub group-hover:text-white`) — Hub-Bg ist
in beiden Modi dunkel genug für weißen Text
- `customer/press-kits/show.blade.php` Logo-Bg `bg-white`
bewusst, weil Firmen-Logos einen weißen Bg brauchen
- Sidebar-`dark:bg-zinc-*` Helper aus dem Starter-Kit —
Zinc-Skala ist in `portal.css` auf warmes Buchpapier
gemapped, läuft
**Außerhalb Phase 5:**
- `shared-styles.css` hat `.dark .card`, `.dark .slider-*`,
`.dark .highlight-*`, `.dark .section-*` — diese sind für
den Web-Bereich (Hub-Frontend, presseecho,
businessportal24). `portal.css` importiert
`shared-styles.css` **nicht** — keine Kollision.
- Web-Frontend bleibt Light-Only (per Roadmap-Definition)
**Validierung:**
- Build: `npm run build:portal` → grün
- Pint: `vendor/bin/pint --dirty --format agent` → passed
- Tests: 230/231 (1 pre-existing `ApiDocumentationTest`, kein
Bezug zur UI-Migration)
**Empfehlung:** Im Browser einmal User-Menü →
Erscheinung → „Dunkel" + Dashboard/Listen/Detail/Security
(QR)/Tokens visuell durchklicken für den Smoke-Test (Pest
hat keine echte Rendering-Pipeline).
Roadmap-Update:
- `03-WEITERE-PHASEN.md` Phase 5 von „⚪ später" auf
„✅ abgeschlossen" gesetzt
- Status-Tabelle aktualisiert
- Empfehlungen verschoben: Phase 6 Auth-Cleanup +
manueller Smoke-Test nach oben
Plan-Doc: `17-PHASE-5-DARK-MODE.md`
---
## 2026-05-20 · Phase 4 · offiziell abgeschlossen ✅
Mit dem Abschluss von 4J ist Phase 4 (Listen/Detail-Pages
durchgehen) in allen 10 Sub-Päckchen 4A4J durch:
| ID | Bereich |
|---|---|
| 4A | Press-Releases Listen (Admin + Customer) |
| 4B | Press-Releases Detail/Show |
| 4C | Press-Releases Forms (create/edit) |
| 4D | Companies (Admin) |
| 4E | Profile/Settings (Admin + Customer) |
| 4F | Restliche Admin-Bereiche (12 Module) |
| 4G | Restliche Customer-Bereiche (5 Module) |
| 4H | Customer „Meine Pressemitteilungen" Mockup-Stil |
| 4I | Admin „Pressemitteilungen" — Patterns übertragen |
| 4J | Dashboard-PM-Listen mit 4H/4I-Patterns |
**Roadmap-Cleanup**:
- `03-WEITERE-PHASEN.md` Phase 4 von „🚧 iterativ" auf
„✅ komplett abgeschlossen" gesetzt
- Phase 2 + 3 (Customer- + Admin-Dashboard) waren faktisch
schon in Phase 1 umgesetzt — Status retroaktiv auf
✅ korrigiert (mit Hinweis auf 4J-Verfeinerung)
- Neuer „Gesamt-Status"-Block in `03-WEITERE-PHASEN.md`
mit Phasen-Tabelle, Sub-Päckchen-Tabelle und konkreten
Empfehlungen für die nächsten Schritte (Phase 5 Dark
Mode > Phase 6 Auth-Cleanup > Web-Frontend-Block als
eigene Roadmap)
- Erkenntnis: Das Mockup `Veröffentlichen Tailwind.html`
ist eine **Public-Facing-Landing-Page** von
businessportal24 (Web-Frontend), nicht ein
Backend-PM-Wizard. Gehört in den separaten
Web-Frontend-Block, nicht in Phase 4.
**Verifikationsstand**:
- 230/231 Tests grün (1 pre-existing
`ApiDocumentationTest`-Fail, unverändert seit 4D)
- Build (Portal) sauber: 424 KB CSS / 16 KB JS gzipped
- Pint sauber
- 16 Plan-Dokumente in `dev/frontend/hub-flux/`
(`00``16` + `PROGRESS.md` + `README.md`)
---
## 2026-05-20 · Phase 4J · Dashboard-PM-Listen mit 4H/4I-Patterns
- **Anlass**: Nach 4H/4I sahen die Voll-Listen exakt wie
das Mockup aus, aber die kompakten PM-Listen in den
Dashboards waren noch im alten Stand (Badge rechts,
Sub-Zeile ohne Portal). 4J schließt diese Inkonsistenz.
- **Befund**: Beide Dashboards waren bereits in Phase 1
großzügig Hub-styled (Page-Header, KPI-Reihe,
`<x-portal.stat-card>`, `<x-portal.hint-card>`,
`panel-dark` Brand-Bridge usw.) — die Roadmap-Status
„⚪ später" für Phase 2 + 3 waren also veraltet und
wurden im Zuge dieses Päckchens auf ✅ gesetzt.
- **Plan-Dokument**: `16-PHASE-4J-DASHBOARD-LISTS.md`.
### Customer-Dashboard (`customer/dashboard.blade.php`)
- Volt: `recent` Select um `portal` + `published_at`
erweitert
- `recent`-Liste:
- Portal-Pills (`pe`/`bp`) neben dem Badge (Both → beide
Pills)
- Sub-Zeile mit `PM-{id} · Firma · Datum`
- `published_at` als Primärdatum für veröffentlichte PMs
- Badge-Mapping erweitert (`muted` für archived/draft
statt `hub`)
### Admin-Dashboard (`admin/dashboard.blade.php`)
- `recentPRs`-Liste:
- Portal-Pills neben Badge (Both → beide Pills)
- Sub-Zeile mit `PM-{id} · Firma · User · Datum`
- Badge-Mapping mit `muted` für archived/draft
- `pendingReviews`-Liste (Review-Queue):
- Row-Tinting `is-row-warn` (gelblich) für alle Items
- Inline-Action „Prüfen →" rechts oben (Link zur
Show-Page, weil Admin-Dashboard Controller+Blade ist
und keine direkte Wire-Methode hat)
- Portal-Pills unter dem Titel
- Container von `<a>` zu `<div>` umgestellt, weil zwei
Links nebeneinander (Titel-Link + Inline-Action) sonst
HTML-invalid wären
- Hover-Underline auf Titel-Link für klare Klickbarkeit
### Tests/Verifikation
- `DashboardTest` (Customer) → 5/5 grün, 21 Assertions
- Volle Suite → 230/231 grün, 1 pre-existing Fail
(`ApiDocumentationTest`)
- `npm run build:portal` → grün (424 KB CSS, +0,2 KB)
- `vendor/bin/pint --dirty` → passed
### Dateien
- `dev/frontend/hub-flux/16-PHASE-4J-DASHBOARD-LISTS.md` (neu)
- `resources/views/livewire/customer/dashboard.blade.php`
- `resources/views/admin/dashboard.blade.php`
- `dev/frontend/hub-flux/PROGRESS.md` (dieser Eintrag)
- `dev/frontend/hub-flux/03-WEITERE-PHASEN.md` (4J +
Phase 2/3 retroaktiv auf ✅)
---
## 2026-05-20 · Phase 4I · Admin „Pressemitteilungen" auf Mockup-Patterns
- **Anlass**: Direktes Folgepäckchen zu 4H — die in der Customer-Liste
entwickelten Mockup-Patterns werden auf die zentrale
Admin-Pressemitteilungen-Liste übertragen (Editorial-Workflow).
- **Plan-Dokument**: `15-PHASE-4I-ADMIN-PRESS-RELEASES.md`.
### Volt-Komponente erweitert (`admin/press-releases/index.blade.php`)
- `pressReleaseStats()` um `rejected` + `archived` Counter
erweitert (zwei zusätzliche `selectRaw` im gleichen Statement,
weiter über `AdminPerformanceCache`)
- Neue Methoden: `setView($view)` (setzt Statusfilter +
resetPage), `resetFilters()` (kompletter Reset inkl.
Entity-Lookups)
### Markup auf Mockup-Stil
- **Saved-Views-Tabs**: 6 Tabs (Alle, In Prüfung,
Veröffentlicht, Entwürfe, Abgelehnt, Archiv) mit
Counter-Pillen, `is-active`-State spiegelt `$statusFilter`
- **Active-Chips** unter Filter-Panel: 8 Filter-Typen
(Suche, Status, Portal, Sprache, Kategorie, User, Firma,
Kontakt) mit Remove-Button + „Alle zurücksetzen"-Link
- **Tabelle umgestellt** (8 → 7 Spalten):
- Status + Inline-Action (Freigeben/Ablehnen für Review,
Archivieren für Published) — Inline-Actions sind
`flux:modal.trigger` für die bestehenden, test-kritischen
Modals
- Titel mit Sub-Zeile (PM-ID + Firma + Sprache, klickbar)
- Portal-Pills (presseecho/businessportal24, bei
`Portal::Both` beide nebeneinander)
- Kategorie (truncate)
- Datum mit Status-Kontext-Sub („veröffentlicht · HH:MM",
„eingereicht · HH:MM", …) und `published_at` als
Primärdatum wenn vorhanden
- Hits monospace
- Aktionen-Spalte rechts reduziert auf view + edit
(Status-Actions wandern in die Status-Zelle)
- **Row-Tinting**: review → `is-row-warn`,
rejected → `is-row-err`
- **Empty-State 2-stufig**: „mit Filter" → Reset-CTA,
„ohne Filter" → Anlegen-CTA
### Was unangetastet bleibt (Test-kritisch)
- `publish()`, `reject()`, `archive()`, `sort()`,
`with()`, alle `clearXFilter()`, `resetEntityFilters()`
- 3 Modals mit Strings „Pressemitteilung veröffentlichen?",
„Pressemitteilung ablehnen?", „Pressemitteilung
archivieren?" — werden weiter vom Markup gemountet,
jetzt zusätzlich via Inline-Action triggerbar
- Combobox-Lookups für User/Firma/Kontakt (Schema +
Verhalten unverändert)
### Pitfall + Fix
- `@php(...)` Inline-Form kompilierte zu `<?php($var = ...)`
ohne Whitespace → PHP-Syntax-Fehler trotz balancierter
Klammern. Workaround: alle drei Inline-`@php(...)` zu
Block-`@php ... @endphp` umgewandelt.
### Verifikation
- `npm run build:portal` → grün (424 KB CSS, +5 KB ggü. 4H)
- `vendor/bin/pint --dirty` → passed
- Gezielt: `AdminPressReleaseActionsTest` +
`PressReleaseWorkflowTest` → 16/16 grün, 52 Assertions
- Volle Suite: 230/231 grün, 1 pre-existing Fail
(`ApiDocumentationTest` — fehlende `docs/api/v1.yml`,
unverändert seit 4D), 3 skipped, 1212 Assertions
### Dateien
- `dev/frontend/hub-flux/15-PHASE-4I-ADMIN-PRESS-RELEASES.md` (neu)
- `resources/views/livewire/admin/press-releases/index.blade.php`
- `dev/frontend/hub-flux/PROGRESS.md` (dieser Eintrag)
- `dev/frontend/hub-flux/03-WEITERE-PHASEN.md` (4I-Eintrag)
---
## 2026-05-20 · Phase 4H · Customer „Meine Pressemitteilungen" auf Mockup
- **Anlass**: Nach Abschluss von 4F entschied sich der User
bewusst gegen die nächste Roadmap-Phase und für **detail-tief
in das wichtigste Customer-Arbeitstool** zu gehen. Vorlage:
`dev/frontend/tailwind_v3/User Pressemitteilungen presseportale.html`.
- **Plan-Dokument**: `14-PHASE-4H-PRESS-RELEASES-MOCKUP.md`.
### Hub-CSS erweitert (`resources/css/shared/hub-components.css`)
Neue Komponenten — alle aus Tokens, KEINE Hex-Literale:
- `.counter-strip` + `.seg` (mit `is-ok`, `is-warn`, `is-err`, `is-muted`) + `.sep`
- `.view-tabs` + `.view-tab` (mit `is-active`, `cnt`-Pille)
- `.filter-chip` (mit `is-active`, `caret`)
- `.active-chip` (mit `x`-Remove-Button)
- `.portal-pill` (mit `pe` + `bp` Dot-Varianten, nutzt
`--color-bridge-presseecho` / `--color-bridge-businessportal`)
- `.inline-action` (mit `warn` + `err` Varianten)
- `.is-row-warn` + `.is-row-err` (Row-Tinting via
`color-mix` aus Status-Soft-Token gegen Card-Background)
- `.empty-stage` + `.empty-ico` (mit `warm` + `err` Varianten)
+ `.empty-title` + `.empty-sub`
- `.badge.muted` (neue Variante neben `ok`, `warn`, `err`, `hub`)
### Volt-Komponente erweitert (`customer/press-releases/index.blade.php`)
- Aggregierte `statusCounts` (assoc) per `groupBy('status')`
über dieselbe `$base`-Query — eine zusätzliche SQL-Query
- Neue Properties: `$portalFilter`
- Neue Methoden: `setView($status)`, `resetFilters()`,
`updatedPortalFilter()`
- Daten an View: `statusCounts`, `portalOptions`
- Paginierung von 100 → 25 (sinnvoller für Mockup-Layout)
### Markup auf Mockup-Stil (~50 % → ~90 %)
- **Counter-Strip im Header**: dynamische Segmente werden nur
angezeigt, wenn Count > 0, mit semantisch eingefärbten
Zahlen (ok/warn/muted/err)
- **Kontext-Hinweis**: „Gefiltert auf :company" als kleine
Sub-Zeile, falls Firma-Kontext aktiv (Test-kompatibel!)
- **Saved-Views-Tabs**: 6 Tabs (Alle, Veröffentlicht,
Entwürfe, In Prüfung, Abgelehnt, Archiv) mit `cnt`-Pille,
klicken setzt `statusFilter` via `setView()`
- **Filter-Sektion**: Suche + Portal-Select + Firma-Select
(letzteres nur wenn `hasGlobalCompanyContext`)
- **Active-Chips**: entfernbare Anzeige aller aktiven Filter
(Status, Portal, Firma, Suche), mit `Alle zurücksetzen`-Link
- **Tabelle**:
- Status-Spalte mit Hub-Badge + Inline-Action „Zur Prüfung →"
für Drafts (ruft `submitForReview` mit `wire:confirm`)
- Titel mit Hub-Style-Link + PM-{id}-Sub
- Portal-Pills (eine oder zwei, abhängig vom Portal-Enum-Wert)
- Firma als Hub-Link oder „— keine —" italic
- Datum: Mono-Font + Sub mit Status-Kontext
(„veröffentlicht · 09:12", „eingereicht · 17:48" …)
- Row-Tint via `is-row-warn` (review) / `is-row-err`
(rejected) — dezent beim Hover
- **3-fach Empty-State**:
- `empty-search` (Suche ohne Treffer)
- `empty-filter` (Filter ohne Treffer, warm-Icon-Box)
- `empty-none` (gar keine PMs, mit 3-Schritt-Onboarding
01-Firma · 02-Verfassen · 03-Zur Prüfung)
- **Status-Aktionen-Legende**: `panel-warm` mit 5-Spalten-
Grid (Entwurf, In Prüfung, Veröffentlicht, Abgelehnt,
Archiviert) und einer Action-Liste je Status
### Was bewusst NICHT umgesetzt wurde
- **Bulk-Selection**: weggelassen (keine Bulk-Actions im
Backend → wäre nur Dekoration ohne Funktion)
- **Inline-Action „Grund ansehen →"** für Rejected: keine
`rejection_reason`-Spalte in `press_releases`-Tabelle
(Grund wird nur via E-Mail an Autor versendet)
- **Spalten- & Export-Buttons** im Header: keine Backend-
Implementierung, weggelassen
- **Modals und Bestätigungs-Flows**: bleiben FluxUI
- **Volt-Logik außerhalb der Erweiterungen**: unangetastet
### Tests & Hygiene
- **Erst-Fail**: `CustomerCompanyContextTest:79` rot, weil
„Gefiltert auf Alpha GmbH" im neuen Layout vom Counter-Strip
verdrängt wurde
- **Fix**: Kontext-Hinweis als zusätzliche kleine Sub-Zeile
unter dem Counter-Strip, immer sichtbar wenn Firma-Kontext
- **PR + Customer Tests**: 50/50 grün (199 Assertions)
- **Volle Suite**: 230 grün (1212 Assertions), 3 skipped,
1 fail = pre-existing `ApiDocumentationTest` (kein Bezug zu UI)
- **Build**: `npm run build:portal` clean
- **Pint**: `vendor/bin/pint --dirty``passed`
- **Lints**: keine Errors
### Status
- Plan-Status: ✅ Phase 4H **abgeschlossen**
- 03-WEITERE-PHASEN.md: 4H ergänzt als ✅
- Match zum Mockup: ≥ 90 %
### Übertragbar auf
- `admin/press-releases/index.blade.php` (Phase 4I als
natürliche Folgephase)
- `admin/users.blade.php`, `admin/contacts/index.blade.php`,
`admin/companies/index.blade.php` (Counter-Strip,
Saved-Views-Tabs, Filter-Chips wären überall sinnvoll)
---
## 2026-05-20 · Phase 4F · Restliche Admin-Bereiche
- **Anlass**: User „4f weiter" nach 4G. Siebtes (und letztes
großes) Päckchen aus Phase 4. Ziel: alle übrigen Admin-Pages
auf Hub-Stil, damit die komplette interne Strecke visuell
abgeschlossen ist.
- **Plan-Dokument**: `13-PHASE-4F-ADMIN-REST.md`.
Aufgrund des Umfangs (~7.500 Z. Blade) in 4 Sub-Päckchen
aufgeteilt.
### 4F-1 · Stammdaten & Switcher
- **`admin/presets/{index,create,edit}.blade.php`** +
`partials/form-fields.blade.php`: Page-Header
(„Admin Backend"-Pille, Eyebrow „Administration · Presets"),
Filter-Panel, Table-Panel mit Hub-Badges und Hub-Empty-State,
Forms in `article.panel`, Required-Marker auf
`text-[color:var(--color-err)]`.
- **`admin/categories/{index,create,edit}.blade.php`**:
Page-Header mit Aktion, KPI-Reihe mit
`<x-portal.stat-card>` (gesamt, aktiv, mit/ohne PMs),
Filter & Sort Panel, Category-Cards als `article.panel`,
Hub-Badges, Hub-Style innere Items, Danger-Zone mit linkem
roten Strip.
- **`admin/portal-switcher.blade.php`** (Sidebar):
Token-basierte Button-Farben mit `--color-bg-elev`,
`--color-bg-rule`, `--color-ink`, `--color-ink-2`,
`--color-ink-3`.
- **Tests**: `CategoryIndexPerformanceTest`,
`AdminCategoryManagementTest`,
`AdminPresetManagementTest` — alle grün.
### 4F-2 · Pressekontakte
- **`admin/contacts/index.blade.php`** (729 Z.): Page-Header
mit Action, KPI-Reihe (`<x-portal.stat-card>`),
Filter-Panel, Preset-Panel, Table-Panel mit Hub-Badges und
Hub-Empty-State, Hub-Style Flash-Boxen.
- **`admin/contacts/create.blade.php`** (275 Z.):
Page-Header mit „prefilled company"-Badge, Forms in
`article.panel`.
- **`admin/contacts/edit.blade.php`** (352 Z.):
Page-Header mit ID + Portal-Badge, Forms in
`article.panel`, Danger-Zone mit linkem roten Strip.
### 4F-3 · Operations & Finance
- **`admin/footer-codes/{index,create,edit}.blade.php`**:
Page-Header, KPI-Reihe, Filter-Panel, Table-Panel mit
Hub-Badges, Forms in `article.panel`, Category-Checkboxes
Hub-styled, Danger-Zone.
- **`admin/reports/slow-requests.blade.php`** +
`slow-requests-table.blade.php`: Page-Header,
Filter-Panel mit Reset-Button, KPI-Reihe, Top Routes/Paths
Panels, Slowest-Requests-Table, Frequent Slow Queries Table,
EXPLAIN Top Slow Queries Panel — alles Hub-styled.
- **`admin/invoices/index.blade.php`** (Legacy-Archiv):
Page-Header mit Archive-Badge, Warning-Box für „unmapped",
KPI-Reihe, Filter-Panel, Table-Panel mit Hub-Badges +
Pagination.
- **`admin/coupons/index.blade.php`** (Stub): Page-Header
„Vertagt"-Badge, Info-Panel mit Hub-Style List-Items.
- **`admin/payments/index.blade.php`** (Stub): Page-Header
„In Vorbereitung"-Badge, Info-Panel mit Hub-Style
List-Items + Rules.
- **Tests**: `AdminFooterCodeManagementTest`,
`AdminSlowRequestReportTest`,
`AdminSlowRequestLoggingTest`,
`AdminLegacyInvoiceArchiveTest` — alle grün.
### 4F-4 · User-Verwaltung
- **`admin/roles/{index,create,edit}.blade.php`**:
Page-Header (mit ID + System-Role-Badges in edit),
Warning-Box für System-Rollen, Forms in `article.panel`,
Table-Panel mit Hub-Badges + Empty-State.
- **`admin/newsletter/sync.blade.php`** (171 Z.):
Page-Header mit Sync-Status-Badge (active/deactivated),
Action-Buttons (Dry Run, Test-Sync) im Header, Hub-Style
Info/Success-Pillen für Notifications, KPI-Reihe mit
`<x-portal.stat-card>` (gesamt, bestätigt, ausstehend,
abgemeldet), Config-Details (Provider, Timeout, Endpoint)
als Definition-List in `article.panel`.
- **`admin/users.blade.php`** (939 Z.): Page-Header mit
Action „Benutzer anlegen", KPI-Reihe (gesamt, aktiv,
inaktiv), Filter-Panel mit Reset-Button, Table-Wrapper
als `article.panel` mit Hub-Empty-State. **Modal**
und alle Tabellen-Inhalte bewusst unangetastet — wegen
Test-Strings + Komplexität.
- **`admin/users/show.blade.php`** (239 Z.): Hub-Header mit
ID + Status-Badges, KPI-Reihe (Portal, Typ, Status, Login),
Rollen-Panel, Rechnungsadresse-Panel,
„Verknüpfte Firmen & Kontakte"-Panel als verschachtelte
Hub-Boxes.
- **`admin/users/create.blade.php`** (421 Z.): Hub-Header,
Forms in `article.panel` (Basisdaten, Rollenzuweisung,
Firmenverknüpfung, Rechnungsadresse), Action-Panel
am Ende.
- **`admin/users/edit.blade.php`** (1.224 Z.): Hub-Header
mit ID/Portal/Status-Badges, Notification als
Hub-Style Ok-Pill, Quick-Nav als Token-Pillen mit
Hover auf Hub-Blue, KPI-Reihe (Account, Legacy-Profil,
Verknüpfungen, Rechnungsadresse). Innere Sektionen
(`#account`, `#legacy-profile`, `#roles`,
`#company-links`, `#contact-links`, `#billing-address`)
bleiben `flux:card` (IDs für Quick-Nav, sehr großes File).
Footer-Action-Panel auf Hub umgestellt.
- **Tests**: `UserManagementTest`, `UserImpersonationTest`,
`UserList*Test` — 29 Tests / 270 Assertions grün.
### Bauplatz-Hygiene
- **Build**: `npm run build:portal` — sauber durch.
- **Pint**: `vendor/bin/pint --dirty``passed`.
- **Lints**: keine Linter-Errors in den editierten Blade-Files.
- **Pre-existing**: `ApiDocumentationTest` weiterhin rot, kein
Bezug zu UI-Styling (siehe frühere Phasen).
### Abgrenzung — was bewusst NICHT angefasst wurde
- Volt-Logik in allen Dateien (PHP, `mount`, `save`,
`with`, …).
- `<flux:input>`, `<flux:select>`, `<flux:checkbox>`,
`<flux:textarea>`, `<flux:field>`, `<flux:error>`,
`<flux:table.*>`, `<flux:button>`, `<flux:modal>`.
- Innere Sektionen von `users/edit.blade.php` mit ID-Ankern
(Quick-Nav-Targets) — diese bleiben `flux:card`, da
Footnote-Logik daran hängt und das File 1.224 Z. groß ist.
- Modal in `users.blade.php` und alle internen Bestätigungs-
Flows (Test-Strings).
- Test-relevante Strings überall.
### Status
- Plan-Status: ✅ Phase 4F **abgeschlossen**.
- 03-WEITERE-PHASEN.md: 4F auf ✅ aktualisiert.
---
## 2026-05-20 · Phase 4G · Customer Portal (Mein Bereich)
- **Anlass**: User „weiter 4G" nach 4E. Sechstes Päckchen aus
Phase 4: alle übrigen Customer-Pages auf Hub-Stil bringen,
damit die komplette User-sichtbare Strecke (Mein Bereich)
visuell abgeschlossen ist.
- **Plan-Dokument**: `12-PHASE-4G-CUSTOMER-PORTAL.md`.
- **Was umgebaut wurde**:
- **`customer/company-switcher.blade.php`** (Sidebar-Helper,
91 Z.): „Aktive Firma"-Label als `.badge hub dot`,
Portal-Suffix als Token-Eyebrow, „Keine Firma zugeordnet"
als `.badge warn`. `<flux:select>`, `Firma öffnen`-Button
und `route('me.press-kits.show', …)` bleiben — alles, was
der `CustomerCompanyContextTest` assertiert, ist erhalten.
- **`customer/bookings.blade.php`** (Coming-Soon, 52 Z.):
Hub-Page-Header („User Backend"-Pille,
„Mein Bereich · Finanzen"-Eyebrow, Warn-Pille
„In Vorbereitung"). Info-Box auf Hub-Soft-Token,
3 Feature-Panels mit Eyebrow + Beschreibung.
- **`customer/invoices.blade.php`** (194 Z.): Page-Header
mit Aktion „Rechnungsadresse im Profil pflegen". Hinweis
in eigenes `.panel`. 4 KPI-Cards (primary/muted/ok/warn).
Filter-Panel, Tabellen-Panel mit Hub-Badges (`ok dot`
für bezahlt, `warn dot` für offen), Empty-State als
Icon-Box. Pagination am Boden im Panel mit Top-Border.
Notification als Hub-Warn-Pille mit Icon.
- **`customer/tokens.blade.php`** (212 Z.): Hub-Page-Header
mit „API-Dokumentation"-Aktion. Flash-Boxen (success/warn)
in Token-Style. „Neuer Token"-Anzeige als eigenes Panel
mit linkem Warn-Strip (`border-left:3px solid
--color-warn`) + `.badge warn`-„Nur jetzt sichtbar". Form
in Panel mit Border-Top-getrenntem Submit-Bereich.
Tabelle in Panel mit Counter, Berechtigungen als
`.badge hub` (statt `flux:badge`), Empty-State als
Icon-Box.
- **`customer/press-kits/index.blade.php`** (119 Z.):
Hub-Page-Header. Filter-Panel. Karten-Grid mit
`.panel`-Karten: `.panel-head` mit Status-Badge
(`ok dot` / `err dot`), Body mit Slug, Portal/Rolle/
Footer-Badges, KPI-Boxen (Border + bg-elev), Footer
mit Border-Top + „Firma öffnen"-Button.
Empty-State als full-width Panel mit Hub-Icon-Box.
- **`customer/press-kits/show.blade.php`** (734 Z. → Polish):
Großes Detail-Cockpit komplett auf Hub:
- **Header**: Pillen-Reihe (User-Backend, Mein
Bereich · Firma, Aktiv/Inaktiv, Portal, Rolle, ggf.
Footer-Code-aus) + Logo-Box (oder Hub-Icon-Box) + H1
+ Slug. Aktionen rechts: Zurück, Stammdaten bearbeiten,
Neue PM.
- **Quick-Nav**: Anker-Links als pillen-artige
Hover-Buttons mit Bottom-Border.
- **4 KPI-Cards**: PMs (primary), Pressekontakte (ok),
Portal (muted), Deine Rolle (muted) — mit
`canManageCompany`-abhängiger Trend.
- **Stammdaten-Panel**: `.panel-head` mit Bearbeiten-
Button. Inline-Form als `bg-elev`-Block mit
Border-Top-getrennten Sections (Logo / Aktionen).
Daten-Liste als `<dl>` mit Token-Labels + Werten,
Website als Hub-Underline-Link.
- **Pressekontakte-Panel**: `.panel-head` mit Counter.
Inline-Form analog Stammdaten. Kontakt-Items als
`bg-elev`-Boxen mit Aktionen rechts. Empty-State als
gestrichelte Box. Flash-Messages
(„Pressekontakt wurde angelegt./aktualisiert./
gelöscht.") in Token-Success-Pille.
- **Pressemitteilungen-Panel**: Tabelle mit Hub-Status-
Badges (ok/warn/err/hub). Empty-State Hub-Icon-Box.
- **Abrechnung & Statistik**: 2 Panels nebeneinander
mit „In Vorbereitung"/„Später"-Warn-Pillen. Abrechnung
mit gestrichelter Hint-Box. Statistik mit
2 Token-Mini-Stats.
- **Was bewusst unverändert blieb**:
- Volt-PHP-Logik in allen Dateien (mount, saveCompany,
saveContact, deleteContact etc.).
- Flash-Strings („Stammdaten wurden gespeichert.",
„Pressekontakt wurde angelegt./aktualisiert./gelöscht.",
„Token wurde erstellt", „Token wurde widerrufen.",
„API-Tokens werden erst freigeschaltet" etc.) —
bleiben in Volt-PHP wie zuvor und erscheinen in den
neuen Hub-Pillen.
- Section-Headings „Abrechnung" und „Statistik" — Tests
assertieren genau diese Strings.
- Strings im Header („Alpha GmbH", „Firma öffnen",
`route('me.press-kits.show', …)`).
- FluxUI-Form-Komponenten (`flux:input`, `flux:select`,
`flux:textarea`, `flux:checkbox`, `flux:field`,
`flux:error`, `flux:table*`) — nur Wrapper-Markup
verändert.
- **Verifikation**:
- `php artisan view:clear`
- `npm run build:portal` ✓ — 418.11 kB CSS / 44.38 kB JS
(keine Größenänderung gegenüber 4E).
- `php artisan test --compact tests/Feature/{
CustomerPortalTest, CustomerCompanyContextTest,
PanelConsolidationTest}.php` →
**29 passed, 131 assertions**.
- Volle Suite: **230 passed, 3 skipped, 1 pre-existing
fail** (`ApiDocumentationTest` — fehlende
`docs/api/v1.yml`, war auch vor 4G/4E/4D rot).
- `vendor/bin/pint --dirty --format agent` → `passed`.
- **Resultat**:
- Mein-Bereich des Users ist visuell **vollständig** auf
Hub-Sprache.
- Sidebar-Nav (presse-kits, invoices, tokens, bookings)
läuft jetzt durchgängig im selben Vokabular wie Dashboard
+ Press-Releases.
- Detail-Cockpit `press-kits/show` ist das visuell
aufwendigste Customer-Page und stimmt jetzt mit Admin-
Detail-Show überein (Pillen-Header, KPI-Reihe, Panels,
Quick-Nav, Tabellen).
- **Nächste mögliche Päckchen**:
- **4F** Restliche Admin-Bereiche (contacts, categories,
presets, footer-codes, slow-requests, users).
- **press-release-images-manager** Komponente (kleiner
Cleanup aus 4C-Resten).
- **Phase 5** Dark-Mode-Konsolidierung.
---
## 2026-05-20 · Phase 4E · Profile & Settings
- **Anlass**: User „okay weiter" nach 4D. Fünftes Päckchen aus
Phase 4: alle Settings-Pages (Admin + Customer) auf Hub-Stil.
- **Plan-Dokument**: `11-PHASE-4E-PROFILE-SETTINGS.md`.
- **Zentraler Trick — Wrapper umgebaut**:
- **`resources/views/partials/settings-heading.blade.php`**:
Komplett neu als Hub-Page-Header (Pille „Admin Backend",
Eyebrow „Mein Konto · Einstellungen", H1 „Settings",
Subtitle).
- **`resources/views/components/settings/layout.blade.php`**:
Komplett neu als 2-Spalten-Grid mit Sidebar-Nav-`.panel`
(„Mein Konto"-Eyebrow + FluxUI-Navlist drin) und
Content-`.panel` mit `.panel-head` für Page-Heading +
Subheading im Body. Heading/Subheading-Slots der einzelnen
Settings-Pages werden so automatisch im Hub-Look gerendert.
- **Effekt**: `settings/appearance.blade.php` musste
**gar nicht** angefasst werden — übernimmt den Hub-Look
via Wrapper. Die anderen beiden brauchen nur
Save-Bar-Polish.
- **Was umgebaut wurde**:
- **`settings/profile.blade.php`**: Verification-Hinweis von
`<flux:text>`-Link auf Hub-Warn-Box (gelber Linker Strip,
Icon, Hub-Link für „re-send the verification email").
Save-Bar mit Border-Top + Token-`Saved.`-Pill.
Delete-Button-Section visuell durch Border-Top abgetrennt.
- **`settings/password.blade.php`**: Save-Bar gleicher Polish.
- **`settings/delete-user-form.blade.php`**: Das `mt-10`-Card
durch Hub-Danger-Box mit `border-l-[3px]
border-l-[color:var(--color-err)]`, „Danger Zone"-Eyebrow,
H3 + Subtitle + Trash-Button. Modal-Markup komplett
unverändert (Confirm-Password-Modal kommt aus FluxUI-Std.).
- **`customer/profile.blade.php`**: Page-Header („User
Backend"-Pille, „Mein Bereich · Profil"-Eyebrow,
„Mein Profil"-H1). Form in 3 Panels + Aktions-Panel:
Konto (Name/E-Mail/Sprache) · Profil (Anrede,
Vor-/Nachname, Telefon, Backlink, Checkboxen) ·
Rechnungsadresse (mit Warn-Hub-Box, wenn unvollständig).
Zugeordnete-Firmen als eigenes `.panel` mit Hub-Badges
(`ok` für Eigentümer, `hub` für Portal/Rolle).
- **`customer/security.blade.php`**: Page-Header. 4-spaltige
KPI-Reihe mit `.panel` + uppercase-Eyebrow + großer Wert +
Hub-Badge (E-Mail bestätigt? · 2FA aktiv? · Letzter Login +
IP · Sessions-Count). 2-Spalten-Grid für Passwort + E-Mail
in `.panel` mit `.panel-head`. 2FA-`.panel` mit
ok-Badge im Header wenn aktiv, Recovery-Codes mit
Hub-Bg-Boxes. Sessions-`.panel` mit Eintrags-Counter,
Empty-State als Hub-Icon-Box. **Alle Test-Strings
erhalten**: „Konto-Sicherheit", „Letzter Login",
„Aktive Sessions", „Passwort ändern", „E-Mail-Adresse
ändern", „Zwei-Faktor-Authentifizierung",
„Rechnungsadresse".
- **Tests**:
- Smoke: `Settings|CustomerProfileSecurity|
CustomerCompanyContext` → 33 passed (146 assertions).
- Volle Suite: 230 passed / 3 skipped /
1 pre-existing `ApiDocumentationTest`-Fail.
- **Build / Pint**: `npm run build:portal` ✓ (418 kB CSS),
`pint --dirty` ✓, keine Linter-Errors.
- **Bewusst NICHT angefasst**:
- Volt-Logik in allen Dateien.
- Confirm-User-Deletion-Modal-Markup
(`settings/delete-user-form.blade.php`).
- Fortify-2FA-Logik (Enable / Disable / Recovery-Codes-
Regenerate / QR-Generation).
- `<x-action-message>` Component-Wrapper — nur Slot-Inhalt.
- **Nächster Schritt** — Vorschlag:
- **4G** Customer-Bereiche (invoices, tokens, bookings,
company-switcher, me/press-kits/*) — Tests fordern
Strings, aber alle gut greifbar.
- **4F** Restliche Admin-Bereiche (contacts, categories,
presets, footer-codes, slow-requests, users) — größeres
Päckchen, sollte weiter unterteilt werden.
---
## 2026-05-20 · Phase 4D · Companies (admin)
- **Anlass**: User „okay weiter" nach 4C. Viertes Päckchen aus
Phase 4: alle vier Admin-Companies-Pages auf Hub-Stil.
- **Plan-Dokument**: `10-PHASE-4D-COMPANIES.md`.
- **Was umgebaut wurde**:
- **`admin/companies/index.blade.php`**: Hub-Page-Header
(„Admin Backend"-Pille, Eyebrow „Stammdaten · Firmen",
H1 „Firmen", Subtitle, CTA „Neue Firma" rechts) →
3 `<x-portal.stat-card>` (Gesamt/Aktiv/Inaktiv) →
Filter-`.panel` mit Combobox-Selects unverändert in der
Logik, nur Hülle getauscht → Tabelle in `.panel
overflow-hidden` mit `.panel-head` „Alle Firmen" +
Eintrags-Counter. Tabellen-Status/Portal/Count-Badges
auf Hub-Klassen (`badge ok|err|hub` + Dot) gesetzt.
Empty-State als Hub-Icon-Box.
- **`admin/companies/show.blade.php`**: Header mit
Status-, Portal- und ID-Pille; Logo-Box neben H1. KPI-Reihe
(3 stat-cards). Tabs „Überblick" / „Kontakte" als schlankes
Bottom-Border-Pattern (kein FluxUI-Tabs-Group nötig). Beide
Tab-Inhalte komplett in `.panel`-Sektionen mit `dl`-Layouts
bzw. Kontakt-Karten. Existing-Contact-Combobox bleibt
FluxUI; Wrapper auf Hub-`bg-elev`. Flash-Boxen
(success/error/info) auf Token-Pillen.
- **`admin/companies/edit.blade.php`**: Page-Header
(„ID"-Pille), 5 Form-Panels (Basisinformationen, Adresse,
Rechtliche Daten, Logo & Status, Aktionen). Required-Marker
auf `text-[color:var(--color-err)]`. Logo-Vorschau-Bild
nutzt Hub-Token-Border. „Logo wird beim Speichern entfernt"
auf Hub-Warn-Box (statt `flux:callout`).
**Delete-Confirm-Modal komplett unverändert.**
- **`admin/companies/create.blade.php`**: gleiches Schema
wie Edit, ohne Status-Pille und ohne Delete-Button. Forms
in 5 Panels strukturiert.
- **Tests**:
- Companies-Smoke: `UserManagement|PortalAssetManifest`
→ 25 passed (227 assertions).
- Volle Suite: 230 passed / 3 skipped /
1 vorbestehender Fail (`ApiDocumentationTest` —
fehlende Datei `docs/api/v1.yml`, nicht durch Phase 4D
verursacht).
- **Build / Pint**: `npm run build:portal` ✓ (418 kB CSS,
44 kB JS), `vendor/bin/pint --dirty --format agent` ✓.
- **Bewusst NICHT angefasst**:
- Volt-Logik in allen vier Dateien.
- `deleteCompany`-Methode und ihr Confirm-Modal-Markup
(Test `UserManagementTest::admin can delete company`
prüft Redirect-Verhalten, nicht UI).
- `<flux:select variant="combobox">` (Kontakt-/User-Lookup)
und alle anderen `flux:field`/`flux:input`-Bausteine —
Token-Bridging trägt.
- Test-relevante Strings: „Firmen", „Portal", „Alle Portale",
„Presseecho", „Businessportal24", „/admin/companies/…".
- **Nächster Schritt (Phase 4E oder 4F)**:
- **4E** = Profile/Settings (`settings.*`, `me.profile`,
`me.security`) — eher klein, viele kleine Panels.
- **4F** = Restliche Admin-Bereiche (contacts/, categories/,
presets/, footer-codes/, slow-requests, …) — Päckchen-Größe.
---
## 2026-05-19 · Phase 4C · Press-Releases Forms (create / edit)
- **Anlass**: User-Freigabe „ja" nach 4B. Drittes Päckchen aus
Phase 4 — Forms (create + edit) für Admin und Customer.
- **Plan-Dokument**: `09-PHASE-4C-PRESS-RELEASES-FORMS.md`.
- **Was umgebaut wurde (alle 4 Forms)**:
- **Page-Header** wie auf Listen und Detail: Hub-Badge
(„Admin Backend" / „User Backend") + Eyebrow + großes H1 +
Subtitle. Bei Edit zusätzlich Status-Pille im Header-Meta
(`@class([])`-Syntax mit `ok|warn|err|hub`) und „ID"-Pill.
Aktions-Buttons rechts (Zurück).
- **Form-Sektionen** als `.panel` mit `.panel-head` und
`section-eyebrow`: „Inhalt", „SEO & Links", „Metadaten",
„Status-Aktionen" (Admin-Edit), „Aktionen". Innenraum
immer `p-5 space-y-4`.
- **Form-Felder** bleiben FluxUI (`<flux:field>`,
`<flux:label>`, `<flux:input>`, `<flux:textarea>`,
`<flux:select>` inkl. Combobox-Variant, `<flux:checkbox>`,
`<flux:error>`) — das Token-Bridging aus Phase 1 zieht.
- **Required-Marker** von `text-red-500` auf Token-Farbe
(`text-[color:var(--color-err)]`) umgestellt.
- **Save-/Submit-Buttons** in eigenem `.panel` mit Header
„Aktionen" statt „nackten" Buttons in der Sidebar.
- **Flash-Boxen** (Success/Error) auf Hub-Token-Pillen.
- **Admin-Edit-spezifisch**: 5 Sidebar-Panels (Status-Aktionen +
Metadaten + Aktionen + Modals). „Status-Aktionen"-Panel zeigt
rechts im Header die aktuelle Status-Pille — visuelle Doppelung
mit dem Page-Header-Status, aber im Kontext der Sidebar
sinnvoll als Vergleichs-Anker für die „Neuer Status"-Auswahl.
- **Was explizit NICHT angefasst wurde**:
- **Volt-Logik** (alle `save`/`publish`/`reject`/`backToDraft`/
`archive`/`changeStatus`/`deletePressRelease`/`mount`/`with`/
`selectedCompany`-Methoden) — Layout-only.
- **Confirm-Modals** der Admin-Edit-Page
(`confirm-status-change`, `confirm-delete-press-release`) —
Tests in `AdminPressReleaseActionsTest` assertieren Wortlaute.
- **Wortlaute**: „Neuer Status", „Status wechseln",
„Status wirklich wechseln?", „Pressemitteilung löschen?",
„Status wurde auf" — alle erhalten.
- **`<livewire:components.press-release-images-manager>`** —
eigene Komponente, kommt im jeweiligen eigenen Päckchen dran.
- **Build/Test**:
- `npm run build:portal` → ok (`portal-D0cNdOWP.css` 418.42 kB).
- Linter clean (alle 4 Dateien).
- `php artisan test --compact --filter='PressRelease|CustomerCompanyContext|CustomerProfileSecurity|PanelConsolidation'`
→ **72 passed (310 assertions)**.
- Volle Suite: 230 passed, 3 skipped, 1 pre-existing failure
(`ApiDocumentationTest`).
- Pint `--dirty --format agent` → passed.
- **Offene Fragen**: Keine.
- **Nächster Schritt**: Phase 4 für Press-Releases ist mit 4A/4B/4C
komplett abgeschlossen. Nächstes Päckchen je nach Sichtbarkeit:
**4D = Companies** (`admin.companies.*`) ODER
**4E = Settings / Profile** (`me.profile`, `me.security`).
---
## 2026-05-19 · Phase 4B · Press-Releases Detail/Show-Pages
- **Anlass**: User-Freigabe „weiter" nach 4A. Zweites Päckchen aus
Phase 4 — Detail/Show-Pages für Admin und Customer.
- **Plan-Dokument**: `08-PHASE-4B-PRESS-RELEASES-DETAIL.md`.
- **Was umgebaut wurde (beide Show-Pages)**:
- **Page-Header** mit Hub-Badge + Eyebrow + Status-Pill +
Sprache + Portal (Admin nur), darunter großer H1 mit dem
PM-Titel und Subtitle mit Firma/Kategorie/Autor bzw. Datum.
Aktions-Buttons rechts (Bearbeiten/Vorschau-Link/Zurück).
- **Status-Workflow-Aktionsbar** als `.panel` mit `.panel-head`
und passend gefärbtem Badge je nach Status (warn=Review,
ok=Published, err=Rejected, hub=Draft).
- **Content-Hauptbereich** (PM-Text) als `.panel` mit eigenem
Header „Inhalt" + `prose` darunter. Keywords/Backlink darunter
als Footer mit Hub-Rule.
- **Sidebar / Side-Cards** (Admin) als kompakte `.panel` mit
`panel-head` „Details" und „Bilder" + Hub-Badges.
- **Status-Verlauf-Timeline** als `.panel` mit Hub-Badge je
Log-Eintrag (`.badge.ok|warn|err|hub`) statt FluxUI-`color`-Props.
- **Status-Badges** in Header und Timelines komplett auf
`<span class="badge …">` mit `@class([])`-Syntax.
- **Customer-Show-spezifisch**:
- **Rejection-Hinweis** als roter `.panel` mit linker
Akzent-Border (`border-left-width:3px`) und Icon-Box —
statt `<flux:callout color="red">`.
- **Review-Pending-Hinweis** als warner `.panel` mit
Akzent-Border und Clock-Icon-Box — statt `<flux:callout color="yellow">`.
- **Share-Link-Erfolgsblock** als ok-`.panel` mit
Gültigkeits-Badge im Header und readonly-Input im Body.
- **Contacts-Liste** als Hub-Items (`bg-bg-elev` +
`border-bg-rule`), Empty-State mit gestrichelter Border.
- **Status-Tile-Grid** (Aktuell/Erstellt/Veröffentlicht/Aufrufe)
als 4-er-Grid mit kleinen Hub-Tiles statt zinc-Hintergründen.
- **Admin-Show-spezifisch**:
- **Modals** (Publish/Reject/Archive) komplett unverändert —
Tests in `AdminPressReleaseActionsTest` assertieren Wortlaute.
- **Was explizit NICHT angefasst wurde**:
- **Volt-Logik** (publish/reject/archive/submitForReview/
generateShareLink/with-Method) — Layout-only.
- **Wortlaute** „Erneut einreichen", „Werbliche Sprache wurde
markiert." aus `PressReleaseWorkflowTest`.
- **Bestehende Modals** und ihre Wortlaute.
- **Mini-Stolperer (sofort gefixt)**:
- Erst zwei nicht-existente Tokens (`--color-rule`,
`--color-panel-soft`) verwendet. Korrigiert zu
`--color-bg-rule` und `--color-bg-elev` (16 + 5 Vorkommen).
Wäre im Browser stumm gefailed (Tailwind hätte die
Klassen einfach nicht ausgegeben).
- **Build/Test**:
- `npm run build:portal` → ok (`portal-Bq4pkLWt.css` 418.36 kB).
- Linter clean.
- `php artisan test --compact --filter='PressReleaseWorkflow|AdminPressReleaseActions'`
→ 16 passed (52 assertions).
- Volle Suite: 230 passed, 3 skipped, 1 pre-existing failure
(`ApiDocumentationTest`, schon vor 4A bekannt).
- Pint `--dirty --format agent` → passed.
- **Offene Fragen**: Keine.
- **Nächster Schritt**: Päckchen **4C** = Press-Releases Forms
(`create.blade.php` + `edit.blade.php`, Admin + Customer).
Forms sind tendenziell aufwendiger (mehr FluxUI-Felder, ggf.
zusätzliche Logik wie Image-Uploads).
---
## 2026-05-19 · Phase 4A · Press-Releases Listen-Pages
- **Anlass**: User-Freigabe „weiter" nach Phase 3 (Admin-Dashboard).
Phase 4 ist laut Roadmap „der Marathon" über Listen-/Detail-Pages
(~35 Tage iterativ). Wegen Umfang in Päckchen geteilt — A = Listen,
B = Detail/Show, C = Forms, D = Companies, E = Settings, F = Rest.
- **Plan-Dokument**: `07-PHASE-4A-PRESS-RELEASES-LISTEN.md` (knapp,
Scope hart auf zwei `index.blade.php`-Files begrenzt, mit explizitem
„NICHT in diesem Päckchen"-Block).
- **Scope dieses Päckchens**:
- `resources/views/livewire/admin/press-releases/index.blade.php`
- `resources/views/livewire/customer/press-releases/index.blade.php`
- **Was umgebaut wurde (beide Listen)**:
- **Page-Header** im Hub-Stil: `<header>` mit `1fr auto`-Grid,
Hub-Badge („Admin Backend" / „User Backend"), Eyebrow, großes H1,
Subtitle, rechts der CTA-Primary-Button (FluxUI bleibt für den Button).
- **Filter-Bar** als `.panel` + `.panel-head` mit `section-eyebrow`
„Filter & Suche". FluxUI-Inputs (Search-Input, Selects, Combobox
für User/Company/Contact-Lookup) bleiben unverändert — Hub hat
kein eigenes Combobox-Pendant.
- **Tabelle** als `.panel` mit `.panel-head` „Alle Pressemitteilungen"
+ Eintrags-Counter rechts. FluxUI-`<flux:table>` bleibt — das
Zinc-→Hub-Mapping aus Phase 1 zieht hier perfekt.
- **Status-Badges**: `<flux:badge color="green|yellow|red|zinc|blue">`
ersetzt durch `<span class="badge ok|warn|err|hub">` für visuelle
Konsistenz mit dem Dashboard (`@class([...])`-Syntax).
- **Empty-State** mit Icon-Box (`bg-[color:var(--color-hub-soft)]`,
Hub-Border, `flux:icon.newspaper`) + Headline + Subtext.
- **Flash-Boxen** auf Hub-Tokens (`--color-ok-soft`, `--color-err-soft`,
`--color-gain-deep`, `--color-loss`) statt `bg-green-50` etc.
- **Admin-spezifisch**: Vier `<x-portal.stat-card>` (Gesamt/Veröffentlicht/
In Prüfung/Entwürfe) als KPI-Reihe — identisches Layout wie Admin-Dashboard.
- **Was explizit NICHT angefasst wurde**:
- **Confirm-Modals** (Publish/Reject/Archive) — Tests in
`AdminPressReleaseActionsTest` assertieren die Wortlaute
(„Pressemitteilung veröffentlichen?" etc.) → unverändert.
- **Volt-Logik** (Sort, Filter, alle Methods) — Layout-only.
- **Bonus-Fix**: `customer/dashboard.blade.php` Subtitle bekommt
einen „Übersicht für :company —"-Einschub, wenn `$selectedCompany`
gesetzt ist. Korrigiert eine Phase-2-Regression bei
`CustomerCompanyContextTest > customer dashboard is filtered by …`.
- **Build/Test**:
- `npm run build:portal` → ok (`portal-DaL-tXm-.css` 418.75 kB).
- Linter clean.
- `php artisan test --compact --filter='PressReleaseWorkflow|AdminPressReleaseActions|Dashboard|CustomerCompanyContext'`
→ 45 passed (163 assertions).
- Volle Suite: 230 passed, 3 skipped, 1 failed.
Der einzelne Fail (`ApiDocumentationTest`) ist **pre-existing** —
via `git stash` verifiziert, war auch vor diesem Päckchen rot
(`/docs/api/v1` liefert nicht das erwartete YAML).
- Pint `--dirty --format agent` → passed.
- **Offene Fragen**: Keine.
- **Nächster Schritt**: Päckchen **4B** = Detail/Show-Pages
(`admin/press-releases/show.blade.php` +
`customer/press-releases/show.blade.php`). Dort ist mit der
„Werbliche Sprache wurde markiert."- und „Erneut einreichen"-
Assertion aus `PressReleaseWorkflowTest` zu rechnen — Wortlaute
bleiben unverändert.
---
## 2026-05-19 · Phase 3 · Admin-Dashboard im Hub-Vokabular
- **Anlass**: User-Freigabe „weiter" nach Phase 5 (Dark Mode). Phase 3
laut Roadmap: Admin-Dashboard (`/dashboard`) im selben Vokabular wie
Customer-Dashboard.
- **Plan-Dokument**: `06-PHASE-3-ADMIN-DASHBOARD.md` (knapper als
Phase 2 — niedrig-risiko, keine neuen Konzepte, reine
Vokabular-Migration auf die DRY-Schicht aus Phase 2).
- **Ausgangslage**: `admin/dashboard.blade.php` war Controller-rendered
(kein Volt), nutzte reines Tailwind mit `zinc-*`-Klassen, harten
Farb-Pillen (`bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 …`)
und keiner FluxUI-Komponente. Visuell aus der Zeit gefallen.
- **`admin/dashboard.blade.php` komplett umgeschrieben**:
- **Page-Header**: Hub-Badge „Admin Backend" + Eyebrow + großes H1
+ Subtitle mit `auth()->user()->name`. Rechts: ok-Pille
„Alle Systeme operational".
- **KPI-Reihe** (5 Stat-Cards via `<x-portal.stat-card>`):
- Pressemitteilungen → `primary` mit Trend-Slot
„X pub · Y prüf · Z entwurf" (Wortlaut für Test-Assertions
bewusst beibehalten).
- In Prüfung → `warn` als eigene KPI (war vorher nur in der PM-Card
versteckt — jetzt klickbar direkt in den Filter).
- Firmen / Kontakte / Benutzer → `muted` mit kurzen Sublines.
- Alle Cards sind klickbar (link-wrapped) → CRM-/Content-Übersichten.
- **2-Spalten-Grid** (`2fr 1fr`):
- Links: Panel „Letzte Pressemitteilungen" mit Hub-Liste +
`.badge.ok|warn|err|hub`-Pillen (statt Tailwind-Farben).
- Rechts: Panel „Zur Prüfung" mit warn-Pille (Count) oder
ok-Pille „leer". „+ N weitere"-Link im Footer.
- **Newsletter + Quick-Actions** (`1fr 2fr`, NEU):
- Links: `panel-warm` Newsletter-Block mit Mono-Zahl
+ Subline + Sync-Link.
- Rechts: Quick-Action-Grid mit 4 Icon-Buttons (Pressemitteilungen,
Firmen, Rechnungen, Voreinstellungen) — Icon-Tile wechselt auf
Hover ins gefüllte Hub-Blau.
- **Footer**: subtle Link-Reihe (Benutzer / Rollen / Performance).
- **Was bewusst NICHT geändert**:
- Controller-Logik, Datenform, Cache-Strategie (`AdminPerformanceCache`).
- Newsletter-Count bleibt, wandert nur in eigenen Block.
- **Build/Verifikation**:
- `npm run build:portal` → `portal: 417.81 kB` (Δ -0.7 kB,
weil viele Zinc-Tailwind-Klassen weggefallen sind).
- `php artisan test --filter='DashboardTest|AuthenticationTest|RegistrationTest|CustomerPortalTest'`
→ **18/18 passed**, 70 Assertions. `DashboardTest` mit seinen
Wortlaut-Assertions (`3`, `1 pub`, `1 prüf`, `1 entwurf`,
`Review Dashboard PM`) bleibt grün ohne Anpassung.
- `vendor/bin/pint --dirty` → `passed`.
- Linter: 0 Errors.
- **Lessons learned**:
- Vokabular-Migrations ohne Logik-Eingriff brauchen ~15 Minuten dank
DRY-Schicht aus Phase 2 — der Wert der `shared/hub-components.css`
+ `<x-portal.stat-card>`-Investition zahlt sich ab Phase 3 deutlich aus.
- Der `<x-portal.stat-card>` ist auch ohne `:value`-Number-Format
flexibel (`number_format()` direkt im Aufruf eingebettet).
- Test-Assertions können bei Layout-Refactors überraschend stabil
bleiben, wenn man die Original-Strings im neuen Layout an
sinnvollen Stellen behält (hier: im Trend-Slot der KPI-Card).
---
## 2026-05-19 · Phase 5 · Dark Mode + Switcher im User-Menü
- **Anlass**: User-Feedback nach Phase 2: „Switch in den Dark Mode funktioniert
nicht. Zusätzlich hätte ich gerne einen Switcher hell/dunkel direkt im
User-Menü." → Phase 5 vorgezogen vor Phase 3/4, weil der Switcher der
natürliche UX-Einstiegspunkt für Dark Mode ist und der Notfall-Hack
aus Phase 1 (`portal.css: .dark { --color-accent: var(--color-hub) }`)
endlich verschwinden soll.
- **Plan-Dokument**: `05-PHASE-5-DARK-MODE.md` mit Token-Mapping-Tabelle,
drei wichtigen Token-Konstanten-Tricks (`--color-accent-warm`,
`--color-panel-dark`, `--color-panel-dark-2`) und Switcher-Snippet.
- **`design-tokens.css` — Dark-Block aktiviert**:
- Vollständiger `.dark { … }`-Block mit Werten aus
`User Dashboard presseportale Dark.html`.
- Surfaces: bg/elev/card/rule schalten auf `#0e1218`-Familie.
- Hub-Blau wird **heller** im Dark Mode (`#5a78c2` statt `#1a2540`) —
notwendig für Lesbarkeit auf dunklem Bg.
- Bernstein-Akzent ebenfalls heller (`#d9a560`).
- Status-Farben (`ok/warn/err`) auf dunkle, gesättigte Variante.
- Schatten-Tokens neutral-schwarz statt hub-blau-warm.
- `color-scheme: dark;` als Hint für native Form-Controls.
- **3 neue Token-Konstanten** (gleicher Wert in beiden Modi):
- `--color-accent-warm` (`#b07a3a`) — für Stellen, die explizit Bernstein
bleiben müssen (Hint-Card-Border-Left, Progress-Bar-Fill); löst die
Kollision auf, dass `--color-accent` im Portal auf Hub-Blau gemapt
ist und im Dark Mode noch heller würde.
- `--color-panel-dark` (`#0f1729`) und `--color-panel-dark-2` (`#1a2540`)
— für `.panel-dark` und Brand-Bridge-Inner-Boxes. Ohne diese würde
der dunkle Bridge-Container im Dark Mode plötzlich hellblau, weil
`var(--color-hub)` zum hellen Wert wird.
- **`portal.css` — Notfall-Hack aus Phase 1 entfernt**:
- Der `.dark { --color-accent: var(--color-hub); … }`-Block ist
überflüssig, weil das echte Dark-Token-Mapping in `design-tokens.css`
`--color-hub` automatisch auf `#5a78c2` schaltet — und
`--color-accent` darüber per `var(--color-hub)`-Verweis dynamisch
mitkommt.
- Primary-Button-Shadows zusätzlich für `.dark` überschrieben: statt
`rgba(26, 37, 64, …)` (warmer Hub-Blau-Alpha) jetzt `rgba(0, 0, 0, …)`
(neutral-schwarz), weil der hub-blaue Schatten auf dunklem Card-BG
zu sichtbar wirkt.
- **`hub-components.css` — Dark-tauglich gemacht**:
- `.panel-dark` nutzt jetzt `var(--color-panel-dark-2)` und
`var(--color-panel-dark)` (vorher `var(--color-hub)` und
`var(--color-topbar-deep)`) → bleibt im Dark Mode dunkel.
- `.hint-card border-left` und `.hint-bar > span` nutzen
`var(--color-accent-warm)` (konstant Bernstein) statt `var(--color-accent)`
(im Portal Hub-Blau-Mapping).
- `.hint-card background` schaltet auf `var(--color-bg-card-warm)` —
ist im Light Mode `#efeadc` (warmes Buchpapier), im Dark Mode
`#1f1a12` (warm-dunkles Bernstein-Substrat).
- Restliche Klassen funktionieren **automatisch**, weil alle Werte
über Tokens laufen — DRY-Architektur zahlt sich aus.
- **`customer/dashboard.blade.php`**:
- Brand-Bridge-Inner-Boxes auf `bg-[color:var(--color-panel-dark-2)]`
umgestellt (statt `--color-hub-2`, das im Dark Mode hell würde).
- **Switcher im User-Menü** (`sidebar.blade.php` — Desktop + Mobile):
- Vor dem Logout-Button: kleiner Block mit Eyebrow „Erscheinung" und
FluxUI-Segmented-Radio-Group mit Icons-only.
```blade
<flux:radio.group x-data variant="segmented" size="sm" x-model="$flux.appearance">
<flux:radio value="light" icon="sun" :title="__('Hell')" />
<flux:radio value="dark" icon="moon" :title="__('Dunkel')" />
<flux:radio value="system" icon="computer-desktop" :title="__('System')" />
</flux:radio.group>
```
- `$flux.appearance` ist FluxUIs Magic-Object — LocalStorage-persistent,
`@fluxAppearance`-Script setzt `class="dark"` auf `<html>`.
- In BEIDEN Dropdowns (Desktop in der Sidebar, Mobile im Header).
- **Hub-Frontend bleibt Light-Only** (Plan-Vorgabe):
- `auth/pressekonto.blade.php` lädt KEIN `@fluxAppearance` und KEIN
`partials/head`. Damit wird `class="dark"` dort nie gesetzt — auch
nicht, wenn LocalStorage `dark` enthält. Kein Eingriff nötig.
- Hub-Landing analog (eigene `<head>`-Pipeline).
- **Build/Verifikation**:
- `npm run build:portal` → `portal: 418.55 kB` (Δ +1.5 kB für
Dark-Tokens + Switcher).
- `php artisan test --filter='DashboardTest|AuthenticationTest|RegistrationTest|CustomerPortalTest'`
→ **18/18 passed**, 70 Assertions. Keine Regressions.
- `vendor/bin/pint --dirty` → `passed`.
- Linter: 0 Errors.
- **Lessons learned**:
- Tailwind v4's `@theme`-Variables sind **dynamisch** zur Laufzeit —
`--color-accent: var(--color-hub)` schaltet beim `.dark`-Switch
automatisch mit, ohne dass man `.dark { --color-accent: … }` extra
setzen muss.
- Wenn ein Wert in beiden Modes IDENTISCH bleiben soll (`--color-panel-dark-2`,
`--color-accent-warm`), gehört er in den Light-Block und wird im
`.dark`-Block bewusst NICHT überschrieben. Vererbung tut den Rest.
- FluxUI's `flux:radio.group variant="segmented"` mit Icons-only ist
perfekt für Dropdown-Switcher; `:title="…"` liefert Tooltips ohne
sichtbares Label.
- **Bonus**: Der ursprüngliche Symptom-Fix aus Phase 1
(Multi-Alpine + Dark-Mode-Bug) ist jetzt strukturell aufgelöst:
- Alpine kommt ausschließlich aus `@fluxScripts`.
- Dark Mode ist echt umgesetzt, nicht maskiert.
---
## 2026-05-19 · Phase 2 · Customer-Dashboard auf Mockup-Stil
- **Anlass**: User-Freigabe „weiter“ nach Behebung des Dark-Mode/Alpine-Bugs.
Phase 2 laut Plan: Customer-Dashboard (`/admin/me`) an
`User Dashboard presseportale.html` angleichen.
- **Vorab-Doku**: `04-PHASE-2-CUSTOMER-DASHBOARD.md` mit Mockup-Diff-Tabelle,
CSS-Strategie, Component-Skizzen, Akzeptanzkriterien.
- **CSS-Architektur — DRY-Schritt**:
- Neue Datei `resources/css/shared/hub-components.css` als **Single Source
of Truth** für Hub-Layout-Bausteine: `.panel` (warm/dark/head),
`.stat-card` (+ Varianten `is-primary|ok|warn|muted`, `.stat-strip`,
`.stat-label`, `.stat-num`, `.stat-meta`, `.stat-trend`), `.hint-card`
(+ `.hint-ico`, `.hint-bar`, `.hint-action`), `.badge` (+ `.warn|ok|hub|err|dot`),
`.bridge-row`/`.dot-pe`/`.dot-bp`, portable `.eyebrow` und
`.section-eyebrow` (für Portal — Web-Build überschreibt idempotent).
- Importiert in **beiden** Builds:
- `resources/css/portal.css` (nach `flux.css`)
- `resources/css/web/shared-styles.css` (nach `design-tokens.css`)
- Alle Werte nutzen `var(--color-*)`-Tokens — keine Hex-Literale.
- Fehlende Tokens nachgezogen in `shared/design-tokens.css`:
`--color-bg-rule-2` (hellere Progress-Track-Variante) und
`--color-gain-deep` (dunkles Grün für `is-ok`-Stat-Num).
- **Neue Blade-Components** in `resources/views/components/portal/`:
- `<x-portal.stat-card variant="…" label="…" :value="…">`
mit Slots `meta` (oben rechts) und `trend` (unten).
- `<x-portal.hint-card :icon :title :percent :href :action>`
mit Progress-Bar bei gesetztem `$percent` und `wire:navigate`-Link.
- **`livewire/customer/dashboard.blade.php` komplett neu**:
- **Page-Header**: Hub-Badge „User Backend“ + Eyebrow + großes H1
+ Subtitle. Rechts entweder Aktive-Firma-Pille **oder** Warn-Pille
„Keine Firma zugeordnet → zuordnen“.
- **KPI-Reihe** (4 `stat-card`s): Gesamt (primary, mit Δ-zu-Vormonat),
Veröffentlicht (ok), In Prüfung (warn), Entwürfe (muted).
- **Zweispalten-Grid** (`lg:grid-cols-[2fr_1fr]`):
- Links: Panel mit Pressemitteilungen-Liste oder Empty-State (Icon-Box
mit Notification-Dot, Headline, Action-Button, Schritt-Karten 01/02/03,
Footer-Tipp „4 Stunden“).
- Rechts: Panel „Datenqualität“ mit `<x-portal.hint-card>`s oder
Success-State („Alles im grünen Bereich“).
- **Unteres Grid**: Firmen-Panel (Liste **oder** dashed Empty-Slot
+ Hinweis-Box) + Brand-Bridge-Dark-Panel (presseecho + businessportal24
mit Status, API-Status-Indikator, Tarif).
- **Footer**: Subtle-Link-Reihe (Sicherheit, API & Tokens, Profil).
- **Volt-`with()` erweitert**:
- `stats.deltaMonth` — Monatsvergleich via zweiter `whereBetween`-Query.
- `profileCompleteness` (Heuristik auf 6 Profile-Kernfelder).
- `billingCompleteness` (5 Address-Pflichtfelder).
- `bridgeStatus` (vorerst hardcoded `connected` — Phase 3+).
- `qualityHints[]` optional um `percent`-Feld erweitert — wenn gesetzt,
rendert Progress-Bar in der Hint-Card.
- **Edge-Case beim Bauen**: Blade interpretierte `<flux:icon>` im PHPDoc-
Kommentar von `hint-card.blade.php` als echten Component-Tag und produzierte
`Undefined variable $component`. Fix: Doc-Block entkontaminiert
(„flux:icon“ ohne Spitzklammern).
- **Tests neu** in `tests/Feature/Customer/DashboardTest.php` (5 Cases):
1. Customer-Dashboard rendert Core-Sections ohne Fehler
2. Empty-State mit 3-Schritt-Intro wird gezeigt
3. PR-Liste + KPI-Zahlen rendern bei vorhandenen Daten
4. Profile-Completeness-Hint mit Prozentwert erscheint bei Teildaten
5. Vollständiges Profil + Billing → Hints werden ausgeblendet,
„Alles im grünen Bereich“ wird gezeigt
- **Ergebnis**: 5/5 passed, 21 Assertions.
- Cross-Check: Verwandte Tests (`Dashboard|Authentication|Registration|CustomerPortal`)
→ **18/18 grün**, 70 Assertions. Keine Regressions.
- **Build/Verifikation**:
- `npm run build:portal` → `portal: 417.02 kB` (Δ +8 kB für neue
Hub-Components-Klassen + Dashboard-Klassen). Web-Build unverändert.
- `vendor/bin/pint --dirty` → `passed`.
- **Was bewusst weggelassen**:
- Sparklines auf den Stat-Cards (kommen mit echten Trend-Daten in Phase 4).
- Topbar-Anpassung (eigene Phase, später).
- `<x-portal.bridge-card>`-Extraktion (Brand-Bridge bleibt inline, bis
sie an mehr Stellen gebraucht wird).
- **Lessons learned**:
- PHPDoc in Blade-Components darf KEINE `<flux:*>`-Tags enthalten —
der Blade-Pre-Compiler scannt das gesamte File vor dem PHP-Parsing.
- `shared/hub-components.css` ist der richtige Hebel für Phase 3
(Admin-Dashboard) und Phase 4 (Listen/Detail) — Components-CSS muss
nicht mehr pro Phase neu definiert werden.
---
## 2026-05-19 · Phase 1 Refinement · Dark-Mode-Bug + Multi-Alpine
- **Anlass**: User-Review nach Kontrast-Refinement: zwei konkrete Befunde
aus der Browser-Konsole.
1. `[Warning] Detected multiple instances of Alpine running (me, line 114)`
2. Button-Default-Farbe ist `rgb(109, 138, 211)` (helles Blau), nicht
das gewünschte Hub-Blau `rgb(26, 37, 64)`. Computed Style zeigt:
`.bg-[var(--color-accent)] { background-color: var(--color-accent); }`
→ `var(--color-accent)` löst zu `#6d8ad3` auf.
- **Diagnose Bug 1 (Alpine)**:
- `partials/head.blade.php` lädt `resources/js/app.js` über `@vite`.
`app.js` ruft `Alpine.start()` auf.
- Am Ende des `<body>` injiziert `@fluxScripts` (sidebar.blade.php Zeile
nahe `</body>`) **eine eigene Alpine-Instanz** (FluxUI bringt Alpine
selbst mit).
- Ergebnis: zwei `window.Alpine`-Objekte, Bindings teils tot, Warning.
- Auf der Login-Seite hatten wir das **bereits** gefixt (app.js dort
rausgenommen), aber im Portal-Layout war der Fix noch offen.
- **Diagnose Bug 2 (Button-Farbe)**:
- Der Wert `rgb(109, 138, 211)` = `#6d8ad3` ist **exakt** der
Dark-Mode-Fallback, den ich in `portal.css` unter `.dark { --color-accent: #6d8ad3 }`
definiert hatte.
- FluxUI's `@fluxAppearance`-Helper schreibt `class="dark"` auf
`<html>`, sobald der User den Appearance-Switcher mal auf "dark"
gestellt hatte (gespeichert in `localStorage`).
- Damit überschreibt der Dark-Block den Light-Mode-Akzent
`var(--color-hub)` (`#1A2540`) — Buttons sehen plötzlich blassblau aus.
- Dark Mode ist laut Plan erst Phase 5, war aber durch den
Fallback-Block bereits halb aktiv.
- **Fixes**:
- `resources/views/partials/head.blade.php`: `resources/js/app.js`
aus dem `@vite`-Aufruf **entfernt**. Alpine kommt im Portal
ausschließlich über `@fluxScripts`. (Hub-Landing nutzt
`partials/head` nicht — eigene `<head>`-Pipeline.)
- `resources/css/portal.css`: Der `.dark { --color-accent: ... }`-
Block setzt jetzt **bewusst** alle Akzent-Tokens auf
`var(--color-hub)` (also den Light-Mode-Wert). Damit bleibt das
Hub-Blau auch bei eingeschaltetem `class="dark"` konsistent.
Kommentar dokumentiert, dass Phase 5 diesen Block durch das
echte Dark-Token-Mapping aus `shared/design-tokens.css` ersetzt.
- **Build/Verifikation**:
- `npm run build:portal` → `portal: 408.97 kB` (Δ +0.02 kB).
- `php artisan test --compact --filter='AuthenticationTest|RegistrationTest'`
→ **6 passed, 19 assertions**, 1.93s.
- `vendor/bin/pint --dirty --format agent` → `passed`.
- **User-Action zur Verifikation**:
- Im Portal Hard-Reload (Cmd/Strg+Shift+R) — die alte `app.js`
hängt sonst im HTTP-Cache.
- Konsole sollte **keine** Multi-Alpine-Warning mehr werfen.
- Primary-Buttons sind im Default-State sattes Hub-Blau (`#1A2540`),
Hover noch dunkler (`#243152`).
---
## 2026-05-19 · Phase 1 Refinement · Kontraste & Button-Hover
- **Anlass**: User-Review nach Phase 1: „Buttons als Primary auf
`rgb(26, 37, 64)` einsetzen, die andere Farbe ist deutlich zu hell.
Es fehlen noch deutliche Kontraste."
- **Diagnose**:
- FluxUI-Primary-Buttons sind eigentlich **schon** auf `var(--color-accent)`
= `var(--color-hub)` = `#1A2540` = `rgb(26, 37, 64)` gesetzt
(im Build verifiziert). Sollte stimmen.
- **ABER**: Der FluxUI-Default-Hover ist
`hover:bg-[color-mix(in_oklab,_var(--color-accent),_transparent_10%)]`
— auf hellem Buchpapier wirkt das hell-blau statt der gewünschten
Hub-Konvention `hover:bg-hub-2` (dunkler als Default).
- Außerdem zu wenig Schatten/Border-Kontrast für klare Button-Kanten.
- **Erkenntnis**: Frühere `[data-flux-button][data-variant="primary"]`-
Overrides griffen **nie**, weil FluxUI kein `data-variant`-Attribut
rendert. Variant-Styling kommt komplett über Tailwind-Klassen
(z.B. `bg-[var(--color-accent)]`). Neue Selektor-Strategie nutzt
jetzt diese Klassen direkt (mit escapeten Brackets).
- **Fixes in `portal.css`**:
- **Primary-Button-Hover** auf `var(--color-hub-2)` (#243152) statt
FluxUI's color-mix-Hellung. Selektor:
`[data-flux-button].hover\:bg-\[color-mix\(in_oklab\,_var\(--color-accent\)\,_transparent_10\%\)\]:hover`
- **Primary-Button-Shadow**: kräftigeres Inset-Highlight + warmer
Drop-Shadow in Hub-Blau-Alpha für klare Kanten auf Buchpapier.
Border zusätzlich auf `var(--color-hub-2)` für definierten Rand.
- **Hover-State**: noch stärkerer Shadow + Drop für Tiefenwirkung.
- **Input-Focus** auf Hub-Blau-Ring (statt blassem Default-Akzent),
mit Buchpapier-Offset für saubere Trennung.
- Alter (defunkter) `[data-flux-button][data-variant="primary"]`-
Block entfernt, weil Selektor nicht existiert.
- **Build/Verifikation**:
- `npm run build:portal` → `portal: 408.95 kB` (von 409.03 kB, -0.08 kB).
- Im finalen CSS verifiziert:
* Hub-2-Hover-Override:
`[data-flux-button].hover\:bg-…:hover{background-color:var(--color-hub-2)!important}`
* Shadow-Override:
`[data-flux-button].bg-\[var\(--color-accent\)\]{border-color:var(--color-hub-2);box-shadow:inset 0 1px #ffffff2e,0 1px 2px #1a254040,…}`
* Input-Focus-Ring auf Hub-Blau.
- `vendor/bin/pint --dirty` → passed.
- **Wirkung**:
- Primary-Button **Default**: `#1A2540` (Hub-Blau), klarer warmer
Schatten, definierter Rand → fühlt sich „solid" an wie auf der
Hub-Landing.
- Primary-Button **Hover**: `#243152` (Hub-2, dunkler statt heller)
— Hub-Konvention, signalisiert Interaktion ohne den Eindruck einer
schwächeren Farbe zu erzeugen.
- Inputs zeigen jetzt einen **erkennbaren Hub-Blau-Ring** beim Fokus
statt eines blassen Bernstein-Schimmers.
- **Hinweis an User**: **Hard-Reload** (Cmd+Shift+R) ist nötig — das
CSS-Bundle hat einen neuen Hash (`portal-kuU-opFv.css`).
- **Verfeinerungen noch offen für Phase 2 / Iteration**:
- Subtle/Filled/Ghost-Buttons (`<flux:button variant="filled">`) sind
weiterhin transparent-zinc → bei Bedarf in Phase 2 angleichen.
- Sidebar-Active-Item hat schon Hub-Soft + 2 px-Strip; ggf. den
Strip noch sichtbarer machen wenn weiter zu unauffällig.
---
## 2026-05-19 · Phase 1 abgeschlossen · Portal-Shell auf Hub-Design
- **Was**: Portal-Shell (Sidebar, Topbar, Layout-Container, Customer-Banner)
visuell ans Hub-Design angeglichen. FluxUI bleibt komplett erhalten —
Anpassung erfolgt über CSS-Token-Bridging und `[data-flux-*]`-Overrides.
Brand-Mark ersetzt das Starter-Kit-Logo. Light Mode ist Default; Dark
Mode für Phase 5 vorbereitet (heller Hub-Blau).
- **Dateien (geändert)**:
- `resources/css/portal.css` — komplett refactored:
* `--font-sans: "Inter Tight"` statt `Instrument Sans`
* `--color-accent: var(--color-hub)` (#1A2540) statt `#3ea3dc`
* `--color-zinc-50..950` auf Hub-Buchpapier-Familie gemappt
(Zinc-100 = #F6F4EF, Zinc-700 = #1A1F1C, Zinc-900 = Hub-Blau)
* Hub-Stil-Overrides: `[data-flux-sidebar]`, `[data-flux-navlist]`,
`[data-flux-navlist-item]` mit Active-Strip links, `[data-flux-button]`
Primary/Filled auf Hub-Blau, `[data-flux-card]` Buchpapier
* Dark-Mode-Block bleibt vorerst minimal (nur Accent), Vollumstellung
in Phase 5
- `resources/views/partials/head.blade.php` — Bunny-Font auf
`inter-tight + jetbrains-mono + source-serif-4` (für Brand-Mark)
- `resources/views/components/layouts/app/sidebar.blade.php`:
* `class="dark"` aus `<html>` entfernt
* `<body>` jetzt `bg-bg text-ink antialiased` (Hub-Buchpapier)
* `<x-app-logo>` ersetzt durch `<x-web.brand-mark brand="pressekonto"
:serif="false" />` + Eyebrow "Publisher · Hub" — sowohl im Desktop-
Brand-Block als auch im Mobile-Header
* Testmodus-Block (Impersonation) komplett im Hub-Stil: dunkles
Hub-Blau-Panel mit Bernstein-Eyebrow „Testmodus aktiv", weiße CTA
„Zurück zum Admin" (statt Amber-Warnfarbe wie zuvor)
* Resources-Block (Tailwind/HeroIcons/Flux/Repository) entfernt —
gehört nicht ins Live-Portal
- `resources/views/components/layouts/app.blade.php`:
* Customer-Banner („User Backend") visuell auf Hub-Stil: Hub-Soft-
Hintergrund + Hub-Soft-2-Border, Hub-Blau-Pille mit Dot, Eyebrow
„Firmenkontext" in Sperrschrift, Heading in Hub-Ink
- **Dateien (Test-Anpassungen, weil rollen-basierter Redirect aus Login-Fix
weitere Tests berührt hat)**:
- `tests/Feature/Auth/AuthenticationTest.php` — Test-User auf
`superAdmin()` umgestellt (sonst `canAccessAdmin() === false` →
Redirect auf `/` statt `/dashboard`)
- `tests/Feature/Auth/RegistrationTest.php` — `terms_accepted` im
Formular gesetzt + Redirect-Erwartung auf `/` angepasst (frisch
registrierte User haben keine Rolle → Fallback `/`)
- **Build/Test**:
- `npm run build:portal` → `portal: 409.03 kB` (vorher 408.89 kB,
+0.14 kB). Unter dem 10 %-Akzeptanzkriterium (≤ 450 kB).
- CSS-Inspektion bestätigt Phase-1-Tokens:
* `--color-accent: var(--color-hub)` und `.dark { --color-accent:
#6d8ad3 }` im `:root`
* `--color-zinc-700: #1a1f1c` (Hub-Ink statt Zinc-Grau)
* `--font-sans: "Inter Tight"` ohne Instrument-Sans-Vorlauf
* Hub-Overrides im Output: `[data-flux-sidebar]{background:var(...)}`,
`[data-flux-navlist-item][aria-current=page]{background:var(
--color-hub-soft);...}`
- Auth-Test-Suite: **0 zusätzliche Regressionen** verifiziert (8 fail
/ 15 passed vor & nach Phase 1; verbleibende Failures sind pre-existing
Domain-Mismatch- und CSRF-Issues im Test-Setup).
- Smoke-Test: `/dashboard`, `/admin/me`, `/settings/profile`,
`/admin/companies`, `/admin/press-releases` antworten alle HTTP 302
→ `/login` (erwartetes Verhalten ohne Auth-Session via curl).
- `vendor/bin/pint --dirty` → passed.
- **Bewusst NICHT in Phase 1**:
- **Topbar** mit Breadcrumb + Bridge-Row + Search + „Neue Mitteilung"-CTA
aus dem Mockup → ist für Phase 2 (Customer-Dashboard) sinnvoller,
weil die Topbar dort Page-Kontext (Breadcrumb-Titel) braucht. Aktuell
nutzen wir FluxUI's Default-Layout ohne dedizierte Topbar.
- Konto-Switcher als Sidebar-Header (Avatar + Name + Firma als
Dropdown-Trigger oben statt unten) → das User-Menü unten bleibt
vorerst FluxUI-Standard. Iterativ in Phase 2.
- Dashboard-Inhalte (Stat-Cards, Hint-Cards) → Phase 2 & 3.
- Listen-Pages → Phase 4 (automatisch durch Token-Bridge schon „okay").
- **Beobachtungen**:
- FluxUI-Navlist-Item-Selektor: `[aria-current="page"]` greift. Falls
künftige FluxUI-Versionen `[data-current="true"]` statt
`[aria-current="page"]` setzen, deckt der Override beides ab.
- Vendor-Pfad in `partials/head.blade.php` bewusst nicht geändert —
Vite-Setup mit `build/portal` bleibt wie gehabt.
- **Nächster Schritt**: **Review-Stopp**. Bei Freigabe → entweder
Phase 2 (Customer-Dashboard-Stat-Cards & Hint-Cards) oder Topbar-
Iteration. Entscheidung bei dir/Frank nach Anschauen.
---
## 2026-05-19 · Login-Funktionsfix · Doppelte Alpine-Instanz
- **Was**: Nach Phase 0 trat ein funktionaler Bug auf: Login-Form ging
nicht durch, Browser-Logs zeigten „Detected multiple instances of
Alpine running" und „Livewire: published assets out of date".
- **Ursache**: Das Hub-Auth-Layout (`pressekonto.blade.php`) lud sowohl
`resources/js/app.js` (das `Alpine.start()` aufruft) als auch
`@livewireScripts` (das Alpine intern mitbringt). Zwei Alpine-Instanzen
→ `wire:submit`, `x-data`, `wire:model` brachen.
- **Fixes**:
- `app.js` aus `@vite([…])` im Auth-Layout entfernt — Alpine kommt nun
nur noch über Livewire.
- `php artisan livewire:publish --assets` → `livewire.js` von 450 kB
auf 552 kB aktualisiert (Versions-Mismatch behoben).
- Login/Register-Redirect auf rollen-basierte Logik umgestellt
(Admin → `/dashboard`, Customer → `/admin/me`, sonst `/`) und
`navigate: true` entfernt — SPA-Navigation kann den Wechsel zwischen
Web-Build (Hub-Auth) und Portal-Build (FluxUI-Dashboard) nicht
handhaben.
- **Dateien**:
- `resources/views/components/layouts/auth/pressekonto.blade.php`
- `resources/views/livewire/auth/login.blade.php`
- `resources/views/livewire/auth/register.blade.php`
- **Verifikation**: Login funktioniert (User bestätigt), Redirect zum
Dashboard läuft, keine Browser-Warnings mehr.
---
## 2026-05-19 · Phase 0 abgeschlossen · Token-Unifizierung
- **Was**: Single Source of Truth für Design-Tokens etabliert. Web- und
Portal-Build importieren beide `resources/css/shared/design-tokens.css`.
Visuelle Unverändertheit verifiziert — FluxUI-Defaults gewinnen im
Portal weiterhin (Instrument Sans, Zinc, `#3ea3dc`), wird in Phase 1
abgelöst.
- **Dateien**:
- `resources/css/shared/design-tokens.css` **neu** — alle Hub-Tokens
plus Status-Reihe (`--color-warn`, `--color-warn-soft`,
`--color-err`, `--color-err-soft`, `--color-ok-soft`), Bridge-Dots
(`--color-bridge-presseecho`, `--color-bridge-businessportal`),
Radii (`--radius-xs/sm/md/lg`) und Schatten (`--shadow-soft`,
`--shadow-auth`). Dark-Mode-Block als auskommentierter Vorgriff.
- `resources/css/web/shared-styles.css` — Token-Import nach
`tailwindcss` ergänzt. Wirkt damit für alle Web-Themes
(pressekonto, presseecho, businessportal24).
- `resources/css/web/theme-pressekonto.css` — kompletter `@theme {}`-
Block entfernt (lebt jetzt in der Token-Datei). HSL-Legacy-Variablen
und `@layer components { … }` blieben unverändert.
- `resources/css/portal.css` — Token-Datei importiert, FluxUI-Setup
mit Zinc + Instrument Sans bleibt vorerst dominant. Phase 1 löst
es ab.
- **Build/Test**:
- `npm run build:web` → `theme-pressekonto: 193 kB` (vorher 189 kB,
+4 kB für neu gebridgde Status-Tokens), `theme-presseecho: 189 kB`,
`theme-businessportal24: 189 kB`.
- `npm run build:portal` → `portal: 408 kB` (vorher 397 kB, +12 kB
für die zusätzlich verfügbaren Hub-Tokens als CSS-Vars im `:root`).
Wird in Phase 1 wieder egalisiert, wenn das Zinc-Setup wegfällt.
- Smoke-Test: `pressekonto.test/`, `/login`, `/register`,
`/dashboard` (302→login), `presseecho.test/`, `businessportal24.test/`
— alle HTTP 200/302 wie erwartet.
- CSS-Inspektion: `--color-hub: #1a2540` und `--color-warn: #a87a1f`
sind in `theme-pressekonto-*.css` enthalten. Im Portal-Build
bleibt `--font-sans: "Instrument Sans"` — bestätigt visuelle
Unverändertheit.
- `vendor/bin/pint --dirty` → passed.
- **Offene Fragen / Beobachtungen**:
- Weil Tailwind v4 alle in `@theme {}` definierten Tokens als CSS-
Variablen im `:root` ausgibt (auch ohne Utility-Verwendung), wird
der Portal-CSS-Wuchs in Phase 1 nicht komplett zurückgehen —
die Hub-Tokens bleiben als Variablen verfügbar. Der Nettoeffekt
nach Phase 1 sollte ähnlich bleiben (+/- 510 kB).
- Dark-Mode-Block in `design-tokens.css` ist auskommentiert
vorbereitet, aber bewusst noch nicht aktiv (Phase 5).
- **Nächster Schritt**: **Review-Stopp**. Bei Freigabe →
Phase 1 starten: Portal-Shell (Sidebar, Topbar, Layout-Container)
auf Hub-Style mappen, Zinc-Palette ablösen, FluxUI-Overrides via
`[data-flux-*]`-Selektoren in `portal.css`. Details:
`02-PHASE-1-PORTAL-SHELL.md`.
---
## 2026-05-19 · Setup
- **Was**: Architektur-Entscheidung getroffen → **Plan B** (Tokens teilen,
Komponenten getrennt lassen). Dokumentation in `dev/frontend/hub-flux/`
angelegt:
- `README.md` — Übersicht & Entscheidung
- `01-PHASE-0-TOKENS.md` — Detail-Plan für Tokens-Vereinheitlichung
- `02-PHASE-1-PORTAL-SHELL.md` — Detail-Plan für Portal-Shell-Refresh
- `03-WEITERE-PHASEN.md` — Outline Phase 26
- `PROGRESS.md` — dieses Log
- **Bestätigt**:
- Hub-Blau als **Primärer Akzent** im Portal (klarer Kontrast zum hellen
Buchpapier-Hintergrund)
- Bernstein als **Sekundärer Akzent** (Notifications, Datenqualität,
Akzent-Ribbons)
- Brand bleibt **pressekonto** (auch im Portal-Sidebar via
`<x-web.brand-mark>`)
- Reihenfolge: erst Phase 0 + 1, dann Review
- **Nächster Schritt**: Phase 0 umsetzen
→ `resources/css/shared/design-tokens.css` erstellen,
`theme-pressekonto.css` refactoren, `portal.css` minimal vorbereiten.
---
## Vorlauf (zur Erinnerung, was schon steht)
- **Hub-Landing** (`web/pressekonto.blade.php`) — fertig, lebt im Web-Build
mit `theme-pressekonto.css`
- **Hub-Auth** (Login, Register, Forgot, Reset, Verify, Confirm) — fertig
im Hub-Design, neues Layout `auth/pressekonto.blade.php` im Web-Build
- **Register-AGB-Checkbox** mit Server-Side-Validierung ergänzt
- **Portal-Backend** mit FluxUI funktional vorhanden (Admin-Dashboard,
Customer-Dashboard, 77 Blade-Dateien mit FluxUI), aber **visuell noch
Starter-Kit-Look** (Zinc + `#3ea3dc` + Instrument Sans)
---
## Template für neue Einträge
```markdown
## YYYY-MM-DD · Phase N · Kurztitel
- **Was**: [Was wurde konkret gemacht?]
- **Dateien**: [Pfade]
- **Build/Test**: [Wie verifiziert?]
- **Offene Fragen**: [Falls etwas unklar geblieben ist]
- **Nächster Schritt**: [Was als Nächstes ansteht]
```