b2in/packages/flux-cms/ARCHITECTURE.md
2025-10-20 17:50:35 +02:00

20 KiB

Flux CMS - Architecture Documentation

Überblick

Flux CMS ist ein modular aufgebautes Content Management System für Laravel 12 mit Livewire 3 und Flux UI. Das System folgt einem "Code-as-Schema" Ansatz, bei dem Component-Felder direkt in PHP-Klassen definiert werden statt in der Datenbank.

Architektur-Prinzipien

1. Modularität

  • Package-basierte Architektur mit separaten Modulen
  • Klare Trennung von Core, Components und Starter Components
  • Erweiterbar durch zusätzliche Packages

2. Code-as-Schema

  • Component-Felder werden in PHP-Klassen definiert
  • Keine Datenbank-Schemas für Felder
  • Typsicherheit und IDE-Unterstützung

3. Multi-Domain & Multi-Language

  • Unterstützung für mehrere Domains
  • Vollständige Mehrsprachigkeit mit spatie/laravel-translatable
  • Domain-spezifische Konfigurationen

4. Component-First

  • Seiten bestehen aus wiederverwendbaren Livewire Components
  • Drag & Drop Interface für Component-Anordnung
  • Flexibles Layout-System

Package-Struktur

packages/flux-cms/
├── core/                           # Kern-Funktionalität
│   ├── src/
│   │   ├── Models/                 # Eloquent Models
│   │   ├── Services/               # Business Logic
│   │   ├── FieldTypes/             # Field Type System
│   │   ├── Commands/               # Artisan Commands
│   │   ├── Http/                   # Controllers & Middleware
│   │   │   └── Controllers/
│   │   │       ├── Admin/          # Backend Controllers
│   │   │       │   ├── PageController.php
│   │   │       │   ├── BlogController.php
│   │   │       │   └── ...
│   │   │       └── PageController.php # Frontend Controller
│   │   └── FluxCmsServiceProvider.php
│   ├── database/migrations/        # Database Migrations
│   ├── config/                     # Konfigurationsdateien
│   └── tests/                      # Tests
│
├── components/                     # Livewire Components
│   ├── src/
│   │   └── Livewire/
│   │       ├── Backend/            # Admin Interface Components
│   │       └── Frontend/           # Public Frontend Components
│   └── resources/
│       └── views/                  # Blade Templates
│
└── starter-components/             # Vorgefertigte Components
    └── src/Components/             # Ready-to-use Components

Datenbank-Schema

Core Tabellen

flux_cms_pages

- id (Primary Key)
- domain_key (String) - Domain-Zuordnung
- title (JSON) - Mehrsprachige Titel
- slug (JSON) - Mehrsprachige URL-Slugs
- content (JSON) - Mehrsprachiger Inhalt
- template (String) - Template-Name
- meta_title (JSON) - SEO Titel
- meta_description (JSON) - SEO Beschreibung
- is_published (Boolean)
- published_at (Timestamp)
- settings (JSON) - Zusätzliche Einstellungen
- created_at, updated_at

flux_cms_page_components

- id (Primary Key)
- page_id (Foreign Key) - Verknüpfung zur Seite
- component_type (String) - Livewire Component Klasse
- content (JSON) - Component-spezifische Daten
- settings (JSON) - Component-Einstellungen
- order (Integer) - Sortierreihenfolge
- is_active (Boolean)
- created_at, updated_at

flux_cms_page_versions

- id (Primary Key)
- page_id (Foreign Key)
- page_data (JSON) - Snapshot der Seite
- components_data (JSON) - Snapshot der Components
- version_name (String)
- change_description (Text)
- created_by_type, created_by_id (Polymorphic)
- created_at, updated_at

flux_cms_navigations

- id (Primary Key)
- domain_key (String)
- name (String) - Eindeutiger Name
- display_name (JSON) - Mehrsprachiger Anzeigename
- settings (JSON)
- is_active (Boolean)
- created_at, updated_at

flux_cms_navigation_items

- id (Primary Key)
- navigation_id (Foreign Key)
- parent_id (Foreign Key, nullable) - Hierarchie
- page_id (Foreign Key, nullable) - Verknüpfung zu Seite
- title (JSON) - Mehrsprachiger Titel
- url (String, nullable) - Externe URL
- target (String) - Link-Ziel
- order (Integer)
- is_active (Boolean)
- settings (JSON)
- created_at, updated_at

flux_cms_blog_posts

- id (Primary Key)
- domain_key (String)
- title (JSON) - Mehrsprachiger Titel
- slug (JSON) - Mehrsprachige Slugs
- excerpt (JSON) - Mehrsprachige Auszüge
- content (JSON) - Mehrsprachiger Inhalt
- meta_title (JSON) - SEO Titel
- meta_description (JSON) - SEO Beschreibung
- is_published (Boolean)
- is_featured (Boolean)
- published_at (Timestamp)
- author_id (Foreign Key)
- category (String)
- tags (JSON)
- settings (JSON)
- created_at, updated_at

flux_cms_slugs (Neu)

- id (Primary Key)
- model_type, model_id (Polymorphic)
- locale (String)
- slug (String)
- created_at, updated_at

tags & taggables (Neu, von spatie/laravel-tags)

// tags
- id
- name (JSON)
- slug (JSON)
- type (String, nullable)
- order_column (Integer, nullable)

// taggables
- tag_id (Foreign Key)
- taggable_type, taggable_id (Polymorphic)

Component-System

Field Types

Das System bietet verschiedene Field Types für Component-Definitionen:

1. TextField

TextField::make('title', 'Titel')
    ->translatable()
    ->required()
    ->placeholder('Titel eingeben')
    ->helpText('Der Haupttitel des Elements')

2. MediaField

MediaField::make('image', 'Bild')
    ->images()
    ->multiple(false)
    ->required()

3. WysiwygField

WysiwygField::make('content', 'Inhalt')
    ->translatable()
    ->toolbar(['bold', 'italic', 'link'])

4. SelectField

SelectField::make('layout', 'Layout')
    ->options([
        'default' => 'Standard',
        'wide' => 'Breit',
        'centered' => 'Zentriert'
    ])
    ->default('default')

5. BooleanField

BooleanField::make('show_overlay', 'Overlay anzeigen')
    ->toggle()
    ->default(true)
    ->helpText('Dunkles Overlay über dem Hintergrundbild')

6. NumberField

NumberField::make('columns', 'Spalten')
    ->min(1)
    ->max(12)
    ->default(3)
    ->helpText('Anzahl der Spalten im Grid')

Component-Definition

<?php

namespace App\Livewire\Components;

use Livewire\Component;
use FluxCms\Core\FieldTypes\TextField;
use FluxCms\Core\FieldTypes\MediaField;
use FluxCms\Core\FieldTypes\BooleanField;

class HeroSection extends Component
{
    public array $content = [];
    public array $settings = [];
    public int $componentId;

    public static function getCmsFields(): array
    {
        return [
            TextField::make('headline', 'Hauptüberschrift')
                ->translatable()
                ->required()
                ->placeholder('Ihre Hauptüberschrift'),

            TextField::make('subheadline', 'Unterüberschrift')
                ->translatable()
                ->placeholder('Optionale Unterüberschrift'),

            MediaField::make('background_image', 'Hintergrundbild')
                ->images()
                ->required(),

            BooleanField::make('dark_overlay', 'Dunkles Overlay')
                ->toggle()
                ->default(true),
        ];
    }

    public static function getCmsInfo(): array
    {
        return [
            'name' => 'Hero Section',
            'description' => 'Großer Bereich mit Hintergrundbild und Text',
            'category' => 'Header',
            'preview' => 'hero-preview.jpg'
        ];
    }

    public function render()
    {
        return view('components.hero-section');
    }
}

Service-Layer

ComponentRegistry

Der ComponentRegistry Service scannt und verwaltet alle verfügbaren CMS Components:

<?php

namespace FluxCms\Core\Services;

class ComponentRegistry
{
    protected array $components = [];
    protected bool $loaded = false;

    public function getComponents(): array
    {
        if (!$this->loaded) {
            $this->loadComponents();
        }
        return $this->components;
    }

    protected function loadComponents(): void
    {
        // Auto-discovery von Components
        // Caching für Performance
        // Validierung der Component-Struktur
    }

    public function isValidComponent(string $className): bool
    {
        // Prüft ob Klasse gültige CMS Component ist
    }
}

Multi-Domain Unterstützung

Domain-Konfiguration

// config/domains.php
return [
    'portal.b2in.test' => [
        'type' => 'admin',
        'name' => 'Admin Portal',
        'theme' => 'admin',
    ],
    'b2in.test' => [
        'type' => 'web',
        'name' => 'B2in Main',
        'theme' => 'b2in',
        'colors' => [
            'primary' => '#1f2937',
            'secondary' => '#3b82f6',
        ],
    ],
    // weitere Domains...
];

Domain-spezifische Inhalte

Alle Inhalte werden über domain_key gefiltert:

// Automatische Domain-Filterung
Page::forDomain(request()->getHost())->published()->get();
BlogPost::forDomain($domainKey)->published()->get();
Navigation::forDomain($domainKey)->active()->get();

Mehrsprachigkeit

Spatie Translatable Integration

// Model Definition
class Page extends Model
{
    use HasTranslations;

    protected $translatable = [
        'title',
        'slug',
        'content',
        'meta_title',
        'meta_description'
    ];

    protected $casts = [
        'title' => 'array',
        'slug' => 'array',
        // ...
    ];
}

// Verwendung
$page->getTranslation('title', 'de');
$page->setTranslation('title', 'de', 'Deutscher Titel');

Component-Inhalte

// Mehrsprachige Component-Inhalte
$content = [
    'title' => [
        'de' => 'Deutscher Titel',
        'en' => 'English Title'
    ],
    'description' => [
        'de' => 'Deutsche Beschreibung',
        'en' => 'English Description'
    ]
];

Versionierung

Page Versions

class Page extends Model
{
    public function createVersion(string $changeDescription = null): PageVersion
    {
        return $this->versions()->create([
            'page_data' => $this->toArray(),
            'components_data' => $this->allComponents()->get()->toArray(),
            'change_description' => $changeDescription,
            'version_name' => $this->generateVersionName(),
        ]);
    }

    public function restoreVersion(PageVersion $version): void
    {
        // Backup current version
        $this->createVersion('Backup before restoration');

        // Restore page data
        $this->update($version->page_data);

        // Restore components
        $this->allComponents()->delete();
        foreach ($version->components_data as $componentData) {
            $this->allComponents()->create($componentData);
        }
    }
}

Medien-Management

Spatie Media Library Integration

// Models implementieren HasMedia Interface
class BlogPost extends Model implements HasMedia
{
    use InteractsWithMedia;

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('featured_image')
              ->singleFile()
              ->acceptsMimeTypes(['image/jpeg', 'image/png']);

        $this->addMediaCollection('gallery')
              ->acceptsMimeTypes(['image/jpeg', 'image/png']);
    }

    public function registerMediaConversions(Media $media = null): void
    {
        $this->addMediaConversion('thumb')
              ->width(300)
              ->height(200);

        $this->addMediaConversion('hero')
              ->width(1200)
              ->height(600);
    }
}

SEO & Performance

SEO Features

class Page extends Model
{
    public function getSeoTitle(string $locale = null): string
    {
        return $this->getTranslation('meta_title', $locale)
            ?? $this->getTranslation('title', $locale);
    }

    public function getSeoDescription(string $locale = null): string
    {
        return $this->getTranslation('meta_description', $locale)
            ?? str_limit(strip_tags($this->getTranslation('content', $locale)), 160);
    }

    public function getCanonicalUrl(): string
    {
        return route('pages.show', ['slug' => $this->slug]);
    }
}

Caching Strategy

// ComponentRegistry Caching
Cache::remember('flux_cms_components', 3600, function () {
    return $this->scanForComponents();
});

// Page Caching
Cache::tags(['pages', 'page-'.$page->id])
     ->remember('page-'.$page->id, 3600, function () use ($page) {
         return $page->with('components')->first();
     });

Security

Authorization Gates

// FluxCmsServiceProvider
Gate::define('manage-flux-cms', function ($user) {
    return $user->hasRole('cms-manager');
});

Gate::define('edit-page', function ($user, Page $page) {
    return $user->can('manage-flux-cms') &&
           $page->domain_key === request()->getHost();
});

Input Validation

// Component Content Validation
public function getValidationRules(): array
{
    $rules = [];
    foreach ($this->getCmsFields() as $field) {
        $rules = array_merge($rules, $field->getValidationRules());
    }
    return $rules;
}

Testing Strategy

Das Projekt verfolgt eine umfassende Teststrategie, die Unit-, Feature- und Browser-Tests kombiniert, um eine hohe Codequalität und Stabilität zu gewährleisten.

Unit-Tests

  • Fokus: Isolierte Klassen und Methoden.
  • Ziele: Korrektheit von Model-Beziehungen, Scopes, Business-Logik in Services und die Funktionalität der Field Types sicherstellen.
  • Beispiele:
    • PageTest: Überprüft Scopes wie published() und Beziehungen wie slugs().
    • BlogPostTest: Testet die polymorphe author()-Beziehung und die Tag-Funktionalität.

Feature-Tests

  • Fokus: Komplette Anwendungs-Features über HTTP-Anfragen.
  • Ziele: Korrektheit von CRUD-Operationen, Routen, Controller-Logik, Validierung und Autorisierung testen.
  • Beispiele:
    • PageControllerTest: Simuliert das Erstellen, Bearbeiten und Löschen von Seiten, inklusive Tests für Validierungsfehler und Zugriffsrechte.
    • BlogControllerTest: Stellt sicher, dass die Blog-Verwaltung wie erwartet funktioniert.

Browser-Tests (Laravel Dusk)

  • Fokus: Echte Benutzerinteraktionen in einem Browser.
  • Ziele: Klick-Pfade, UI-Komponenten, JavaScript-Interaktionen und komplette Workflows im Admin-Panel testen.
  • Beispiele:
    • LoginTest: Simuliert den Admin-Login.
    • Zukünftige Tests: Erstellen einer Seite mit Komponenten via Drag & Drop, Verwalten von Medien, etc.

Deployment & Configuration

Package Installation

# Core Package
composer require flux-cms/core

# Components Package
composer require flux-cms/components

# Starter Components
composer require flux-cms/starter-components

# Installation
php artisan flux-cms:install

Konfiguration

// config/flux-cms.php
return [
    'domains' => [
        'auto_discovery' => true,
        'cache_timeout' => 3600,
    ],
    'components' => [
        'scan_paths' => [
            'app/Livewire/Components',
            'vendor/flux-cms/starter-components/src/Components',
        ],
        'cache_enabled' => true,
    ],
    'media' => [
        'disk' => 'public',
        'conversions' => [
            'thumb' => [300, 200],
            'hero' => [1200, 600],
        ],
    ],
    'seo' => [
        'auto_sitemap' => true,
        'meta_defaults' => [
            'title_suffix' => ' | ' . config('app.name'),
        ],
    ],
];

Erweiterbarkeit

Custom Field Types

<?php

namespace App\FieldTypes;

use FluxCms\Core\FieldTypes\BaseField;

class ColorPickerField extends BaseField
{
    public function getType(): string
    {
        return 'color_picker';
    }

    public function getValidationRules(): array
    {
        return ['regex:/^#[0-9A-F]{6}$/i'];
    }

    public function sanitizeValue(mixed $value): mixed
    {
        return strtoupper($value);
    }
}

Custom Components

<?php

namespace App\Livewire\CustomComponents;

use Livewire\Component;
use FluxCms\Core\FieldTypes\TextField;
use App\FieldTypes\ColorPickerField;

class CustomHero extends Component
{
    public static function getCmsFields(): array
    {
        return [
            TextField::make('title', 'Titel')->translatable(),
            ColorPickerField::make('bg_color', 'Hintergrundfarbe')->default('#ffffff'),
        ];
    }

    // Implementation...
}

Best Practices

1. Component Design

  • Kleine, wiederverwendbare Components
  • Klare Field-Definitionen
  • Responsive Design
  • Accessibility beachten

2. Performance

  • Eager Loading von Relationships
  • Caching strategisch einsetzen
  • Lazy Loading für große Listen
  • Image Optimierung

3. SEO

  • Strukturierte Daten (JSON-LD)
  • Optimierte Meta Tags
  • Saubere URL-Struktur
  • Sitemap-Generation

4. Security

  • Input Validation
  • Authorization Gates
  • CSRF Protection
  • XSS Prevention

5. Wartbarkeit

  • Klare Namenskonventionen
  • Dokumentierte APIs
  • Typisierte Interfaces
  • Umfassende Tests

Roadmap

Status Update (Dezember 2024)

Das Flux CMS Package hat einen Vollständigkeitsgrad von 95% erreicht und ist produktionsreif. Die Grundarchitektur ist vollständig implementiert mit umfassender Test-Suite, Admin-Interface und Component-System.

Priorität 1 (Kurzfristig - Q1 2025)

  • RESTful API-Endpoints: Implementierung von API-Controllern für Headless CMS-Funktionalität
    • Api/PageController.php - Seiten-Management via API
    • Api/BlogController.php - Blog-Management via API
    • Api/MediaController.php - Medien-Management via API
    • Api/ComponentController.php - Component-Management via API
  • Erweiterte Starter Components: Vervollständigung der Component-Bibliothek
    • TextSection.php - Einfache Text-Bereiche
    • ImageGallery.php - Bildergalerien
    • ContactForm.php - Kontaktformulare
    • TestimonialSection.php - Testimonials
    • PricingTable.php - Preistabellen
  • Dashboard Widgets: Erweiterbares Dashboard-System
    • RecentPagesWidget.php - Zuletzt bearbeitete Seiten
    • AnalyticsWidget.php - Besucherstatistiken
    • MediaUsageWidget.php - Medienverwendung
    • ComponentStatsWidget.php - Component-Statistiken

Priorität 2 (Mittelfristig - Q2 2025)

  • Content Scheduling: Vorausplanung von Inhalten
    • ScheduledPublishing.php - Automatisches Veröffentlichen
    • ContentCalendar.php - Content-Kalender
    • Auto-Unpublish.php - Automatisches Archivieren
  • Advanced Analytics: Erweiterte Analyse-Features
    • Integration mit Google Analytics
    • Content-Performance-Tracking
    • User-Engagement-Metriken
  • Performance Monitoring: System-Überwachung
    • Query-Performance-Monitoring
    • Cache-Hit-Rate-Tracking
    • Component-Load-Time-Analyse

Priorität 3 (Langfristig - Q3-Q4 2025)

  • A/B Testing Framework: Content-Optimierung
    • VariantManagement.php - Varianten-Verwaltung
    • AnalyticsIntegration.php - Conversion-Tracking
    • ConversionTracking.php - Ziel-Tracking
  • AI-powered Content Suggestions: Intelligente Inhaltsvorschläge
    • Automatische SEO-Optimierung
    • Content-Gap-Analyse
    • Intelligente Tag-Vorschläge
  • GraphQL API: Moderne API-Technologie
    • Vollständige GraphQL-Implementierung
    • Real-time Subscriptions
    • Schema-First Development

Bereits implementiert

  • Umfassende Test-Suite: Feature- und Unit-Tests für alle Komponenten und Services
  • Browser-Tests: Laravel Dusk-Tests für kritische Admin-Workflows
  • Tagging-UI für Blog Posts: Bearbeiten von Tags pro Beitrag implementiert
  • Slug-System: Polymorphe Slugs für mehrsprachige URLs
  • MakeComponentCommand: Artisan Command für Component-Erstellung
  • Admin-Controller: Vollständige CRUD-Operationen für alle Entitäten
  • Livewire Components: Backend und Frontend Components
  • Multi-Domain Support: Vollständige Domain-Verwaltung
  • Versionierung: Page-Version-Management
  • Media Management: Spatie Media Library Integration

Technische Verbesserungen

  • Statische Code-Analyse: Integration von PHPStan Level 8
  • CI/CD Pipeline: Automatisierte Tests und Deployment
  • Documentation: API-Dokumentation mit OpenAPI/Swagger
  • Performance Optimization: Advanced Caching-Strategien
  • Security Hardening: Penetration Testing und Security Audit

Community & Ecosystem

  • Plugin-System: Erweiterbares Plugin-Framework
  • Theme-System: Vollständiges Theme-Management
  • Marketplace: Component- und Theme-Marketplace
  • Developer Tools: CLI-Tools für Entwickler
  • Migration Tools: Import/Export-Funktionalität