myCRM/docs/PLUGIN_SYSTEM_SUMMARY.md
olli 42e7bc7e10 feat(billing-module): Implementieren der Modulstruktur und Lizenzverwaltung
- Hinzufügen der DependencyInjection-Konfiguration für das Billing-Modul.
- Erstellen der Invoice-Entity mit API-Ressourcen und Berechtigungen.
- Konfigurieren der Services in services.yaml für das Billing-Modul.
- Implementieren von CLI-Commands zur Verwaltung von Modul-Lizenzen und zur Auflistung installierter Module.
- Erstellen eines API-Controllers zur Verwaltung von Modulen und Lizenzen.
- Hinzufügen eines EventListeners für das Booten von Modulen.
- Definieren von Interfaces für Lizenzvalidierung und Modul-Plugins.
- Implementieren der ModuleRegistry zur Verwaltung und Booten von Modulen.
- Erstellen eines LicenseValidator-Services zur Validierung und Registrierung von Lizenzen.
2025-12-03 15:14:07 +01:00

12 KiB

Plugin-System: Zusammenfassung der Implementierung

Executive Summary

Das implementierte Plugin-System ermöglicht die Installation und Verwaltung von optionalen, lizenzierbaren Modulen in myCRM. Module sind vollständig unabhängige Composer-Packages, die ohne Änderungen am Core nachträglich installiert werden können und nur mit gültiger Lizenz funktionieren.

Kernmerkmale

Anforderung: Leicht nachträglich installierbar

Gelöst durch:

  • Composer-basierte Installation (composer require mycrm/modul-name)
  • Symfony Flex Auto-Configuration für Bundle-Registrierung
  • Automatische Service-Discovery über Tagged Iterators
  • Keine manuelle Code-Änderung im Core erforderlich

Anforderung: Keine Core-Abhängigkeiten

Gelöst durch:

  • Interface-basierte Architektur (ModulePluginInterface, LicenseValidatorInterface)
  • Core kennt nur Interfaces, keine konkreten Module
  • Module registrieren sich selbst via Dependency Injection
  • Loose Coupling durch Event-System und Service-Tags

Anforderung: Lizenzvalidierung erforderlich

Gelöst durch:

  • REST-API basierte Lizenzprüfung gegen externen Server
  • JWT-Token Format für Lizenzschlüssel
  • Caching mit 24h TTL + 7 Tage Grace Period
  • Offline-Betrieb möglich (gecachte Validierung)
  • Module werden nur mit gültiger Lizenz gebootet

Architektur-Komponenten

1. Core-System (Hauptprojekt)

Interfaces:

/src/Plugin/
├── ModulePluginInterface.php          # Plugin-Contract
└── LicenseValidatorInterface.php      # Lizenz-Contract

Implementierungen:

/src/
├── Plugin/ModuleRegistry.php          # Plugin-Verwaltung
├── Service/LicenseValidator.php       # Lizenzprüfung
├── EventListener/ModuleBootListener.php   # Auto-Boot
├── Command/
│   ├── ModuleListCommand.php          # CLI: Liste
│   └── ModuleLicenseCommand.php       # CLI: Lizenz-Verwaltung
└── Controller/Api/ModuleManagementController.php  # REST-API

Frontend:

/assets/js/views/
└── ModuleManagement.vue               # Admin-UI

2. Modul-Package (externes Repository)

mycrm-modulname/
├── composer.json                      # Symfony Bundle Type
├── src/
│   ├── ModulnameModulePlugin.php      # Implements ModulePluginInterface
│   ├── ModulnameBundle.php            # Symfony Bundle
│   ├── DependencyInjection/           # Container Extension
│   ├── Entity/                        # Doctrine Entities
│   ├── Controller/                    # API Controllers
│   ├── Security/Voter/                # Permissions
│   └── Service/                       # Business Logic
├── config/
│   ├── services.yaml                  # Service-Tag: app.module_plugin
│   └── routes.yaml
└── migrations/                        # Doctrine Migrations

Workflow

Installation eines Moduls

graph TD
    A[composer require mycrm/modul] --> B[Composer installiert Package]
    B --> C[Symfony Flex registriert Bundle]
    C --> D[DI Container lädt Services]
    D --> E[ModuleRegistry erkennt Plugin via Tag]
    E --> F[Admin registriert Lizenz]
    F --> G[LicenseValidator prüft gegen Server]
    G --> H{Lizenz gültig?}
    H -->|Ja| I[ModuleBootListener bootet Modul]
    H -->|Nein| J[Modul bleibt inaktiv]
    I --> K[Modul verfügbar]

Lizenzvalidierung

sequenceDiagram
    participant App as myCRM
    participant Cache as Cache
    participant Validator as LicenseValidator
    participant Server as Lizenzserver

    App->>Validator: validate("billing")
    Validator->>Cache: getCached("billing")

    alt Cache Hit & Grace Period aktiv
        Cache-->>Validator: Gecachte Lizenz
        Validator-->>App: Valid (cached)
    else Cache Miss oder abgelaufen
        Validator->>Server: POST /api/validate
        alt Server erreichbar
            Server-->>Validator: {valid: true, ...}
            Validator->>Cache: speichern (24h TTL)
            Validator-->>App: Valid
        else Server nicht erreichbar
            alt Gecachte Lizenz in Grace Period
                Validator-->>App: Valid (offline)
            else Keine Grace Period
                Validator-->>App: Invalid
            end
        end
    end

API-Übersicht

REST-API Endpunkte

GET    /api/modules                    # Alle Module auflisten
GET    /api/modules/{id}               # Modul-Details
POST   /api/modules/{id}/license       # Lizenz registrieren
DELETE /api/modules/{id}/license       # Lizenz widerrufen
POST   /api/modules/{id}/validate      # Lizenz validieren
GET    /api/modules/licenses           # Alle Lizenzen

CLI-Commands

app:module:list                        # Module auflisten
app:module:license <module> [key]      # Lizenz verwalten
  --revoke                             # Lizenz widerrufen
  --validate                           # Lizenz prüfen

Integration mit bestehendem System

Permission-System

Module können eigene Permission-Module registrieren:

public function getPermissionModules(): array
{
    return ['billing', 'invoices', 'payments'];
}

Diese werden automatisch im Role-Permission-System verfügbar und können über die bestehenden Voter geprüft werden:

$this->denyAccessUnlessGranted('VIEW', 'billing');

API Platform Integration

Modul-Entities implementieren ModuleAwareInterface:

class Invoice implements ModuleAwareInterface
{
    public function getModuleName(): string
    {
        return 'billing';
    }
}

#[ApiResource(
    security: "is_granted('VIEW', 'billing')"
)]

Vue.js Frontend

Module können eigene Vue-Komponenten bereitstellen:

// Modul-Package: assets/js/index.js
export default {
    components: { InvoiceManagement },
    routes: [/* ... */]
}

// Haupt-App: Bedingte Integration
if (window.myCRM.modules.billing?.active) {
    app.use(BillingModule)
}

Sicherheits-Features

1. Lizenzschlüssel-Speicherung

  • Environment-Variablen (.env.local)
  • Nicht im Git-Repository (.env.local in .gitignore)
  • Optional: Verschlüsselte DB-Speicherung

2. API-Zugriff

  • Alle Management-Endpunkte: #[IsGranted('ROLE_ADMIN')]
  • Lizenzschlüssel werden nie im Frontend exponiert
  • CSRF-Protection via Symfony

3. Offline-Schutz

  • Grace Period verhindert Dauerbetrieb ohne Validierung
  • Cache-TTL: 24 Stunden
  • Grace Period: 7 Tage nach letzter Validierung

4. Modul-Isolation

  • Module können Core nicht modifizieren
  • Eigene Doctrine Entity-Manager möglich
  • Eigene Namespaces, keine Konflikte

Performance-Optimierung

Caching-Strategie

Lizenzvalidierung:
├── Online-Check: Nur alle 24h
├── Cache-Hit: < 1ms
└── Offline-Mode: Grace Period 7 Tage

Lazy-Loading

  • Module booten nur beim ersten Request
  • Frontend-Komponenten lazy-loaded
  • Doctrine-Mappings on-demand

Service-Tagging

  • Automatische Plugin-Discovery
  • Kein manuelles Service-Scanning
  • Symfony DI Container optimiert

Testing-Strategie

Unit-Tests

class MyModulePluginTest extends TestCase
{
    public function testIsLicensedWithValidLicense(): void
    {
        $validator = $this->createMock(LicenseValidatorInterface::class);
        $validator->method('validate')->willReturn(['valid' => true]);

        $plugin = new MyModulePlugin($validator);

        $this->assertTrue($plugin->isLicensed());
    }
}

Integration-Tests

class LicenseValidatorTest extends KernelTestCase
{
    public function testValidateFetchesFromServer(): void
    {
        $client = $this->createMock(HttpClientInterface::class);
        // Mock HTTP-Response

        $validator = new LicenseValidator($client, ...);
        $result = $validator->validate('billing');

        $this->assertTrue($result['valid']);
    }
}

Functional-Tests

class ModuleManagementControllerTest extends WebTestCase
{
    public function testListModulesRequiresAdmin(): void
    {
        $client = static::createClient();
        $client->request('GET', '/api/modules');

        $this->assertResponseStatusCodeSame(401);
    }
}

Deployment-Checklist

Erstinstallation

  • Core-System: services_plugin.yaml importieren
  • Environment: LICENSE_SERVER_URL setzen
  • Environment: INSTANCE_ID generieren
  • Cache-Clear: php bin/console cache:clear

Modul-Installation

  • Composer: composer require mycrm/modul-name
  • Bundle: Automatisch registriert oder manuell in bundles.php
  • Migrations: php bin/console doctrine:migrations:migrate
  • Lizenz: php bin/console app:module:license modul-name
  • Cache: php bin/console cache:clear
  • Test: php bin/console app:module:list

Produktion

  • .env.local mit Lizenzen auf Server deployen
  • Lizenzserver-Firewall: Zugriff erlauben
  • Monitoring: Lizenz-Ablaufdaten überwachen
  • Backup: .env.local in Backup einschließen

Erweiterungsmöglichkeiten

Bereits implementiert

Interface-basierte Architektur Lizenzvalidierung mit Online/Offline-Modus CLI-Commands für Verwaltung REST-API für Admin-UI Vue.js Admin-Interface Integration mit Permission-System Caching mit Grace Period Composer-basierte Installation

Zukünftige Features (optional)

  • 🔮 Multi-Tenancy-Support (mehrere Instanzen, eine Lizenz)
  • 🔮 Offline-Lizenzierung (Air-Gapped Systeme)
  • 🔮 Automatische Update-Benachrichtigungen
  • 🔮 Modul-Marketplace Integration
  • 🔮 Feature-Flags innerhalb von Modulen
  • 🔮 Modul-Dependencies (Modul A benötigt Modul B)
  • 🔮 Rollback-Mechanismus bei Installation

Technologie-Stack

Backend

  • PHP 8.3+
  • Symfony 7.1 LTS
  • Doctrine ORM
  • API Platform
  • PSR-6 Cache (Symfony Cache)
  • PSR-3 Logger (Monolog)

Frontend

  • Vue.js 3 (Composition API)
  • PrimeVue (UI-Komponenten)
  • Tailwind CSS

DevOps

  • Composer (Package Management)
  • Symfony Flex (Auto-Configuration)
  • Doctrine Migrations

Code-Statistik

Core-System (neu):
├── Interfaces: 2 Dateien
├── Services: 2 Dateien
├── Commands: 2 Dateien
├── Controller: 1 Datei
├── EventListener: 1 Datei
└── Vue-Komponenten: 1 Datei

Beispiel-Modul:
├── Plugin-Klasse: 1 Datei
├── Bundle: 1 Datei
├── DependencyInjection: 2 Dateien
├── Entity: 1 Datei (Beispiel)
└── Konfiguration: 1 Datei

Dokumentation:
├── PLUGIN_SYSTEM.md: Vollständige Anleitung
├── PLUGIN_SYSTEM_SUMMARY.md: Diese Datei
├── EXAMPLE_MODULE_STRUCTURE.md: Modul-Template
└── example-module/: Code-Beispiele

Kosten-Nutzen-Analyse

Vorteile

Modularität: Kunden zahlen nur für benötigte Features Wartbarkeit: Module unabhängig updatebar Skalierbarkeit: Beliebig viele Module möglich Lizenzierung: Automatische Kontrolle über Funktionen Entwicklung: Parallele Modul-Entwicklung möglich Testing: Module isoliert testbar Deployment: Schrittweise Einführung möglich

Aufwand

⚠️ Initial: ~2-3 Tage für Core-System (bereits implementiert) ⚠️ Pro Modul: ~1-2 Tage zusätzlich für Plugin-Setup ⚠️ Lizenzserver: Separater Service erforderlich ⚠️ Dokumentation: Pro Modul individuell

ROI

Mit diesem System können Sie:

  • Module einzeln lizenzieren und verkaufen
  • Upselling durch Feature-Module
  • Trial-Lizenzen mit Ablaufdatum
  • Pay-per-Feature-Modelle
  • White-Label-Lösungen mit unterschiedlichen Modulen

Kontakt und Support

Diese Implementierung wurde mit Claude Code entwickelt und basiert auf Symfony Best Practices.

Nächste Schritte:

  1. Lizenzserver implementieren (externe Komponente)
  2. Erstes Produktiv-Modul entwickeln (z.B. Billing)
  3. Testing und Monitoring in Produktion
  4. Dokumentation für Modul-Entwickler erweitern