# Plugin-Menüs und Permissions
Anleitung zur dynamischen Registrierung von Menü-Items und Permissions durch Plugins.
## Übersicht
Das Plugin-System unterstützt jetzt:
✅ **Dynamische Menü-Items** - Plugins können eigene Menüpunkte hinzufügen
✅ **Automatische Permission-Synchronisation** - Modul-Permissions werden automatisch in der DB angelegt
✅ **Permission-basierte Sichtbarkeit** - Menüpunkte erscheinen nur für berechtigte User
✅ **Gruppierung** - Plugin-Menüs können gruppiert werden
---
## 1. Menü-Items im Plugin definieren
### In deiner Plugin-Klasse:
```php
public function getMenuItems(): array
{
return [
[
'label' => 'Rechnungen', // Menü-Titel (Container)
'icon' => 'pi-file-pdf', // PrimeIcons Icon (ohne pi pi-fw prefix)
'group' => 'Finanzen', // Gruppierung im Menü
// WICHTIG: Container-Items brauchen KEINE permission Property
'items' => [
[
'label' => 'Alle Rechnungen',
'icon' => 'pi-list',
'to' => '/billing/invoices', // Vue Router path
'permission' => 'billing.view' // WICHTIG: Jedes Sub-Item braucht permission
],
[
'label' => 'Neue Rechnung',
'icon' => 'pi-plus',
'to' => '/billing/invoices/create',
'permission' => 'billing.create' // Explizite Permission
],
[
'separator' => true // Optional: Trennlinie
],
[
'label' => 'Einstellungen',
'icon' => 'pi-cog',
'to' => '/billing/settings',
'permission' => 'billing.manage' // Explizite Permission
]
]
]
];
}
```
### Menü-Item Optionen:
| Feld | Typ | Required | Beschreibung |
|------|-----|----------|--------------|
| `label` | string | ✅ | Anzeigename des Menüpunkts |
| `icon` | string | ❌ | PrimeIcons Icon (ohne `pi pi-fw` prefix) |
| `to` | string | ❌ | Vue Router path |
| `url` | string | ❌ | Externe URL (alternativ zu `to`) |
| `items` | array | ❌ | Sub-Menüpunkte |
| `permission` | string | ❌ | Permission-String für Sichtbarkeits-Check |
| `group` | string | ❌ | Gruppierung im Hauptmenü |
| `separator` | bool | ❌ | Trennlinie (nur in Sub-Items) |
---
## 2. Permissions definieren
### In deiner Plugin-Klasse:
```php
public function getPermissionModules(): array
{
// Best Practice: Ein einziges Modul pro Plugin
return ['billing'];
}
```
**WICHTIG:** Verwende nur **ein** Permission-Modul pro Plugin, nicht mehrere! Dies vereinfacht die Administration massiv.
Das System erstellt automatisch folgende Permissions für das Modul `billing`:
- `billing.view`
- `billing.create`
- `billing.edit`
- `billing.delete`
- `billing.export`
- `billing.manage`
### Permission-Synchronisation durchführen:
```bash
# Alle Plugins synchronisieren
php bin/console app:plugin:sync-permissions
# Nur ein bestimmtes Plugin
php bin/console app:plugin:sync-permissions billing
# Dry-Run (zeigt nur was passieren würde)
php bin/console app:plugin:sync-permissions --dry-run
```
**Output:**
```
Plugin Permission-Module Synchronisation
========================================
Synchronisiere alle Plugins...
------------------------------
Aktion Anzahl
Neu erstellt 2
Aktualisiert 0
Übersprungen 5
```
---
## 3. Frontend Integration
### API-Endpoints:
#### GET /api/plugin-menu
Gibt alle Plugin-Menü-Items als flache Liste zurück.
**Response:**
```json
{
"success": true,
"data": [
{
"label": "Alle Rechnungen",
"icon": "pi-list",
"to": "/billing/invoices",
"permission": "billing.view",
"source": "billing"
}
],
"count": 1
}
```
#### GET /api/plugin-menu/grouped
Gibt gruppierte Plugin-Menü-Items zurück.
**Response:**
```json
{
"success": true,
"data": {
"Finanzen": [
{
"label": "Rechnungen",
"icon": "pi-file-pdf",
"items": [...]
}
]
},
"groups": ["Finanzen"]
}
```
### AppMenu.vue
Das Menü lädt automatisch Plugin-Menüs beim Mount:
```vue
```
---
## 4. Permission-Checks im Frontend
### Mit Composition API:
```vue
```
### Im Template:
```vue
```
---
## 5. Beispiel: Vollständiges Plugin
### BillingModulePlugin.php
```php
licenseValidator->validate('billing')['valid'];
}
public function getLicenseInfo(): array
{
return $this->licenseValidator->validate('billing');
}
public function boot(): void
{
if (!$this->isLicensed()) {
throw new \RuntimeException('Billing Module nicht lizenziert');
}
// Services, Routes, etc. registrieren
}
public function getPermissionModules(): array
{
// Best Practice: Ein einziges Modul für das gesamte Plugin
return ['billing'];
}
public function getMenuItems(): array
{
return [
[
'label' => 'Rechnungen',
'icon' => 'pi-file-pdf',
'group' => 'Finanzen',
// Wichtig: Container-Item hat KEINE permission Property
'items' => [
[
'label' => 'Dashboard',
'icon' => 'pi-chart-line',
'to' => '/billing/dashboard',
'permission' => 'billing.view' // Explizite Permission
],
[
'label' => 'Alle Rechnungen',
'icon' => 'pi-list',
'to' => '/billing/invoices',
'permission' => 'billing.view'
],
[
'label' => 'Neue Rechnung',
'icon' => 'pi-plus',
'to' => '/billing/invoices/create',
'permission' => 'billing.create'
],
[
'separator' => true
],
[
'label' => 'Zahlungen',
'icon' => 'pi-money-bill',
'to' => '/billing/payments',
'permission' => 'billing.view' // Einheitliches Modul!
],
[
'label' => 'Einstellungen',
'icon' => 'pi-cog',
'to' => '/billing/settings',
'permission' => 'billing.manage'
]
]
]
];
}
public function canInstall(): array
{
$errors = [];
if (PHP_VERSION_ID < 80200) {
$errors[] = 'PHP 8.2+ erforderlich';
}
return [
'success' => empty($errors),
'errors' => $errors
];
}
}
```
---
## 6. Workflow: Neues Plugin mit Menüs
### Schritt 1: Plugin erstellen
```bash
cd ../mycrm-billing-module
composer init
# Name: mycrm/billing-module
```
### Schritt 2: Plugin-Klasse implementieren
Siehe Beispiel oben - implementiere `getMenuItems()` und `getPermissionModules()`.
### Schritt 3: In myCRM installieren
```bash
cd ../myCRM
composer config repositories.mycrm-billing-module path ../mycrm-billing-module
composer require mycrm/billing-module:@dev
```
### Schritt 4: Permissions synchronisieren
```bash
php bin/console app:plugin:sync-permissions billing
```
**Output:**
```
Neu erstellt: 3 (billing, invoicing, payments)
```
### Schritt 5: Cache leeren
```bash
php bin/console cache:clear
```
### Schritt 6: Lizenz aktivieren
```bash
php bin/console app:module:license billing YOUR_GITEA_TOKEN
```
### Schritt 7: Testen
1. Frontend öffnen
2. Plugin-Menü erscheint unter "Finanzen"
3. Menüpunkte sind nur sichtbar mit Berechtigung
---
## 7. Debugging
### Menü-Items überprüfen:
```bash
curl http://localhost:8000/api/plugin-menu | jq
```
### Permissions in DB überprüfen:
```sql
SELECT * FROM modules WHERE code IN ('billing', 'invoicing', 'payments');
```
### Plugin-Status:
```bash
php bin/console app:module:list
```
### Logs:
```bash
tail -f var/log/dev.log | grep -E "(Plugin|Menu|Permission)"
```
---
## 8. Best Practices
### ✅ DO's:
- **Gruppiere verwandte Menüs** - Nutze `group` für bessere Organisation
- **Permission-Checks** - Definiere `permission` für alle sensiblen Menüpunkte
- **Icons verwenden** - Macht das Menü übersichtlicher
- **Synchronisiere nach Installation** - `app:plugin:sync-permissions` nach jedem Plugin-Update
### ❌ DON'Ts:
- **Keine Core-Gruppen überschreiben** - "Home", "CRM", "Administration" sind reserviert
- **Keine tiefen Verschachtelungen** - Max. 2 Ebenen (Gruppe → Items)
- **Keine externen URLs ohne Warnung** - User erwarten interne Navigation
- **Nicht mehrere Permission-Module für ein Plugin** - Erschwert die Administration unnötig
### 🎯 WICHTIG: Permission-Format und Sub-Items (Stand: 2025-12-28)
**Ein Permission-Modul pro Plugin:**
```php
// ✅ RICHTIG: Ein einziges Modul
public function getPermissionModules(): array
{
return ['billing'];
}
// ❌ FALSCH: Unnötig aufgeteilt
public function getPermissionModules(): array
{
return ['billing', 'invoices', 'payments'];
}
```
**Explizite Permissions für ALLE Sub-Items:**
```php
// ✅ RICHTIG: Jedes anklickbare Item hat permission
public function getMenuItems(): array
{
return [
[
'label' => 'Rechnungen', // Container - KEINE Permission nötig
'icon' => 'pi-file-pdf',
'group' => 'Finanzen',
'items' => [
[
'label' => 'Alle Rechnungen',
'to' => '/billing/invoices',
'permission' => 'billing.view' // ✅ Explizite Permission
],
[
'label' => 'Neue Rechnung',
'to' => '/billing/invoices/create',
'permission' => 'billing.create' // ✅ Explizite Permission
]
]
]
];
}
// ❌ FALSCH: Sub-Items ohne Permission
public function getMenuItems(): array
{
return [
[
'label' => 'Rechnungen',
'permission' => 'billing.view', // ❌ Container braucht keine Permission
'items' => [
[
'label' => 'Alle Rechnungen',
'to' => '/billing/invoices'
// ❌ FEHLT: permission Property!
]
]
]
];
}
```
**Warum ist das wichtig?**
Das Frontend (`AppMenu.vue`) verwendet eine **rekursive `convertMenuItem()` Funktion**, die:
1. Alle Sub-Items durchläuft und deren `permission` Properties in `visible` Funktionen umwandelt
2. Items mit `source` Property automatisch zu `${source}.view` Permission konvertiert
3. Nur Items mit erfüllter Permission anzeigt
**Container-Items** (mit `items` Array) brauchen **KEINE eigene Permission**, da sie nur dann angezeigt werden, wenn mindestens ein Sub-Item sichtbar ist.
---
## 9. Troubleshooting
### Problem: Menü erscheint nicht
**Lösung:**
```bash
# Cache leeren
php bin/console cache:clear
# Plugin-Status prüfen
php bin/console app:module:list
# API testen
curl http://localhost:8000/api/plugin-menu/grouped
# Browser-Console überprüfen
```
### Problem: Permissions fehlen
**Lösung:**
```bash
# Permissions synchronisieren
php bin/console app:plugin:sync-permissions
# DB überprüfen
SELECT * FROM modules WHERE code = 'billing';
# Rolle zuweisen
# In der Rollenverwaltung das neue Modul auswählen
```
### Problem: Permission-Checks funktionieren nicht
**Lösung:**
- Prüfe ob User die Rolle hat
- Prüfe ob Rolle die Permission hat
- Prüfe `authStore.hasPermission()` Implementierung
---
## 10. Migration bestehender Plugins
Wenn du bereits Plugins hast, füge einfach `getMenuItems()` hinzu:
```php
// Altes Plugin
class MyPlugin implements ModulePluginInterface {
// ... bestehende Methoden ...
}
// Neu: Füge hinzu
class MyPlugin implements ModulePluginInterface {
// ... bestehende Methoden ...
public function getMenuItems(): array
{
return [
// Deine Menüs hier
];
}
}
```
Dann:
```bash
composer dump-autoload
php bin/console cache:clear
```
---
## Support
Bei Fragen siehe:
- `PLUGIN_SYSTEM.md` - Allgemeine Plugin-Architektur
- `GITEA_LICENSE_SYSTEM.md` - Lizenzierung
- `docs/PERMISSIONS.md` - Permission-System