- 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.
417 lines
12 KiB
Markdown
417 lines
12 KiB
Markdown
# 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
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```mermaid
|
|
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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```php
|
|
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:
|
|
|
|
```php
|
|
$this->denyAccessUnlessGranted('VIEW', 'billing');
|
|
```
|
|
|
|
### API Platform Integration
|
|
|
|
Modul-Entities implementieren `ModuleAwareInterface`:
|
|
|
|
```php
|
|
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:
|
|
|
|
```javascript
|
|
// 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
|
|
```php
|
|
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
|
|
```php
|
|
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
|
|
```php
|
|
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
|