# Flux CMS Integration – Entwicklungsplan > **Ziel:** Integration des flux-cms Packages für die b2in-Webseite. > **Scope:** Nur b2in – weitere Subseiten (b2a, stileigentum, style2own) folgen später. > **Stand:** 2026-03-18 --- ## Ausgangslage ### Was existiert - **Package:** `packages/flux-cms/` (core, components, starter-components) liegt im Projekt - **Composer:** `packages/*/*` Repository-Pfad ist in `composer.json` konfiguriert - **Frontend:** Vollständige b2in-Webseite mit ~15 Seiten - **Content-Quelle:** `config/content.php` – statische PHP-Arrays pro Theme - **Content-Zugriff:** Livewire-Sections laden via `config("content.themes.{$theme}.{$section}")` - **Immobilien/Projekte:** Komplett in `config/content.php` definiert (Slug, Titel, Preise, Galerie, Quick Facts, Investment Case, Location etc.), Route `immobilien/{slug}` liest direkt aus Config - **Admin-Portal:** `portal.b2in.test` mit eigenem CMS (Cabinets/Displays), User-/Partner-Management - **Domain-System:** Multi-Domain-Setup in `config/domains.php` ### Was fehlt - flux-cms/core ist **nicht** als Composer-Dependency installiert - Keine `app/helpers.php` mit `cms()`/`tcms()`/`cms_media_url()` - Keine `config/flux-cms.php` publiziert - Keine `flux_cms_*` Datenbanktabellen - Keine Admin-Views/Routes für das CMS - Keine Medienbibliothek - Kein Immobilien-Model (Projekte leben in Config) ### Scope-Einschränkung Phase 1 **Nur diese Tabellen werden initial benötigt:** - `flux_cms_contents` – Alle Seiteninhalte (Key-Value mit Übersetzungen) - `flux_cms_media` – Medienbibliothek (Bilder, PDFs) **Nicht benötigt (kommt später bei Bedarf):** - ~~`flux_cms_news_items`~~ – Nachrichteneinträge - ~~`flux_cms_industries`~~ – Branchen - ~~`flux_cms_faqs`~~ – FAQ-Einträge - ~~`flux_cms_downloads`~~ – Downloads - ~~`flux_cms_linkedin_posts`~~ – LinkedIn-Posts - ~~`flux_cms_search_index`~~ – Suchindex **Zusätzlich benötigt:** - Neues **Immobilien/Projekte-Model** mit eigenem CRUD im CMS-Backend (ersetzt die statischen Projekte aus `config/content.php`) --- ## Phasen-Übersicht | Phase | Beschreibung | Abhängig von | |-------|-------------|--------------| | **1** | Package-Installation & Infrastruktur | – | | **2** | Immobilien-Model & CRUD | Phase 1 | | **3** | Content-Migration (config → DB) | Phase 1 | | **4** | CMS Admin-Backend | Phase 1 | | **5** | Frontend-Umstellung (config → cms) | Phase 2, 3 | | **6** | Medienbibliothek & Bilder | Phase 1, 4 | | **7** | Tests | Phase 2–6 | | **8** | Feinschliff & Dokumentation | Phase 5–7 | --- ## Phase 1 – Package-Installation & Infrastruktur ### 1.1 Composer-Dependency installieren ```bash composer require flux-cms/core:@dev composer require intervention/image ``` **Prüfen:** - [ ] `FluxCmsServiceProvider` wird automatisch geladen - [ ] Keine Konflikte mit bestehenden Dependencies ### 1.2 Konfiguration publizieren ```bash php artisan vendor:publish --tag=flux-cms-config ``` **Anpassen in `config/flux-cms.php`:** - `default_locale` → `'de'` - `locales` → `['de' => 'Deutsch', 'en' => 'English']` - `media.profiles` → an b2in-Bildgrößen anpassen - `routes.enabled` → `false` (eigene Admin-Routes im Portal) ### 1.3 Migrations ausführen **Nur die benötigten Migrations:** - `create_flux_cms_contents_table` - `create_flux_cms_media_table` Die restlichen Migrations (news, industries, faqs, downloads, linkedin, search_index) werden **nicht ausgeführt** – sie liegen im Package und können bei Bedarf später migriert werden. **Optionen:** - A) Alle Migrations laufen lassen (Tabellen existieren, werden aber nicht genutzt) – einfacher - B) Nur selektiv migrieren – sauberer, erfordert ggf. Anpassung am ServiceProvider → **Empfehlung: Option A** – leere Tabellen stören nicht und vereinfachen spätere Erweiterung. ```bash php artisan migrate ``` ### 1.4 Helper-Funktionen einrichten **Erstellen:** `app/helpers.php` mit `cms()`, `tcms()`, `cms_media_url()`, `media_url()` **Registrieren in `composer.json`:** ```json "autoload": { "files": ["app/helpers.php"] } ``` ```bash composer dump-autoload ``` ### 1.5 Storage-Link ```bash php artisan storage:link ``` **Ergebnis Phase 1:** Package installiert, DB-Tabellen vorhanden, Helper verfügbar. --- ## Phase 2 – Immobilien/Projekte-Model & CRUD ### 2.1 Datenstruktur analysieren Aktuelle Projekt-Daten aus `config/content.php` (am Beispiel Azizi Creek Views 4): | Feld | Typ | Beispiel | |------|-----|---------| | `slug` | string | `azizi-creek-views-4` | | `title` | string | `Azizi Developments: Creek Views 4` | | `location` | string | `Al Jaddaf, Dubai` | | `status` | string | `NEW LAUNCH` | | `launch_date` | string | `03.03.2026` | | `price_from` | integer (AED) | `1125000` | | `image` | string (Pfad) | `expose/a1/image-4.jpeg` | | `highlights` | array\ | `['Prime Waterfront Views', ...]` | | `quick_facts` | array\<{icon, label, value}\> | Typen, Größe, Einheiten, Entwickler | | `investment_case` | object | `{title, text, views[]}` | | `gallery` | array\ | Bildpfade | | `location_info` | object | `{title, map_url, points[]}` | | `contact` | object | `{title, subtitle, options[]}` | ### 2.2 Migration erstellen Neue Migration `create_cms_projects_table`: ```php Schema::create('cms_projects', function (Blueprint $table) { $table->id(); $table->string('slug')->unique(); $table->json('title'); // translatable $table->json('location'); // translatable $table->string('status')->nullable(); $table->date('launch_date')->nullable(); $table->unsignedInteger('price_from_aed')->nullable(); $table->string('currency')->default('AED'); $table->string('image')->nullable(); // CmsMedia Referenz $table->json('highlights')->nullable(); // translatable array $table->json('quick_facts')->nullable(); // [{icon, label, value}] $table->json('investment_case')->nullable(); // {title, text, views[]} $table->json('gallery')->nullable(); // [filename, ...] $table->json('location_info')->nullable(); // {title, map_url, points[]} $table->json('contact')->nullable(); // {title, subtitle, options[]} $table->boolean('is_published')->default(false); $table->unsignedInteger('order')->default(0); $table->timestamps(); }); ``` ### 2.3 Model erstellen `App\Models\CmsProject` mit: - `HasTranslations` (Spatie) für `title`, `location`, `highlights` - Scopes: `published()`, `ordered()` - `toFrontendArray()` → kompatibles Array für bestehende Blade-Views - `getFormattedPrice()` → nutzt `PriceHelper::formatAed()` - Accessors für `gallery_urls`, `image_url` etc. ### 2.4 Factory & Seeder - **Factory:** `CmsProjectFactory` für Tests - **Seeder:** `CmsProjectSeeder` – importiert die bestehenden Projekte aus `config/content.php` in die DB ### 2.5 Admin CRUD (Volt-Komponente) Admin-View `admin.cms.projects-index`: - Liste aller Projekte (Titel, Status, Preis, Published, Order) - Erstellen/Bearbeiten Modal oder Inline - Felder: alle aus 2.2 - Galerie-Management via MediaPicker - Bild-Upload via MediaLibraryUploader - Sortierung per Drag & Drop oder Order-Feld - Publish/Unpublish Toggle ### 2.6 Route für Immobilien-Show anpassen ```php // Vorher: Route::get('/immobilien/{slug}', function (string $slug) { $project = config("content.themes.{$theme}.immobilien_projects.projects.{$slug}"); ... }); // Nachher: Route::get('/immobilien/{slug}', function (string $slug) { $project = CmsProject::where('slug', $slug)->published()->firstOrFail(); return view('web.immobilien-show', ['project' => $project->toFrontendArray()]); }); ``` **Ergebnis Phase 2:** Immobilien-Projekte in DB, editierbar im CMS, Frontend nutzt Model. --- ## Phase 3 – Content-Migration (config → DB) ### 3.1 Content-Struktur analysieren Die `config/content.php` enthält das b2in-Theme mit folgenden Sektionen: | Page | Section | Typ | |------|---------|-----| | global | `announcement_bar` | Text + Links | | global | `header` | Navigation | | global | `footer` | Text + Links | | home | `hero` | Text + Bild + Stats | | home | `founder_bar` | Text + Bild | | home | `synergie_section` | Text + Bild | | home | `vision_section` | Text + Bild | | home | `ecosystem_core` | Text + Items | | home | `cta_section` | Text + Link | | home | `brand_worlds` | Text + Items | | about | `about_hero`, `our_story`, `our_values`, `leadership_team` | Diverse | | immobilien | `immobilien_hero_v2`, `immobilien_warum_dubai`, `immobilien_kaufprozess`, `immobilien_bruecke`, `immobilien_mindset`, `immobilien_moebel_vorteil` | Diverse | | faq | FAQ-Kategorien | Q&A | | netzwerk | Hero, Stats, Sections | Diverse | | contact | Form-Info | Text | | impressum/privacy/terms/cookie-policy | Langtext | HTML | ### 3.2 CmsContentSeeder erstellen **Strategie:** Alle b2in-Inhalte aus `config/content.php` in `flux_cms_contents` überführen. - **Key-Schema:** `{page}.{section}.{field}` (z.B. `home.hero.title`, `about.our_story.title`) - **Typen:** `text`, `html`, `image`, `json` (für Arrays wie `pillars`, `stats`, `navigation`) - **Gruppen:** `home`, `about`, `immobilien`, `netzwerk`, `faq`, `contact`, `impressum`, `privacy`, `terms`, `cookie_policy`, `global` (Header, Footer) **Datei:** `database/seeders/CmsContentSeeder.php` – liest `config/content.php` und schreibt in DB. ### 3.3 Seeders ausführen & verifizieren ```bash php artisan db:seed --class=CmsContentSeeder ``` **Ergebnis Phase 3:** Alle b2in-Inhalte in der DB, abrufbar über `cms('home.hero.title')`. --- ## Phase 4 – CMS Admin-Backend ### 4.1 CMS als eigener Menüpunkt Das CMS wird im Admin-Portal (`portal.b2in.test`) als **eigener Top-Level-Menüpunkt "CMS"** in der Sidebar integriert. **Sidebar-Erweiterung** (`resources/views/components/layouts/app/sidebar.blade.php`): ``` CMS ├── Dashboard (Übersicht: Anzahl Contents, Medien, Projekte) ├── Inhalte (Content-Editor für Text/HTML/Image/JSON Keys) ├── Projekte (Immobilien-CRUD – aus Phase 2) ├── Medienbibliothek (Upload, Grid, Conversions) ``` ### 4.2 CMS-Layout **Entscheidung:** Die CMS-Views nutzen das bestehende Admin-Portal-Layout (`admin-master.blade.php` / `app.blade.php`), damit Navigation und User-Menü konsistent bleiben. → Das Reference-Layout `layout-cms.blade.php` wird **nicht** als separates Layout genutzt, sondern als Vorlage für die Content-Struktur innerhalb des bestehenden Layouts. ### 4.3 Admin-Views erstellen Aus den Package-Referenz-Views nur die benötigten kopieren und anpassen: | View | Quelle | Ziel | |------|--------|------| | Dashboard | `admin-reference/cms/dashboard.blade.php` | `livewire/admin/cms/dashboard.blade.php` | | Content-Editor | `admin-reference/cms/content-index.blade.php` | `livewire/admin/cms/content-index.blade.php` | | Medienbibliothek | `admin-reference/cms/media-index.blade.php` | `livewire/admin/cms/media-index.blade.php` | | MediaPicker | `admin-reference/cms/media-picker.blade.php` | `livewire/admin/cms/media-picker.blade.php` | | MediaUploader | `admin-reference/cms/media-library-uploader.blade.php` | `livewire/admin/cms/media-library-uploader.blade.php` | | **Projekte** | **Neu erstellen** | `livewire/admin/cms/projects-index.blade.php` | **Nicht benötigt (vorerst):** news-index, industries-index, faqs-index, linkedin-index, downloads-index, team-index, search-index ### 4.4 Livewire-Komponenten einrichten ```bash mkdir -p app/Livewire/Admin/Cms/ ``` Aus Package kopieren + Namespace anpassen: - `MediaLibraryUploader.php` → `App\Livewire\Admin\Cms` - `MediaPicker.php` → `App\Livewire\Admin\Cms` - `MediaUploader.php` → `App\Livewire\Admin\Cms` ### 4.5 Admin-Routes registrieren In `routes/admin.php` innerhalb der bestehenden `auth`-Middleware-Gruppe: ```php // Flux CMS Routes Volt::route('admin/cms', 'admin.cms.dashboard')->name('cms.dashboard'); Volt::route('admin/cms/content', 'admin.cms.content-index')->name('cms.content.index'); Volt::route('admin/cms/media', 'admin.cms.media-index')->name('cms.media.index'); Volt::route('admin/cms/projects', 'admin.cms.projects-index')->name('cms.projects.index'); ``` **Ergebnis Phase 4:** Funktionierendes Admin-Backend unter `portal.b2in.test/admin/cms` mit Dashboard, Content-Editor, Medienbibliothek und Projekte-CRUD. --- ## Phase 5 – Frontend-Umstellung (config → cms) ### 5.1 Strategie: Dualer Betrieb mit Fallback Die Umstellung erfolgt inkrementell. Jede Section einzeln umstellen, mit Fallback auf `config()`: ```php // Vorher (Hero.php): $this->content = config("content.themes.{$theme}.hero", []); // Nachher: $this->content = $this->loadFromCms('home.hero'); // Fallback-Methode in einem Trait oder Base-Class: protected function loadFromCms(string $group): array { $cmsContent = app(CmsContentService::class)->getGroup($group); if (empty($cmsContent)) { $theme = config('app.theme', 'b2in'); $section = Str::afterLast($group, '.'); return config("content.themes.{$theme}.{$section}", []); } return $cmsContent; } ``` ### 5.2 Sections schrittweise umstellen **Reihenfolge (nach Priorität / Sichtbarkeit):** 1. **Home-Page Sections:** - [ ] Hero → `home.hero` - [ ] FounderBar → `home.founder_bar` - [ ] ContentSection → `home.{section}` (dynamisch) - [ ] VisionSection → `home.vision_section` - [ ] EcosystemCore → `home.ecosystem_core` - [ ] CTASection → `home.cta_section` 2. **Globale Elemente:** - [ ] Header (Navigation) → `global.header` - [ ] Footer → `global.footer` - [ ] AnnouncementBar → `global.announcement_bar` 3. **Immobilien-Seite (statischer Content):** - [ ] HeroV2 → `immobilien.hero_v2` - [ ] WarumDubai → `immobilien.warum_dubai` - [ ] Kaufprozess → `immobilien.kaufprozess` - [ ] Brücke → `immobilien.bruecke` - [ ] Mindset → `immobilien.mindset` - [ ] MöbelVorteil → `immobilien.moebel_vorteil` - [ ] Projekte-Liste → **CmsProject::published()->ordered()** (aus Phase 2) 4. **Unterseiten:** - [ ] About - [ ] FAQ - [ ] Contact - [ ] Impressum / Privacy / Terms / Cookie-Policy - [ ] Netzwerk - [ ] Service / Portfolio ### 5.3 Immobilien-Route umstellen ```php // routes/web.php – von config auf Model: Route::get('/immobilien/{slug}', function (string $slug) { $project = \App\Models\CmsProject::where('slug', $slug) ->published() ->firstOrFail(); return view('web.immobilien-show', ['project' => $project->toFrontendArray()]); })->name('immobilien.show'); ``` Die `immobilien.blade.php` Projekte-Liste ebenfalls umstellen: ```php // Vorher: $projects = config("content.themes.{$theme}.immobilien_projects", []); // Nachher: $projects = CmsProject::published()->ordered()->get(); ``` ### 5.4 Bilder umstellen ```diff - asset('img/assets/' . $heroV2['image']) + cms_media_url('immobilien.hero_v2.image', 'hero') ``` **Ergebnis Phase 5:** b2in-Frontend liest Inhalte aus DB + CmsProject-Model, editierbar über Admin. --- ## Phase 6 – Medienbibliothek & Bilder ### 6.1 Bestehende Bilder importieren Alle b2in-Bilder (aus `public/img/assets/`) in die CMS-Medienbibliothek importieren: - `b2in/` – allgemeine b2in-Bilder (Hero, Founder, Sections) - `expose/` – Immobilien-Projektbilder ### 6.2 CmsMediaSeeder Seeder erstellt `CmsMedia`-Einträge für alle bestehenden Bilder und verknüpft sie mit den CmsContent-Keys vom Typ `image`. ### 6.3 Bildprofile definieren In `config/flux-cms.php`: - `hero` → 1920×800 (Hero-Banner) - `card` → 768×512 (Kacheln, Sections) - `thumbnail` → 400×300 (Listen, Übersichten) - `avatar` → 400×400 (Team-Fotos, Founder) - `gallery` → 1200×900 (Projekt-Galerie) - `og_image` → 1200×630 (Social Sharing) ### 6.4 Conversions generieren ```bash php artisan flux-cms:clear-cache ``` **Ergebnis Phase 6:** Alle Bilder in Medienbibliothek, Conversions generiert, URLs aufgelöst. --- ## Phase 7 – Tests ### 7.1 Referenz-Tests kopieren (selektiv) ```bash mkdir -p tests/Feature/Cms cp packages/flux-cms/core/tests-reference/Feature/Cms/CmsMediaTest.php tests/Feature/Cms/ cp packages/flux-cms/core/tests-reference/Feature/Cms/CmsContentServiceTest.php tests/Feature/Cms/ ``` ### 7.2 Projektspezifische Tests - **CmsProjectTest** – CRUD, published/unpublished, toFrontendArray(), Validierung - **CmsContentSeederTest** – Prüft ob alle Keys aus config in DB existieren - **CmsAdminAccessTest** – Prüft Zugriffskontrolle auf CMS-Admin-Routen - **ImmobilienRouteTest** – Prüft `/immobilien/{slug}` mit DB-Daten - **FrontendFallbackTest** – Prüft dualen Betrieb (CMS → config Fallback) - **MediaIntegrationTest** – Upload, Conversion, URL-Auflösung ### 7.3 Tests ausführen ```bash php artisan test --compact --filter=Cms php artisan test --compact --filter=Immobilien ``` **Ergebnis Phase 7:** Alle CMS-Funktionalitäten sind getestet. --- ## Phase 8 – Feinschliff & Dokumentation ### 8.1 Cache & Performance - CMS-Content-Cache aktivieren - Eager Loading optimieren - Prüfen: Keine N+1-Queries auf Frontseiten ### 8.2 config/content.php aufräumen - Nach vollständiger Umstellung: b2in-Theme-Daten als `@deprecated` markieren - Noch nicht entfernen (Fallback für andere Themes!) - Immobilien-Projekte aus Config entfernen (leben jetzt in DB) ### 8.3 Sidebar-Berechtigungen - CMS-Zugang über Spatie-Permission absichern (`permission:manage-cms`) - CMS-Menüpunkt nur für berechtigte User anzeigen ### 8.4 Dokumentation - Diesen Plan aktualisieren mit Status - Notizen für Integration weiterer Subseiten (b2a, stileigentum, style2own) --- ## Offene Fragen / Entscheidungen | # | Frage | Entscheidung | |---|-------|-------------| | 1 | Alle flux-cms Migrations laufen lassen oder nur contents + media? | Empfehlung: Alle (leere Tabellen stören nicht) | | 2 | CmsProject: Eigene Migration oder flux-cms erweitern? | Eigene Migration im Projekt | | 3 | FAQ-Daten: Vorerst in config belassen oder direkt in `flux_cms_faqs`? | Vorerst config | | 4 | Magazin: Eigenes System belassen oder später auf CMS? | Vorerst belassen | | 5 | Andere Themes (b2a etc.) weiterhin via `config()`? | Ja | --- ## Fortschritt | Phase | Status | Notizen | |-------|--------|---------| | 1 – Installation & Infrastruktur | ✅ Fertig | 2026-03-18: Package installiert, Config angepasst, Migrations gelaufen, Helpers eingerichtet, 434 Tests grün | | 2 – Immobilien-Model & CRUD | ✅ Fertig | 2026-03-18: Migration, Model, Factory, Seeder, 9 Tests grün. CRUD Admin-View folgt in Phase 4. | | 3 – Content-Migration | ✅ Fertig | 2026-03-18: 61 Sections in 8 Gruppen migriert, Section-als-JSON-Ansatz, 8 Tests grün | | 4 – CMS Admin-Backend | ✅ Fertig | 2026-03-18: Dashboard, Content-Editor, Projekte-CRUD, Medienbibliothek, Sidebar-Menü, MediaPicker/Uploader, 16 Tests grün | | 5 – Frontend-Umstellung | ⬜ Offen | | | 6 – Medienbibliothek | ⬜ Offen | | | 7 – Tests | ⬜ Offen | |j | 8 – Feinschliff | ⬜ Offen | |