From 0a3e52d6036b242683f8270fe7b05ee05295c03b Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Tue, 19 May 2026 16:36:13 +0000 Subject: [PATCH] 19-05-2026 Rebrand Pressekonto, Hub-Flux UI und Legacy-Media-Migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Umbenennung presseportale → pressekonto in Domains, Themes und Dokumentation. Design-Tokens, Portal-Shell, Customer-Dashboard, Auth- und Admin-PM-Views. Artisan-Befehl migrate:legacy-media mit Tests und Hub-Flux-Entwicklungsdocs. Co-authored-by: Cursor --- .codex/config.toml | 2 +- .devcontainer/Readme.md | 2 +- .devcontainer/devcontainer.json | 2 +- .gitignore | 3 +- CLAUDE.md | 4 +- Readme.md | 2 +- _docs/ASSET-URLS-GUIDE.md | 60 +- _docs/DOMAINS-CONFIG.md | 16 +- _docs/FINAL-FIX-SUMMARY.md | 10 +- _docs/FINALE-ASSET-URL-FIXES.md | 6 +- _docs/FORTIFY-SANCTUM-SETUP.md | 10 +- _docs/THEME-INTEGRATION.md | 8 +- _docs/VITE-SETUP-NEUE-STRUKTUR.md | 8 +- _docs/VITE-SETUP.md | 14 +- _docs/WICHTIG-NAECHSTE-SCHRITTE.md | 8 +- _docs/ZUSAMMENFASSUNG-VITE-SETUP.md | 24 +- _docs/api/v1.yml | 2 +- app/Console/Commands/MigrateLegacyMedia.php | 472 ++++++++++ app/Helpers/ThemeHelper.php | 10 +- app/Mail/MagicLoginLink.php | 2 +- app/Providers/AppServiceProvider.php | 2 +- app/Providers/ThemeServiceProvider.php | 2 +- app/Services/Image/ImageService.php | 18 + config/domains.php | 32 +- ...e-workspace => pressekonto.code-workspace} | 0 config/vite.php | 2 +- database/seeders/DatabaseSeeder.php | 4 +- ...KLUNGSKONZEPT-BusinessPortal24-Frontend.md | 50 +- .../Ver_ffentlichen _ Variante A _aktiv_.html | 2 +- dev/frontend/hub-flux/01-PHASE-0-TOKENS.md | 216 +++++ .../hub-flux/02-PHASE-1-PORTAL-SHELL.md | 290 +++++++ dev/frontend/hub-flux/03-WEITERE-PHASEN.md | 162 ++++ .../hub-flux/04-PHASE-2-CUSTOMER-DASHBOARD.md | 177 ++++ dev/frontend/hub-flux/05-PHASE-5-DARK-MODE.md | 159 ++++ .../hub-flux/06-PHASE-3-ADMIN-DASHBOARD.md | 55 ++ .../07-PHASE-4A-PRESS-RELEASES-LISTEN.md | 58 ++ .../08-PHASE-4B-PRESS-RELEASES-DETAIL.md | 56 ++ .../09-PHASE-4C-PRESS-RELEASES-FORMS.md | 69 ++ dev/frontend/hub-flux/PROGRESS.md | 812 ++++++++++++++++++ dev/frontend/hub-flux/README.md | 143 +++ ...-2.html => Hub Landing pressekonto-2.html} | 22 +- ...tml => Login pressekonto A3 Tailwind.html} | 4 +- .../User Dashboard presseportale Dark.html | 767 +++++++++++++++++ .../User Dashboard presseportale.html | 764 ++++++++++++++++ .../tailwind_v3/Veröffentlichen Tailwind.html | 10 +- dev/migration 2026/00-OVERVIEW.md | 4 +- dev/migration 2026/02-TARGET-ARCHITECTURE.md | 4 +- dev/migration 2026/03-MIGRATION-PLAN.md | 2 +- dev/migration 2026/07-API-MIGRATION.md | 4 +- dev/migration 2026/08-PROGRESS.md | 4 +- dev/migration 2026/12-NAECHSTE-SCHRITTE.md | 2 +- dev/migration 2026/MIGRATION-STEPS.md | 3 + dev/migration 2026/README.md | 6 +- docker-compose.yml | 18 +- phpunit.xml | 2 +- resources/css/portal.css | 240 +++++- resources/css/shared/design-tokens.css | 248 ++++++ resources/css/shared/hub-components.css | 340 ++++++++ resources/css/web/shared-styles.css | 10 + resources/css/web/theme-presseecho.css | 4 +- resources/css/web/theme-pressekonto.css | 484 +++++++++++ resources/css/web/theme-presseportale.css | 319 ------- resources/views/admin/BACKEND_STATUS.md | 28 +- resources/views/admin/FLUX_COMPONENTS.md | 4 +- resources/views/admin/README.md | 2 +- resources/views/admin/dashboard.blade.php | 293 +++++-- .../views/components/layouts/app.blade.php | 19 +- .../components/layouts/app/sidebar.blade.php | 123 ++- .../layouts/auth/pressekonto.blade.php | 154 ++++ .../components/portal/hint-card.blade.php | 64 ++ .../components/portal/stat-card.blade.php | 37 + .../views/components/web/brand-mark.blade.php | 46 +- .../components/web/hub/site-footer.blade.php | 8 +- .../components/web/hub/site-header.blade.php | 8 +- .../components/web/site-footer.blade.php | 4 +- .../components/web/site-header.blade.php | 4 +- .../admin/press-releases/create.blade.php | 94 +- .../admin/press-releases/edit.blade.php | 154 ++-- .../admin/press-releases/index.blade.php | 131 ++- .../admin/press-releases/show.blade.php | 307 ++++--- .../livewire/auth/confirm-password.blade.php | 55 +- .../livewire/auth/forgot-password.blade.php | 59 +- resources/views/livewire/auth/login.blade.php | 164 ++-- .../views/livewire/auth/register.blade.php | 200 +++-- .../livewire/auth/reset-password.blade.php | 120 ++- .../livewire/auth/verify-email.blade.php | 45 +- .../livewire/customer/dashboard.blade.php | 576 ++++++++++--- .../customer/press-releases/create.blade.php | 71 +- .../customer/press-releases/edit.blade.php | 72 +- .../customer/press-releases/index.blade.php | 91 +- .../customer/press-releases/show.blade.php | 444 ++++++---- resources/views/partials/head.blade.php | 12 +- .../views/web/layouts/web-master.blade.php | 4 +- ...ortale.blade.php => pressekonto.blade.php} | 20 +- resources/views/web/welcome.blade.php | 2 +- routes/ADMIN_ROUTES.md | 2 +- routes/admin.php | 2 +- routes/domains.php | 4 +- routes/web.php | 6 +- setup-new-asset-urls.sh | 8 +- tailwind.portal.config.js | 2 +- .../Admin/AdminFooterCodeManagementTest.php | 2 +- .../Feature/Admin/PortalAssetManifestTest.php | 2 +- tests/Feature/Auth/AuthenticationTest.php | 7 +- tests/Feature/Auth/RegistrationTest.php | 8 +- tests/Feature/Customer/DashboardTest.php | 130 +++ .../Feature/MigrateLegacyMediaCommandTest.php | 229 +++++ .../Feature/Web/Businessportal24HomeTest.php | 3 +- ...omeTest.php => PressekontoHubHomeTest.php} | 40 +- vite.config.js | 8 +- vite.portal.config.js | 4 +- vite.web.config.js | 6 +- 112 files changed, 8464 insertions(+), 1649 deletions(-) create mode 100644 app/Console/Commands/MigrateLegacyMedia.php rename config/{presseportale.code-workspace => pressekonto.code-workspace} (100%) create mode 100644 dev/frontend/hub-flux/01-PHASE-0-TOKENS.md create mode 100644 dev/frontend/hub-flux/02-PHASE-1-PORTAL-SHELL.md create mode 100644 dev/frontend/hub-flux/03-WEITERE-PHASEN.md create mode 100644 dev/frontend/hub-flux/04-PHASE-2-CUSTOMER-DASHBOARD.md create mode 100644 dev/frontend/hub-flux/05-PHASE-5-DARK-MODE.md create mode 100644 dev/frontend/hub-flux/06-PHASE-3-ADMIN-DASHBOARD.md create mode 100644 dev/frontend/hub-flux/07-PHASE-4A-PRESS-RELEASES-LISTEN.md create mode 100644 dev/frontend/hub-flux/08-PHASE-4B-PRESS-RELEASES-DETAIL.md create mode 100644 dev/frontend/hub-flux/09-PHASE-4C-PRESS-RELEASES-FORMS.md create mode 100644 dev/frontend/hub-flux/PROGRESS.md create mode 100644 dev/frontend/hub-flux/README.md rename dev/frontend/tailwind_v3/{Hub Landing presseportale-2.html => Hub Landing pressekonto-2.html} (98%) rename dev/frontend/tailwind_v3/{Login presseportale A3 Tailwind.html => Login pressekonto A3 Tailwind.html} (99%) create mode 100644 dev/frontend/tailwind_v3/User Dashboard presseportale Dark.html create mode 100644 dev/frontend/tailwind_v3/User Dashboard presseportale.html create mode 100644 resources/css/shared/design-tokens.css create mode 100644 resources/css/shared/hub-components.css create mode 100644 resources/css/web/theme-pressekonto.css delete mode 100644 resources/css/web/theme-presseportale.css create mode 100644 resources/views/components/layouts/auth/pressekonto.blade.php create mode 100644 resources/views/components/portal/hint-card.blade.php create mode 100644 resources/views/components/portal/stat-card.blade.php rename resources/views/web/{presseportale.blade.php => pressekonto.blade.php} (98%) create mode 100644 tests/Feature/Customer/DashboardTest.php create mode 100644 tests/Feature/MigrateLegacyMediaCommandTest.php rename tests/Feature/Web/{PresseportaleHubHomeTest.php => PressekontoHubHomeTest.php} (58%) diff --git a/.codex/config.toml b/.codex/config.toml index e1178c9..8b77b15 100644 --- a/.codex/config.toml +++ b/.codex/config.toml @@ -17,6 +17,6 @@ args = [ command = "npx" [mcp_servers.laravel-boost] -command = "vendor/bin/sail" +command = "php" args = ["artisan", "boost:mcp"] cwd = "/var/www/html" diff --git a/.devcontainer/Readme.md b/.devcontainer/Readme.md index d6b2a58..6b25ad3 100644 --- a/.devcontainer/Readme.md +++ b/.devcontainer/Readme.md @@ -47,7 +47,7 @@ Das Dockerfile wurde angepasst um: Falls die automatische Installation fehlschlägt, können Sie den Container manuell bauen: ```bash -cd /Users/pandora/Sites/presseportale.com +cd /Users/pandora/Sites/pressekonto.de docker build --build-arg WWWUSER=501 --build-arg WWWGROUP=20 -f docker/8.4/Dockerfile -t sail-8.4/app docker/8.4 ``` diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 17cb1d6..9f57753 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "name": "Presseportale (Dev Container)", + "name": "Pressekonto (Dev Container)", "dockerComposeFile": [ "../docker-compose.yml" ], diff --git a/.gitignore b/.gitignore index 3db1a34..9aa9d6a 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,5 @@ Icon _static/ _work/ _storage/ -_businessportal24.com/ \ No newline at end of file +_businessportal24.com/ +dev/migration/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 62477de..7819095 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,11 +4,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -This is a multi-domain Laravel application ("Presseportale") that supports different domains with distinct themes and styling. The application uses Laravel with Livewire, Volt, and Fortify for authentication, along with Flux UI components. +This is a multi-domain Laravel application ("Pressekonto") that supports different domains with distinct themes and styling. The application uses Laravel with Livewire, Volt, and Fortify for authentication, along with Flux UI components. ### Supported Domains -- **Main Portal**: presseportale.test (local) / presseportale.com (live) – Main admin portal page +- **Main Portal**: pressekonto.test (local) / pressekonto.de (live) – Main admin portal page - **Presseecho**: presseecho.test - Landing page with presseecho theme - **Business Portal**: businessportal24.test - Landing page with business portal theme diff --git a/Readme.md b/Readme.md index 257ac9a..920afa4 100644 --- a/Readme.md +++ b/Readme.md @@ -4,7 +4,7 @@ Diese Laravel-Anwendung unterstützt verschiedene Domains mit unterschiedlichen Styles: -- **Haupt-Website**: https://presseportale.test (lokal) / https://presseportale.com (live) – Haupt-Portal Admin-Page +- **Haupt-Website**: https://pressekonto.test (lokal) / https://pressekonto.de (live) – Haupt-Portal Admin-Page - **APP_PRESSEECHO**: https://presseecho.test - **APP_BUSINESSPORTAL**: https://businessportal24.test diff --git a/_docs/ASSET-URLS-GUIDE.md b/_docs/ASSET-URLS-GUIDE.md index 5348068..1b27fec 100644 --- a/_docs/ASSET-URLS-GUIDE.md +++ b/_docs/ASSET-URLS-GUIDE.md @@ -8,18 +8,18 @@ Für dein Multi-Domain-Setup empfehle ich folgende Asset-URLs: | Bereich | Domain | Asset-URL | Port | Verwendung | |---------|--------|-----------|------|------------| -| **Backend** | presseportale.test | `assets.presseportale.test` | 5177 | Portal + FluxUI | -| **Frontend** | presseecho.test
businessportal24.test | `assets-web.presseportale.test` | 5178 | Beide Frontend-Domains | +| **Backend** | pressekonto.test | `assets.pressekonto.test` | 5177 | Portal + FluxUI | +| **Frontend** | presseecho.test
businessportal24.test | `assets-web.pressekonto.test` | 5178 | Beide Frontend-Domains | ### Warum diese URLs? -#### 1. **assets.presseportale.test** (Portal/Backend) +#### 1. **assets.pressekonto.test** (Portal/Backend) - ✅ Kurz und prägnant - ✅ Eindeutig dem Portal zugeordnet - ✅ Keine zusätzliche Subdomain-Tiefe - ✅ Folgt gängiger Konvention -#### 2. **assets-web.presseportale.test** (Web/Frontend) +#### 2. **assets-web.pressekonto.test** (Web/Frontend) - ✅ Klar als "Web" (Frontend) gekennzeichnet - ✅ Ein Asset-Server für beide Frontend-Domains - ✅ Gute Trennung zu Portal-Assets @@ -31,23 +31,23 @@ Falls du andere URLs bevorzugst, hier sind Alternativen: ### Option A: Mit Suffix-Präfix ``` -portal-assets.presseportale.test → Port 5177 -web-assets.presseportale.test → Port 5178 +portal-assets.pressekonto.test → Port 5177 +web-assets.pressekonto.test → Port 5178 ``` - ⚠️ Etwas länger - ✅ Sehr explizit ### Option B: Mit "vite" im Namen ``` -vite.presseportale.test → Port 5177 -vite-web.presseportale.test → Port 5178 +vite.pressekonto.test → Port 5177 +vite-web.pressekonto.test → Port 5178 ``` - ⚠️ Technologie-spezifisch (was wenn du später zu einem anderen Build-Tool wechselst?) - ⚠️ Weniger klar was geladen wird ### Option C: Separate Domains pro Frontend ``` -assets.presseportale.test → Port 5177 (Portal) +assets.pressekonto.test → Port 5177 (Portal) assets.presseecho.test → Port 5178 (Presseecho) assets.businessportal24.test → Port 5178 (Businessportal24) ``` @@ -61,7 +61,7 @@ assets.businessportal24.test → Port 5178 (Businessportal24) ```yaml # Portal Assets (Backend) -- "traefik.http.routers.assets-portal.rule=Host(`assets.presseportale.test`)" +- "traefik.http.routers.assets-portal.rule=Host(`assets.pressekonto.test`)" - "traefik.http.routers.assets-portal.entrypoints=websecure" - "traefik.http.routers.assets-portal.tls=true" - "traefik.http.routers.assets-portal.service=assets-portal-service" @@ -69,7 +69,7 @@ assets.businessportal24.test → Port 5178 (Businessportal24) - "traefik.http.services.assets-portal-service.loadbalancer.server.scheme=http" # Web Assets (Frontend) -- "traefik.http.routers.assets-web.rule=Host(`assets-web.presseportale.test`)" +- "traefik.http.routers.assets-web.rule=Host(`assets-web.pressekonto.test`)" - "traefik.http.routers.assets-web.entrypoints=websecure" - "traefik.http.routers.assets-web.tls=true" - "traefik.http.routers.assets-web.service=assets-web-service" @@ -89,8 +89,8 @@ ports: ```env # Vite Asset Domains -ASSET_URL_PORTAL=https://assets.presseportale.test -ASSET_URL_WEB=https://assets-web.presseportale.test +ASSET_URL_PORTAL=https://assets.pressekonto.test +ASSET_URL_WEB=https://assets-web.pressekonto.test # Vite Development Ports VITE_PORT_PORTAL=5177 @@ -102,11 +102,11 @@ VITE_PORT_WEB=5178 Füge folgende Einträge zu deiner `/etc/hosts` (Linux/Mac) oder `C:\Windows\System32\drivers\etc\hosts` (Windows) hinzu: ``` -127.0.0.1 presseportale.test +127.0.0.1 pressekonto.test 127.0.0.1 presseecho.test 127.0.0.1 businessportal24.test -127.0.0.1 assets.presseportale.test -127.0.0.1 assets-web.presseportale.test +127.0.0.1 assets.pressekonto.test +127.0.0.1 assets-web.pressekonto.test ``` ## Vite-Konfigurationen @@ -121,7 +121,7 @@ export default defineConfig({ host: "0.0.0.0", port: 5177, hmr: { - host: "assets.presseportale.test", // ← Asset-URL + host: "assets.pressekonto.test", // ← Asset-URL protocol: "wss", }, }, @@ -139,7 +139,7 @@ export default defineConfig({ host: "0.0.0.0", port: 5178, hmr: { - host: "assets-web.presseportale.test", // ← Asset-URL + host: "assets-web.pressekonto.test", // ← Asset-URL protocol: "wss", }, }, @@ -156,16 +156,16 @@ Browser-Request ↓ 2. Laravel lädt View mit: @vite(['resources/css/web/theme-presseecho.css', ...]) ↓ -3. Vite-Helper generiert: - +3. Vite-Helper generiert: + ↓ -4. Browser requested: assets-web.presseportale.test +4. Browser requested: assets-web.pressekonto.test ↓ 5. Traefik routet zu: Container Port 5178 ↓ 6. Vite Web Server antwortet ↓ -7. HMR WebSocket öffnet: wss://assets-web.presseportale.test +7. HMR WebSocket öffnet: wss://assets-web.pressekonto.test ↓ 8. ✅ Hot Module Replacement funktioniert! ``` @@ -175,8 +175,8 @@ Browser-Request ### 1. DNS-Auflösung testen ```bash # Sollte zu 127.0.0.1 auflösen -ping assets.presseportale.test -ping assets-web.presseportale.test +ping assets.pressekonto.test +ping assets-web.pressekonto.test ``` ### 2. Vite-Server starten @@ -195,15 +195,15 @@ Du solltest sehen: ### 3. Browser-Test Öffne: -- https://presseportale.test (sollte Assets von assets.presseportale.test laden) -- https://presseecho.test (sollte Assets von assets-web.presseportale.test laden) -- https://businessportal24.test (sollte Assets von assets-web.presseportale.test laden) +- https://pressekonto.test (sollte Assets von assets.pressekonto.test laden) +- https://presseecho.test (sollte Assets von assets-web.pressekonto.test laden) +- https://businessportal24.test (sollte Assets von assets-web.pressekonto.test laden) ### 4. HMR-Test 1. Öffne Browser DevTools (F12) 2. Gehe zu "Network" Tab 3. Filter auf "WS" (WebSocket) -4. Du solltest Verbindungen zu `wss://assets.*.presseportale.test` sehen +4. Du solltest Verbindungen zu `wss://assets.*.pressekonto.test` sehen 5. Ändere eine CSS-Datei 6. Browser sollte automatisch neu laden (ohne vollständigen Page-Refresh) @@ -256,8 +256,8 @@ docker compose logs laravel.test | grep traefik ### ✅ Verwende diese Asset-URLs: ``` -assets.presseportale.test → Port 5177 (Portal/Backend) -assets-web.presseportale.test → Port 5178 (Web/Frontend) +assets.pressekonto.test → Port 5177 (Portal/Backend) +assets-web.pressekonto.test → Port 5178 (Web/Frontend) ``` ### ✅ Vorteile: diff --git a/_docs/DOMAINS-CONFIG.md b/_docs/DOMAINS-CONFIG.md index 52589e0..6a64524 100644 --- a/_docs/DOMAINS-CONFIG.md +++ b/_docs/DOMAINS-CONFIG.md @@ -9,14 +9,14 @@ Füge die folgenden Variablen zu deiner `.env`-Datei hinzu: ```env # Domain-Konfigurationen -APP_NAME=presseportale -APP_URL=https://presseportale.test +APP_NAME=pressekonto +APP_URL=https://pressekonto.test APP_PRIMARY="#3ea3dc" APP_ACCENT="#5c5c60" # Entwicklungseinstellungen für Domains DEV_SIMULATE_DOMAIN=false -DEV_SIMULATED_DOMAIN=presseportale.test +DEV_SIMULATED_DOMAIN=pressekonto.test ``` ## Entwicklungsmodus @@ -34,10 +34,10 @@ unabhängig von der tatsächlichen URL. Jede Domain kann eigene Einstellungen haben: -### Haupt-Website (presseportale.test) +### Haupt-Website (pressekonto.test) -- `APP_URL`: Die Domain für die Haupt-Website (https://presseportale.test) -- `APP_NAME`: Der Name der Haupt-Website (presseportale) +- `APP_URL`: Die Domain für die Haupt-Website (https://pressekonto.test) +- `APP_NAME`: Der Name der Haupt-Website (pressekonto) - `APP_PRIMARY`: Die primäre Farbe im HEX-Format (#3ea3dc) - `APP_ACCENT`: Die Akzentfarbe im HEX-Format (#5c5c60) @@ -62,7 +62,7 @@ Jede Domain kann eigene Einstellungen haben: Um die verschiedenen Domains lokal zu testen, füge folgende Zeilen zu deiner Hosts-Datei hinzu: ``` -127.0.0.1 presseportale.test +127.0.0.1 pressekonto.test 127.0.0.1 presseecho.test 127.0.0.1 businessportal24.test ``` @@ -101,7 +101,7 @@ Im Code kannst du auf die Domain-Konfiguration zugreifen: Das Projekt verwendet bereits eine Multi-Domain-Architektur mit: -- **Hauptwebsite:** `presseportale.test` - Hauptwebsite mit blauem Theme (#3ea3dc) +- **Hauptwebsite:** `pressekonto.test` - Hauptwebsite mit blauem Theme (#3ea3dc) - **Presseecho:** `presseecho.test` - Presseecho-Website mit rotem Theme (#e94a3c) - **Business Portal:** `businessportal24.test` - Business Portal mit orangem Theme (#f69f0f) diff --git a/_docs/FINAL-FIX-SUMMARY.md b/_docs/FINAL-FIX-SUMMARY.md index 67a1b0d..029f0ea 100644 --- a/_docs/FINAL-FIX-SUMMARY.md +++ b/_docs/FINAL-FIX-SUMMARY.md @@ -2,7 +2,7 @@ ## 🔍 Ursprüngliches Problem -Auf https://presseportale.test erschien der Fehler: +Auf https://pressekonto.test erschien der Fehler: ``` [Error] Not allowed to use restricted network host "0.0.0.0": https://0.0.0.0:5178/@vite/client @@ -53,7 +53,7 @@ npm run dev:all ```bash # Portal CSS wird korrekt geladen: -curl -Iks https://assets.presseportale.test/resources/css/portal.css +curl -Iks https://assets.pressekonto.test/resources/css/portal.css # → HTTP/2 200 ✅ # Web Assets funktionieren: @@ -65,13 +65,13 @@ curl -Iks https://assets.businessportal24.test/resources/css/web/theme-businessp | Domain | Asset-Domain | Port | Build-Dir | CSS-Datei | |--------|-------------|------|-----------|-----------| -| presseportale.test | assets.presseportale.test | 5177 | build/portal | portal.css | +| pressekonto.test | assets.pressekonto.test | 5177 | build/portal | portal.css | | presseecho.test | assets.presseecho.test | 5178 | build/web | theme-presseecho.css | | businessportal24.test | assets.businessportal24.test | 5178 | build/web | theme-businessportal24.css | ## 🚀 Nächste Schritte -1. **Browser testen**: Öffne https://presseportale.test und mache einen Hard-Refresh (`Ctrl+Shift+R`) +1. **Browser testen**: Öffne https://pressekonto.test und mache einen Hard-Refresh (`Ctrl+Shift+R`) 2. **Keine Fehler mehr**: Die "0.0.0.0" Fehler sollten verschwunden sein 3. **Assets laden über HTTPS**: Alle CSS/JS-Dateien werden über die korrekten Asset-Subdomains geladen @@ -87,7 +87,7 @@ Falls du die Docker Container neu gestartet hast, stelle sicher dass: 1. ✅ DNS-Einträge in `/etc/hosts` vorhanden sind: ``` - 127.0.0.1 assets.presseportale.test + 127.0.0.1 assets.pressekonto.test 127.0.0.1 assets.presseecho.test 127.0.0.1 assets.businessportal24.test ``` diff --git a/_docs/FINALE-ASSET-URL-FIXES.md b/_docs/FINALE-ASSET-URL-FIXES.md index ba23526..9c454da 100644 --- a/_docs/FINALE-ASSET-URL-FIXES.md +++ b/_docs/FINALE-ASSET-URL-FIXES.md @@ -4,7 +4,7 @@ ### 1. `config/domains.php` Jede Domain hat jetzt eine dedizierte `asset_url`: -- `portal`: `https://assets.presseportale.test` +- `portal`: `https://assets.pressekonto.test` - `presseecho`: `https://assets.presseecho.test` - `businessportal24`: `https://assets.businessportal24.test` @@ -39,7 +39,7 @@ sleep 5 && tail -30 /tmp/vite-server.log ### 2. Im Browser testen Öffne mit Hard-Refresh (`Ctrl+Shift+R`): -- ✅ https://presseportale.test +- ✅ https://pressekonto.test - ✅ https://presseecho.test - ✅ https://businessportal24.test @@ -52,7 +52,7 @@ https://0.0.0.0:5178/@vite/client **NACHHER (✅)**: ``` -https://assets.presseportale.test/@vite/client +https://assets.pressekonto.test/@vite/client https://assets.presseecho.test/@vite/client https://assets.businessportal24.test/@vite/client ``` diff --git a/_docs/FORTIFY-SANCTUM-SETUP.md b/_docs/FORTIFY-SANCTUM-SETUP.md index 702f932..61d219a 100644 --- a/_docs/FORTIFY-SANCTUM-SETUP.md +++ b/_docs/FORTIFY-SANCTUM-SETUP.md @@ -54,7 +54,7 @@ composer require laravel/fortify laravel/sanctum ## Routen -### Web-Authentifizierung (presseportale.test) +### Web-Authentifizierung (pressekonto.test) - `GET /login` - Anmeldeseite (Livewire) - `POST /login` - Anmeldung (Livewire) @@ -68,7 +68,7 @@ composer require laravel/fortify laravel/sanctum - `GET /verify-email` - E-Mail-Verifizierung (Livewire) - `GET /confirm-password` - Passwort bestätigen (Livewire) -### API-Routen (api.presseportale.test) +### API-Routen (api.pressekonto.test) - `GET /api/user` - Aktueller Benutzer (geschützt) - `GET /api/profile` - Benutzerprofil (geschützt) @@ -78,7 +78,7 @@ composer require laravel/fortify laravel/sanctum ### Web-Authentifizierung -1. Besuchen Sie `http://portal.presseportale.test/login` +1. Besuchen Sie `http://portal.pressekonto.test/login` 2. Registrieren Sie sich oder melden Sie sich an 3. Nutzen Sie die verschiedenen Authentifizierungsfeatures @@ -87,7 +87,7 @@ composer require laravel/fortify laravel/sanctum 1. **Token erstellen**: ```bash -curl -X POST http://api.presseportale.test/login \ +curl -X POST http://api.pressekonto.test/login \ -H "Content-Type: application/json" \ -d '{"email":"user@example.com","password":"password"}' ``` @@ -95,7 +95,7 @@ curl -X POST http://api.presseportale.test/login \ 2. **Geschützte Route aufrufen**: ```bash -curl -X GET http://api.presseportale.test/api/user \ +curl -X GET http://api.pressekonto.test/api/user \ -H "Authorization: Bearer YOUR_TOKEN_HERE" ``` diff --git a/_docs/THEME-INTEGRATION.md b/_docs/THEME-INTEGRATION.md index 5869888..451aeb2 100644 --- a/_docs/THEME-INTEGRATION.md +++ b/_docs/THEME-INTEGRATION.md @@ -6,7 +6,7 @@ Das Projekt nutzt ein dynamisches Theme-System mit 3 Domains: | Domain | Theme | Primary Color | Secondary Color | CSS-Datei | |--------|-------|---------------|-----------------|-----------| -| **presseportale.test** | portal | #526266 | #82a0a7 | `resources/css/portal.css` | +| **pressekonto.test** | portal | #526266 | #82a0a7 | `resources/css/portal.css` | | **presseecho.test** | presseecho | #345636 (Grün) | #6b8f71 | `resources/css/web/theme-presseecho.css` | | **businessportal24.test** | businessportal24 | #cf3628 (Rot) | #f0834a | `resources/css/web/theme-businessportal24.css` | @@ -276,8 +276,8 @@ npm run build:web Der `ThemeServiceProvider` unterstützt einen `?theme=` URL-Parameter zum Testen: ``` -https://presseportale.test?theme=presseecho -https://presseportale.test?theme=businessportal24 +https://pressekonto.test?theme=presseecho +https://pressekonto.test?theme=businessportal24 ``` ### Via Host @@ -285,7 +285,7 @@ https://presseportale.test?theme=businessportal24 Einfach die entsprechende Domain aufrufen: ``` -https://presseportale.test → Portal Theme +https://pressekonto.test → Portal Theme https://presseecho.test → Presseecho Theme https://businessportal24.test → Businessportal24 Theme ``` diff --git a/_docs/VITE-SETUP-NEUE-STRUKTUR.md b/_docs/VITE-SETUP-NEUE-STRUKTUR.md index f103653..37bea56 100644 --- a/_docs/VITE-SETUP-NEUE-STRUKTUR.md +++ b/_docs/VITE-SETUP-NEUE-STRUKTUR.md @@ -6,7 +6,7 @@ Jede Domain hat jetzt ihre eigene dedizierte Asset-Subdomain: | Domain | Asset-Subdomain | Port | Vite-Config | |--------|----------------|------|-------------| -| `presseportale.test` | `assets.presseportale.test` | 5177 | `vite.portal.config.js` | +| `pressekonto.test` | `assets.pressekonto.test` | 5177 | `vite.portal.config.js` | | `presseecho.test` | `assets.presseecho.test` | 5178 | `vite.web.config.js` | | `businessportal24.test` | `assets.businessportal24.test` | 5178 | `vite.web.config.js` | @@ -20,7 +20,7 @@ Füge folgende Einträge zu deiner Hosts-Datei hinzu (lokal auf deinem Host-Syst **Windows**: `C:\Windows\System32\drivers\etc\hosts` ``` -127.0.0.1 assets.presseportale.test +127.0.0.1 assets.pressekonto.test 127.0.0.1 assets.presseecho.test 127.0.0.1 assets.businessportal24.test ``` @@ -47,7 +47,7 @@ npm run dev:all ### 1. `docker-compose.yml` Neue Traefik-Routen hinzugefügt: -- `assets.presseportale.test` → Port 5177 (Portal) +- `assets.pressekonto.test` → Port 5177 (Portal) - `assets.presseecho.test` → Port 5178 (Presseecho) - `assets.businessportal24.test` → Port 5178 (Businessportal24) @@ -66,7 +66,7 @@ Nach dem Neustart kannst du testen: ```bash # Im DevContainer: -curl -Ik https://assets.presseportale.test/@vite/client +curl -Ik https://assets.pressekonto.test/@vite/client curl -Ik https://assets.presseecho.test/@vite/client curl -Ik https://assets.businessportal24.test/@vite/client ``` diff --git a/_docs/VITE-SETUP.md b/_docs/VITE-SETUP.md index 365cd1d..08412db 100644 --- a/_docs/VITE-SETUP.md +++ b/_docs/VITE-SETUP.md @@ -6,7 +6,7 @@ Dieses Projekt verwendet **2 separate Vite-Ports** für unterschiedliche Domain- | Bereich | Port | Vite Config | Tailwind Config | Domains | FluxUI | |---------|------|-------------|-----------------|---------|--------| -| **Backend (Portal)** | 5177 | `vite.portal.config.js` | `tailwind.portal.config.js` | `presseportale.test` | ✅ Ja | +| **Backend (Portal)** | 5177 | `vite.portal.config.js` | `tailwind.portal.config.js` | `pressekonto.test` | ✅ Ja | | **Frontend (Web)** | 5178 | `vite.web.config.js` | `tailwind.web.config.js` | `presseecho.test`, `businessportal24.test` | ❌ Nein | ## Warum 2 Ports? @@ -35,15 +35,15 @@ Startet beide Vite-Server parallel mit `concurrently` npm run dev:portal ``` - Port: 5177 -- HMR-Host: assets.presseportale.test -- Domain: presseportale.test +- HMR-Host: assets.pressekonto.test +- Domain: pressekonto.test ### Option 3: Nur Frontend (Web) ```bash npm run dev:web ``` - Port: 5178 -- HMR-Host: assets-web.presseportale.test +- HMR-Host: assets-web.pressekonto.test - Domains: presseecho.test, businessportal24.test ## Production Build @@ -86,7 +86,7 @@ public/ ## Theme-System ### Backend (Portal) -- **Domain:** presseportale.test +- **Domain:** pressekonto.test - **Theme:** `portal` - **CSS:** `resources/css/portal.css` - **Views:** `resources/views/portal/**` @@ -110,8 +110,8 @@ public/ Beide Vite-Server laufen intern auf HTTP (`https: false`), Traefik übernimmt SSL-Terminierung: -- **Portal HMR:** `wss://assets.presseportale.test` → Port 5177 -- **Web HMR:** `wss://assets-web.presseportale.test` → Port 5178 +- **Portal HMR:** `wss://assets.pressekonto.test` → Port 5177 +- **Web HMR:** `wss://assets-web.pressekonto.test` → Port 5178 ## Troubleshooting diff --git a/_docs/WICHTIG-NAECHSTE-SCHRITTE.md b/_docs/WICHTIG-NAECHSTE-SCHRITTE.md index 90c0764..dfd273b 100644 --- a/_docs/WICHTIG-NAECHSTE-SCHRITTE.md +++ b/_docs/WICHTIG-NAECHSTE-SCHRITTE.md @@ -37,7 +37,7 @@ sudo nano /etc/hosts **Einträge:** ``` -127.0.0.1 assets.presseportale.test +127.0.0.1 assets.pressekonto.test 127.0.0.1 assets.presseecho.test 127.0.0.1 assets.businessportal24.test ``` @@ -51,7 +51,7 @@ Zurück im DevContainer: tail -20 /tmp/vite-server.log # Teste die Asset-URLs: -curl -Ik https://assets.presseportale.test/@vite/client +curl -Ik https://assets.pressekonto.test/@vite/client curl -Ik https://assets.presseecho.test/@vite/client curl -Ik https://assets.businessportal24.test/@vite/client @@ -63,7 +63,7 @@ curl -Ik https://assets.businessportal24.test/@vite/client Öffne: - https://businessportal24.test - https://presseecho.test -- https://presseportale.test +- https://pressekonto.test Die Assets sollten nun korrekt über HTTPS von den jeweiligen Asset-Subdomains geladen werden! @@ -71,7 +71,7 @@ Die Assets sollten nun korrekt über HTTPS von den jeweiligen Asset-Subdomains g | Hauptdomain | Asset-Domain | Port | Build-Dir | |------------|-------------|------|-----------| -| presseportale.test | assets.presseportale.test | 5177 | public/build/portal | +| pressekonto.test | assets.pressekonto.test | 5177 | public/build/portal | | presseecho.test | assets.presseecho.test | 5178 | public/build/web | | businessportal24.test | assets.businessportal24.test | 5178 | public/build/web | diff --git a/_docs/ZUSAMMENFASSUNG-VITE-SETUP.md b/_docs/ZUSAMMENFASSUNG-VITE-SETUP.md index 9098da3..3809c70 100644 --- a/_docs/ZUSAMMENFASSUNG-VITE-SETUP.md +++ b/_docs/ZUSAMMENFASSUNG-VITE-SETUP.md @@ -65,7 +65,7 @@ Du benötigst **mindestens 2 Vite-Ports**: │ └──────────────────┘ └──────────────────┘ │ │ ↓ ↓ │ │ ┌──────────────────┐ ┌──────────────────┐ │ -│ │ presseportale.test │ │ presseecho.test │ │ +│ │ pressekonto.test │ │ presseecho.test │ │ │ │ │ │ businessp24.test│ │ │ └──────────────────┘ └──────────────────┘ │ │ │ @@ -80,14 +80,14 @@ Du benötigst **mindestens 2 Vite-Ports**: - Port: **5177** - Input: `resources/css/portal.css` - Build: `public/build/portal` -- HMR: `assets.presseportale.test` +- HMR: `assets.pressekonto.test` - FluxUI: ✅ Ja #### ✅ `vite.web.config.js` - Port: **5178** (geändert von 5177!) - Input: `theme-presseecho.css`, `theme-businessportal24.css` - Build: `public/build/web` -- HMR: `assets-web.presseportale.test` +- HMR: `assets-web.pressekonto.test` - FluxUI: ❌ Nein #### ❌ `vite.config.js` (deprecated) @@ -190,14 +190,14 @@ npm run build:web | URL | Vite-Port | Theme | FluxUI | |-----|-----------|-------|--------| -| https://presseportale.test | 5177 | portal | ✅ | +| https://pressekonto.test | 5177 | portal | ✅ | | https://presseecho.test | 5178 | presseecho | ❌ | | https://businessportal24.test | 5178 | businessportal24 | ❌ | ## HMR (Hot Module Replacement) -- **Portal:** `wss://assets.presseportale.test` → Port 5177 -- **Web:** `wss://assets-web.presseportale.test` → Port 5178 +- **Portal:** `wss://assets.pressekonto.test` → Port 5177 +- **Web:** `wss://assets-web.pressekonto.test` → Port 5178 ⚠️ **Wichtig:** Traefik muss beide HMR-Hosts routen! @@ -210,12 +210,12 @@ Stelle sicher, dass Traefik beide Vite-Ports routet: # docker-compose.yml oder traefik.yml labels: # Portal Assets - - "traefik.http.routers.vite-portal.rule=Host(`assets.presseportale.test`)" + - "traefik.http.routers.vite-portal.rule=Host(`assets.pressekonto.test`)" - "traefik.http.routers.vite-portal.service=vite-portal" - "traefik.http.services.vite-portal.loadbalancer.server.port=5177" # Web Assets - - "traefik.http.routers.vite-web.rule=Host(`assets-web.presseportale.test`)" + - "traefik.http.routers.vite-web.rule=Host(`assets-web.pressekonto.test`)" - "traefik.http.routers.vite-web.service=vite-web" - "traefik.http.services.vite-web.loadbalancer.server.port=5178" ``` @@ -223,11 +223,11 @@ labels: ### 2. DNS/Hosts-Datei aktualisieren ``` -127.0.0.1 presseportale.test +127.0.0.1 pressekonto.test 127.0.0.1 presseecho.test 127.0.0.1 businessportal24.test -127.0.0.1 assets.presseportale.test -127.0.0.1 assets-web.presseportale.test +127.0.0.1 assets.pressekonto.test +127.0.0.1 assets-web.pressekonto.test ``` ### 3. Blade-Templates aktualisieren @@ -258,7 +258,7 @@ Diese Dateien werden nicht mehr benötigt: npm run dev:all # 2. Browser öffnen -# - https://presseportale.test (Backend) +# - https://pressekonto.test (Backend) # - https://presseecho.test (Frontend Grün) # - https://businessportal24.test (Frontend Rot) diff --git a/_docs/api/v1.yml b/_docs/api/v1.yml index 8e52160..59c3af3 100644 --- a/_docs/api/v1.yml +++ b/_docs/api/v1.yml @@ -1,6 +1,6 @@ openapi: 3.1.0 info: - title: Presseportale API + title: Pressekonto API version: 1.0.0 description: > REST API for customer integrations after the 2026 migration. Legacy diff --git a/app/Console/Commands/MigrateLegacyMedia.php b/app/Console/Commands/MigrateLegacyMedia.php new file mode 100644 index 0000000..a312056 --- /dev/null +++ b/app/Console/Commands/MigrateLegacyMedia.php @@ -0,0 +1,472 @@ + 'mysql_presseecho', + 'businessportal24' => 'mysql_businessportal', + ]; + + /** + * @var array> + */ + private const SOURCE_DIRECTORIES = [ + 'company-logos' => [ + 'uploads/company', + 'thumbnails/company', + ], + 'press-release-images' => [ + 'uploads/pressreleaseimage', + 'uploads/pressreleaseimage_', + 'uploads/_pressreleaseimage', + 'thumbnails/pressreleaseimage', + ], + ]; + + public function __construct(private readonly ImageService $imageService) + { + parent::__construct(); + } + + public function handle(): int + { + $portals = $this->selectedPortals(); + $types = $this->selectedTypes(); + + if ($portals === []) { + $this->error('Ungültiges Portal. Erlaubt: presseecho, businessportal24, all.'); + + return self::FAILURE; + } + + if ($types === []) { + $this->error('Ungültiger Medientyp. Erlaubt: company-logos, press-release-images, all.'); + + return self::FAILURE; + } + + $configuredBasePath = (string) $this->option('base-path'); + $basePath = Str::startsWith($configuredBasePath, '/') + ? rtrim($configuredBasePath, '/') + : base_path(trim($configuredBasePath, '/')); + $dryRun = (bool) $this->option('dry-run'); + $force = (bool) $this->option('force'); + $limit = max(0, (int) $this->option('limit')); + $totals = $this->emptyStats(); + + foreach ($portals as $portal) { + foreach ($types as $type) { + $stats = match ($type) { + 'company-logos' => $this->migrateCompanyLogos($portal, $basePath, $dryRun, $force, $limit), + 'press-release-images' => $this->migratePressReleaseImages($portal, $basePath, $dryRun, $force, $limit), + }; + + foreach ($totals as $key => $value) { + $totals[$key] = $value + $stats[$key]; + } + + $this->line(sprintf( + '%s/%s: Legacy %d, migriert %d, Thumbnail-Fallback %d, DB-Updates %d, bereits synchron %d, Ziel fehlt %d, Datei fehlt %d', + $portal, + $type, + $stats['legacy_rows'], + $stats['migrated'], + $stats['thumbnail_fallback'], + $stats['updated'], + $stats['already_synced'], + $stats['missing_target'], + $stats['missing_file'], + )); + } + } + + $this->newLine(); + $this->info(sprintf( + 'Gesamt: Legacy %d, migriert %d, Thumbnail-Fallback %d, DB-Updates %d, bereits synchron %d, Ziel fehlt %d, Datei fehlt %d%s', + $totals['legacy_rows'], + $totals['migrated'], + $totals['thumbnail_fallback'], + $totals['updated'], + $totals['already_synced'], + $totals['missing_target'], + $totals['missing_file'], + $dryRun ? ' (Dry-Run)' : '', + )); + + return ($totals['missing_target'] + $totals['missing_file']) > 0 + ? self::FAILURE + : self::SUCCESS; + } + + /** + * @return array{legacy_rows:int,migrated:int,thumbnail_fallback:int,updated:int,already_synced:int,missing_target:int,missing_file:int} + */ + private function migrateCompanyLogos(string $portal, string $basePath, bool $dryRun, bool $force, int $limit): array + { + $stats = $this->emptyStats(); + $sourceIndex = $this->sourceIndex($basePath, $portal, 'company-logos'); + $processed = 0; + + DB::connection(self::PORTAL_CONNECTIONS[$portal]) + ->table('company') + ->whereNotNull('logo') + ->where('logo', '!=', '') + ->orderBy('id') + ->chunk(500, function ($rows) use ($portal, $sourceIndex, $dryRun, $force, $limit, &$processed, &$stats): bool { + foreach ($rows as $row) { + if ($limit > 0 && $processed >= $limit) { + return false; + } + + $processed++; + $stats['legacy_rows']++; + + $company = Company::withoutGlobalScopes() + ->where('legacy_portal', $portal) + ->where('legacy_id', $row->id) + ->first(['id', 'logo_path', 'logo_variants']); + + if (! $company) { + $stats['missing_target']++; + $this->warn("Ziel fehlt: {$portal}/company/{$row->id}"); + + continue; + } + + $sourceFilename = $this->legacyFilename((string) $row->logo); + $sourcePath = $sourceIndex[$sourceFilename] ?? $sourceIndex[Str::lower($sourceFilename)] ?? null; + $destinationPath = "company-logos/{$portal}/{$company->id}/{$sourceFilename}"; + + if ($this->isAlreadySynced($company->logo_path, $destinationPath, $force)) { + $stats['already_synced']++; + + if (! $dryRun && (! is_array($company->logo_variants) || $company->logo_variants === [])) { + $variants = $this->imageService->generateMissingCompanyLogoVariants($destinationPath); + + if ($variants !== []) { + $company->forceFill(['logo_variants' => $variants])->save(); + $stats['updated']++; + } + } + + continue; + } + + if (! $sourcePath) { + $stats['missing_file']++; + $this->warn("Datei fehlt: {$portal}/company/{$sourceFilename} (Company #{$company->id})"); + + continue; + } + + if (! $dryRun) { + $this->copyToPublicStorage($sourcePath, $destinationPath, $force); + $company->forceFill([ + 'logo_path' => $destinationPath, + 'logo_variants' => $this->imageService->generateMissingCompanyLogoVariants($destinationPath), + ])->save(); + } + + $stats['migrated']++; + $stats['updated']++; + } + + return true; + }); + + return $stats; + } + + /** + * @return array{legacy_rows:int,migrated:int,thumbnail_fallback:int,updated:int,already_synced:int,missing_target:int,missing_file:int} + */ + private function migratePressReleaseImages(string $portal, string $basePath, bool $dryRun, bool $force, int $limit): array + { + $stats = $this->emptyStats(); + $sourceIndex = $this->sourceIndex($basePath, $portal, 'press-release-images'); + $thumbnailIndex = $this->thumbnailIndex($basePath, $portal); + $processed = 0; + + DB::connection(self::PORTAL_CONNECTIONS[$portal]) + ->table('press_release_image') + ->orderBy('id') + ->chunk(500, function ($rows) use ($portal, $sourceIndex, $thumbnailIndex, $dryRun, $force, $limit, &$processed, &$stats): bool { + foreach ($rows as $row) { + if ($limit > 0 && $processed >= $limit) { + return false; + } + + if (blank($row->image)) { + continue; + } + + $processed++; + $stats['legacy_rows']++; + + $pressRelease = PressRelease::withoutGlobalScopes() + ->where('legacy_portal', $portal) + ->where('legacy_id', $row->press_release_id) + ->first(['id']); + + if (! $pressRelease) { + $stats['missing_target']++; + $this->warn("Ziel fehlt: {$portal}/press_release/{$row->press_release_id}"); + + continue; + } + + $sourceFilename = $this->legacyFilename((string) $row->image); + $sourcePath = $sourceIndex[$sourceFilename] ?? $sourceIndex[Str::lower($sourceFilename)] ?? null; + $usedThumbnailFallback = false; + + if (! $sourcePath) { + $sourcePath = $thumbnailIndex[(int) $row->id] ?? null; + $usedThumbnailFallback = $sourcePath !== null; + } + + $destinationFilename = $usedThumbnailFallback ? basename($sourcePath) : $sourceFilename; + $destinationPath = "press-releases/{$pressRelease->id}/images/{$destinationFilename}"; + $image = PressReleaseImage::withTrashed() + ->where('legacy_portal', $portal) + ->where('legacy_id', $row->id) + ->first(); + + if ($image && $this->isAlreadySynced($image->path, $destinationPath, $force)) { + $stats['already_synced']++; + + if (! $dryRun && (! is_array($image->variants) || $image->variants === [])) { + $variants = $this->imageService->generateMissingPressReleaseVariants($destinationPath); + + if ($variants !== []) { + $image->forceFill(['variants' => $variants])->save(); + $stats['updated']++; + } + } + + continue; + } + + if (! $sourcePath) { + $stats['missing_file']++; + $this->warn("Datei fehlt: {$portal}/press_release_image/{$sourceFilename} (Image #{$row->id})"); + + continue; + } + + if ($usedThumbnailFallback) { + $stats['thumbnail_fallback']++; + } + + $variants = []; + $size = [null, null]; + $mime = null; + + if (! $dryRun) { + $this->copyToPublicStorage($sourcePath, $destinationPath, $force); + $variants = $this->imageService->generateMissingPressReleaseVariants($destinationPath); + $size = @getimagesize(Storage::disk('public')->path($destinationPath)) ?: [null, null]; + $mime = File::mimeType($sourcePath) ?: null; + + $image = $image ?: new PressReleaseImage; + $image->forceFill([ + 'press_release_id' => $pressRelease->id, + 'disk' => 'public', + 'path' => $destinationPath, + 'variants' => $variants, + 'title' => $row->title ?: null, + 'description' => $row->description ?: null, + 'copyright' => $row->copyright ?: null, + 'is_preview' => (bool) $row->is_preview_image, + 'sort_order' => 0, + 'width' => is_int($size[0] ?? null) ? $size[0] : null, + 'height' => is_int($size[1] ?? null) ? $size[1] : null, + 'mime' => $mime, + 'legacy_portal' => $portal, + 'legacy_id' => $row->id, + ]); + + if ($image->trashed()) { + $image->restore(); + } + + $image->save(); + } + + $stats['migrated']++; + $stats['updated']++; + } + + return true; + }); + + return $stats; + } + + /** + * @return list + */ + private function selectedPortals(): array + { + $portal = (string) $this->option('portal'); + + return match ($portal) { + 'all' => [Portal::Presseecho->value, Portal::Businessportal24->value], + Portal::Presseecho->value, Portal::Businessportal24->value => [$portal], + default => [], + }; + } + + /** + * @return list + */ + private function selectedTypes(): array + { + $type = (string) $this->option('type'); + + return match ($type) { + 'all' => ['company-logos', 'press-release-images'], + 'company-logos', 'press-release-images' => [$type], + default => [], + }; + } + + /** + * @return array{legacy_rows:int,migrated:int,thumbnail_fallback:int,updated:int,already_synced:int,missing_target:int,missing_file:int} + */ + private function emptyStats(): array + { + return [ + 'legacy_rows' => 0, + 'migrated' => 0, + 'thumbnail_fallback' => 0, + 'updated' => 0, + 'already_synced' => 0, + 'missing_target' => 0, + 'missing_file' => 0, + ]; + } + + /** + * @return array + */ + private function sourceIndex(string $basePath, string $portal, string $type): array + { + $index = []; + + foreach (self::SOURCE_DIRECTORIES[$type] as $relativeDirectory) { + $directory = "{$basePath}/{$portal}/{$relativeDirectory}"; + + if (! File::isDirectory($directory)) { + continue; + } + + foreach (File::allFiles($directory) as $file) { + $index[$file->getFilename()] ??= $file->getPathname(); + $index[Str::lower($file->getFilename())] ??= $file->getPathname(); + } + } + + return $index; + } + + /** + * @return array + */ + private function thumbnailIndex(string $basePath, string $portal): array + { + $directory = "{$basePath}/{$portal}/thumbnails/pressreleaseimage"; + + if (! File::isDirectory($directory)) { + return []; + } + + $index = []; + $priorities = [ + 'press_image_preview' => 50, + 'pressrelease_form' => 40, + 'backend_list' => 30, + 'press_image_list' => 20, + 'press_list_image' => 10, + ]; + + foreach (File::allFiles($directory) as $file) { + if (! preg_match('/-(\d+)\.[^.]+$/', $file->getFilename(), $matches)) { + continue; + } + + $legacyImageId = (int) $matches[1]; + $thumbnailType = Str::after($file->getPathname(), "{$directory}/"); + $thumbnailType = Str::before($thumbnailType, DIRECTORY_SEPARATOR); + $priority = $priorities[$thumbnailType] ?? 0; + $current = $index[$legacyImageId] ?? null; + + if (! $current || $priority > ($current['priority'] ?? 0)) { + $index[$legacyImageId] = [ + 'path' => $file->getPathname(), + 'priority' => $priority, + ]; + } + } + + return collect($index) + ->map(fn (array $entry): string => $entry['path']) + ->all(); + } + + private function legacyFilename(string $path): string + { + $urlPath = parse_url($path, PHP_URL_PATH); + $filename = basename(rawurldecode((string) ($urlPath ?: $path))); + + return Str::of($filename)->trim()->toString(); + } + + private function isAlreadySynced(?string $currentPath, string $destinationPath, bool $force): bool + { + return ! $force + && $currentPath === $destinationPath + && Storage::disk('public')->exists($destinationPath); + } + + private function copyToPublicStorage(string $sourcePath, string $destinationPath, bool $force): void + { + if (! $force && Storage::disk('public')->exists($destinationPath)) { + return; + } + + $stream = fopen($sourcePath, 'rb'); + + if ($stream === false) { + throw new \RuntimeException("Quelldatei kann nicht gelesen werden: {$sourcePath}"); + } + + try { + Storage::disk('public')->put($destinationPath, $stream, 'public'); + } finally { + fclose($stream); + } + } +} diff --git a/app/Helpers/ThemeHelper.php b/app/Helpers/ThemeHelper.php index ea16f01..3ce4832 100644 --- a/app/Helpers/ThemeHelper.php +++ b/app/Helpers/ThemeHelper.php @@ -16,7 +16,7 @@ class ThemeHelper 'positive' => 'img/logos/portal-logo-positive.svg', 'negative' => 'img/logos/portal-logo-negative.svg', ], - 'presseportale' => [ + 'pressekonto' => [ 'positive' => 'img/logos/portal-logo-positive.svg', 'negative' => 'img/logos/portal-logo-negative.svg', ], @@ -100,7 +100,7 @@ class ThemeHelper { $config = self::getDomainConfig(); - return $config['domain_name'] ?? 'presseportale.test'; + return $config['domain_name'] ?? 'pressekonto.test'; } public static function getDomainUrl(): string @@ -118,12 +118,12 @@ class ThemeHelper $theme = config('app.theme', 'portal'); $assetUrlMap = [ - 'portal' => 'https://assets.presseportale.test', - 'presseportale' => 'https://assets.presseportale.test', + 'portal' => 'https://assets.pressekonto.test', + 'pressekonto' => 'https://assets.pressekonto.test', 'presseecho' => 'https://assets.presseecho.test', 'businessportal24' => 'https://assets.businessportal24.test', ]; - return $assetUrlMap[$theme] ?? 'https://assets.presseportale.test'; + return $assetUrlMap[$theme] ?? 'https://assets.pressekonto.test'; } } diff --git a/app/Mail/MagicLoginLink.php b/app/Mail/MagicLoginLink.php index bf068bd..e9a3898 100644 --- a/app/Mail/MagicLoginLink.php +++ b/app/Mail/MagicLoginLink.php @@ -22,7 +22,7 @@ class MagicLoginLink extends Mailable public function envelope(): Envelope { return new Envelope( - subject: 'Ihr Login-Link fuer presseportale' + subject: 'Ihr Login-Link fuer pressekonto' ); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 0515d5a..78558cf 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -80,7 +80,7 @@ class AppServiceProvider extends ServiceProvider config(['app.asset_url' => $assetUrl]); } catch (\Exception $e) { // Fallback to default if theme detection fails - config(['app.asset_url' => 'https://assets.presseportale.test']); + config(['app.asset_url' => 'https://assets.pressekonto.test']); } } } diff --git a/app/Providers/ThemeServiceProvider.php b/app/Providers/ThemeServiceProvider.php index 505e563..9f34a45 100644 --- a/app/Providers/ThemeServiceProvider.php +++ b/app/Providers/ThemeServiceProvider.php @@ -97,7 +97,7 @@ class ThemeServiceProvider extends ServiceProvider if (app()->environment('local')) { // Entwicklung: Vite Dev Server mit HMR - $viteDevServerUrl = env('VITE_DEV_SERVER_URL', 'https://assets.presseportale.test'); + $viteDevServerUrl = env('VITE_DEV_SERVER_URL', 'https://assets.pressekonto.test'); Vite::useHotFile(public_path('hot')); config(['app.vite_dev_server_url' => $viteDevServerUrl]); View::share('viteDevServerUrl', $viteDevServerUrl); diff --git a/app/Services/Image/ImageService.php b/app/Services/Image/ImageService.php index c9665a8..35a6804 100644 --- a/app/Services/Image/ImageService.php +++ b/app/Services/Image/ImageService.php @@ -177,6 +177,24 @@ class ImageService ); } + /** + * Generates and persists missing variants for an existing company logo. + * + * @return array + */ + public function generateMissingCompanyLogoVariants(string $relativePath): array + { + $disk = $this->disk(); + + if (! $disk->exists($relativePath)) { + return []; + } + + $extension = strtolower(pathinfo($relativePath, PATHINFO_EXTENSION) ?: 'jpg'); + + return $this->generateLogoVariants($disk, $relativePath, $extension); + } + private function deleteWithVariants(?string $relativePath, ?array $variants, ?string $diskName = null): void { $disk = $diskName ? Storage::disk($diskName) : $this->disk(); diff --git a/config/domains.php b/config/domains.php index 838ed34..d53bf69 100644 --- a/config/domains.php +++ b/config/domains.php @@ -13,23 +13,23 @@ return [ */ 'protocol' => env('APP_PROTOCOL', 'https://'), - 'domain_portal' => env('APP_PORTAL_NAME', 'presseportale.test'), + 'domain_portal' => env('APP_PORTAL_NAME', 'pressekonto.test'), 'domain_presseecho' => env('APP_PRESSEECHO_NAME', 'presseecho.test'), 'domain_businessportal' => env('APP_BUSINESSPORTAL_NAME', 'businessportal24.test'), - 'domain_portal_url' => env('APP_PORTAL_URL', 'https://presseportale.test'), + 'domain_portal_url' => env('APP_PORTAL_URL', 'https://pressekonto.test'), 'domain_presseecho_url' => env('APP_PRESSEECHO_URL', 'https://presseecho.test'), 'domain_businessportal_url' => env('APP_BUSINESSPORTAL_URL', 'https://businessportal24.test'), 'domains' => [ 'portal' => [ - 'domain_name' => env('APP_PORTAL_NAME', 'presseportale.test'), - 'url' => env('APP_PORTAL_URL', 'https://presseportale.test'), - 'asset_url' => env('APP_PORTAL_ASSET_URL', 'https://assets.presseportale.test'), + 'domain_name' => env('APP_PORTAL_NAME', 'pressekonto.test'), + 'url' => env('APP_PORTAL_URL', 'https://pressekonto.test'), + 'asset_url' => env('APP_PORTAL_ASSET_URL', 'https://assets.pressekonto.test'), 'theme' => 'main', 'view_prefix' => 'portal', 'assets_dir' => 'build/portal', - 'description' => 'Backend Presseportale', + 'description' => 'Backend Pressekonto', 'color_scheme' => [ 'primary' => env('APP_PORTAL_PRIMARY', '#526266'), // 'secondary' => env('APP_PORTAL_SECONDARY', '#82a0a7'), // @@ -37,14 +37,14 @@ return [ 'font' => 'Montserrat', ], - 'presseportale' => [ - 'domain_name' => env('APP_PORTAL_NAME', 'presseportale.test'), - 'url' => env('APP_PORTAL_URL', 'https://presseportale.test'), - 'asset_url' => env('APP_PORTAL_ASSET_URL', 'https://assets.presseportale.test'), - 'theme' => 'presseportale', + 'pressekonto' => [ + 'domain_name' => env('APP_PORTAL_NAME', 'pressekonto.test'), + 'url' => env('APP_PORTAL_URL', 'https://pressekonto.test'), + 'asset_url' => env('APP_PORTAL_ASSET_URL', 'https://assets.pressekonto.test'), + 'theme' => 'pressekonto', 'view_prefix' => 'web', 'assets_dir' => 'build/web', - 'description' => 'Hub-Landing presseportale.com (öffentlicher Publisher-Bereich)', + 'description' => 'Hub-Landing pressekonto.de (öffentlicher Publisher-Bereich)', 'color_scheme' => [ 'primary' => '#1A2540', 'secondary' => '#B07A3A', @@ -52,12 +52,12 @@ return [ 'font' => 'Inter Tight', 'brand' => [ 'name' => 'presse', - 'accent' => 'portale', + 'accent' => 'konto', 'tagline_short' => 'Publisher · Hub', 'tagline_long' => 'Der gemeinsame Publisher-Bereich für presseecho und businessportal24 – Pressemitteilungen schreiben, redaktionell prüfen lassen, auf beiden Reichweiten veröffentlichen.', - 'footer_legal' => '© :year presseportale · Alle Rechte vorbehalten', - 'about_label' => 'Über presseportale', - 'meta_title' => 'presseportale – Publisher-Hub für presseecho und businessportal24', + 'footer_legal' => '© :year pressekonto · Alle Rechte vorbehalten', + 'about_label' => 'Über pressekonto', + 'meta_title' => 'pressekonto – Publisher-Hub für presseecho und businessportal24', 'meta_description' => 'Ein Konto, zwei Reichweiten: Pressemitteilungen redaktionell geprüft auf presseecho und businessportal24 gleichzeitig veröffentlichen.', ], ], diff --git a/config/presseportale.code-workspace b/config/pressekonto.code-workspace similarity index 100% rename from config/presseportale.code-workspace rename to config/pressekonto.code-workspace diff --git a/config/vite.php b/config/vite.php index 938b499..701b7c4 100644 --- a/config/vite.php +++ b/config/vite.php @@ -25,7 +25,7 @@ return [ | */ - 'dev_url' => env('ASSET_URL', env('VITE_DEV_SERVER_URL', 'https://assets.presseportale.test')), + 'dev_url' => env('ASSET_URL', env('VITE_DEV_SERVER_URL', 'https://assets.pressekonto.test')), /* |-------------------------------------------------------------------------- diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 092a63b..e429bb6 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -20,11 +20,11 @@ class DatabaseSeeder extends Seeder RolesAndPermissionsSeeder::class, AdminPresetSeeder::class, PaymentOptionSeeder::class, - CategorySeeder::class, + // CategorySeeder::class, ]); $adminUser = User::firstOrCreate([ - 'email' => 'admin@presseportale.test', + 'email' => 'admin@pressekonto.test', ], [ 'name' => 'Portal Admin', 'password' => Hash::make('password'), diff --git a/dev/frontend/ENTWICKLUNGSKONZEPT-BusinessPortal24-Frontend.md b/dev/frontend/ENTWICKLUNGSKONZEPT-BusinessPortal24-Frontend.md index ccdb8c7..ae29a5a 100644 --- a/dev/frontend/ENTWICKLUNGSKONZEPT-BusinessPortal24-Frontend.md +++ b/dev/frontend/ENTWICKLUNGSKONZEPT-BusinessPortal24-Frontend.md @@ -1,12 +1,12 @@ -# Entwicklungskonzept – BusinessPortal24, Presseecho & presseportale-Hub Frontend +# Entwicklungskonzept – BusinessPortal24, Presseecho & pressekonto-Hub Frontend > **Stand:** 13. Mai 2026 -> **Domains:** `businessportal24.test` / `.com` · `presseecho.test` / `.de` · `presseportale.test` / `.com` (Hub) -> **Theme-Slugs:** `businessportal24` (warm-rotes Editorial) · `presseecho` (grünes Editorial) · `presseportale` (Hub-Blau · Publisher-Landing) +> **Domains:** `businessportal24.test` / `.com` · `presseecho.test` / `.de` · `pressekonto.test` / `.de` (Hub) +> **Theme-Slugs:** `businessportal24` (warm-rotes Editorial) · `presseecho` (grünes Editorial) · `pressekonto` (Hub-Blau · Publisher-Landing) > **Assets-Dir (geteilt):** `public/build/web/` -> **Ziel:** Editoriales DACH-Pressemitteilungs-Ökosystem mit 1:1-Mockup-Umsetzung. Presseecho nutzt die **gleiche Komponenten-Architektur** wie BP24, der Hub `presseportale.com` ist eine **eigenständige Publisher-Landing** mit klar abgegrenztem Charakter (Hub-Blau + Bernstein, kein Editorial-Feed). +> **Ziel:** Editoriales DACH-Pressemitteilungs-Ökosystem mit 1:1-Mockup-Umsetzung. Presseecho nutzt die **gleiche Komponenten-Architektur** wie BP24, der Hub `pressekonto.de` ist eine **eigenständige Publisher-Landing** mit klar abgegrenztem Charakter (Hub-Blau + Bernstein, kein Editorial-Feed). -Dieses Dokument beschreibt den aktuellen Stand und die wichtigsten Architektur­entscheidungen der BusinessPortal24-, Presseecho- und presseportale-Hub-Frontend-Entwicklung. Es ist die zentrale Anlaufstelle für alle, die im Frontend weiterarbeiten oder neue Seiten ergänzen. +Dieses Dokument beschreibt den aktuellen Stand und die wichtigsten Architektur­entscheidungen der BusinessPortal24-, Presseecho- und pressekonto-Hub-Frontend-Entwicklung. Es ist die zentrale Anlaufstelle für alle, die im Frontend weiterarbeiten oder neue Seiten ergänzen. --- @@ -67,9 +67,9 @@ Request (Host: presseecho.test) Lokale Domain-Simulation: - `.env`: `DEV_SIMULATE_DOMAIN=true`, `DEV_SIMULATED_DOMAIN=businessportal24.test|presseecho.test` -- Alternativ: `?theme=businessportal24|presseecho|presseportale` als Query-Parameter +- Alternativ: `?theme=businessportal24|presseecho|pressekonto` als Query-Parameter -> **Hub-Sonderfall (`presseportale.test`):** Diese Domain ist gleichzeitig **Admin-Backend** (Auth/Admin/Customer-Routen, theme = `main`, Build-Dir `build/portal/`) **und** öffentliche **Hub-Landing** (theme = `presseportale`, Build-Dir `build/web/`). In `config/domains.php` existieren beide Einträge (`portal` und `presseportale`) für dieselbe `domain_name`. Der `ThemeServiceProvider` matcht zuerst `portal` (Backend-Standard); für die öffentliche Landing schaltet **`routes/web.php` per `$applyWebDomainConfig('presseportale')` explizit auf das Hub-Theme** um. Auth- und Admin-Routen bleiben unbeeinflusst. +> **Hub-Sonderfall (`pressekonto.test`):** Diese Domain ist gleichzeitig **Admin-Backend** (Auth/Admin/Customer-Routen, theme = `main`, Build-Dir `build/portal/`) **und** öffentliche **Hub-Landing** (theme = `pressekonto`, Build-Dir `build/web/`). In `config/domains.php` existieren beide Einträge (`portal` und `pressekonto`) für dieselbe `domain_name`. Der `ThemeServiceProvider` matcht zuerst `portal` (Backend-Standard); für die öffentliche Landing schaltet **`routes/web.php` per `$applyWebDomainConfig('pressekonto')` explizit auf das Hub-Theme** um. Auth- und Admin-Routen bleiben unbeeinflusst. ### 3.1 Generischer Daten-Provider @@ -138,7 +138,7 @@ Damit das Theme für Presseecho dokumentiert ist, hier der **verbindliche Token- | Erste Variante | `#1f4d3a → #163a2c` | **zu hell** | | **Final** | **`#1a3d2e → #122d22`** | **abgenommen** ✅ | -### 3.1.2 presseportale-Hub-Palette (Stand 13.05.2026) +### 3.1.2 pressekonto-Hub-Palette (Stand 13.05.2026) Der **Hub** ist bewusst eigenständig positioniert: er ist **kein Editorial-Feed**, sondern eine reine Publisher-Landing („Ein Konto – zwei Reichweiten"). Er bekommt daher einen ganz eigenen Charakter: @@ -147,7 +147,7 @@ Der **Hub** ist bewusst eigenständig positioniert: er ist **kein Editorial-Feed * **Akzent:** gedecktes Bernstein `#B07A3A` – **bewusst gewählt**, weil weder Orange (BP24) noch Grün (Presseecho). Der Hub steht visuell „zwischen" den beiden Brands. * **Schrift:** Inter Tight (Standardtext) + JetBrains Mono (Mono) + Source Serif 4 (**nur für Marken-Mentions** der Tochter-Portale, damit typografische Konsistenz zur jeweiligen Brand-Landing erhalten bleibt; im Hub-Fließtext nicht verwendet). -Token-Snapshot aus `resources/css/web/theme-presseportale.css`: +Token-Snapshot aus `resources/css/web/theme-pressekonto.css`: ```css @theme { @@ -225,12 +225,12 @@ In `config/domains.php` liegt pro Domain ein **`brand`-Block**, der Komponenten ... ], ], -'presseportale' => [ // Hub-Variante (web) - 'theme' => 'presseportale', +'pressekonto' => [ // Hub-Variante (web) + 'theme' => 'pressekonto', 'brand' => [ 'name' => 'presse', // hub-blau - 'accent' => 'portale', // bernstein - 'footer_legal' => '© :year presseportale · Alle Rechte vorbehalten', + 'accent' => 'konto', // bernstein + 'footer_legal' => '© :year pressekonto · Alle Rechte vorbehalten', ... ], ], @@ -246,12 +246,12 @@ Die Schreibweise der drei Marken folgt einer einheitlichen Regel: **keine TLD-En | ------------------ | ------------------------------------------ | ---------------------- | --------------------- | | `presseecho` | **presse**·*echo* | `#345636` (Forest) | `#9BD5B2` | | `businessportal24` | **businessportal**·*24* | `#C84A1E` (Orange) | `#F4B098` | -| `presseportale` | **presse**·*portale* | `#B07A3A` (Bernstein) | `#B07A3A` | +| `pressekonto` | **presse**·*konto* | `#B07A3A` (Bernstein) | `#B07A3A` | **Single Source of Truth:** Die Komponente `` rendert die Markenschreibung zentral inkl. Span-Splitting, Schriftart und Akzent­farbe. Sie wird überall verwendet, wo eine Marke als Fließtext-Mention erscheint: * Hub-Komponenten (`hub/top-utility-bar`, `hub/site-header`, `hub/site-footer`, `hub/brand-context-banner`) -* Hub-View `presseportale.blade.php` (Hero-Headline, Architektur-Diagramm, Tarif-Subline, Plattform-Familie, FAQ) +* Hub-View `pressekonto.blade.php` (Hero-Headline, Architektur-Diagramm, Tarif-Subline, Plattform-Familie, FAQ) * Cross-Brand-Mentions auf BP24-/Presseecho-Landings, falls ergänzt ```blade @@ -417,22 +417,22 @@ Alle Komponenten haben **konsistente Konventionen**: ### 5.4 Hub-Komponenten (`components/web/hub/`) -Der Hub `presseportale.com` hat einen **eigenen, deutlich anderen Charakter** als die beiden Brand-Portale (kein Editorial-Feed, sondern Publisher-Landing) und bekommt daher einen eigenen Komponenten-Namespace. Die Sektionen selbst (Hero, Features, How-it-works, Tarife, Plattform-Familie, Social-Proof, FAQ, CTA) sind als **inline-Markup** in `resources/views/web/presseportale.blade.php` umgesetzt, weil sie page-spezifisch sind. +Der Hub `pressekonto.de` hat einen **eigenen, deutlich anderen Charakter** als die beiden Brand-Portale (kein Editorial-Feed, sondern Publisher-Landing) und bekommt daher einen eigenen Komponenten-Namespace. Die Sektionen selbst (Hero, Features, How-it-works, Tarife, Plattform-Familie, Social-Proof, FAQ, CTA) sind als **inline-Markup** in `resources/views/web/pressekonto.blade.php` umgesetzt, weil sie page-spezifisch sind. | Datei | Rolle | | --- | --- | | `hub/top-utility-bar.blade.php` | Schmale Hub-Blau-Topbar mit Datum, „Publisher-Hub für …"-Brand-Family-Links (rendert ``), Status/Doku/Kontakt. Props: `date`, `siblingPortals` (jetzt Liste mit `brand`-Key statt fixer Strings). | -| `hub/site-header.blade.php` | Wortmark `presse`·`portale` (über ``) + Untertitel „Publisher · Hub", zentrale Primary-Nav (Tarife, So funktioniert es, …), Anmelden + Konto erstellen CTAs. Routes: `login`, `register`. | +| `hub/site-header.blade.php` | Wortmark `presse`·`konto` (über ``) + Untertitel „Publisher · Hub", zentrale Primary-Nav (Tarife, So funktioniert es, …), Anmelden + Konto erstellen CTAs. Routes: `login`, `register`. | | `hub/brand-context-banner.blade.php` | **Conditional Banner** unter dem Header – greift nur bei `?from=presseecho` oder `?from=businessportal24` und zeigt: „Sie kommen von … – Ihr Konto hier funktioniert für beide Portale". Markenname über Brand-Mark (font-serif), „Zurück zu …"-Link nutzt sans-Variante. | | `hub/site-footer.blade.php` | 4-Spaltiger Hub-Footer (Konto / Plattform / Rechtliches + Brand-Spalte mit Plattform-Familie-Links über Brand-Mark `variant="on-dark"`), Hub-Gradient `linear-gradient(180deg,#1A2540,#0F1729)`. Brand-Block aus `config/domains.php`. | -**Hub-Sektionen als inline-Blade** (in `presseportale.blade.php`): +**Hub-Sektionen als inline-Blade** (in `pressekonto.blade.php`): 1. **Hero** mit Architektur-Diagramm rechts (zentraler Hub-Knoten + Brand-Portal-Karten + Output-Boxen, alles SVG-only). 2. **Was Sie hier können** – 3-Karten-Grid (Veröffentlichen / Newsrooms / Reichweite). 3. **So funktioniert es** – 4-Step-Ol mit Differenzierungs-Highlight in Schritt 3 (Bernstein-Akzent für „Unsere Qualitätssicherung"). 4. **Tarife** – 3 Karten (Starter / Standard / Pro mit `.ribbon-recommend`) + breiter Enterprise-Streifen in Hub-Blau. -5. **Hinter presseportale.com** – 2-Spalten-Plattform-Familie mit den **Original-Brand-Gradients** der Tochter-Portale (`#1F4D3A→#163A2C` für Presseecho, `#1A1F26→#232A33` für BP24). +5. **Hinter pressekonto.de** – 2-Spalten-Plattform-Familie mit den **Original-Brand-Gradients** der Tochter-Portale (`#1F4D3A→#163A2C` für Presseecho, `#1A1F26→#232A33` für BP24). 6. **Aktive Newsrooms** – Prose-Auflistung statt Logo-Wall + kompakte Stats-Sidebar. 7. **FAQ** – CSS-only-Accordion (`
` + `.faq-chev`) mit 8 Fragen, eine offen by default. 8. **CTA-Wiederholung** + Footer. @@ -496,12 +496,12 @@ Drei spiegelbildliche Test-Szenarien: 2. **`feed only shows published presseecho content`** – Portal-Trennung gespiegelt: Presseecho + Both sichtbar, BP24-Only und Drafts nicht. 3. **`shows most read releases in the sidebar`** – Hits-Sortierung. -### Datei: `tests/Feature/Web/PresseportaleHubHomeTest.php` +### Datei: `tests/Feature/Web/PressekontoHubHomeTest.php` Fünf Test-Szenarien rund um die Hub-Landing: -1. **`renders the publisher landing shell`** – prüft alle Hauptsektionen sind sichtbar (Publisher-Hub, Was Sie hier können, So funktioniert es, Vier Schritte, Tarife, Starter, Standard, Pro, Enterprise, Hinter presseportale.com, Plattform im Überblick, Häufige Fragen, Loslegen, Alle Systeme betriebsbereit). -2. **`loads the hub theme assets, not portal admin`** – stellt sicher, dass `theme-presseportale` aus dem Manifest geladen wird (nicht `theme-businessportal24` oder `theme-presseecho`). +1. **`renders the publisher landing shell`** – prüft alle Hauptsektionen sind sichtbar (Publisher-Hub, Was Sie hier können, So funktioniert es, Vier Schritte, Tarife, Starter, Standard, Pro, Enterprise, Hinter pressekonto.de, Plattform im Überblick, Häufige Fragen, Loslegen, Alle Systeme betriebsbereit). +2. **`loads the hub theme assets, not portal admin`** – stellt sicher, dass `theme-pressekonto` aus dem Manifest geladen wird (nicht `theme-businessportal24` oder `theme-presseecho`). 3. **`hides the brand-context banner without a from parameter`** – Default-Aufruf zeigt keinen „Sie kommen von …"-Banner. 4. **`shows the brand-context banner when arriving from presseecho`** – `?from=presseecho` triggert den Banner inkl. Link „Zurück zu presseecho.de". 5. **`shows the brand-context banner when arriving from businessportal24`** – `?from=businessportal24` triggert den Banner für BP24. @@ -563,9 +563,9 @@ vendor/bin/pint --dirty --format agent | 13 | 12.05.2026 | Brand-Konfiguration in `config/domains.php` pro Domain (`brand.name`, `brand.accent`, `brand.tagline_*`, `brand.newsletter_topics`, `brand.footer_legal`, `brand.about_label`) – `site-header`, `site-footer`, `newsletter-strip` lesen daraus | ✅ | | 14 | 12.05.2026 | `press-release-feed`-Volt-Component portal-agnostisch (Prop `:portal`); Aufruf vom View-Layer aus | ✅ | | 15 | 12.05.2026 | `PresseechoHomeTest` analog zu `Businessportal24HomeTest` (3 Szenarien, RefreshDatabase) | ✅ | -| 16 | 13.05.2026 | **presseportale-Hub-Landing live**: neues Web-Theme `presseportale` (Hub-Blau + Bernstein, `theme-presseportale.css`), eigener Komponenten-Namespace `components/web/hub/` (Top-Bar, Site-Header, Brand-Context-Banner, Site-Footer), Hub-View `web/presseportale.blade.php` mit Hero/Architektur-Diagramm, Features, How-it-works, Tarife (Starter/Standard/Pro+Ribbon, Enterprise-Streifen), Plattform-Familie, Aktive-Newsrooms, FAQ-Accordion, CTA. `routes/web.php` schaltet für `presseportale.test` auf das Hub-Theme um. Root-Route in `routes/admin.php` entfernt (Layout referenziert jetzt `route('dashboard')`). | ✅ | -| 17 | 13.05.2026 | `PresseportaleHubHomeTest` (5 Szenarien inkl. Brand-Context-Banner-Conditional). Vite-Config + ThemeHelper + `web-master`-Fonts (Inter Tight + JetBrains Mono ohne Serif) für `presseportale` ergänzt. | ✅ | -| 18 | 13.05.2026 | **Brand-Mark-Konvention etabliert** (Feintuning Marken-Schreibweise): keine TLD am Marken­schriftzug, Akzent farblich vom Basis-Wort abgesetzt. Single Source of Truth `` (Marken-Tabelle inkl. Standard- und On-Dark-Akzentfarben, Serif/Sans-Switch). `config/domains.php` umgestellt (`presseecho`: `name=presse`/`accent=echo`; `presseportale`: `name=presse`/`accent=portale`; Footer-Legal & Meta-Texte ohne TLD). Hub-Komponenten und Hub-View durchgehend auf Brand-Mark migriert (Top-Utility-Bar, Site-Header, Brand-Context-Banner, Site-Footer, Hero-Headline, Architektur-Diagramm, Tarif-Subline, Plattform-Familie, FAQ). Hub-Theme bekommt Source Serif 4 als `--font-serif` (für Marken-Mentions) – Bunny-Font-Loader erweitert. **+1 neuer Test `uses the brand-mark splitting without TLDs`**; alle 12 Web-Tests grün. | ✅ | +| 16 | 13.05.2026 | **pressekonto-Hub-Landing live**: neues Web-Theme `pressekonto` (Hub-Blau + Bernstein, `theme-pressekonto.css`), eigener Komponenten-Namespace `components/web/hub/` (Top-Bar, Site-Header, Brand-Context-Banner, Site-Footer), Hub-View `web/pressekonto.blade.php` mit Hero/Architektur-Diagramm, Features, How-it-works, Tarife (Starter/Standard/Pro+Ribbon, Enterprise-Streifen), Plattform-Familie, Aktive-Newsrooms, FAQ-Accordion, CTA. `routes/web.php` schaltet für `pressekonto.test` auf das Hub-Theme um. Root-Route in `routes/admin.php` entfernt (Layout referenziert jetzt `route('dashboard')`). | ✅ | +| 17 | 13.05.2026 | `PressekontoHubHomeTest` (5 Szenarien inkl. Brand-Context-Banner-Conditional). Vite-Config + ThemeHelper + `web-master`-Fonts (Inter Tight + JetBrains Mono ohne Serif) für `pressekonto` ergänzt. | ✅ | +| 18 | 13.05.2026 | **Brand-Mark-Konvention etabliert** (Feintuning Marken-Schreibweise): keine TLD am Marken­schriftzug, Akzent farblich vom Basis-Wort abgesetzt. Single Source of Truth `` (Marken-Tabelle inkl. Standard- und On-Dark-Akzentfarben, Serif/Sans-Switch). `config/domains.php` umgestellt (`presseecho`: `name=presse`/`accent=echo`; `pressekonto`: `name=presse`/`accent=konto`; Footer-Legal & Meta-Texte ohne TLD). Hub-Komponenten und Hub-View durchgehend auf Brand-Mark migriert (Top-Utility-Bar, Site-Header, Brand-Context-Banner, Site-Footer, Hero-Headline, Architektur-Diagramm, Tarif-Subline, Plattform-Familie, FAQ). Hub-Theme bekommt Source Serif 4 als `--font-serif` (für Marken-Mentions) – Bunny-Font-Loader erweitert. **+1 neuer Test `uses the brand-mark splitting without TLDs`**; alle 12 Web-Tests grün. | ✅ | | 19 | 12.05.2026 | **Aktuell offen:** Detailseite, Branchenseite, Veröffentlichen-Landing für BP24 + Presseecho. Hub-Folgeseiten (Konto-Erstellen-Flow als Landing, Tarif-Detail, Doku-Hub) ebenfalls offen. | 🟡 | --- diff --git a/dev/frontend/Ver_ffentlichen _ Variante A _aktiv_.html b/dev/frontend/Ver_ffentlichen _ Variante A _aktiv_.html index 0086b59..5e2e4f1 100644 --- a/dev/frontend/Ver_ffentlichen _ Variante A _aktiv_.html +++ b/dev/frontend/Ver_ffentlichen _ Variante A _aktiv_.html @@ -509,4 +509,4 @@ font-display: swap; src: url("data:font/woff2;base64,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") format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; -}
Mittwoch, 6. Mai 2026·DAX18.247+0,8%EUR/USD1,0842−0,2%
businessportal24
Pressemitteilungen · DACH
Pressemitteilungen, Unternehmen, Branchen, ISIN…
businessportal24Veröffentlichen
Redaktionell geprüft seit 2012·Hilfe & SupportMediadaten
Pressestelle · Veröffentlichen

Pressemitteilung veröffentlichen.
Geprüft.
Dauerhaft auffindbar.

businessportal24 ist die Presseplattform für mittelständische Unternehmen, Selbstständige und PR-Agenturen aus Deutschland, Österreich und der Schweiz. Jede Mitteilung wird auf Qualität geprüft und bleibt dauerhaft im Archiv auffindbar.

Einreichen im Publisher-Bereich

Die Einreichung läuft über presseportale.com.

Dort verwalten Sie Mitteilungen, Credits und Newsroom — einmaliges Konto, beide Portale nutzbar (businessportal24 & presseecho.de).

Login per Magic-Link · ohne Vertragsbindung

Seit
2012
im Betrieb · über ein Jahrzehnt durchgehende Archivierung
Archiv
100.000+
Mitteilungen weiterhin abrufbar — auch ältere Jahrgänge
Reichweite
DACH
Deutschland, Österreich, Schweiz · vier Sprach-Ausgaben
Heute
12 / 4
veröffentlicht / in redaktioneller Prüfung — Stand 14:42 Uhr
Aktive Newsrooms heute

Siemens AG · BASF SE · Deutsche Telekom · Volkswagen AG · Allianz SE · Deutsche Bank · RWE · OMV · Voestalpine · Roche — und 187 weitere veröffentlichende Unternehmen im laufenden Monat.

Alle Newsrooms →
§ 01
Was uns ausmacht

Vier Prinzipien, die diese Plattform tragen

Qualität

Geprüfte Mitteilungen

Jede Mitteilung durchläuft eine Qualitätsprüfung, bevor sie online geht. Keine SEO-Spam-Texte, keine reinen Werbeanzeigen.

Auffindbarkeit

Dauerhaft im Archiv

Pressemitteilungen bleiben im Archiv – auch nach Jahren. Über 100.000 Mitteilungen aus mehr als einem Jahrzehnt sind weiterhin abrufbar.

Konditionen

Faire Preise, keine Bindung

Transparente Preise, kein Abo-Zwang, keine Vertragsfallen. Sie zahlen, was Sie einreichen.

Umgang mit Fehlern

Korrektur statt Löschung

Fehler in einer Mitteilung? Wir korrigieren statt zu löschen – damit Verweise und Verlinkungen bestehen bleiben.

§ 02
Ablauf

So funktioniert's — drei Schritte

Keine Magic-Sprache. Was hier passiert, passiert sichtbar.
01≈ 2 Minuten

Konto anlegen

Mit E-Mail-Adresse. Kein Passwort nötig — Login per Magic-Link. Konto und Abrechnung liegen im zentralen Publisher-Bereich.

02üblich werktags · innerhalb 24 h

Mitteilung einreichen

Text, Bild, Ansprechpartner. Eine automatische Qualitätsprüfung läuft parallel zu einer kurzen redaktionellen Sichtung.

03permanent · indexiert

Veröffentlichung

Nach Freigabe online und im Archiv. Bei Bedarf jederzeit korrigierbar — die URL bleibt stabil, Verweise und Verlinkungen bestehen weiter.

Die Veröffentlichung erfolgt über den zentralen Publisher-Bereich auf presseportale.com. Cross-Publishing nach presseecho.de ist optional verfügbar.

§ 03
Für wen

Typische Anlässe einer Veröffentlichung

Anhaltspunkt für die Eignung. Eine Aufzählung, keine Liste der Möglichkeiten.
  1. 01
    Neue Produkte oder Dienstleistungen
    Markteinführungen, Produktupdates, neue Services.
  2. 02
    Personalien und Geschäftsleitungs-Wechsel
    Berufungen, Bestellungen, Verabschiedungen.
  3. 03
    Auszeichnungen und Zertifizierungen
    Awards, ISO- und Branchen-Zertifikate, Audits.
  4. 04
    Standort-Eröffnungen, Expansionen, Aufträge
    Werke, Niederlassungen, Großaufträge, Investitionen.
  5. 05
    Veranstaltungs-Ankündigungen
    Tage der offenen Tür, Fachtage, Hauptversammlungen.
  6. 06
    Studien und Marktanalysen
    Eigene Erhebungen, Trendberichte, Branchenkennzahlen.
§ 04
Preise

Sie zahlen, was Sie einreichen.

Logik

Sie kaufen Credits, die für Veröffentlichungen eingesetzt werden. Keine Mindestlaufzeit, keine versteckten Gebühren.

  • Credits verfallen nicht.
  • Korrekturen sind kostenfrei.
  • Mengenrabatte ab dem zweiten Paket.
Anker
Eine Veröffentlichung
ab 89 €
netto · zzgl. USt. · Mengenrabatte verfügbar.
Beispiel-Pakete: 5er ab 79 € / Mitteilung · 25er ab 64 € / Mitteilung.
Vollständige Übersicht

Pakete, Cross-Publishing nach presseecho.de, Agentur-Konditionen und Rechnungseinstellungen finden Sie im zentralen Publisher-Bereich.

Preisübersicht im Publisher-Bereich
§ 05
Häufige Fragen

Kurz beantwortet

Eine ausführliche Wissensdatenbank liegt im Publisher-Bereich.

Sie finden hier keine Antwort?

Redaktion direkt anschreiben
redaktion@businessportal24.com
Mo–Fr · 09:00–17:00 Uhr (MEZ)
Werktags üblicherweise innerhalb von 24 Stunden nach Einreichung. Bei zeitkritischen Mitteilungen ist eine vorab-Absprache möglich.
Mitteilung einreichen · Schritt eins

Bereit, Ihre Mitteilung einzureichen?

Konto in zwei Minuten anlegen, Text und Bild einreichen, nach redaktioneller Sichtung veröffentlicht. Einmaliges Konto — beide Portale (businessportal24 & presseecho.de) nutzbar.

Einreichung läuft über presseportale.com · Login per Magic-LinkOder zuerst Beispiele ansehen →
\ No newline at end of file +}
Mittwoch, 6. Mai 2026·DAX18.247+0,8%EUR/USD1,0842−0,2%
businessportal24
Pressemitteilungen · DACH
Pressemitteilungen, Unternehmen, Branchen, ISIN…
businessportal24Veröffentlichen
Redaktionell geprüft seit 2012·Hilfe & SupportMediadaten
Pressestelle · Veröffentlichen

Pressemitteilung veröffentlichen.
Geprüft.
Dauerhaft auffindbar.

businessportal24 ist die Presseplattform für mittelständische Unternehmen, Selbstständige und PR-Agenturen aus Deutschland, Österreich und der Schweiz. Jede Mitteilung wird auf Qualität geprüft und bleibt dauerhaft im Archiv auffindbar.

Einreichen im Publisher-Bereich

Die Einreichung läuft über pressekonto.de.

Dort verwalten Sie Mitteilungen, Credits und Newsroom — einmaliges Konto, beide Portale nutzbar (businessportal24 & presseecho.de).

Login per Magic-Link · ohne Vertragsbindung

Seit
2012
im Betrieb · über ein Jahrzehnt durchgehende Archivierung
Archiv
100.000+
Mitteilungen weiterhin abrufbar — auch ältere Jahrgänge
Reichweite
DACH
Deutschland, Österreich, Schweiz · vier Sprach-Ausgaben
Heute
12 / 4
veröffentlicht / in redaktioneller Prüfung — Stand 14:42 Uhr
Aktive Newsrooms heute

Siemens AG · BASF SE · Deutsche Telekom · Volkswagen AG · Allianz SE · Deutsche Bank · RWE · OMV · Voestalpine · Roche — und 187 weitere veröffentlichende Unternehmen im laufenden Monat.

Alle Newsrooms →
§ 01
Was uns ausmacht

Vier Prinzipien, die diese Plattform tragen

Qualität

Geprüfte Mitteilungen

Jede Mitteilung durchläuft eine Qualitätsprüfung, bevor sie online geht. Keine SEO-Spam-Texte, keine reinen Werbeanzeigen.

Auffindbarkeit

Dauerhaft im Archiv

Pressemitteilungen bleiben im Archiv – auch nach Jahren. Über 100.000 Mitteilungen aus mehr als einem Jahrzehnt sind weiterhin abrufbar.

Konditionen

Faire Preise, keine Bindung

Transparente Preise, kein Abo-Zwang, keine Vertragsfallen. Sie zahlen, was Sie einreichen.

Umgang mit Fehlern

Korrektur statt Löschung

Fehler in einer Mitteilung? Wir korrigieren statt zu löschen – damit Verweise und Verlinkungen bestehen bleiben.

§ 02
Ablauf

So funktioniert's — drei Schritte

Keine Magic-Sprache. Was hier passiert, passiert sichtbar.
01≈ 2 Minuten

Konto anlegen

Mit E-Mail-Adresse. Kein Passwort nötig — Login per Magic-Link. Konto und Abrechnung liegen im zentralen Publisher-Bereich.

02üblich werktags · innerhalb 24 h

Mitteilung einreichen

Text, Bild, Ansprechpartner. Eine automatische Qualitätsprüfung läuft parallel zu einer kurzen redaktionellen Sichtung.

03permanent · indexiert

Veröffentlichung

Nach Freigabe online und im Archiv. Bei Bedarf jederzeit korrigierbar — die URL bleibt stabil, Verweise und Verlinkungen bestehen weiter.

Die Veröffentlichung erfolgt über den zentralen Publisher-Bereich auf pressekonto.de. Cross-Publishing nach presseecho.de ist optional verfügbar.

§ 03
Für wen

Typische Anlässe einer Veröffentlichung

Anhaltspunkt für die Eignung. Eine Aufzählung, keine Liste der Möglichkeiten.
  1. 01
    Neue Produkte oder Dienstleistungen
    Markteinführungen, Produktupdates, neue Services.
  2. 02
    Personalien und Geschäftsleitungs-Wechsel
    Berufungen, Bestellungen, Verabschiedungen.
  3. 03
    Auszeichnungen und Zertifizierungen
    Awards, ISO- und Branchen-Zertifikate, Audits.
  4. 04
    Standort-Eröffnungen, Expansionen, Aufträge
    Werke, Niederlassungen, Großaufträge, Investitionen.
  5. 05
    Veranstaltungs-Ankündigungen
    Tage der offenen Tür, Fachtage, Hauptversammlungen.
  6. 06
    Studien und Marktanalysen
    Eigene Erhebungen, Trendberichte, Branchenkennzahlen.
§ 04
Preise

Sie zahlen, was Sie einreichen.

Logik

Sie kaufen Credits, die für Veröffentlichungen eingesetzt werden. Keine Mindestlaufzeit, keine versteckten Gebühren.

  • Credits verfallen nicht.
  • Korrekturen sind kostenfrei.
  • Mengenrabatte ab dem zweiten Paket.
Anker
Eine Veröffentlichung
ab 89 €
netto · zzgl. USt. · Mengenrabatte verfügbar.
Beispiel-Pakete: 5er ab 79 € / Mitteilung · 25er ab 64 € / Mitteilung.
Vollständige Übersicht

Pakete, Cross-Publishing nach presseecho.de, Agentur-Konditionen und Rechnungseinstellungen finden Sie im zentralen Publisher-Bereich.

Preisübersicht im Publisher-Bereich
§ 05
Häufige Fragen

Kurz beantwortet

Eine ausführliche Wissensdatenbank liegt im Publisher-Bereich.

Sie finden hier keine Antwort?

Redaktion direkt anschreiben
redaktion@businessportal24.com
Mo–Fr · 09:00–17:00 Uhr (MEZ)
Werktags üblicherweise innerhalb von 24 Stunden nach Einreichung. Bei zeitkritischen Mitteilungen ist eine vorab-Absprache möglich.
Mitteilung einreichen · Schritt eins

Bereit, Ihre Mitteilung einzureichen?

Konto in zwei Minuten anlegen, Text und Bild einreichen, nach redaktioneller Sichtung veröffentlicht. Einmaliges Konto — beide Portale (businessportal24 & presseecho.de) nutzbar.

Einreichung läuft über pressekonto.de · Login per Magic-LinkOder zuerst Beispiele ansehen →
\ No newline at end of file diff --git a/dev/frontend/hub-flux/01-PHASE-0-TOKENS.md b/dev/frontend/hub-flux/01-PHASE-0-TOKENS.md new file mode 100644 index 0000000..3ed966f --- /dev/null +++ b/dev/frontend/hub-flux/01-PHASE-0-TOKENS.md @@ -0,0 +1,216 @@ +# Phase 0 — Design-Tokens vereinheitlichen + +> **Ziel**: Single Source of Truth für alle Design-Tokens (Farben, Fonts, +> Radii, Schatten). Sowohl Hub-Build als auch Portal-Build beziehen ihre +> Werte aus derselben Datei. **Visuell ändert sich noch nichts.** + +**Status**: ✅ abgeschlossen am 2026-05-19 +**Risiko**: sehr niedrig +**Aufwand (tatsächlich)**: ~½ Tag + +## Ergebnis-Check (2026-05-19) + +- Single Source of Truth liegt in `resources/css/shared/design-tokens.css`. +- Web-Build und Portal-Build importieren sie beide. +- **Visuelle Unverändertheit verifiziert**: + - Hub (`pressekonto.test/`, `/login`, `/register`) — unverändert. + - Portal (`/dashboard`) — FluxUI-Defaults bleiben dominant + (`--font-sans: "Instrument Sans"`, Zinc-Palette, `#3ea3dc`-Akzent). +- Build-Sizes: + - `theme-pressekonto: 193 kB` (vorher 189 kB · +4 kB für neue Tokens) + - `theme-presseecho`, `theme-businessportal24`: praktisch unverändert + - `portal: 408 kB` (vorher 397 kB · +12 kB für zusätzlich bereitgestellte Token-Vars im `:root`) +- Details: `PROGRESS.md` (Eintrag vom 2026-05-19). + +## Warum + +Heute leben Tokens an zwei Orten: + +- `resources/css/web/theme-pressekonto.css` — Hub-Tokens (Hub-Blau, + Bernstein, Buchpapier, Inter Tight) +- `resources/css/portal.css` — Portal-Tokens (Zinc, `#3ea3dc`, Instrument + Sans) + +Solange diese parallel gepflegt werden, **driften** sie auseinander. Wir +ziehen die gemeinsame Wahrheit in eine eigene Datei und referenzieren +sie aus beiden Welten. + +## Liefergegenstand + +``` +resources/css/shared/ +└── design-tokens.css ← NEU +``` + +Inhalt: alle `--color-*`, `--font-*`, `--radius-*`, `--shadow-*` Tokens, +die in Hub und Portal gleichermaßen gelten. Strukturiert als +`@theme`-Block, sodass Tailwind v4 die Variablen sowohl als +CSS-Custom-Properties als auch als Tailwind-Utility-Klassen erkennt. + +## Schritte + +### 1. Token-Inventur aus `theme-pressekonto.css` + +Die folgenden Tokens werden aus `theme-pressekonto.css` extrahiert und +nach `shared/design-tokens.css` verschoben: + +#### Surfaces +- `--color-bg`, `--color-bg-elev`, `--color-bg-rule`, `--color-bg-rule-strong` +- `--color-bg-dark`, `--color-bg-card`, `--color-bg-card-warm`, + `--color-bg-card-warm-border`, `--color-bg-card-warm-hover`, + `--color-bg-card-warm-rule` + +#### Hub-Palette +- `--color-hub`, `--color-hub-2`, `--color-hub-3` +- `--color-hub-soft`, `--color-hub-soft-2`, `--color-hub-line` +- `--color-topbar`, `--color-topbar2`, `--color-topbar-deep` + +#### Akzent (Bernstein) +- `--color-accent`, `--color-accent-deep`, `--color-accent-soft`, + `--color-accent-warm` + +#### Ink (Anthrazit) +- `--color-ink`, `--color-ink-2`, `--color-ink-3`, `--color-ink-4` +- `--color-ink-on-dark`, `--color-ink-on-dark-2`, `--color-ink-on-dark-3`, + `--color-ink-on-dark-muted`, `--color-ink-on-dark-rule` + +#### Brand-Aliase + Status +- `--color-brand`, `--color-brand-deep`, `--color-brand-soft` +- `--color-live`, `--color-gain`, `--color-loss`, `--color-ok` + +#### Editorial / Cards +- `--color-card-warm-cat`, `--color-card-warm-title`, + `--color-feature-line`, `--color-feature-dot` + +#### Status (für KPI-Cards / Badges — laut Mockup ergänzen) +- `--color-warn` `#A87A1F`, `--color-warn-soft` `#F6EAC8` +- `--color-err` `#A8331F`, `--color-err-soft` `#F4DAD2` +- `--color-ok-soft` `#E2F1E5` + +#### Fonts +- `--font-sans` (Inter Tight) +- `--font-serif` (Source Serif 4 — nur für Brand-Mark) +- `--font-mono` (JetBrains Mono) + +#### Layout +- `--container-layout: 1280px` + +#### Radii (laut Mockup) +- `--radius-xs: 3px`, `--radius-sm: 4px`, `--radius-md: 6px`, + `--radius-lg: 8px` + +#### Schatten (laut Mockup + Hub-Login) +- `--shadow-soft`: leicht warm, für Cards +- `--shadow-card`: Standard-Card-Schatten +- `--shadow-card-hover`: Hover-Stufe +- `--shadow-auth`: weiche Glocke unter Auth-Card + +### 2. Datei `resources/css/shared/design-tokens.css` anlegen + +Aufbau: + +```css +/** + * Hub × FluxUI — Gemeinsame Design-Tokens + * + * Single Source of Truth für Hub-Frontend (build/web) und Portal-Backend + * (build/portal). Beide CSS-Builds @import diese Datei. + * + * Token-Names sind STABIL — Werte können sich ändern (z.B. Dark Mode in + * Phase 5), Namen nicht. + */ + +@theme { + /* Surfaces */ + --color-bg: #f6f4ef; + --color-bg-elev: #fbfaf6; + /* … alle Tokens aus der Inventur … */ +} + +/* Dark Mode (vorbereitet, in Phase 5 finalisiert) */ +@media (prefers-color-scheme: dark) { + @theme { + /* Spätere Dark-Werte */ + } +} +``` + +### 3. `theme-pressekonto.css` refactoren + +Die `@theme {}`-Definitionen werden durch einen +`@import "../shared/design-tokens.css";` ersetzt. Nur die `@layer +components {}`-Klassen (`.eyebrow`, `.auth-card`, `.field-input`, etc.) +bleiben in `theme-pressekonto.css`. + +`:root { … --background, --primary … }`-HSL-Variablen für Legacy-Komponenten +bleiben ebenfalls hier (sind Portal-unspezifisch). + +### 4. `portal.css` minimal vorbereiten (noch keine Werte übernehmen) + +In Phase 0 importieren wir die Token-Datei in `portal.css`, **aber lassen +das alte `@theme`-Setup mit Zinc/Accent zunächst stehen**. Damit: + +- Beide Welten greifen technisch auf die gleiche Datei zu +- Aber Portal bleibt visuell unverändert (Zinc-Palette gewinnt durch + Reihenfolge im `@theme`) + +In Phase 1 wird das Zinc-Setup dann **gezielt durch Hub-Werte ersetzt**. + +### 5. Build & Verifikation + +```bash +npm run build:web # → erzeugt theme-pressekonto.css ohne Drift +npm run build:portal # → erzeugt portal.css unverändert +``` + +Erwartung: +- Hub-Landing rendert visuell **identisch** wie vorher +- Hub-Auth-Pages rendern visuell **identisch** wie vorher +- Portal rendert visuell **identisch** wie vorher + +Smoke-Test (kein neues Test-Schreiben nötig): + +```bash +php artisan tinker --execute ' +$urls = [ + "https://pressekonto.test/", + "https://pressekonto.test/login", + "https://pressekonto.test/dashboard", +]; +foreach ($urls as $u) { + echo $u . " => " . + app(\Illuminate\Contracts\Http\Kernel::class) + ->handle(\Illuminate\Http\Request::create($u, "GET")) + ->getStatusCode() . "\n"; +}' +``` + +Alle 3 URLs müssen weiterhin `200` liefern (für `/dashboard` ggf. +`302`-Redirect, je nach Auth-Status — beides ist okay, solange kein `500`). + +## Akzeptanzkriterien + +- [ ] `resources/css/shared/design-tokens.css` existiert mit allen Hub-Tokens +- [ ] `theme-pressekonto.css` importiert die Token-Datei und enthält + keine doppelten `--color-*`-Definitionen mehr +- [ ] `portal.css` importiert die Token-Datei (Werte werden in Phase 1 genutzt) +- [ ] `npm run build:web` und `npm run build:portal` laufen ohne Fehler durch +- [ ] Hub-Landing, Hub-Auth und Portal-Login visuell **unverändert** +- [ ] Pint passed (`vendor/bin/sail bin pint --dirty --format agent`) + +## Risiken & Fallstricke + +- **Tailwind v4 + `@theme`**: Mehrere `@theme {}`-Blöcke in importierten + Dateien werden zusammengeführt. Das funktioniert, solange die + Token-Namen eindeutig sind. +- **Reihenfolge der Imports**: Tokens müssen **vor** den + `@layer components {}`-Definitionen importiert werden, sonst + greifen die Variablen in den Komponenten nicht. +- **Portal-Tailwind-Config**: `tailwind.portal.config.js` darf die + Token-Datei nicht ausschließen. `@source`-Direktiven prüfen. + +## Was Phase 0 NICHT macht + +- Portal sieht **noch nicht** wie der Hub aus — das ist Phase 1 +- Keine Änderung am Sidebar-Layout, am Logo oder am Dashboard +- Keine Dark-Mode-Aktivierung (nur vorbereitet) diff --git a/dev/frontend/hub-flux/02-PHASE-1-PORTAL-SHELL.md b/dev/frontend/hub-flux/02-PHASE-1-PORTAL-SHELL.md new file mode 100644 index 0000000..6dc0c71 --- /dev/null +++ b/dev/frontend/hub-flux/02-PHASE-1-PORTAL-SHELL.md @@ -0,0 +1,290 @@ +# Phase 1 — Portal-Shell ans Hub-Design angleichen + +> **Ziel**: Sidebar, Topbar und Layout-Container des Portals sehen aus +> wie das Mockup `User Dashboard presseportale.html`. Inhalt der +> einzelnen Pages bleibt unverändert — wir tauschen nur die Shell. + +**Status**: ✅ abgeschlossen am 2026-05-19 +**Risiko (tatsächlich)**: niedrig — keine Test-Regressionen +**Aufwand (tatsächlich)**: ~½ Tag (kleiner als geschätzt, weil Topbar +auf Phase 2 verschoben wurde) + +## Ergebnis-Check (2026-05-19) + +**Umgesetzt**: +- `portal.css` mit Hub-Token-Bridge, Inter-Tight-Font, Zinc→Hub-Mapping, + FluxUI-Overrides für Sidebar / Navlist / Buttons / Cards. +- Sidebar mit Brand-Mark + Eyebrow „Publisher · Hub", neuem Hub-Stil- + Testmodus-Block, ohne Starter-Kit-Resources-Block. +- Customer-Banner (`app.blade.php`) im Hub-Soft-Look mit Hub-Pille. +- `class="dark"` aus Sidebar-Layout entfernt — Light Mode ist Default. +- Font-Wechsel auf Bunny: `inter-tight + jetbrains-mono + source-serif-4`. + +**Verschoben auf Phase 2**: +- Eigene Topbar mit Breadcrumb + Bridge-Row + Search + „Neue Mitteilung"-CTA + (lebt sinnvoller im Customer-Dashboard-Kontext). +- Konto-Switcher als Sidebar-Header oben (statt User-Menü unten). + +**Build-Sizes**: +- `portal.css: 409.03 kB` (vorher 408.89 kB · +0.14 kB · weit unter dem + 10 %-Limit aus den Akzeptanzkriterien). + +**Tests**: +- Auth-Test-Suite Vergleich (Stash vs Phase 1): `8 failed, 15 passed` + in beiden Ständen — 0 zusätzliche Regressionen durch Phase 1. +- Zwei Tests im Zuge des Login-Fixes angepasst (Admin-Rolle bzw. + `terms_accepted: true`), siehe `PROGRESS.md` Eintrag „Phase 1". + +**Details**: `PROGRESS.md` (Eintrag vom 2026-05-19, Abschnitt „Phase 1"). + +## Sichtbarer Mehrwert + +Nach Phase 1 sieht der eingeloggte User: +- Eine **warme Sidebar** im Hub-Stil mit Brand-Wortmarke statt + Starter-Kit-Logo +- Eine **schlanke Topbar** mit Breadcrumb, Bridge-Row, Search, Notification, + "Neue Mitteilung"-Button +- Den **Testmodus-Block** (Impersonation) als Hub-Karten-Element +- Den **Konto-Switcher** als oberen Sidebar-Header + +Innenleben (Tabellen, Formulare, Cards) bleiben FluxUI — wirken aber +durch Token-Anpassung **automatisch passender**. + +## Liefergegenstand + +### Geänderte Dateien + +| Datei | Änderung | +|-------|----------| +| `resources/css/portal.css` | Zinc → Hub-Palette, Font auf Inter Tight, `--color-accent` auf Hub-Blau, FluxUI-Overrides | +| `resources/views/components/layouts/app/sidebar.blade.php` | Brand-Mark statt App-Logo, Eyebrow „Publisher · Hub", Sidebar-Design am Mockup orientiert, Testmodus-Block neu | +| `resources/views/partials/head.blade.php` | Font-Wechsel (Bunny: inter-tight + jetbrains-mono statt instrument-sans) | +| `resources/views/components/layouts/app.blade.php` | Customer-Banner ggf. an neues Design anpassen | + +### Vermutlich gelöscht + +| Datei | Begründung | +|-------|------------| +| `resources/views/components/layouts/app/header.blade.php` | Wird laut Inventur nirgends referenziert | +| `resources/views/partials/admin-head.blade.php` | Legacy, im Code nicht eingebunden | +| `resources/views/components/app-logo.blade.php` | Wird durch `brand-mark` ersetzt | +| `resources/views/components/app-logo-icon.blade.php` | Wird durch `brand-mark` ersetzt | + +Vor Löschung: per `rg "x-app-logo"` und `rg "auth.split|auth.card"` +prüfen, dass nichts mehr referenziert wird. + +## Schritte + +### 1. `portal.css` — Token-Bridge zu FluxUI + +```css +@import "tailwindcss"; +@import "../../vendor/livewire/flux/dist/flux.css"; +@import "./shared/design-tokens.css"; /* aus Phase 0 */ + +@source '../views'; +@source '../../vendor/livewire/flux-pro/stubs/**/*.blade.php'; +@source '../../vendor/livewire/flux/stubs/**/*.blade.php'; + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + /* FluxUI-Akzent auf Hub-Blau */ + --color-accent: var(--color-hub); + --color-accent-content: var(--color-hub); + --color-accent-foreground: #ffffff; + + /* Zinc auf warmes Buchpapier mappen */ + --color-zinc-50: var(--color-bg-elev); /* #FBFAF6 */ + --color-zinc-100: var(--color-bg); /* #F6F4EF */ + --color-zinc-200: var(--color-bg-rule); /* #E2DDD0 */ + --color-zinc-300: #cfc8b5; + --color-zinc-400: var(--color-ink-4); /* #8A918D */ + --color-zinc-500: var(--color-ink-3); /* #5A6360 */ + --color-zinc-600: var(--color-ink-2); /* #3A413D */ + --color-zinc-700: var(--color-ink); /* #1A1F1C */ + --color-zinc-800: var(--color-hub-2); /* #243152 */ + --color-zinc-900: var(--color-hub); /* #1A2540 */ + --color-zinc-950: var(--color-topbar-deep); /* #0F1729 */ +} +``` + +#### FluxUI-spezifische Overrides + +```css +/* Navlist — Hub-Stil mit Active-Strip links */ +[data-flux-navlist-item][data-active="true"] { + background: var(--color-hub-soft); + color: var(--color-hub); + font-weight: 600; + position: relative; +} +[data-flux-navlist-item][data-active="true"]::before { + content: ""; + position: absolute; + left: 0; + top: 6px; + bottom: 6px; + width: 2px; + background: var(--color-hub); + border-radius: 0 2px 2px 0; +} + +/* Buttons — Hub-Primär */ +[data-flux-button][data-variant="primary"] { + background: var(--color-hub); + color: #ffffff; +} +[data-flux-button][data-variant="primary"]:hover { + background: var(--color-hub-2); +} + +/* Sidebar-Section-Headings */ +[data-flux-navlist] [data-flux-navlist-group-heading] { + font-size: 10px; + font-weight: 700; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--color-ink-4); +} + +/* Cards bekommen Hub-Buchpapier statt Zinc */ +[data-flux-card] { + background: var(--color-bg-card); + border-color: var(--color-bg-rule); +} +``` + +> **Hinweis**: Die exakten `[data-flux-*]`-Attribute werden beim Bauen +> per Dev-Tools verifiziert. Die hier gezeigten sind die wahrscheinlichsten +> laut FluxUI-Doku. + +### 2. `partials/head.blade.php` — Font wechseln + +```diff +- +``` + +### 3. Sidebar neu — `components/layouts/app/sidebar.blade.php` + +Aufbau **strikt am Mockup** orientiert (s. `dev/frontend/tailwind_v3/User Dashboard presseportale.html`): + +#### Sidebar-Aufbau (oben → unten) + +1. **Brand-Block** (`px-5 pt-6 pb-5`): + - `` (19 px, bold) + - Eyebrow „Publisher · Hub" darunter + - **Konto-Switcher-Button** mit Avatar (Initialen), Name, Firma — als + ``-Trigger mit Custom-Stil + +2. **Navigation** (`px-3 flex-1`): + - Section „Mein Bereich": Übersicht, Meine Pressemitteilungen (mit Counter-Badge), + Firmen, Buchungen & Add-ons, Statistiken (disabled, „bald") + - Section „Finanzen": Credits & Tarif (bald), Rechnungen, Zahlungsarten (bald) + - Section „Konto": Profil, Sicherheit, API & Integrationen, Benachrichtigungen (bald) + - Section „Administration" (nur für Admins/Editoren): Press-Releases, Companies, Users, Roles, etc. + +3. **Testmodus-Block** (`px-4 pb-4`) — wenn Impersonation aktiv: + - Hub-blaues Panel mit Bernstein-Eyebrow „Testmodus aktiv" + - „Zurück zum Admin"-Button (weiß auf Hub-Blau) + +4. **Resources-Block** (`px-3 pb-5 border-t`): + - Optional: Tailwind CSS, Hero Icons, Flux UI, Repository + - Im Live-Portal vermutlich weglassen oder durch eigene Hilfe-Links ersetzen + +#### Komponenten-Strategie + +Wo immer möglich **FluxUI-Komponenten** verwenden: +- `` als Wrapper +- `` für Section-Gruppen +- `` für Einträge, `data-active`-Markierung übernimmt CSS-Override +- `` für Konto-Switcher +- `` für Counter + +Wo FluxUI nicht passt (z.B. Konto-Switcher-Header mit Avatar+Name+Firma+Chevron): +**Custom Blade** in `` als wiederverwendbare Komponente. + +### 4. `app.blade.php` — Customer-Banner Hub-Stil + +Der Banner „User Backend" (für Customer-Rolle) wird visuell ans Hub-Design +angeglichen — Hub-Soft-Hintergrund, Hub-Blau-Eyebrow, Firma-Switcher als +Pille. + +### 5. `class="dark"` entfernen + +In allen Auth- und App-Layouts: + +```diff +- ++ +``` + +FluxUI Appearance-Switcher in den Settings übernimmt die Steuerung. +Dark-Mode-Werte landen in Phase 5 in `design-tokens.css`. + +### 6. Build & Visual-Check + +```bash +npm run build:portal +``` + +Öffnen und visuell prüfen: +- `https://pressekonto.test/dashboard` (Admin-Dashboard) +- `https://pressekonto.test/admin/me` (Customer-Dashboard) +- `https://pressekonto.test/settings/profile` +- `https://pressekonto.test/admin/companies` +- `https://pressekonto.test/admin/press-releases` + +Erwartung: +- Sidebar wie Mockup +- Topbar mit Breadcrumb + Aktionen +- Inhalt unverändert, aber Tabellen/Cards/Buttons in Hub-Tonart +- Keine kaputten Layouts + +## Akzeptanzkriterien + +- [ ] Sidebar nutzt `` statt `x-app-logo` +- [ ] Sidebar-Sections und Active-Item entsprechen visuell dem Mockup +- [ ] Topbar hat Breadcrumb, Search, Notification, „Neue Mitteilung"-CTA +- [ ] Font im Portal ist **Inter Tight** (sichtbar im DevTools) +- [ ] FluxUI-Buttons (Primary) sind **Hub-Blau**, nicht mehr `#3ea3dc` +- [ ] FluxUI-Tabellen sehen sauber aus mit Buchpapier-Hintergrund +- [ ] `class="dark"` ist aus allen Layouts entfernt +- [ ] Alle bestehenden Routen `/dashboard`, `/admin/*`, `/admin/me/*`, + `/settings/*` rendern Status 200 +- [ ] Pint & vorhandene Tests bleiben grün +- [ ] Page-Last-Vergleich: `portal.css`-Größe darf um max. 10 % wachsen + +## Risiken & Fallstricke + +- **FluxUI-Selektoren ändern sich**: `[data-flux-*]`-Attribute sind nicht + öffentlich dokumentierte API, sondern Implementation-Detail. Bei + FluxUI-Update kann ein Override brechen. Mitigation: Selektoren so + spezifisch wie nötig, so generisch wie möglich; gut kommentieren. +- **Zinc-Remapping kann Side-Effects haben**: Stellen, die hardcoded + `zinc-700` für Text-Farben verwenden, werden plötzlich Hub-Blau. + Mitigation: nach dem Build kritische Pages durchklicken; gegebenenfalls + einzelne Stellen explizit auf `text-ink` umstellen. +- **Tailwind v4 Custom-Properties**: Reihenfolge im `@theme`-Block ist + wichtig — Tokens müssen vor Overrides definiert sein. +- **Mobile Sidebar**: Das Mockup zeigt nur Desktop. `flux:sidebar` hat + einen eingebauten Mobile-Toggle — der bleibt erhalten und wird visuell + angeglichen. + +## Was Phase 1 NICHT macht + +- Dashboards (`admin.dashboard`, `customer.dashboard`) bekommen noch + **kein** Stat-Card-Strip-Redesign — das ist Phase 2 + 3 +- Listen-Pages werden nicht überarbeitet — passt automatisch durch + Token-Anpassung „gut genug" bis Phase 4 +- Dark Mode wird nicht aktiv ausgeliefert — Token-Werte werden vorbereitet, + aber bleiben in Phase 5 + +## Review-Punkt + +Nach Phase 1 wird Frank/Du visuell drüberschauen und entscheiden: +- Welche Detail-Pages priorisiert werden (Phase 4) +- Ob Customer-Dashboard (Phase 2) direkt danach kommt +- Ob das Auth-Layout im Portal (`auth.split`, `auth.card`) entfernt werden kann diff --git a/dev/frontend/hub-flux/03-WEITERE-PHASEN.md b/dev/frontend/hub-flux/03-WEITERE-PHASEN.md new file mode 100644 index 0000000..61ef609 --- /dev/null +++ b/dev/frontend/hub-flux/03-WEITERE-PHASEN.md @@ -0,0 +1,162 @@ +# Weitere Phasen — Outline + +> Übersicht über Phasen 2–6. Diese werden detailliert ausgearbeitet, +> sobald Phase 0+1 abgenommen sind. Jede Phase bekommt ein eigenes +> `0X-PHASE-N-NAME.md`, wenn sie aktiv wird. + +--- + +## Phase 2 — Customer-Dashboard auf Mockup-Stil + +**Status**: ⚪ später · **Aufwand**: ~½ Tag · **Risiko**: niedrig + +### Ziel +`livewire/customer/dashboard.blade.php` matched das Mockup +`User Dashboard presseportale.html` zu ≥ 90 %. + +### Bausteine +- **Page-Header** mit „Mein Dashboard" + Begrüßung + Firma-zugeordnet-Pille +- **KPI-Reihe** (4 Stat-Cards mit linkem Farb-Strip) + - Gesamt (Hub-Blau-Strip) + - Veröffentlicht (Grün-Strip, `is-ok`) + - In Prüfung (Bernstein-Strip, `is-warn`) + - Entwürfe (Grau-Strip, `is-muted`) +- **2-Spalten-Grid**: + - Links: Empty-State / Liste „Meine letzten Pressemitteilungen" + - Rechts: „Datenqualität" mit Progress-Bars (Profil-Vollständigkeit, + Rechnungsadresse) +- **Unten**: + - Links: Firmen-Slots + - Rechts: Brand-Bridge-Dark-Card (presseecho + businessportal24) + +### Neue Blade-Components +- `` — Stat-Card mit Slot + Strip-Variante +- `` — Datenqualitäts-Hint mit Icon + Progress-Bar +- `` — Dunkle Brand-Bridge-Card + +→ Diese landen in `resources/views/components/portal/`. + +--- + +## Phase 3 — Admin-Dashboard konsistent + +**Status**: ⚪ später · **Aufwand**: ~½ Tag · **Risiko**: niedrig + +### Ziel +`resources/views/admin/dashboard.blade.php` nutzt dasselbe Vokabular wie +Customer-Dashboard. + +### Heutiger Stand +Reines Tailwind mit `zinc-*`-Klassen, **keine** FluxUI-Komponenten, +visuell aus der Zeit gefallen. + +### Schritte +- KPI-Karten als `` +- Wenn Charts vorhanden: über `flux:chart` umsetzen (FluxUI Pro) +- Recent-Activity-Liste in `flux:card` mit Hub-Akzenten + +--- + +## Phase 4 — Listen-/Detail-Pages durchgehen + +**Status**: 🚧 iterativ · **Aufwand**: ~3–5 Tage gesamt · **Risiko**: niedrig + +### Ziel +Alle Volt-Pages im Admin- und Customer-Bereich nutzen denselben Hub-Stil. + +### Vorgehen +- Pro Page: 15–30 min +- In Päckchen geteilt: + - **4A** = Press-Releases Listen (Admin + Customer) — ✅ **abgeschlossen** + siehe `07-PHASE-4A-PRESS-RELEASES-LISTEN.md` + - **4B** = Press-Releases Detail/Show (Admin + Customer) — ✅ **abgeschlossen** + siehe `08-PHASE-4B-PRESS-RELEASES-DETAIL.md` + - **4C** = Press-Releases Forms (create/edit, Admin + Customer) — ✅ **abgeschlossen** + siehe `09-PHASE-4C-PRESS-RELEASES-FORMS.md` + - **4D** = Companies (`admin.companies.*`) — ⚪ pending + - **4E** = Profile/Settings (`settings.*`, `me.profile`, `me.security`) — ⚪ pending + - **4F** = Restliche Admin-Bereiche — ⚪ pending + +### Was geändert wird +- Page-Header-Struktur (Eyebrow + H1 + Subtitle + Aktions-Bar) +- Filter-Bars werden Hub-konform gestylt +- `flux:table`-Header bekommen Eyebrow-Optik +- Form-Felder bleiben FluxUI, aber mit Hub-Tokens + +### Was nicht geändert wird +- Logik / Volt-Methoden +- Datenbank / Models + +--- + +## Phase 5 — Dark Mode konsistent + +**Status**: ⚪ später · **Aufwand**: ~½ Tag · **Risiko**: niedrig + +### Ziel +Dark Mode funktioniert sauber im Portal, **ohne doppelte UI-Pflege**. + +### Quelle +`dev/frontend/tailwind_v3/User Dashboard presseportale Dark.html` hat +alle Dark-Tokens bereits vorgegeben. + +### Schritte +1. In `shared/design-tokens.css` Dark-Werte ergänzen: + ```css + @media (prefers-color-scheme: dark) { + @theme { + --color-bg: #0E1218; + --color-bg-elev: #14181F; + --color-hub: #5A78C2; + --color-accent: #D9A560; + /* … */ + } + } + .dark { + /* gleiche Werte für expliziten Switch */ + } + ``` +2. `class="dark"` wird **nicht** mehr hardcoded gesetzt +3. Flux Appearance-Switcher (`settings/appearance.blade.php`) steuert + `.dark` auf `` +4. Hub-Frontend bleibt erstmal Light-Only (so wie heute) + +### Erwartung +- Settings → Appearance → „Dark" schaltet Portal um +- Settings → Appearance → „System" folgt OS-Präferenz +- Sidebar, Topbar, Dashboards, Listen, Forms — alles funktioniert +- Hub-Landing und Hub-Auth bleiben Light + +--- + +## Phase 6 — Auth-Konsolidierung (optional) + +**Status**: ⚪ optional · **Aufwand**: 0–1 Tag · **Risiko**: mittel + +### Frage +Bleibt der Hub-Login (`auth/pressekonto`-Layout, Web-Build) so wie er ist? +Oder konsolidieren wir auf den Portal-Build? + +### Pro Konsolidierung +- Ein Build weniger +- Konsistente Komponenten-Sprache + +### Pro Beibehaltung (heutiger Stand) +- Hub-Atmosphäre der Auth-Seiten (Konzentrische Kreise, Hub-Grid) ist + visuell sehr stark — würde verloren gehen +- Hub-Auth ist **leichtgewichtig** (kein FluxUI im Bundle) +- Vorlage `Login pressekonto A3 Tailwind.html` ist bewusst minimalistisch + +### Entscheidung +Vermutlich **beibehalten**. Aber: Die alten Auth-Layouts +`auth/simple.blade.php`, `auth/split.blade.php`, `auth/card.blade.php` aus +dem Starter-Kit können vermutlich gelöscht werden, sobald geprüft ist, +dass keine Komponente sie noch verwendet. + +### Schritte (wenn konsolidiert) +- Hub-Auth-CSS in `portal.css` ziehen (mit `@source` für die Tokens) +- `auth/pressekonto`-Layout auf Portal-Build umstellen +- Hub-Auth-Klassen (`.auth-card`, `.auth-grid`, `.auth-btn-primary`) + bleiben — laufen nur jetzt aus dem Portal-Bundle +- `theme-pressekonto.css` aus dem Web-Build entfernen (oder behalten + für die Landing) diff --git a/dev/frontend/hub-flux/04-PHASE-2-CUSTOMER-DASHBOARD.md b/dev/frontend/hub-flux/04-PHASE-2-CUSTOMER-DASHBOARD.md new file mode 100644 index 0000000..5f9e0bf --- /dev/null +++ b/dev/frontend/hub-flux/04-PHASE-2-CUSTOMER-DASHBOARD.md @@ -0,0 +1,177 @@ +# Phase 2 — Customer-Dashboard auf Mockup-Stil + +> Detail-Plan analog zu `01-PHASE-0-TOKENS.md` und +> `02-PHASE-1-PORTAL-SHELL.md`. Wird beim Abschluss auf Status `✅ abgeschlossen` +> gesetzt; Lessons learned wandern in `PROGRESS.md`. + +**Status**: ✅ abgeschlossen · **Aufwand**: ~½ Tag · **Risiko**: niedrig + +--- + +## Ziel + +`resources/views/livewire/customer/dashboard.blade.php` matched das Mockup +`dev/frontend/tailwind_v3/User Dashboard presseportale.html` zu ≥ 90 %. +Sichtbarer Wow-Moment für den Kunden, ohne neue Business-Logik. + +## Was sich ändert + +### Visuell + +| Bereich | Heute | Mockup | +| ----------------- | ------------------------------------------------ | --------------------------------------------------------------------- | +| Page-Header | `` mit `` „Willkommen“ | Hub-Badge + Eyebrow + großes H1 + Untertitel + rechts Status-Pille | +| KPI-Reihe | 4 schmale `` mit ``-Zahl | 4 `stat-card`s mit Strip links, Mono-Zahl groß, Sub-Info, Sparkline | +| Pressemitteilungen-Block | `` mit Liste / Empty-State | `panel` mit `section-eyebrow`, Empty-State mit Schritt-Karten 01/02/03 | +| Datenqualität | Grid aus ``-Karten | `panel` rechts mit 2 `hint-card`s (Progress-Bar + Action-Link) | +| Firmen-Slot | `` mit Firmen-Liste | `panel` mit gestrichelten Empty-Slot-Karten + Hinweis-Box | +| Brand-Bridge | (nicht vorhanden) | `panel-dark` rechts: presseecho + businessportal24 Status | +| Footer | (nicht vorhanden) | Subtle-Footer mit Tastenkürzel / Changelog / Status / Support | + +### Datenmodell + +Heute liefert das Volt-`with()`: + +- `stats.total | published | review | draft` +- `qualityHints[]` +- `recent` (PressRelease-Collection, max. 5) +- `companies` + +Mockup verlangt **zusätzlich**: + +- `stats.deltaMonth` — Veränderung ggü. Vormonat (Total) +- `profileCompleteness` — Prozentwert für Profil-Progress-Bar +- `billingCompleteness` — Prozentwert für Rechnungsadresse +- `bridgeStatus` — `['presseecho' => 'connected'|'pending', 'businessportal24' => …]` + (vorerst `connected` fest verdrahtet, später aus echtem Sync-Status) + +## Was NICHT geändert wird + +- Logik / Volt-Methoden — Layout-only. +- Statistik-Backend (`PressRelease::where(...)`) bleibt 1:1. +- `qualityHints`-Logik bleibt — wird nur anders gerendert. +- Topbar (eigene Phase, später). + +--- + +## Implementierungs-Schritte + +### 1. Shared Hub-Components-CSS + +Klassen wandern in **`resources/css/shared/hub-components.css`** (neue Datei). +Importiert in: + +- `resources/css/portal.css` (nach `flux.css`) +- `resources/css/web/shared-styles.css` (nach `design-tokens.css`) + +Damit haben **Portal-Build und Web-Build** dieselbe Hub-Komponenten-Sprache — +DRY für späteres Wiederverwenden (z. B. Admin-Dashboard in Phase 3). + +Folgende Klassen kommen rein (alle mit `var(--color-*)`-Tokens, keine Hex-Literale): + +- `.panel`, `.panel-warm`, `.panel-dark`, `.panel-head` +- `.stat-card` + `.stat-strip` + `.stat-label` + `.stat-num` + + Varianten: `.is-primary`, `.is-ok`, `.is-warn`, `.is-muted` +- `.hint-card` + `.hint-card .hint-ico` +- `.badge` + `.badge.warn` + `.badge.ok` + `.badge.hub` + `.badge.dot` +- `.bridge-row`, `.dot-pe`, `.dot-bp` + +### 2. Blade-Components in `resources/views/components/portal/` + +#### `stat-card.blade.php` + +```blade + + 2026 {{-- rechts oben --}} + 0 ggü. Vormonat {{-- unten --}} + +``` + +Render: `
` + Strip + Label + Mono-Zahl ++ Meta-Slot oben rechts + Trend-Slot unten. Sparkline (SVG) erstmal weggelassen +— optionales Detail; lässt sich nachschieben, wenn Daten dafür da sind. + +#### `hint-card.blade.php` + +```blade + + {{ $hint['description'] }} + Profil öffnen + +``` + +Render: `.hint-card`-Grid mit Icon-Square + Progress-Bar + Text + Action-Link +in `text-accent-deep`. + +#### `bridge-card.blade.php` (optional, Phase 2 minimal) + +Bleibt erstmal **inline** im Dashboard (sehr spezifisch, eine Stelle). +Wird in Phase 3/4 extrahiert, wenn klar ist wie weit der Brand-Bridge-Pattern +sich verbreitet. + +### 3. `customer/dashboard.blade.php` umbauen + +Layout-Skelett (alles im `
`-Container): + +1. **Page-Header** — `
` mit Grid `1fr auto`: + - Links: Hub-Badge `User Backend` + Eyebrow + `

Mein Dashboard

` + + Subtitle (Name + Reichweiten-Hinweis) + - Rechts: Status-Pille + - Wenn `$selectedCompany`: Hub-Badge mit Firma-Name (grün/ok-Stil) + - Wenn nicht: Warn-Pille „Keine Firma zugeordnet → zuordnen“ +2. **KPI-Reihe** — 4 `` (Gesamt/Veröffentlicht/Prüfung/Entwürfe) +3. **Zweispalten-Grid** (`2fr 1fr`): + - Links: `
` mit Pressemitteilungen — Liste **oder** + Empty-State (3 Schritt-Karten) + - Rechts: `
` mit ``s +4. **Unteres Grid** (`2fr 1fr`): + - Links: `
` Firmen — Liste **oder** Empty-Slot-Karten + - Rechts: `
` Brand-Bridge (inline) +5. **Footer** — kleine Link-Reihe in `text-ink-3` + +### 4. Volt `with()` ergänzen + +- `stats.deltaMonth` via zweiter Query (Vormonats-Counts vs. Aktuell) +- `profileCompleteness` als simpler Heuristik-Wert (firstname/lastname/phone/etc.) +- `billingCompleteness` analog (Vorhanden = 100, sonst 0; oder Ist-Felder/Soll-Felder) +- `bridgeStatus` vorerst hardcoded `['presseecho' => 'connected', 'businessportal24' => 'connected']` + → später aus echtem Sync-Service + +### 5. Tests + +`tests/Feature/Customer/DashboardTest.php` (oder bestehender Test, falls vorhanden): + +- Rendert ohne Fehler bei eingeloggtem Customer +- Stat-Zahlen werden korrekt ausgegeben +- Empty-State wird angezeigt, wenn keine PRs existieren +- Quality-Hints werden angezeigt, wenn `profile()` fehlt + +--- + +## Akzeptanzkriterien + +- [x] Phase-2-Plan-Dokument geschrieben +- [x] `shared/hub-components.css` existiert, importiert in beiden Builds +- [x] `` und `` rendern wie Mockup +- [x] `/admin/me` zeigt das neue Dashboard ohne Console-Errors +- [x] Empty-State für Pressemitteilungen ist sichtbar, wenn keine vorhanden +- [x] Quality-Hints rendern mit Progress-Bar +- [x] Brand-Bridge-Dark-Card unten rechts zeigt presseecho + businessportal24 +- [x] Neuer Smoke-Test `tests/Feature/Customer/DashboardTest.php` mit 5 Cases + (Core-Sections, Empty-State, PR-Liste, Profil-Hint, vollständiges Profil + blendet Hints aus). Cross-Check: alle 18 verwandten Tests bleiben grün. +- [x] Pint clean +- [x] `PROGRESS.md`-Eintrag + +--- + +## Risiken & Mitigation + +- **FluxUI-Klassen vs. Custom-CSS-Kollisionen** — wir mischen `` + weiterhin **nicht** im Dashboard (für Status-Pillen nehmen wir + `.badge.hub|.warn|.ok|.dot`). Auf den Detail-Seiten (Phase 4) bleibt + FluxUI dominant. +- **Sparklines weggelassen** — minimaler Stilverlust, wird in Phase 4 mit + echten Trend-Daten nachgereicht. Mockup-Match weiterhin ≥ 90 %. +- **`stats.deltaMonth`-Performance** — zweite Query auf gleicher Tabelle; + bei wachsendem Datensatz später cachen. Heute irrelevant. diff --git a/dev/frontend/hub-flux/05-PHASE-5-DARK-MODE.md b/dev/frontend/hub-flux/05-PHASE-5-DARK-MODE.md new file mode 100644 index 0000000..b8c2e6f --- /dev/null +++ b/dev/frontend/hub-flux/05-PHASE-5-DARK-MODE.md @@ -0,0 +1,159 @@ +# Phase 5 — Dark Mode konsistent + Appearance-Switcher im User-Menü + +> **Vorzugsphase**: Eigentlich Phase 5, vorgezogen vor Phase 3/4 nach +> User-Wunsch. Grund: Der FluxUI-Appearance-Switcher hat in Phase 1 den +> Dark-Mode-Bug ausgelöst (`#6d8ad3` statt Hub-Blau); statt Symptom-Fix +> wollen wir den vollen Dark Mode jetzt richtig. + +**Status**: ✅ abgeschlossen · **Aufwand**: ~½ Tag · **Risiko**: niedrig + +--- + +## Ziele + +1. Dark Mode funktioniert sauber auf allen Portal-Seiten (Customer-Dashboard, + Sidebar, FluxUI-Komponenten, Hub-Components). +2. Switcher (Light / Dark / System) **direkt im User-Menü** verfügbar — kein + Umweg über `/settings/appearance` mehr nötig. +3. Hub-Frontend (Landing + Auth) bleibt **bewusst Light-Only** — Hub-Atmosphäre + ist Buchpapier. +4. Der Notfall-Hack aus Phase 1 (`portal.css: .dark { --color-accent: var(--color-hub) }`) + wird durch das echte Dark-Token-Mapping ersetzt. + +## Quelle der Wahrheit + +`dev/frontend/tailwind_v3/User Dashboard presseportale Dark.html` — +liefert alle Dark-Werte. Wir spiegeln die Token-Namen aus dem Light-Mode 1:1. + +--- + +## Was sich ändert + +### 1. `shared/design-tokens.css` + +Der seit Phase 0 vorbereitete `.dark`-Block wird **aktiviert** und um die seit +Phase 2 nachgezogenen Tokens (`--color-bg-rule-2`, `--color-gain-deep`) ergänzt. + +Wichtige Umwidmungen im Dark Mode (gleiche Namen, andere Werte): + +| Token | Light | Dark | Bedeutung | +| ----------------------- | ----------- | ----------- | ------------------------------------------ | +| `--color-bg` | `#f6f4ef` | `#0e1218` | Page-Background | +| `--color-bg-elev` | `#fbfaf6` | `#14181f` | Sidebar / leicht hervorgehoben | +| `--color-bg-card` | `#ffffff` | `#181d27` | Card-Body | +| `--color-bg-rule` | `#e2ddd0` | `#2a3142` | Trennlinien | +| `--color-bg-rule-2` | `#ede7d7` | `#232838` | Progress-Track | +| `--color-hub` | `#1a2540` | `#5a78c2` | Primary-Akzent (heller im Dark) | +| `--color-hub-soft` | `#e5e9f1` | `#1f2a47` | Hint-Hintergrund | +| `--color-accent` | `#b07a3a` | `#d9a560` | Bernstein-Akzent (heller im Dark) | +| `--color-accent-warm` | `#b07a3a` | `#b07a3a` | **bleibt gleich** — für Border-Akzente | +| `--color-accent-deep` | `#8a5e27` | `#b07a3a` | Action-Link-Color (heller im Dark) | +| `--color-accent-soft` | `#f1e6d3` | `#2a2418` | Hint-Icon-BG | +| `--color-ink` | `#1a1f1c` | `#ece9e0` | Text-Primary | +| `--color-ink-2` | `#3a413d` | `#c9c5b8` | Text-Secondary | +| `--color-ok / -soft` | `#2e8540 / #e2f1e5` | `#4dc076 / #1a2d22` | Status grün | + +`--color-accent-warm` als **konstanter** Bernstein-Token (gleicher Wert in +beiden Modi) ist ein bewusster Trick: Im Portal mapt `--color-accent` auf +`var(--color-hub)` (Primary-Akzent), aber Bernstein-Borders (Hint-Card, +Schritt-Karten-Eyebrow) brauchen weiterhin den ungeänderten Bernstein-Wert. +`--color-accent-warm` ist der Token dafür. + +### 2. `portal.css` + +- Den `.dark { --color-accent: var(--color-hub); … }`-Notfall-Block aus + Phase 1 entfernen — er ist mit echtem Dark-Mapping überflüssig. +- Stattdessen einen kurzen Kommentar setzen, dass das Token-Mapping aus + `design-tokens.css` greift. +- Primary-Button-Hover-Override: heute hartcodiert auf `--color-hub-2` + (`#243152`). Im Dark Mode ist `--color-hub-2` = `#6d8ad3` (heller), + was richtig ist (Hover = noch heller als Default-Button). Override bleibt + via Variable korrekt, kein Eingriff nötig. +- Button-Shadows: `rgba(26, 37, 64, …)` ist Light-Mode-spezifisch. Im Dark + Mode wirkt der bläuliche Shadow auf dunklem Card-BG falsch. Lösung: + per `@media (prefers-color-scheme: dark)` ODER `.dark`-Selektor die + Shadow-Farben auf transparenten Schwarz tönen. + +### 3. `shared/hub-components.css` + +- Bernstein-Stellen umstellen: `var(--color-accent)` → + `var(--color-accent-warm)` für **Hint-Card-Border-Left** und + **Progress-Bar-Fill** (sonst wird's im Portal Hub-Blau gemapt). +- Wegen Tokens-Architektur (`hub-soft` etc. werden im Dark Mode dunkler) + funktioniert der Großteil **automatisch** — keine `.dark`-Overrides nötig. +- Eine Ausnahme: `.panel-dark` und die Brand-Bridge-Boxes — im Light Mode + ist `panel-dark` Hub-Blau (#1a2540). Im Dark Mode bleibt das auch + `var(--color-hub)` — und da ist `--color-hub` heller (#5a78c2). Wir + brauchen also einen **konstanten dunklen Token** für `panel-dark` — sonst + wird die „dunkle“ Bridge-Card im Dark Mode plötzlich hellblau. + → Neuer Token `--color-panel-dark` (immer #0f1729, in beiden Modi) + oder direkt `var(--color-topbar-deep)` (existiert bereits). + +### 4. User-Menü-Switcher + +Beide Dropdowns (Desktop in `sidebar.blade.php`, Mobile in derselben Datei) +bekommen vor dem Logout einen Block: + +```blade + +
+ + + + + +
+``` + +Das ist exakt das Pattern aus `livewire/settings/appearance.blade.php`, nur +kompakt mit Icons-only. `$flux.appearance` ist FluxUI's Magic-Object, +LocalStorage-persistent, von `@fluxAppearance` injiziert. + +### 5. Hub-Auth bleibt Light + +`auth/pressekonto.blade.php` lädt **kein** `@fluxAppearance` und **kein** +`partials/head` — die Hub-Auth-Pipeline ist eigenständig. Damit wird `class="dark"` +dort nie gesetzt, selbst wenn das LocalStorage `dark` enthält. Hub-Auth bleibt +also automatisch Light. **Kein Eingriff nötig.** + +--- + +## Implementierungs-Schritte (Reihenfolge) + +1. `design-tokens.css`: Dark-Block aktivieren, `--color-accent-warm` definieren, + `--color-panel-dark` einführen (oder Re-Use `--color-topbar-deep`). +2. `portal.css`: Hack rausnehmen, Button-Shadow für Dark Mode tönen. +3. `hub-components.css`: Bernstein-Stellen auf `--color-accent-warm`, + `.panel-dark` auf `--color-panel-dark`. +4. `sidebar.blade.php`: Switcher in beide Dropdowns einbauen. +5. Build + Smoke-Test im Browser. +6. Bestehende Tests laufen lassen (sollten alle weiter grün sein, weil + keine Test-Assertion farbbezogen ist). +7. Pint + PROGRESS + Plan-Status. + +## Akzeptanzkriterien + +- [x] Plan-Dokument geschrieben +- [x] Switcher Light/Dark/System im User-Menü (Desktop + Mobile) sichtbar, + Änderung wirkt sofort + persistent (LocalStorage) +- [x] Dark Mode: Customer-Dashboard rendert mit allen Sektionen korrekt + (Tokens schalten um, kein hellblauer Akzent-Bug) +- [x] Brand-Bridge-Karte bleibt im Dark Mode dunkel (`--color-panel-dark-2` + konstant in beiden Modi) +- [x] Hub-Auth bleibt im Dark Mode Light (lädt kein `@fluxAppearance`) +- [x] Tests grün (18/18) +- [x] Pint clean +- [x] PROGRESS-Eintrag + +## Risiken & Mitigation + +- **FluxUI-Default-Komponenten im Dark Mode** (z.B. Modals, Dropdowns): + unsere Zinc→Hub-Mapping in `portal.css` bridgt die Skala. Im Dark Mode + müssen die Zinc-Werte auch umgekippt werden — passiert automatisch über + die Token-Vars, weil wir `var(--color-bg-*)` nutzen. Restrisiko: einzelne + FluxUI-Komponenten könnten harte Tailwind-Klassen wie `bg-white` haben, + die im Dark unverändert weiß bleiben. Smoke-Test deckt das auf. +- **Hub-Components-Schatten** sind in Hub-Blau-Alpha definiert + (`rgba(26, 37, 64, …)`). Im Dark Mode auf dunklem Bg wirken sie evtl. + „falsch warm“. Akzeptabel im ersten Wurf; Feintuning per `prefers-color-scheme` + Media-Query falls visuell stört. diff --git a/dev/frontend/hub-flux/06-PHASE-3-ADMIN-DASHBOARD.md b/dev/frontend/hub-flux/06-PHASE-3-ADMIN-DASHBOARD.md new file mode 100644 index 0000000..f48004d --- /dev/null +++ b/dev/frontend/hub-flux/06-PHASE-3-ADMIN-DASHBOARD.md @@ -0,0 +1,55 @@ +# Phase 3 — Admin-Dashboard im Hub-Vokabular + +**Status**: ✅ abgeschlossen · **Aufwand**: ~¼ Tag · **Risiko**: niedrig + +--- + +## Ziel + +`resources/views/admin/dashboard.blade.php` nutzt dieselbe Designsprache wie +das Customer-Dashboard (Phase 2). Keine neuen Komponenten, keine neue Logik +— nur Vokabular-Umbau auf die DRY-Schicht. + +## Was sich ändert + +### Layout + +- Page-Header: Hub-Badge „Admin Backend" + Eyebrow + großes H1 + „Admin Dashboard" + Subtitle. Rechts: Status-Pille „Alle Systeme operational" + (ok-Style mit Dot). +- KPI-Reihe: weiter **5 Stat-Cards** (wie heute), aber als + `` mit Strip-Variante: + - Pressemitteilungen → `primary` (mit Sub: `X pub · Y prüf · Z entwurf`) + - In Prüfung → `warn` (eigene KPI, war vorher in der PM-Card versteckt) + - Firmen → `muted` + - Kontakte → `muted` + - Benutzer → `muted` +- 2-Spalten-Grid (`2fr 1fr`) — wie heute: + - Links: Panel „Letzte Pressemitteilungen" (Liste + Status-Badges + in `.badge.ok|warn|err|hub`). + - Rechts: Panel „Zur Prüfung" mit warn-Pille (Count) + Liste + + „+ N weitere"-Link. +- Bottom-Reihe (`1fr 2fr`) — **neu**: + - Links: `panel-warm` Newsletter-Block (Mono-Zahl + Subline). + - Rechts: `panel` Quick-Actions mit Section-Eyebrow + Schnellzugriff + auf Invoices/Payments/Coupons/Presets. +- Footer: subtle Link-Reihe analog Customer-Dashboard. + +### Was NICHT geändert wird + +- Controller-Logik / Datenform. +- Newsletter-Count bleibt erhalten, wandert nur in einen eigenen Block. +- Bestehende Tests (`DashboardTest`) bleiben grün — alle geprüften + Strings (`3`, `1 pub`, `1 prüf`, `1 entwurf`, `Review Dashboard PM`) + bleiben im Output. + +## Akzeptanzkriterien + +- [x] Plan geschrieben +- [x] Admin-Dashboard verwendet ``, `.panel`, + `.section-eyebrow`, `.badge` +- [x] Customer-Dashboard und Admin-Dashboard sind visuell aus einem Guss +- [x] Dark Mode greift automatisch (alle Tokens) +- [x] `DashboardTest` bleibt grün ohne Anpassung (alle 3 Cases + + Wortlaut „1 pub / 1 prüf / 1 entwurf / Review Dashboard PM") +- [x] Pint clean, PROGRESS-Eintrag diff --git a/dev/frontend/hub-flux/07-PHASE-4A-PRESS-RELEASES-LISTEN.md b/dev/frontend/hub-flux/07-PHASE-4A-PRESS-RELEASES-LISTEN.md new file mode 100644 index 0000000..85d5e7a --- /dev/null +++ b/dev/frontend/hub-flux/07-PHASE-4A-PRESS-RELEASES-LISTEN.md @@ -0,0 +1,58 @@ +# Phase 4A — Press-Releases Listen-Pages + +> Erstes Päckchen aus Phase 4 (Listen/Detail-Pages iterativ). Wegen +> Umfang teilen wir Phase 4 in Päckchen — A = Listen, B = Detail/Show, +> C = Forms (create/edit), D = Companies, E = Settings/Profile, F = Rest. + +**Status**: ✅ abgeschlossen · **Aufwand**: ~¼ Tag · **Risiko**: niedrig + +--- + +## Scope + +In diesem Päckchen NUR: + +- `resources/views/livewire/admin/press-releases/index.blade.php` +- `resources/views/livewire/customer/press-releases/index.blade.php` + +NICHT in diesem Päckchen: +- `show.blade.php`, `create.blade.php`, `edit.blade.php` (Päckchen B/C) +- Companies, Settings, Profile (Päckchen D/E) + +## Ziel + +Beide Listen nutzen das Hub-Vokabular: + +- **Page-Header** wie im Dashboard (Hub-Badge + Eyebrow + H1 + Subtitle, + CTA rechts). +- **KPI-Reihe** (nur Admin) als `` — exakt + wie auf dem Admin-Dashboard (DRY: vier Cards mit primary/ok/warn/muted). +- **Filter-Bar** als `.panel` mit `.panel-head` „Filter & Suche". +- **Tabelle** in `.panel` (kein FluxUI-Card-Wrapper mehr). FluxUI-Table + bleibt — wir bridgen über Zinc-→Hub-Mapping. +- **Status-Badges** auf eigene `.badge.ok|warn|err|hub`-Pillen + (statt ``) — visuelle Konsistenz zum Dashboard. +- **Empty-State** in Hub-Stil mit Icon-Box. + +## Was NICHT angefasst wird + +- **Confirm-Modals** für Publish/Reject/Archive — Tests assertieren + Wortlaut („Pressemitteilung veröffentlichen?" etc.). +- **Volt-Logik** (Sort, Filter, Methods) — Layout-only. +- **FluxUI-Form-Inputs** (Search, Select, Combobox) — bleiben, weil + Hub kein eigenes Combobox-Pendant hat. + +## Akzeptanzkriterien + +- [x] Plan +- [x] Admin-Liste: Page-Header + 4 Stat-Cards + Filter-Panel + Tabelle-Panel + Hub-Badges +- [x] Customer-Liste: Page-Header + Filter-Panel + Tabelle-Panel + Hub-Badges + Empty-State +- [x] Visuell aus einem Guss mit Dashboard +- [x] `PressReleaseWorkflowTest` + `AdminPressReleaseActionsTest` bleiben grün +- [x] Build + Pint + PROGRESS + +## Bonus-Fix + +- `customer/dashboard.blade.php` Subtitle ergänzt um „Übersicht für {Firma}", + wenn `$selectedCompany` gesetzt ist. Korrigiert eine Phase-2-Regression + bei `CustomerCompanyContextTest > customer dashboard is filtered by …`. diff --git a/dev/frontend/hub-flux/08-PHASE-4B-PRESS-RELEASES-DETAIL.md b/dev/frontend/hub-flux/08-PHASE-4B-PRESS-RELEASES-DETAIL.md new file mode 100644 index 0000000..6046767 --- /dev/null +++ b/dev/frontend/hub-flux/08-PHASE-4B-PRESS-RELEASES-DETAIL.md @@ -0,0 +1,56 @@ +# Phase 4B — Press-Releases Detail/Show-Pages + +> Zweites Päckchen aus Phase 4. Folgt auf 4A (Listen). + +**Status**: ✅ abgeschlossen · **Aufwand**: ~⅓ Tag · **Risiko**: niedrig + +--- + +## Scope + +- `resources/views/livewire/admin/press-releases/show.blade.php` +- `resources/views/livewire/customer/press-releases/show.blade.php` + +NICHT in diesem Päckchen: +- `create.blade.php`, `edit.blade.php` (Päckchen 4C — Forms) +- Companies, Settings, Profile (Päckchen 4D/4E) + +## Ziel + +Beide Detail-Pages im Hub-Vokabular: + +- **Page-Header** wie auf den Listen (Hub-Badge + Eyebrow + H1 + + Subtitle), Status-Pill direkt unter dem Eyebrow oder im Header-Meta, + Aktions-Buttons (Bearbeiten / Zurück / Vorschau-Link) rechts. +- **Status-Workflow-Aktionsbar** als `.panel` mit klarer Optik + je nach Status (review = warn, published = ok, draft = neutral). +- **Content-Hauptbereich** (PM-Text) als `.panel` (kein FluxUI-Card-Wrapper). +- **Sidebar / Side-Cards** als kleine `.panel` mit `panel-head`. +- **Status-Verlauf-Timeline** als `.panel` mit Hub-Badges + (`.badge.ok|warn|err|hub`). +- **Rejection-Hinweis** (Customer) als Hub-Style-Error-Panel mit + Linker Akzent-Border (statt ``). +- **Share-Link-Erfolgsbox** (Customer) als Hub-Style-Success-Block. +- **Pressekontakte-Liste** (Customer) als Hub-Items in `.panel`. + +## Was explizit NICHT angefasst wird + +- **Confirm-Modals** (Publish / Reject / Archive) — Tests in + `AdminPressReleaseActionsTest` assertieren Wortlaute. +- **Wortlaute** `Werbliche Sprache wurde markiert.` und + `Erneut einreichen` aus `PressReleaseWorkflowTest`. +- **Volt-Logik** (publish/reject/archive/submitForReview/ + generateShareLink/with) — Layout-only. + +## Akzeptanzkriterien + +- [x] Plan +- [x] Admin-Show: Page-Header + Status-Workflow-Bar + Text-Panel + + Sidebar-Panels + Timeline + Hub-Badges. Modals unverändert. +- [x] Customer-Show: Page-Header + Status-Workflow-Bar + + Rejection-Panel + Share-Erfolgsblock + Contacts-Panel + + Verlauf-Panel + Text-Panel + Hub-Badges. „Erneut einreichen" + + „Werbliche Sprache wurde markiert." Wortlaute bleiben. +- [x] `PressReleaseWorkflowTest` + `AdminPressReleaseActionsTest` + bleiben grün (16 passed, 52 assertions). +- [x] Build + Pint + PROGRESS. diff --git a/dev/frontend/hub-flux/09-PHASE-4C-PRESS-RELEASES-FORMS.md b/dev/frontend/hub-flux/09-PHASE-4C-PRESS-RELEASES-FORMS.md new file mode 100644 index 0000000..1850fac --- /dev/null +++ b/dev/frontend/hub-flux/09-PHASE-4C-PRESS-RELEASES-FORMS.md @@ -0,0 +1,69 @@ +# Phase 4C — Press-Releases Forms (create / edit) + +> Drittes Päckchen aus Phase 4. Folgt auf 4A (Listen) und 4B (Show). + +**Status**: ✅ abgeschlossen · **Aufwand**: ~⅓–½ Tag · **Risiko**: niedrig + +--- + +## Scope + +- `resources/views/livewire/admin/press-releases/create.blade.php` +- `resources/views/livewire/admin/press-releases/edit.blade.php` +- `resources/views/livewire/customer/press-releases/create.blade.php` +- `resources/views/livewire/customer/press-releases/edit.blade.php` + +NICHT in diesem Päckchen: +- Companies (Päckchen 4D) +- Settings / Profile (Päckchen 4E) +- Restliche Admin-Bereiche (Päckchen 4F) + +## Ziel + +Alle vier Forms im Hub-Vokabular: + +- **Page-Header** wie auf Listen und Detail-Pages: Hub-Badge + + Eyebrow + H1 + Subtitle. Bei Edit zusätzlich Status-Pille im + Header-Meta. Aktions-Buttons rechts. +- **Form-Sektionen** als `.panel` mit `.panel-head` und + `section-eyebrow` ("Inhalt", "SEO & Links", "Metadaten", + "Status-Aktionen", "Aktionen"). +- **Form-Felder** bleiben FluxUI (``, ``, + ``, ``, `` inkl. + Combobox-Variant, ``, ``) — das + Token-Bridging aus Phase 1 zieht. Required-Marker werden auf + Hub-Error-Token umgestellt. +- **Action-Buttons** ("Speichern", "Zur Prüfung einreichen", + "Als Entwurf speichern", "Status wechseln") in einem `.panel` + mit `.panel-head` "Aktionen". +- **Flash-Boxen** auf Hub-Token-Pillen. + +## Was explizit NICHT angefasst wird + +- **Volt-Logik** (`save`, `submitForReview`, `publish`, `reject`, + `backToDraft`, `archive`, `changeStatus`, `deletePressRelease`, + `mount`, `with`, `selectedCompany`) — Layout-only. +- **Confirm-Modals** der Admin-Edit-Page (`confirm-status-change`, + `confirm-delete-press-release`) — Tests assertieren Wortlaute. +- **Wortlaute** aus `AdminPressReleaseActionsTest`: + `Neuer Status`, `Status wechseln`, `Status wirklich wechseln?`, + `Pressemitteilung löschen?`, `Status wurde auf`. +- **Image-Manager-Komponente** (``). +- **Wortlaute** für Customer-Create-Page: `Beta GmbH` (Firma + aus Faktur via `companyId`) — Combobox/Select bleibt funktional. + +## Akzeptanzkriterien + +- [x] Plan +- [x] Admin-Edit: Page-Header + 5 Panels + Hub-Status-Badge, + beide Modals unverändert, alle Wortlaut-Assertions grün. +- [x] Admin-Create: Page-Header + 3 Panels (Inhalt, SEO, Metadaten) + + Aktions-Panel. +- [x] Customer-Create: Page-Header + 2 Panels (Inhalt, Metadaten) + + Aktions-Panel. +- [x] Customer-Edit: Page-Header + 2 Panels (Inhalt mit Image-Manager, + Metadaten) + Aktions-Panel. +- [x] `AdminPressReleaseActionsTest`, + `CustomerCompanyContextTest > customer press releases create …`, + `CustomerProfileSecurityTest` bleiben grün (72 Tests, 310 assertions). +- [x] Build + Pint + PROGRESS. diff --git a/dev/frontend/hub-flux/PROGRESS.md b/dev/frontend/hub-flux/PROGRESS.md new file mode 100644 index 0000000..570761e --- /dev/null +++ b/dev/frontend/hub-flux/PROGRESS.md @@ -0,0 +1,812 @@ +# Fortschritts-Log — Hub × FluxUI + +> Tagebuch der Umsetzung. Neue Einträge **oben** anfügen. +> Format pro Eintrag: Datum · Phase · Was wurde gemacht · Wer · Notizen + +--- + +## 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 (``, + ``, ``, ``, + `` inkl. Combobox-Variant, ``, + ``) — 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. + - **``** — + 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 + `` mit `@class([])`-Syntax. + +- **Customer-Show-spezifisch**: + - **Rejection-Hinweis** als roter `.panel` mit linker + Akzent-Border (`border-left-width:3px`) und Icon-Box — + statt ``. + - **Review-Pending-Hinweis** als warner `.panel` mit + Akzent-Border und Clock-Icon-Box — statt ``. + - **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: `
` 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-`` bleibt — das + Zinc-→Hub-Mapping aus Phase 1 zieht hier perfekt. + - **Status-Badges**: `` + ersetzt durch `` 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 `` (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 ``): + - 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` + + ``-Investition zahlt sich ab Phase 3 deutlich aus. + - Der `` 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.appearance` ist FluxUIs Magic-Object — LocalStorage-persistent, + `@fluxAppearance`-Script setzt `class="dark"` auf ``. + - 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 ``-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/`: + - `` + mit Slots `meta` (oben rechts) und `trend` (unten). + - `` + 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 ``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 `` 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). + - ``-Extraktion (Brand-Bridge bleibt inline, bis + sie an mehr Stellen gebraucht wird). + +- **Lessons learned**: + - PHPDoc in Blade-Components darf KEINE ``-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 `` injiziert `@fluxScripts` (sidebar.blade.php Zeile + nahe ``) **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 + ``, 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 ``-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 (``) 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 `` entfernt + * `` jetzt `bg-bg text-ink antialiased` (Hub-Buchpapier) + * `` ersetzt durch `` + 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 + ``) + - 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] +``` diff --git a/dev/frontend/hub-flux/README.md b/dev/frontend/hub-flux/README.md new file mode 100644 index 0000000..601b1ed --- /dev/null +++ b/dev/frontend/hub-flux/README.md @@ -0,0 +1,143 @@ +# Hub × FluxUI — Visuelle Vereinheitlichung Portal ↔ Hub + +> **Ziel**: Das Portal-Backend (User-Panel, Admin-Bereich) wird visuell an den +> Hub-Stil (`pressekonto.test`-Landing + Auth-Seiten) angeglichen, **ohne +> FluxUI aufzugeben**. Die FluxUI-Komponenten werden über Design-Tokens und +> CSS-Overrides ans Hub-Design adaptiert. + +## Status + +| Phase | Beschreibung | Status | +|-------|--------------|--------| +| 0 | Design-Tokens vereinheitlichen | **✅ abgeschlossen** (2026-05-19) | +| 1 | Portal-Shell (Sidebar, Layout, Brand-Mark) | **✅ abgeschlossen** (2026-05-19) | +| 2 | Customer-Dashboard auf Mockup-Stil (inkl. Topbar) | 🟡 wartet auf Freigabe | +| 3 | Admin-Dashboard konsistent | ⚪ später | +| 4 | Listen-/Detail-Pages | ⚪ iterativ | +| 5 | Dark Mode konsistent | ⚪ später | +| 6 | Auth-Konsolidierung (optional) | ⚪ optional | + +→ Tagesaktueller Fortschritt: [`PROGRESS.md`](./PROGRESS.md) + +## Dokumente in diesem Verzeichnis + +| Datei | Zweck | +|-------|-------| +| [`README.md`](./README.md) | Diese Übersicht: Entscheidung, Architektur, Status | +| [`01-PHASE-0-TOKENS.md`](./01-PHASE-0-TOKENS.md) | Phase 0: Tokens vereinheitlichen (aktiv) | +| [`02-PHASE-1-PORTAL-SHELL.md`](./02-PHASE-1-PORTAL-SHELL.md) | Phase 1: Portal-Shell ans Hub-Design angleichen | +| [`03-WEITERE-PHASEN.md`](./03-WEITERE-PHASEN.md) | Outline für Phasen 2–6 | +| [`PROGRESS.md`](./PROGRESS.md) | Fortschritts-Log + Notizen | + +## Visuelle Vorlagen + +Maßgebliche Mockups für diese Arbeit: + +- `dev/frontend/tailwind_v3/User Dashboard presseportale.html` — Light-Variante +- `dev/frontend/tailwind_v3/User Dashboard presseportale Dark.html` — Dark-Variante +- `dev/frontend/tailwind_v3/Login pressekonto A3 Tailwind.html` — Hub-Auth-Vorlage (bereits umgesetzt) +- `dev/frontend/tailwind_v3/Hub Landing pressekonto-2.html` — Hub-Landing-Vorlage (bereits umgesetzt) + +## Architektur-Entscheidung + +### Plan B (gewählt) — Tokens teilen, Komponenten getrennt lassen + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ shared/design-tokens.css │ +│ (Hub-Blau, Bernstein, Buchpapier, Inter Tight, JetBrains Mono) │ +└────────────────┬────────────────────────┬───────────────────────┘ + │ │ + ┌────────▼─────────┐ ┌─────────▼──────────┐ + │ portal.css │ │ theme-pressekonto │ + │ + FluxUI │ │ + shared-styles │ + │ (Backend) │ │ (Hub-Landing/Auth)│ + └──────────────────┘ └────────────────────┘ + build/portal build/web +``` + +**Warum nicht alles in FluxUI?** +- Die Hub-Landing lebt von Atmosphäre (konzentrische Kreise, Hub-Grid, eigene + Eyebrows, Bridge-Cards), die mit FluxUI-Komponenten nicht 1:1 abbildbar ist +- FluxUI würde im Hub-Frontend zur unnötigen Bundle-Last +- Der gerade gebaute Hub-Login wäre verloren + +**Warum nicht alles Custom?** +- 77 Blade-Dateien nutzen FluxUI – ein Rewrite wäre Aufwand ohne Mehrwert +- FluxUI-Tabellen, -Forms, -Modals, -Date-Picker sind im Backend Gold wert +- FluxUI ist sehr gut **customizable** über CSS-Custom-Properties + und `[data-flux-*]`-Selectoren + +### Verworfen — Plan A (alles FluxUI) & Plan C (alles im Web-Build) + +Siehe Chat-Historie für die Begründung. Kurz: zu viel Aufwand, zu wenig +Mehrwert, würde bereits gelieferte Hub-Atmosphäre verschlechtern. + +## Branding & Tokens + +### Brand +- **Marke**: pressekonto (verbindlich, für Portal und Hub) +- **Wortmarke**: `` — auch im Portal +- **Logo-Komponente** `` wird im Portal **abgelöst** + +### Farben (Light) + +| Token | Wert | Rolle | +|-------|------|-------| +| `--color-hub` | `#1A2540` | **Primärer Akzent** (Sidebar-Active, Primary-Buttons, Eyebrows) | +| `--color-hub-2` | `#243152` | Hover-Stufe von `--color-hub` | +| `--color-hub-3` | `#2E3D66` | Tertiäre Stufe (Dekoration auf dunklem Grund) | +| `--color-hub-soft` | `#E5E9F1` | Active-Pill-Hintergrund in der Sidebar | +| `--color-accent` | `#B07A3A` | **Sekundärer Akzent** (Bernstein – Notifications, Datenqualität, Empfehlungs-Ribbon) | +| `--color-accent-deep` | `#8A5E27` | Akzent-Hover/Text | +| `--color-bg` | `#F6F4EF` | Warmes Buchpapier — Haupt-Hintergrund | +| `--color-bg-elev` | `#FBFAF6` | Elevation 1 (Sidebar, Topbar, leichte Cards) | +| `--color-bg-card` | `#FFFFFF` | Reine Cards | +| `--color-bg-rule` | `#E2DDD0` | Standard-Trennlinien | +| `--color-ink` | `#1A1F1C` | Primärtext | +| `--color-ink-2` | `#3A413D` | Sekundärtext (Begleittexte) | +| `--color-ink-3` | `#5A6360` | Meta, Labels | +| `--color-ink-4` | `#8A918D` | Disabled, Hintergrund-Meta | + +### Farben (Dark) — laut Mockup +Wird in Phase 5 ausgearbeitet. Hub-Blau wird heller (`#5A78C2`), Akzent +wärmer (`#D9A560`), Hintergrund tief Anthrazit (`#0E1218`). Wichtig: die +Token-Namen bleiben gleich, nur die Werte tauschen — keine doppelte +UI-Pflege. + +### Typografie + +| Token | Wert | +|-------|------| +| `--font-sans` | `"Inter Tight", Inter, system-ui, sans-serif` | +| `--font-mono` | `"JetBrains Mono", "SF Mono", ui-monospace, monospace` | +| `--font-serif` | `"Source Serif 4", Georgia, serif` (nur für Brand-Mark) | + +Aktuell im Portal: **Instrument Sans** → wird in Phase 1 abgelöst. + +## Konventionen + +- **Light Mode** ist Default. `class="dark"` auf `` wird entfernt. +- Dark Mode wird via `prefers-color-scheme` + Flux Appearance-Switcher + gesteuert. Token-Layer übernimmt die Umschaltung. +- Token-Names sind **identisch** zwischen Hub-Theme und Portal-Theme. + Sowohl `bg-bg-elev` als auch `bg-hub-soft` funktionieren in beiden Welten. +- FluxUI-Komponenten werden **nicht überschrieben**, sondern über + `[data-flux-*]`-Selectoren in `portal.css` ergänzt — minimaler Eingriff, + maximale Kompatibilität mit FluxUI-Updates. + +## Was wir bewusst NICHT machen + +- **Kein FluxUI-Rewrite**. Nur Token-Anpassung + Selektor-Overrides. +- **Keine zweite UI-Pflege für Dark Mode**. Tokens-only-Ansatz. +- **Kein Verschmelzen der Builds** (Phase 6 optional). +- **Keine Änderung an Volt-/Livewire-Logik** in dieser Arbeit. + +## Wer ändert was + +- **Diese Doku** wird mit jeder Phase aktualisiert. `PROGRESS.md` enthält + die Tages-Notes. +- Code-Änderungen sind kleinteilig und werden in eigenen Commits gebündelt + (`hub-flux: phase 0 — tokens vereinheitlicht`, etc.). +- Bei Unklarheiten/Entscheidungen: kurz in `PROGRESS.md` festhalten, + damit nachvollziehbar bleibt warum etwas so und nicht anders. diff --git a/dev/frontend/tailwind_v3/Hub Landing presseportale-2.html b/dev/frontend/tailwind_v3/Hub Landing pressekonto-2.html similarity index 98% rename from dev/frontend/tailwind_v3/Hub Landing presseportale-2.html rename to dev/frontend/tailwind_v3/Hub Landing pressekonto-2.html index 06ebb0a..bb34067 100644 --- a/dev/frontend/tailwind_v3/Hub Landing presseportale-2.html +++ b/dev/frontend/tailwind_v3/Hub Landing pressekonto-2.html @@ -3,7 +3,7 @@ -presseportale.com — Publisher-Hub +pressekonto.de — Publisher-Hub @@ -163,7 +163,7 @@ - presseportale.com + pressekonto.com Publisher · Hub @@ -230,7 +230,7 @@

- presseportale.com ist der gemeinsame Publisher-Bereich für unsere beiden Pressefachportale. Pressemitteilungen schreiben, redaktionell prüfen lassen, auf beiden Reichweiten veröffentlichen — und Reichweite, Empfänger und Abrechnung an einem Ort verwalten. + pressekonto.de ist der gemeinsame Publisher-Bereich für unsere beiden Pressefachportale. Pressemitteilungen schreiben, redaktionell prüfen lassen, auf beiden Reichweiten veröffentlichen — und Reichweite, Empfänger und Abrechnung an einem Ort verwalten.

@@ -290,7 +290,7 @@
Hub
-
presseportale
+
pressekonto
.com
@@ -767,15 +767,15 @@
- +
-
Hinter presseportale.com
+
Hinter pressekonto.de

Zwei eigenständige Pressefachportale. Eine kuratierte Verlags-Familie.

- presseportale.com ist nicht „irgendein Tool" — es ist die zentrale Plattform für unsere beiden redaktionell geführten Pressefachportale. Jedes Portal hat einen eigenen Charakter, eigene Leserschaft und eigene Themen-Schwerpunkte. + pressekonto.de ist nicht „irgendein Tool" — es ist die zentrale Plattform für unsere beiden redaktionell geführten Pressefachportale. Jedes Portal hat einen eigenen Charakter, eigene Leserschaft und eigene Themen-Schwerpunkte.

@@ -856,7 +856,7 @@
- Pressemitteilungen, die Sie über presseportale.com einreichen, erscheinen auf beiden Portalen — ohne Aufpreis, ohne doppelte Eingabe. Sie haben eine zentrale Mitteilungs-Verwaltung und eine zentrale Reichweiten-Statistik. + Pressemitteilungen, die Sie über pressekonto.de einreichen, erscheinen auf beiden Portalen — ohne Aufpreis, ohne doppelte Eingabe. Sie haben eine zentrale Mitteilungs-Verwaltung und eine zentrale Reichweiten-Statistik.
@@ -876,7 +876,7 @@

- Über presseportale.com veröffentlichen unter anderem + Über pressekonto.de veröffentlichen unter anderem Siemens AG, BASF SE, Deutsche Bank, @@ -1069,7 +1069,7 @@

- presseportale.com + pressekonto.com
Publisher · Hub @@ -1121,7 +1121,7 @@
- © 2026 presseportale.com · Alle Rechte vorbehalten + © 2026 pressekonto.de · Alle Rechte vorbehalten Alle Systeme betriebsbereit diff --git a/dev/frontend/tailwind_v3/Login presseportale A3 Tailwind.html b/dev/frontend/tailwind_v3/Login pressekonto A3 Tailwind.html similarity index 99% rename from dev/frontend/tailwind_v3/Login presseportale A3 Tailwind.html rename to dev/frontend/tailwind_v3/Login pressekonto A3 Tailwind.html index ceddb0d..7e4c4ab 100644 --- a/dev/frontend/tailwind_v3/Login presseportale A3 Tailwind.html +++ b/dev/frontend/tailwind_v3/Login pressekonto A3 Tailwind.html @@ -3,7 +3,7 @@ -presseportale.com — Anmelden +pressekonto.de — Anmelden @@ -160,7 +160,7 @@
- presseportale.com + pressekonto.com diff --git a/dev/frontend/tailwind_v3/User Dashboard presseportale Dark.html b/dev/frontend/tailwind_v3/User Dashboard presseportale Dark.html new file mode 100644 index 0000000..1993be2 --- /dev/null +++ b/dev/frontend/tailwind_v3/User Dashboard presseportale Dark.html @@ -0,0 +1,767 @@ + + + + + +presseportale.com — Mein Dashboard · Dark + + + + + + + + + + + + + + +
+ +
+ + + + + +
+ + +
+
+ +
+ Hub + / + User Backend + / + Übersicht +
+ + + + + + presseecho + · + businessportal24 + + + + + +
+ + + + + + ⌘K +
+ + + + + + + + Neue Mitteilung + +
+
+ + +
+ + +
+
+
+ User Backend + Mein Bereich · A · 01 +
+

Mein Dashboard

+

+ Willkommen zurück, Test User. Hier sehen Sie Status und Reichweite Ihres Kundenkontos für presseecho und businessportal24. +

+
+ +
+ + + + + + + Keine Firma zugeordnet + zuordnen → + +
+
+ + +
+ +
+ +
+
Gesamt
+ 2026 +
+
0
+
+ + + 0 ggü. Vormonat + +
+ + + + + +
+ +
+ +
+
Veröffentlicht
+ live +
+
0
+
+ auf beiden Portalen +
+ + + + +
+ +
+ +
+
In Prüfung
+ Ø 4 h +
+
0
+
+ redaktionelle Prüfung +
+ + + + +
+ +
+ +
+
Entwürfe
+ privat +
+
0
+
+ gespeichert, nicht eingereicht +
+ + + +
+
+ + +
+ + +
+
+
+ Meine letzten Pressemitteilungen +
+
+ 0 von 0 + Alle anzeigen → +
+
+ + +
+ +
+ + + + + + 0 +
+
Noch keine Pressemitteilungen
+

+ Starten Sie mit einer ersten Mitteilung für die aktive Firma oder Ihr Kundenkonto. Veröffentlichung erfolgt nach redaktioneller Prüfung auf beiden Portalen. +

+ + + +
+
+
01
+
Firma zuordnen
+
+
+
02
+
Mitteilung verfassen
+
+
+
03
+
Zur Prüfung senden
+
+
+
+ +
+ + + + + Tipp: Geprüfte Mitteilungen erscheinen i. d. R. binnen 4 Stunden werktags auf beiden Portalen. +
+
+ + +
+
+ Datenqualität + 2 offen +
+
+

+ Diese Hinweise helfen, Ihr User Backend vollständig und sauber zu halten. +

+ +
+
+ + + +
+
+
Profil unvollständig
+ 60 % +
+
+
+
+

+ Vorname, Telefon und Pressekontakt fehlen für saubere Kundenakte. +

+ Profil öffnen → +
+
+ +
+ + + +
+
+
Rechnungsadresse fehlt
+ 0 % +
+
+
+
+

+ Hinterlegen Sie eine Rechnungsadresse, damit spätere Buchungen sauber abgerechnet werden können. +

+ Rechnungsadresse ergänzen → +
+
+
+
+
+
+ + +
+ + +
+
+ Meine Firmen +
+ 0 zugeordnet + Profil & Firma verwalten → +
+
+ +
+
+ + +
+
+ + + +
+
Firma hinzufügen
+
Slot frei · 1 von 3
+
+
+

+ Pressestellen, für die Sie Mitteilungen erstellen — mit eigenem Logo, Kontaktperson und Themen-Tags. +

+ + + +
+ + +
+
Hinweis
+
+ Keine Firmen zugeordnet. Wenn hier eine Firma fehlen sollte, prüfen Sie bitte Ihr Profil oder wenden Sie sich an den Support. +
+ +
+
+
+
+ + +
+
+ Brand-Bridge + A · B +
+
+
+ Ein Konto, beide Portale — Veröffentlichungen werden parallel auf presseecho und businessportal24 ausgespielt. +
+ +
+
+
+ + presseecho +
+
verbunden
+
Archiv · Branchen-Tiefe
+
+
+
+ + businessportal24 +
+
verbunden
+
Wirtschaft · Live
+
+
+ +
+ +
+
+ API-Status + operational +
+
+ Letzte Synchronisation + vor 2 min +
+
+ Tarif + Starter +
+
+ + + Tarife & Add-ons ansehen → + +
+
+
+ + + + +
+
+
+
+ + + diff --git a/dev/frontend/tailwind_v3/User Dashboard presseportale.html b/dev/frontend/tailwind_v3/User Dashboard presseportale.html new file mode 100644 index 0000000..579b2fa --- /dev/null +++ b/dev/frontend/tailwind_v3/User Dashboard presseportale.html @@ -0,0 +1,764 @@ + + + + + +presseportale.com — Mein Dashboard + + + + + + + + + + + + + + +
+ +
+ + + + + +
+ + +
+
+ +
+ Hub + / + User Backend + / + Übersicht +
+ + + + + + presseecho + · + businessportal24 + + + + + +
+ + + + + + ⌘K +
+ + + + + + + + Neue Mitteilung + +
+
+ + +
+ + +
+
+
+ User Backend + Mein Bereich · A · 01 +
+

Mein Dashboard

+

+ Willkommen zurück, Test User. Hier sehen Sie Status und Reichweite Ihres Kundenkontos für presseecho und businessportal24. +

+
+ +
+ + + + + + + Keine Firma zugeordnet + zuordnen → + +
+
+ + +
+ +
+ +
+
Gesamt
+ 2026 +
+
0
+
+ + + 0 ggü. Vormonat + +
+ + + + + +
+ +
+ +
+
Veröffentlicht
+ live +
+
0
+
+ auf beiden Portalen +
+ + + + +
+ +
+ +
+
In Prüfung
+ Ø 4 h +
+
0
+
+ redaktionelle Prüfung +
+ + + + +
+ +
+ +
+
Entwürfe
+ privat +
+
0
+
+ gespeichert, nicht eingereicht +
+ + + +
+
+ + +
+ + +
+
+
+ Meine letzten Pressemitteilungen +
+
+ 0 von 0 + Alle anzeigen → +
+
+ + +
+ +
+ + + + + + 0 +
+
Noch keine Pressemitteilungen
+

+ Starten Sie mit einer ersten Mitteilung für die aktive Firma oder Ihr Kundenkonto. Veröffentlichung erfolgt nach redaktioneller Prüfung auf beiden Portalen. +

+ + + +
+
+
01
+
Firma zuordnen
+
+
+
02
+
Mitteilung verfassen
+
+
+
03
+
Zur Prüfung senden
+
+
+
+ +
+ + + + + Tipp: Geprüfte Mitteilungen erscheinen i. d. R. binnen 4 Stunden werktags auf beiden Portalen. +
+
+ + +
+
+ Datenqualität + 2 offen +
+
+

+ Diese Hinweise helfen, Ihr User Backend vollständig und sauber zu halten. +

+ +
+
+ + + +
+
+
Profil unvollständig
+ 60 % +
+
+
+
+

+ Vorname, Telefon und Pressekontakt fehlen für saubere Kundenakte. +

+ Profil öffnen → +
+
+ +
+ + + +
+
+
Rechnungsadresse fehlt
+ 0 % +
+
+
+
+

+ Hinterlegen Sie eine Rechnungsadresse, damit spätere Buchungen sauber abgerechnet werden können. +

+ Rechnungsadresse ergänzen → +
+
+
+
+
+
+ + +
+ + +
+
+ Meine Firmen +
+ 0 zugeordnet + Profil & Firma verwalten → +
+
+ +
+
+ + +
+
+ + + +
+
Firma hinzufügen
+
Slot frei · 1 von 3
+
+
+

+ Pressestellen, für die Sie Mitteilungen erstellen — mit eigenem Logo, Kontaktperson und Themen-Tags. +

+ + + +
+ + +
+
Hinweis
+
+ Keine Firmen zugeordnet. Wenn hier eine Firma fehlen sollte, prüfen Sie bitte Ihr Profil oder wenden Sie sich an den Support. +
+ +
+
+
+
+ + +
+
+ Brand-Bridge + A · B +
+
+
+ Ein Konto, beide Portale — Veröffentlichungen werden parallel auf presseecho und businessportal24 ausgespielt. +
+ +
+
+
+ + presseecho +
+
verbunden
+
Archiv · Branchen-Tiefe
+
+
+
+ + businessportal24 +
+
verbunden
+
Wirtschaft · Live
+
+
+ +
+ +
+
+ API-Status + operational +
+
+ Letzte Synchronisation + vor 2 min +
+
+ Tarif + Starter +
+
+ + + Tarife & Add-ons ansehen → + +
+
+
+ + + + +
+
+
+
+ + + diff --git a/dev/frontend/tailwind_v3/Veröffentlichen Tailwind.html b/dev/frontend/tailwind_v3/Veröffentlichen Tailwind.html index 197d255..e8a5c3a 100644 --- a/dev/frontend/tailwind_v3/Veröffentlichen Tailwind.html +++ b/dev/frontend/tailwind_v3/Veröffentlichen Tailwind.html @@ -165,7 +165,7 @@
Einreichen im Publisher-Bereich
-

Die Einreichung läuft über presseportale.com.

+

Die Einreichung läuft über pressekonto.de.

Dort verwalten Sie Mitteilungen, Credits und Newsroom — einmaliges Konto, beide Portale nutzbar (businessportal24 & presseecho.de).

@@ -342,7 +342,7 @@

Die Veröffentlichung erfolgt über den zentralen Publisher-Bereich auf - presseportale.com. + pressekonto.de. Cross-Publishing nach presseecho.de ist optional verfügbar.

@@ -583,7 +583,7 @@ Zum Publisher-Bereich - Einreichung läuft über presseportale.com · Login per Magic-Link + Einreichung läuft über pressekonto.de · Login per Magic-Link Oder zuerst Beispiele ansehen →
@@ -597,7 +597,7 @@
businessportal24
-

businessportal24 ist ein Service der Presseportale-Gruppe. Plattform für Pressemitteilungen mittelständischer Unternehmen, Selbstständiger und PR-Agenturen im deutschsprachigen Raum.

+

businessportal24 ist ein Service der Pressekonto-Gruppe. Plattform für Pressemitteilungen mittelständischer Unternehmen, Selbstständiger und PR-Agenturen im deutschsprachigen Raum.

Einreichen
@@ -628,7 +628,7 @@
-
© 2026 Presseportale-Gruppe · Alle Rechte vorbehalten
+
© 2026 Pressekonto-Gruppe · Alle Rechte vorbehalten
Für fachlich-spezifische Themen: presseecho.de → diff --git a/dev/migration 2026/00-OVERVIEW.md b/dev/migration 2026/00-OVERVIEW.md index a0d9f83..063294e 100644 --- a/dev/migration 2026/00-OVERVIEW.md +++ b/dev/migration 2026/00-OVERVIEW.md @@ -24,7 +24,7 @@ Diese Frontends sollen künftig **gegen das neue Backend arbeiten** – via dire ### 1.3 Neues Backend (Aufgabe dieses Projekts) -- Läuft unter `presseportale.test` / `presseportale.com` +- Läuft unter `pressekonto.test` / `pressekonto.de` - Stack: **Laravel 12, PHP 8.4, Livewire 4, Volt, Flux UI 2, MySQL 8, Tailwind 4** - **Vorarbeiten bereits vorhanden**: Admin-UI-Gerüst, Routes, Auth-Stack - **Noch zu tun**: Eloquent-Models, Migrations, Services, Daten-Migration, API, Payment (Stripe), Cron-Jobs @@ -58,7 +58,7 @@ Diese Frontends sollen künftig **gegen das neue Backend arbeiten** – via dire | Kriterium | Messbar an | |---|---| -| Backend unter `presseportale.test` erreichbar | HTTP 200 auf Login-Seite | +| Backend unter `pressekonto.test` erreichbar | HTTP 200 auf Login-Seite | | Admin-Login (Fortify + 2FA) funktioniert | Feature-Test `AuthTest` | | Customer-Portal via Magic-Link erreichbar | Feature-Test `MagicLinkLoginTest` | | Pressemitteilungen CRUD (Admin + Customer) | Livewire-Tests `PressReleaseIndex/Create/Edit/Show` | diff --git a/dev/migration 2026/02-TARGET-ARCHITECTURE.md b/dev/migration 2026/02-TARGET-ARCHITECTURE.md index e81f9e7..830c6bb 100644 --- a/dev/migration 2026/02-TARGET-ARCHITECTURE.md +++ b/dev/migration 2026/02-TARGET-ARCHITECTURE.md @@ -4,7 +4,7 @@ ``` ┌─────────────────────────────────────────────────────────────────────────┐ -│ Presseportale Backend (presseportale.test) │ +│ Pressekonto Backend (pressekonto.test) │ │ Laravel 12 · PHP 8.4 · Livewire 4 · Volt · Flux UI 2 │ │ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌─────────┐ │ @@ -268,7 +268,7 @@ app/ ## 6. Multi-Domain & Portal-Scope -- Pro Domain ein Frontend, aber alle Admin-Screens auf `presseportale.test`. +- Pro Domain ein Frontend, aber alle Admin-Screens auf `pressekonto.test`. - Middleware `SetCurrentPortal`: - Web (presseecho.test / businessportal24.test) → `app()->instance('current_portal', Portal::Presseecho|Businessportal24)` - Admin → Portal-Auswahl via Dropdown, gespeichert in Session (`current_portal`) diff --git a/dev/migration 2026/03-MIGRATION-PLAN.md b/dev/migration 2026/03-MIGRATION-PLAN.md index f179d58..4271fad 100644 --- a/dev/migration 2026/03-MIGRATION-PLAN.md +++ b/dev/migration 2026/03-MIGRATION-PLAN.md @@ -224,7 +224,7 @@ Die Views existieren bereits als Blade/Livewire-Stubs (`resources/views/admin/*` | 11.3 | Produktiv-Import-**Rehearsal** gegen aktuellen Legacy-Snapshot | ⬜ | | 11.4 | **Go-Live-Mailing**: Passwort-Reset + Sicherheitshinweis an alle User | 🔄 Command/Mailable fertig; Versand und finale Texte offen | | 11.5 | **API-Kunden-Kommunikation** (Token-Migration) | 🔄 Kundenreport fertig; Freigabeliste und operative Mailtexte offen | -| 11.6 | DNS-Cutover-Plan: `presseportale.com` auf neuen Server | ⬜ | +| 11.6 | DNS-Cutover-Plan: `pressekonto.de` auf neuen Server | ⬜ | | 11.7 | Read-Only-Modus auf Legacy-Systemen während Final-Import | ⬜ | | 11.8 | Abschalten der alten Symfony-Server (nach Review-Periode) | ⬜ | diff --git a/dev/migration 2026/07-API-MIGRATION.md b/dev/migration 2026/07-API-MIGRATION.md index 10c96e8..e29968d 100644 --- a/dev/migration 2026/07-API-MIGRATION.md +++ b/dev/migration 2026/07-API-MIGRATION.md @@ -175,8 +175,8 @@ Content-Type: application/json { "message": "Legacy API keys are no longer supported.", - "migration_url": "https://presseportale.com/account/tokens", - "docs_url": "https://presseportale.com/docs/api/v1" + "migration_url": "https://pressekonto.de/account/tokens", + "docs_url": "https://pressekonto.de/docs/api/v1" } ``` diff --git a/dev/migration 2026/08-PROGRESS.md b/dev/migration 2026/08-PROGRESS.md index 2a855eb..419b712 100644 --- a/dev/migration 2026/08-PROGRESS.md +++ b/dev/migration 2026/08-PROGRESS.md @@ -154,7 +154,7 @@ php artisan test --compact tests/Feature/LegacyInvoiceArchiveCommandTest.php tes ## 2026-05-04 – Architektur-Entscheidung: ein gemeinsames Admin-Panel mit rollenbasierter Sichtbarkeit -Der Auftraggeber hat festgelegt: **es gibt nur ein gemeinsames Admin-Panel** unter dem Presseportale-Backend. Admins, Editoren und Customer arbeiten im selben UI – Sichtbarkeit von Menüpunkten und Aktionen entscheidet die Rolle/Permission. +Der Auftraggeber hat festgelegt: **es gibt nur ein gemeinsames Admin-Panel** unter dem Pressekonto-Backend. Admins, Editoren und Customer arbeiten im selben UI – Sichtbarkeit von Menüpunkten und Aktionen entscheidet die Rolle/Permission. - Aktuell laufen Admin-/Editor-Funktionen unter `/admin/*` und Customer-Funktionen unter `/customer/*`. Diese Trennung wird **vor dem Pressemitteilungs-Veröffentlichungs-Block** in eine **gemeinsame Panel-Architektur** überführt. - Sidebar wird rollenbasiert gefiltert (Admin/Editor sehen alle PMs, Customer nur seine etc.). Routen-Konsolidierung Customer → Admin-Panel. @@ -318,7 +318,7 @@ Status in `03-MIGRATION-PLAN.md` ist auf `⏸️ Vertagt 2026-05-04` gesetzt. ### Was wurde gemacht #### Paket A – Test-Suite stabilisiert -- `phpunit.xml`: `APP_URL=https://presseportale.test` ergänzt, damit `route('login')` etc. nicht mehr auf eine fremde Domain ohne Auth-Routen zeigen. +- `phpunit.xml`: `APP_URL=https://pressekonto.test` ergänzt, damit `route('login')` etc. nicht mehr auf eine fremde Domain ohne Auth-Routen zeigen. - `tests/Feature/Auth/EmailVerificationTest.php`: Tests werden jetzt sauber per `markTestSkipped()` übersprungen, solange `Features::emailVerification()` in `config/fortify.php` deaktiviert ist. Sobald das Feature aktiviert wird, laufen die Tests automatisch wieder. - `tests/Feature/ExampleTest.php`: testet jetzt den Health-Endpoint `/up` statt der von Vite/Theme-Layout abhängigen Startseite. - Leerer `tests/Feature/Feature/` / `tests/Feature/Feature/Billing/`-Doppelpfad entfernt. diff --git a/dev/migration 2026/12-NAECHSTE-SCHRITTE.md b/dev/migration 2026/12-NAECHSTE-SCHRITTE.md index 08cca10..ae4429b 100644 --- a/dev/migration 2026/12-NAECHSTE-SCHRITTE.md +++ b/dev/migration 2026/12-NAECHSTE-SCHRITTE.md @@ -166,7 +166,7 @@ Hängt komplett an §2 (Stripe-Account + Produktliste). | 11.3 | Produktiv-Import-**Rehearsal** gegen aktuellen Legacy-Snapshot | 🔴 | ⬜ | | 11.4 | Go-Live-Mailing (Passwort-Reset + Sicherheitshinweis) versenden | 🔴 | 🔄 (Code fertig, Texte/Versand offen) | | 11.5 | API-Kunden-Kommunikation (Token-Migration) versenden | 🔴 | 🔄 (Report fertig, Texte/Versand offen) | -| 11.6 | DNS-Cutover-Plan: `presseportale.com` auf neuen Server | 🔴 | ⬜ | +| 11.6 | DNS-Cutover-Plan: `pressekonto.de` auf neuen Server | 🔴 | ⬜ | | 11.7 | Read-Only-Modus auf Legacy-Systemen während Final-Import | 🔴 | ⬜ | | 11.8 | Abschalten der alten Symfony-Server (nach Review-Periode) | 🟡 | ⬜ | diff --git a/dev/migration 2026/MIGRATION-STEPS.md b/dev/migration 2026/MIGRATION-STEPS.md index fe4d58c..ce96c6b 100644 --- a/dev/migration 2026/MIGRATION-STEPS.md +++ b/dev/migration 2026/MIGRATION-STEPS.md @@ -8,6 +8,8 @@ Stand: 2026-05-04. Dieses Kurz-Runbook spiegelt den aktuell implementierten Comm php artisan legacy:import --source=all --dry-run php artisan legacy:archive-invoices --dry-run php artisan legacy:verify --no-report +php artisan legacy:migrate-media --portal=all --type=all --base-path=dev/migration --dry-run + ``` Hinweis: `legacy:archive-invoices` importiert die Legacy-Rechnungen vollständig in `legacy_invoices`, inkl. Status/User-Zuordnung, `raw_snapshot`, `pdf_payload` und Report. Die PDF-Erzeugung erfolgt im Customer-Bereich bei Abruf aus diesen Archivdaten. @@ -38,6 +40,7 @@ php artisan legacy:import --source=all --force php artisan legacy:archive-invoices php artisan legacy:fix-timestamps php artisan legacy:verify +php artisan legacy:migrate-media --portal=all --type=all --base-path=dev/migration ``` ## Noch nicht im Runbook finalisiert diff --git a/dev/migration 2026/README.md b/dev/migration 2026/README.md index d293924..3ce290c 100644 --- a/dev/migration 2026/README.md +++ b/dev/migration 2026/README.md @@ -1,6 +1,6 @@ -# Migration 2026 – Presseportale Backend +# Migration 2026 – Pressekonto Backend -> **Migration des Backends** der beiden Legacy-Portale `presseecho` und `businessportal24` (Symfony 1.4, PHP 5.6) in ein **gemeinsames, modernes Laravel 12 Backend** unter der Domain `presseportale.test` / `presseportale.com`. +> **Migration des Backends** der beiden Legacy-Portale `presseecho` und `businessportal24` (Symfony 1.4, PHP 5.6) in ein **gemeinsames, modernes Laravel 12 Backend** unter der Domain `pressekonto.test` / `pressekonto.de`. **Start:** 23.04.2026 **Lead-Technologie:** Laravel 12 · PHP 8.4 · Livewire 4 · Volt · Flux UI 2 · Tailwind CSS 4 · MySQL 8 @@ -43,7 +43,7 @@ Historisch existieren zwei technisch identische Symfony-1.4-Installationen (`pre - **DB-Dumps** (2026-04-23): `businessportal24` 42 Tabellen / 578 MB, `presseecho` 43 Tabellen / 369 MB – 41 Tabellen sind strukturell identisch, 3 abweichend (`press_release_image_old` nur BP24, `category_pe_data` + `press_release_pe_data` nur PE) Aktueller Implementierungsstand (Code-Abgleich 2026-04-29): -- ✅ **Domain-basiertes Theme-System** (`presseportale` / `presseecho` / `businessportal24`) +- ✅ **Domain-basiertes Theme-System** (`pressekonto` / `presseecho` / `businessportal24`) - ✅ **Admin-UI** mit echten Daten für Dashboard, Users/Roles, Companies, Contacts, Categories-Index und PressRelease-CRUD/-Workflow - ✅ **Auth-Stack**: Fortify, Sanctum, Spatie/Permission - ✅ **Admin-Schutz und Portal-Scoping**: `EnsureUserIsAdmin`, `SetCurrentPortal`, `PortalScope`, Sidebar-Portal-Switcher diff --git a/docker-compose.yml b/docker-compose.yml index afe468d..c89d938 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,7 +26,7 @@ services: DB_PORT: 3306 # Hier definieren wir nur die Haupt-Datenbank für .env # Die anderen beiden richtest du in Laravel ein - DB_DATABASE: presseportale + DB_DATABASE: pressekonto DB_USERNAME: root DB_PASSWORD: password MAIL_HOST: global-mailpit @@ -40,23 +40,23 @@ services: labels: - "traefik.enable=true" # Portal Domain - - "traefik.http.routers.presseportale.rule=Host(`presseportale.test`)" - - "traefik.http.routers.presseportale.entrypoints=websecure" - - "traefik.http.routers.presseportale.tls=true" - - "traefik.http.routers.presseportale.service=presseportale-service-prc" + - "traefik.http.routers.pressekonto.rule=Host(`pressekonto.test`)" + - "traefik.http.routers.pressekonto.entrypoints=websecure" + - "traefik.http.routers.pressekonto.tls=true" + - "traefik.http.routers.pressekonto.service=pressekonto-service-prc" # Presseecho Domain - "traefik.http.routers.presseecho.rule=Host(`presseecho.test`)" - "traefik.http.routers.presseecho.entrypoints=websecure" - "traefik.http.routers.presseecho.tls=true" - - "traefik.http.routers.presseecho.service=presseportale-service-prc" + - "traefik.http.routers.presseecho.service=pressekonto-service-prc" # Business Portal Domain - "traefik.http.routers.businessportal.rule=Host(`businessportal24.test`)" - "traefik.http.routers.businessportal.entrypoints=websecure" - "traefik.http.routers.businessportal.tls=true" - - "traefik.http.routers.businessportal.service=presseportale-service-prc" + - "traefik.http.routers.businessportal.service=pressekonto-service-prc" # Asset Domain für Vite-Server Portal (Port 5177) - - "traefik.http.routers.assets-portal.rule=Host(`assets.presseportale.test`)" + - "traefik.http.routers.assets-portal.rule=Host(`assets.pressekonto.test`)" - "traefik.http.routers.assets-portal.entrypoints=websecure" - "traefik.http.routers.assets-portal.tls=true" - "traefik.http.routers.assets-portal.service=assets-portal-service-prc" @@ -74,7 +74,7 @@ services: - "traefik.http.routers.assets-businessportal.service=assets-web-service-prc" # Service Definition - NUR EINMAL! - - "traefik.http.services.presseportale-service-prc.loadbalancer.server.port=80" + - "traefik.http.services.pressekonto-service-prc.loadbalancer.server.port=80" - "traefik.http.services.assets-portal-service-prc.loadbalancer.server.port=5177" - "traefik.http.services.assets-portal-service-prc.loadbalancer.server.scheme=http" - "traefik.http.services.assets-web-service-prc.loadbalancer.server.port=5178" diff --git a/phpunit.xml b/phpunit.xml index b00fa95..21f22e5 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -19,7 +19,7 @@ - + diff --git a/resources/css/portal.css b/resources/css/portal.css index eba4af4..f7fdcc2 100644 --- a/resources/css/portal.css +++ b/resources/css/portal.css @@ -1,6 +1,23 @@ @import "tailwindcss"; @import "../../vendor/livewire/flux/dist/flux.css"; +/** + * Hub × FluxUI — Phase 1: Portal-Shell auf Hub-Design. + * + * Tokens leben in shared/design-tokens.css (Single Source of Truth aus Phase 0). + * Hier: + * 1. Tokens importieren + * 2. Zinc-Skala auf Hub-Buchpapier-Familie mappen (für FluxUI-Komponenten, + * die ihre Skala-Defaults aus Zinc beziehen) + * 3. FluxUI-Akzent (--color-accent) auf Hub-Blau umstellen + * 4. FluxUI-Komponenten via [data-flux-*]-Selektoren ans Hub-Design angleichen + * (Sidebar, Navlist-Active, Primary-Buttons, Cards) + * + * Dokumentation: dev/frontend/hub-flux/02-PHASE-1-PORTAL-SHELL.md + */ +@import "./shared/design-tokens.css"; +@import "./shared/hub-components.css"; + @source '../views'; @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; @source '../../vendor/livewire/flux-pro/stubs/**/*.blade.php'; @@ -9,34 +26,46 @@ @custom-variant dark (&:where(.dark, .dark *)); @theme { - --font-sans: "Instrument Sans", ui-sans-serif, system-ui, sans-serif, + /* Font: Inter Tight statt Instrument Sans + (Token --font-sans aus design-tokens.css wird hier nochmal explizit + gesetzt, weil FluxUI zuvor seinen eigenen Wert setzen würde) */ + --font-sans: + "Inter Tight", Inter, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - --color-zinc-50: var(--color-neutral-50); - --color-zinc-100: var(--color-neutral-100); - --color-zinc-200: var(--color-neutral-200); - --color-zinc-300: var(--color-neutral-300); - --color-zinc-400: var(--color-neutral-400); - --color-zinc-500: var(--color-neutral-500); - --color-zinc-600: var(--color-neutral-600); - --color-zinc-700: var(--color-neutral-700); - --color-zinc-800: var(--color-neutral-800); - --color-zinc-900: var(--color-neutral-900); - --color-zinc-950: var(--color-neutral-950); + /* FluxUI-Akzent (für Buttons, Focus-Rings, Active-States) auf Hub-Blau. + Vorher: #3ea3dc (Starter-Kit-Türkis). */ + --color-accent: var(--color-hub); + --color-accent-content: var(--color-hub); + --color-accent-foreground: #ffffff; - --color-accent: #3ea3dc; - --color-accent-content: #3ea3dc; - --color-accent-foreground: var(--color-white); + /* Zinc-Skala auf warmes Buchpapier mappen. + FluxUI nutzt Zinc als neutrale Skala für Sidebars, Borders, Text. + Wir bridgen die ganze Skala, damit der Look automatisch auf Hub-Stil + umschwenkt — ohne dass wir hunderte FluxUI-Klassen einzeln umbiegen + müssen. */ + --color-zinc-50: #fbfaf6; + --color-zinc-100: #f6f4ef; + --color-zinc-200: #e2ddd0; + --color-zinc-300: #cfc8b5; + --color-zinc-400: #8a918d; + --color-zinc-500: #5a6360; + --color-zinc-600: #3a413d; + --color-zinc-700: #1a1f1c; + --color-zinc-800: #243152; + --color-zinc-900: #1a2540; + --color-zinc-950: #0f1729; } -@layer theme { - .dark { - --color-accent: #3ea3dc; - --color-accent-content: #5bb8e6; - --color-accent-foreground: var(--color-white); - } -} +/* Phase 5: Dark-Mode-Mapping liegt jetzt vollständig in + shared/design-tokens.css (`.dark { … }`). FluxUI Appearance-Switcher + setzt `class="dark"` auf , alle `--color-*`-Vars schalten + automatisch um — inklusive `--color-accent`, weil das oben im @theme + per `var(--color-hub)`-Verweis dynamisch ist. + + Der Notfall-Hack aus Phase 1 (`.dark { --color-accent: var(--color-hub) }`) + ist damit gegenstandslos und entfernt. */ @layer base { *, @@ -48,6 +77,10 @@ } } +/* ============================================================ + * FluxUI Form-Felder — Layout vom Starter-Kit übernommen + * Input-Focus wird weiter unten im Kontrast-Tuning auf Hub-Blau gesetzt. + * ============================================================ */ [data-flux-field]:not(ui-radio, ui-checkbox) { @apply grid gap-2; } @@ -56,12 +89,165 @@ @apply !mb-0 !leading-tight; } +/* ============================================================ + * Phase 1 — Hub-Style-Overrides für FluxUI-Komponenten + * ============================================================ + * + * Strategie: minimal-invasive Overrides via [data-flux-*]-Attribute und + * der Tailwind-Klassen, die FluxUI auf seinen Komponenten setzt. Wir + * ändern KEINE Vendor-Dateien, sondern legen unsere Styles mit höherer + * Spezifität darüber. + * + * Wichtig: FluxUI nutzt für variant-spezifisches Styling KEINE + * `data-variant`-Attribute, sondern direkt Tailwind-Klassen wie + * `bg-[var(--color-accent)]` (für variant="primary"). Wir greifen + * deshalb über diese Klassen-Selektoren. + * + * Bei FluxUI-Updates können sich diese Klassen ändern — Selektoren bewusst + * konservativ, gut kommentiert. Visueller Smoke-Test pro Release-Bump. + * ============================================================ */ + +/* Sidebar — warmes Buchpapier statt Zinc-Grau, klare Trennlinie */ +[data-flux-sidebar] { + background: var(--color-bg-elev); + border-color: var(--color-bg-rule); +} + +/* Sidebar-Section-Headings — Mockup-Konvention: + 10 px, fett, gesperrt, anthrazit */ +[data-flux-navlist] [data-flux-navlist-group-heading], +[data-flux-navlist] [data-flux-group-heading] { + font-size: 10px; + font-weight: 700; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--color-ink-4); + padding-bottom: 6px; +} + +/* Navlist-Item — Hub-Stil: kompakter, mit Active-Strip links */ +[data-flux-navlist-item] { + font-size: 13px; + font-weight: 500; + color: var(--color-ink-2); + border-radius: var(--radius-sm); + transition: + background 0.12s, + color 0.12s; +} + +[data-flux-navlist-item]:hover { + background: var(--color-bg); + color: var(--color-hub); +} + +[data-flux-navlist-item][data-current="true"], +[data-flux-navlist-item][aria-current="page"], +[data-flux-navlist-item].active { + background: var(--color-hub-soft); + color: var(--color-hub); + font-weight: 600; + position: relative; +} + +[data-flux-navlist-item][data-current="true"]::before, +[data-flux-navlist-item][aria-current="page"]::before, +[data-flux-navlist-item].active::before { + content: ""; + position: absolute; + left: -1px; + top: 6px; + bottom: 6px; + width: 2px; + background: var(--color-hub); + border-radius: 0 2px 2px 0; +} + +/* ============================================================ + * FluxUI Buttons — Hub-Stil + * ============================================================ + * FluxUI rendert `` als + * class="… bg-[var(--color-accent)] + * hover:bg-[color-mix(in_oklab,_var(--color-accent),_transparent_10%)] + * shadow-[inset_0px_1px_--theme(--color-white/.2)] …" + * + * `--color-accent` haben wir auf `var(--color-hub)` (#1A2540) gesetzt → + * Default-Background passt schon. ABER: + * + * 1. Der Hover ("10 % transparent") wirkt auf hellem Buchpapier + * hellblau — wir wollen statt dessen Hub-2 (#243152, dunkler) wie + * auf der Hub-Landing (`hover:bg-hub-2`). + * 2. FluxUI's Default-Shadow (1 px Weiß-Inset) braucht auf dem warmen + * Hintergrund mehr Kontrast für klare Button-Kanten. + * + * Wir greifen über `data-flux-button` (Attribut auf dem gerenderten + *
{{-- Warteschlange Prüfung --}} -
-
-

{{ __('Zur Prüfung') }}

- @if($stats['press_releases']['review'] > 0) - - {{ $stats['press_releases']['review'] }} +
+
+ {{ __('Zur Prüfung') }} + @if ($stats['press_releases']['review'] > 0) + + {{ $stats['press_releases']['review'] }} {{ __('offen') }} + @else + {{ __('leer') }} @endif
-
- @forelse($pendingReviews as $pr) - -

{{ $pr->title }}

-

- {{ $pr->company?->name ?? '–' }} · {{ $pr->portal->label() }} · {{ $pr->created_at->format('d.m.Y') }} -

-
- @empty -

{{ __('Keine PMs in der Prüfwarteschlange.') }}

- @endforelse -
- @if($stats['press_releases']['review'] > count($pendingReviews)) - -
+ + + + {{-- ============== NEWSLETTER + QUICK ACTIONS ============== --}} +
+ + {{-- Newsletter-Stat als panel-warm Block --}} +
+
+ {{ __('Newsletter') }} + {{ __('bestätigt') }} +
+
+
+ {{ number_format($stats['newsletter']) }} +
+

+ {{ __('Aktive Newsletter-Abonnenten über beide Portale.') }} +

+ + {{ __('Sync verwalten') }} → + +
+
+ + {{-- Quick-Actions Panel --}} +
+
+ {{ __('Quick Actions') }} +
+
+ @foreach ([ + ['icon' => 'newspaper', 'label' => __('Pressemitteilungen'), 'route' => 'admin.press-releases.index'], + ['icon' => 'building-office', 'label' => __('Firmen'), 'route' => 'admin.companies.index'], + ['icon' => 'document-text', 'label' => __('Rechnungen'), 'route' => 'admin.invoices.index'], + ['icon' => 'cog', 'label' => __('Voreinstellungen'), 'route' => 'admin.presets.index'], + ] as $action) + + + + + + {{ $action['label'] }} + + + @endforeach +
+
+
+ + {{-- ============== FOOTER ============== --}} +
diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php index 3a92828..71b95dd 100644 --- a/resources/views/components/layouts/app.blade.php +++ b/resources/views/components/layouts/app.blade.php @@ -6,18 +6,23 @@ @endphp @if($canCustomer) -
+ {{-- Hub-Stil-Banner: Hub-Soft-Hintergrund, Hub-Blau-Badge, + dezente Buchpapier-Rule. Ersetzt das Zinc-Starter-Kit-Card. --}} +
-
- {{ __('User Backend') }} -
diff --git a/resources/views/components/layouts/app/sidebar.blade.php b/resources/views/components/layouts/app/sidebar.blade.php index 8d62e13..c891da7 100644 --- a/resources/views/components/layouts/app/sidebar.blade.php +++ b/resources/views/components/layouts/app/sidebar.blade.php @@ -1,13 +1,25 @@ - +{{-- + Hub × FluxUI Phase 1 — Portal-Shell im Hub-Design. + class="dark" wurde entfernt; Light Mode ist Default, Dark kommt mit + FluxUI Appearance-Switcher in Phase 5. +--}} + @include('partials.head') - - + + - - + + {{-- Brand-Block: Wortmarke + Hub-Eyebrow --}} + + + + +
+ Publisher · Hub +
@php @@ -158,43 +170,42 @@ @endauth @if($impersonator) -
- {{ __('Testmodus aktiv') }} - - {{ __('Angemeldet als :user. Admin: :admin.', ['user' => $user?->name, 'admin' => $impersonator->name]) }} - - -
- @csrf - - {{ __('Zurück zum Admin') }} - -
+ {{-- Testmodus-Block im Hub-Stil (statt Amber-Warnfarbe). + Dunkles Hub-Blau-Panel mit Bernstein-Eyebrow, klare + CTA „Zurück zum Admin" als helle Pille. --}} +
+
+
+
+
+ + + {{ __('Testmodus aktiv') }} + +
+

+ {{ __('Angemeldet als') }} + {{ $user?->name }}.
+ {{ __('Admin:') }} + {{ $impersonator->name }} +

+
+ @csrf + +
+
@endif - - - - - {{ __('Tailwind CSS') }} - - - {{ __('Hero Icons') }} - - - {{ __('Flux UI') }} - - - {{ __('Repository') }} - - - - {{ __('Documentation') }} - - - + {{-- Phase 5: Appearance-Switcher direkt im User-Menü. + `$flux.appearance` ist FluxUIs Magic-Object, persistent + über LocalStorage. Werte: 'light' | 'dark' | 'system'. --}} +
+
+ {{ __('Erscheinung') }} +
+ + + + + +
+ + +
@csrf @@ -245,8 +272,10 @@ - - + + + + @@ -284,6 +313,20 @@ + {{-- Phase 5: Appearance-Switcher (Mobile-Dropdown). --}} +
+
+ {{ __('Erscheinung') }} +
+ + + + + +
+ + + @csrf diff --git a/resources/views/components/layouts/auth/pressekonto.blade.php b/resources/views/components/layouts/auth/pressekonto.blade.php new file mode 100644 index 0000000..c0653b1 --- /dev/null +++ b/resources/views/components/layouts/auth/pressekonto.blade.php @@ -0,0 +1,154 @@ +@props([ + 'title' => null, + 'eyebrow' => 'Publisher-Hub', + 'heading' => null, + 'topRightLabel' => null, + 'topRightLinkText' => null, + 'topRightLinkHref' => null, + 'showFromBanner' => true, +]) + +@php + $brand = config('domains.domains.pressekonto.brand', []); + $from = request()->query('from'); + + $brandLabelMap = [ + 'presseecho' => 'presseecho.de', + 'businessportal24' => 'businessportal24.com', + ]; + $fromBrandLabel = $brandLabelMap[$from] ?? null; + + $pageTitle = $title ?? ($brand['meta_title'] ?? 'pressekonto – Publisher-Hub'); + + config([ + 'app.theme' => 'pressekonto', + 'app.view_prefix' => 'web', + ]); + $themeCssPath = \App\Helpers\ThemeHelper::getThemeCssPath(); + $assetsDir = config('domains.domains.pressekonto.assets_dir', 'build/web'); + \Illuminate\Support\Facades\Vite::useBuildDirectory($assetsDir); +@endphp + + + + + + + + + {{ $pageTitle }} + + + + + + + + {{-- Nur CSS aus dem Web-Build laden. Alpine bringt @livewireScripts mit; + würden wir hier zusätzlich resources/js/app.js mit Alpine.start() + laden, gäbe es zwei Alpine-Instanzen und wire:submit, x-data, + wire:model würden brechen (siehe Browser-Logs vor diesem Fix). --}} + @vite([$themeCssPath], $assetsDir) + @livewireStyles + + + + +
+ + {{-- Atmosphäre: subtiles Raster --}} + + + {{-- Atmosphäre: konzentrische Kreise um die Bildmitte --}} + + + {{-- 3px Hub-Blau-Streifen --}} +
+ + {{-- Header --}} +
+ + + + + + + + + @if ($topRightLinkText && $topRightLinkHref) + + @if ($topRightLabel) + {{ $topRightLabel }} + @endif + {{ $topRightLinkText }} + + @endif +
+ + {{-- Auth-Card --}} +
+
+ + @if ($showFromBanner && $fromBrandLabel) +
+ Sie kommen von {{ $fromBrandLabel }}. + Ihr Konto funktioniert für beide Portale – + presseecho.de und businessportal24.com. +
+ @elseif ($showFromBanner) +
+ Ihr Konto funktioniert auch für + presseecho.de + und + businessportal24.com. +
+ @endif + +
+ @if ($eyebrow) +
{{ $eyebrow }}
+ @endif + + @if ($heading) +

+ {{ $heading }} +

+ @endif + + {{ $slot }} +
+
+
+ + {{-- Micro-Footer --}} + +
+ +@livewireScripts + + diff --git a/resources/views/components/portal/hint-card.blade.php b/resources/views/components/portal/hint-card.blade.php new file mode 100644 index 0000000..67733f5 --- /dev/null +++ b/resources/views/components/portal/hint-card.blade.php @@ -0,0 +1,64 @@ +@props([ + /** + * Heroicon-Name (ohne flux:icon Prefix), z.B. user, archive-box, newspaper. + * Wird unten via flux:icon gerendert. + */ + 'icon' => 'information-circle', + + /** Titel (fett, dunkel) */ + 'title' => '', + + /** Vollständigkeitswert in Prozent (0–100) für die Progress-Bar */ + 'percent' => null, + + /** Ziel-URL der Aktion (Pflicht für ein klickbares Hint) */ + 'href' => null, + + /** Optionaler Action-Text — wenn null wird `action`-Slot oder „Öffnen“ verwendet */ + 'action' => null, + + /** Wenn `true`, wird das Hint als Volt-`wire:navigate`-Link gerendert */ + 'navigate' => true, +]) + +@php + $percent = $percent !== null ? max(0, min(100, (int) $percent)) : null; +@endphp + +
+ + + + +
+
+
+ {{ $title }} +
+ + @if ($percent !== null) + {{ $percent }} % + @endif +
+ + @if ($percent !== null) +
+ +
+ @endif + +

+ {{ $slot }} +

+ + @if ($href) + + {{ $action ?? (isset($actionSlot) ? $actionSlot : __('Öffnen')) }} → + + @endif +
+
diff --git a/resources/views/components/portal/stat-card.blade.php b/resources/views/components/portal/stat-card.blade.php new file mode 100644 index 0000000..c02cc46 --- /dev/null +++ b/resources/views/components/portal/stat-card.blade.php @@ -0,0 +1,37 @@ +@props([ + /** + * Strip- und Label-Farbvariante. + * Erlaubte Werte: primary | ok | warn | muted. + * Mockup: dev/frontend/tailwind_v3/User Dashboard presseportale.html + */ + 'variant' => 'muted', + + /** Eyebrow-Label oben links (UPPERCASE, sperrgesetzt) */ + 'label' => '', + + /** Hauptzahl in JetBrains Mono */ + 'value' => 0, +]) + +@php + $allowedVariants = ['primary', 'ok', 'warn', 'muted']; + $variant = in_array($variant, $allowedVariants, true) ? $variant : 'muted'; +@endphp + +
class(['stat-card', "is-{$variant}"]) }}> + + +
+
{{ $label }}
+ + @isset($meta) + {{ $meta }} + @endisset +
+ +
{{ $value }}
+ + @isset($trend) +
{{ $trend }}
+ @endisset +
diff --git a/resources/views/components/web/brand-mark.blade.php b/resources/views/components/web/brand-mark.blade.php index 42fffff..ab8db8c 100644 --- a/resources/views/components/web/brand-mark.blade.php +++ b/resources/views/components/web/brand-mark.blade.php @@ -1,5 +1,5 @@ @props([ - 'brand' => 'presseportale', + 'brand' => 'pressekonto', 'variant' => 'auto', 'serif' => true, ]) @@ -9,47 +9,66 @@ * Zentrale Brand-Wortmarke für alle drei Marken der Verlags-Familie. * * Schreibweise (verbindlich): - * - presseecho → "presse" + "echo" (echo ist die Akzentfarbe) - * - businessportal24 → "businessportal" + "24" (24 ist orange) - * - presseportale → "presse" + "portale" (portale ist Bernstein) + * - presseecho → "presse" + "echo" (echo grün) + * - businessportal24 → "businessportal" + "24" (24 orange) + * - pressekonto → "presse" + "konto" (konto bernstein) * * Keine TLD-Endung (".de", ".com") direkt am Markennamen. Diese gehören * – falls überhaupt – getrennt in den juristischen Bereich (Impressum, Kontakt). * * Schriftart: * - Standard `font-serif` (Source Serif 4) – passt zum Editorial-Charakter - * von Presseecho und BusinessPortal24. Der Hub lädt Source Serif 4 - * ebenfalls mit, damit Markennennungen typografisch konsistent bleiben. + * aller drei Portale. * - `:serif="false"` schaltet auf font-sans (Inter Tight) – etwa für die * Top-Utility-Bar, in der die Marken sehr klein erscheinen. * * Variant: - * - `auto` → Akzentfarbe = Theme-Default (Orange / Grün / Bernstein) - * - `on-dark` → hellere/wärmere Akzentfarbe (für dunkle Hub-Panels) - * - `mono` → Akzent identisch zum Basis-Ton (z. B. wenn beides weiß sein soll) + * - `auto` → Name + Akzent in den Marken-Standardfarben (auf hellem Grund) + * - `on-dark` → Name in Weiß (Negativ), Akzent in der dunkel-tauglichen Variante + * - `mono` → Name + Akzent erben vom Parent (z. B. wenn beides weiß sein soll) + * + * Logo-Farben (siehe Brand-Manual): + * - businessportal: #232A33 (auf hell) / #FFFFFF (negativ) + * - presse (Echo): #1B2417 (auf hell) / #FFFFFF (negativ) + * - presse (Konto): #1A2540 (auf hell) / #FFFFFF (negativ) + * - 24: #C84A1E immer + * - echo: #345636 (auf hell) / #9BD5B2 (negativ) + * - konto: #B07A3A immer */ $marks = [ 'presseecho' => [ 'name' => 'presse', 'accent' => 'echo', + 'name_color_auto' => '#1B2417', + 'name_color_on_dark' => '#FFFFFF', 'accent_color_auto' => '#345636', 'accent_color_on_dark' => '#9BD5B2', ], 'businessportal24' => [ 'name' => 'businessportal', 'accent' => '24', + 'name_color_auto' => '#232A33', + 'name_color_on_dark' => '#FFFFFF', 'accent_color_auto' => '#C84A1E', 'accent_color_on_dark' => '#C84A1E', ], - 'presseportale' => [ + 'pressekonto' => [ 'name' => 'presse', - 'accent' => 'portale', + 'accent' => 'konto', + 'name_color_auto' => '#1A2540', + 'name_color_on_dark' => '#FFFFFF', 'accent_color_auto' => '#B07A3A', 'accent_color_on_dark' => '#B07A3A', ], ]; - $mark = $marks[$brand] ?? $marks['presseportale']; + $mark = $marks[$brand] ?? $marks['pressekonto']; + + $nameColor = match ($variant) { + 'on-dark' => $mark['name_color_on_dark'], + 'mono' => 'inherit', + default => $mark['name_color_auto'], + }; $accentColor = match ($variant) { 'on-dark' => $mark['accent_color_on_dark'], @@ -62,5 +81,6 @@ $baseAttributes = $attributes->merge(['class' => $fontClass]); @endphp -{{ $mark['name'] }}{{ $mark['name'] }}{{ $mark['accent'] }} diff --git a/resources/views/components/web/hub/site-footer.blade.php b/resources/views/components/web/hub/site-footer.blade.php index 2f9cbda..f630891 100644 --- a/resources/views/components/web/hub/site-footer.blade.php +++ b/resources/views/components/web/hub/site-footer.blade.php @@ -3,19 +3,19 @@ ]) @php - $themeKey = config('app.theme', 'presseportale'); + $themeKey = config('app.theme', 'pressekonto'); $brand = $brand ?? config('domains.domains.' . $themeKey . '.brand', []); $brandTagline = $brand['tagline_short'] ?? 'Publisher · Hub'; $brandTaglineLong = $brand['tagline_long'] ?? 'Der gemeinsame Publisher-Bereich für presseecho und businessportal24.'; - $footerLegal = str_replace(':year', (string) now()->year, $brand['footer_legal'] ?? '© ' . now()->year . ' presseportale'); + $footerLegal = str_replace(':year', (string) now()->year, $brand['footer_legal'] ?? '© ' . now()->year . ' pressekonto'); @endphp