10-04-2026

This commit is contained in:
Kevin Adametz 2026-04-10 17:18:17 +02:00
parent 4d6b4930b2
commit 4bb89aad8c
836 changed files with 52961 additions and 5950 deletions

524
dev/flux-cms/PLAN.md Normal file
View file

@ -0,0 +1,524 @@
# 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 26 |
| **8** | Feinschliff & Dokumentation | Phase 57 |
---
## 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\<string\> | `['Prime Waterfront Views', ...]` |
| `quick_facts` | array\<{icon, label, value}\> | Typen, Größe, Einheiten, Entwickler |
| `investment_case` | object | `{title, text, views[]}` |
| `gallery` | array\<string\> | 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 | |