2187 lines
101 KiB
Markdown
2187 lines
101 KiB
Markdown
# 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 · 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 640–1024px). (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 (9A–9C) ✅
|
||
|
||
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 (9D–9J: Tarif-Datenmodell,
|
||
Stripe/Cashier — Dependency-Freigabe nötig, Tarif-UI, Tageslimit,
|
||
Einzel-PM, Launch-Credits).
|
||
|
||
---
|
||
|
||
## 2026-05-29 · Phase 8 · User-Panel-Konsolidierung abgeschlossen (8F–8K) ✅
|
||
|
||
Abschluss von Phase 8. Die erste Hälfte (8A–8E: 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 (8A–8E 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 0–7 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 (0–6). 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 0–6) **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 0–4 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. 182–248) 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 4A–4J 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
|
||
(~3–5 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 (+/- 5–10 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 2–6
|
||
- `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]
|
||
```
|