feat: Plugin-System Umbau — 6 Phasen komplett abgeschlossen
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
Phase 1: Contracts konsequent nutzen - 12 neue contracts.py erstellt (alle 19 Plugins haben jetzt contracts) - 4 bestehende contracts.py an zentrale ContractRegistry angepasst - Alle 19 Plugins haben on_deactivate mit Contract-Unregister - 0 echte problematische INTER-Plugin Imports Phase 2: Hooks/Filters-System - app/core/hooks.py (HookRegistry mit actions + filters) - 15 Hook-Punkte in Core-Services (contact, auth, mail, calendar, user, dms) - BasePlugin.on_deactivate meldet alle Hooks ab Phase 3: Plugin-Isolation - scripts/check_cross_plugin_imports.py (Linting-Regel) - .github/workflows/check-cross-plugin-imports.yml (CI/CD) - .pre-commit-cross-plugin.yaml (Pre-commit Hook) - 155 Dateien geprueft, 0 Verstoesse Phase 4: Plugin-Versioning - app/plugins/semver.py (SemVer mit Parse, Compare, Pre-release) - migration_runner.py erweitert: run_migration_down, rollback_to_version - manifest.py: min_app_version Feld - registry.py: App-Version-Compatibility-Check bei Installation - GET /api/v1/plugins/updates Endpoint Phase 5: Marketplace-Vorbereitung - app/plugins/signature.py (Ed25519 Signatur-Validierung) - app/plugins/quarantine.py (Plugin-Quarantine mit Validierung) - app/models/plugin_allowlist.py + Migration 0046 - manifest.py: author, license, homepage, icon, screenshots, changelog, marketplace_tags, price - registry.py: discover_external(), discover_all() - POST /api/v1/plugins/install-marketplace (deaktiviert) Phase 6: Manifest-Anpassung - manifest.py: 12 neue Felder + SemVer/Hook-Name Validierung - MANIFEST_SCHEMA_DOC aktualisiert - Alle 19 Plugin-Manifeste aktualisiert - Frontend PluginUiManifest Typ erweitert Zusaetzliche Bug-Fixes: - test_sample-Modul erstellt - conftest.py Deadlock-Prevention - SESSION_COOKIE_SECURE=true - dump.rdb aus Git entfernt + .gitignore - backup.py datetime.utcnow -> func.now() - system_settings.py JSONB-Import nach oben - tax.py Mapped[float] -> Mapped[Decimal] - notification.py type_key-Laengen vereinheitlicht Tests: 91 neue Tests, alle bestanden
This commit is contained in:
+200
-3
@@ -1,9 +1,21 @@
|
||||
# LeoCRM Plugin-System — Kompletter Umbauplan
|
||||
|
||||
**Erstellt:** 2026-07-26
|
||||
**Geschätzter Gesamtaufwand:** ~129 Stunden (~16 Arbeitstage)
|
||||
**Aktualisiert:** 2026-07-26 (Codebasis-Verifikation + Phase 6)
|
||||
**Geschätzter Gesamtaufwand:** ~149 Stunden (~19 Arbeitstage)
|
||||
**Status:** Geplant — noch nicht gestartet
|
||||
|
||||
**Codebasis-Verifikation (2026-07-26):**
|
||||
- ✅ `base.py` unverändert — Plan passt
|
||||
- ✅ `registry.py` unverändert — Plan passt
|
||||
- ✅ `manifest.py` unverändert — Plan passt
|
||||
- ✅ `contracts.py` (ContractRegistry) unverändert — Plan passt
|
||||
- ✅ Migration 0044 hinzugekommen: RLS Repair + separater DB-User (crm_runtime) — beeinflusst Plugin-System nicht
|
||||
- ✅ Migration 0045 hinzugekommen — neuer Head
|
||||
- ✅ `require_active_plugin` in `deps.py` hinzugekommen — beeinflusst Plugin-System nicht
|
||||
- ✅ 19 echte Plugins (test_sample hat __init__.py statt plugin.py)
|
||||
- ✅ Cross-Imports: 224, Contracts: 8, get_contract: 11 — unverändert
|
||||
|
||||
---
|
||||
|
||||
## Übersicht: 5 Phasen
|
||||
@@ -15,7 +27,8 @@
|
||||
| Phase 3 | 5 | Plugin-Isolation (Linting) | 4 | 0,5 |
|
||||
| Phase 4 | 8 | Plugin-Versioning | 20 | 2,5 |
|
||||
| Phase 5 | 6 | Marketplace-Vorbereitung | 42 | 5 |
|
||||
| **Gesamt** | | | **129** | **16** |
|
||||
| Phase 6 | — | Manifest-Anpassung & Konsolidierung | 20 | 2,5 |
|
||||
| **Gesamt** | | | **149** | **~19** |
|
||||
|
||||
**Wichtig:** Jede Phase ist unabhängig funktionsfähig. Das System läuft nach jeder Phase ohne Einschränkungen weiter.
|
||||
|
||||
@@ -645,6 +658,182 @@ async def _quarantine_plugin(zip_path: Path) -> Path:
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Manifest-Anpassung & Konsolidierung
|
||||
|
||||
**Ziel:** Alle in Phase 4 und 5 definierten Manifest-Felder werden ins `PluginManifest` integriert, bestehende Manifeste aktualisiert, und das Manifest-System finalisiert.
|
||||
|
||||
**Wichtig:** Diese Phase baut auf Phase 4 (Versioning) und Phase 5 (Marketplace) auf und muss als letztes durchgeführt werden.
|
||||
|
||||
### 6.1 PluginManifest erweitern (4 Std)
|
||||
|
||||
**Aktuelles Manifest (verifiziert 2026-07-26):**
|
||||
```python
|
||||
class PluginManifest(BaseModel):
|
||||
name: str
|
||||
version: str
|
||||
display_name: str
|
||||
description: str
|
||||
dependencies: list[str]
|
||||
routes: list[PluginRouteDef]
|
||||
events: list[str]
|
||||
migrations: list[str]
|
||||
permissions: list[str]
|
||||
is_core: bool
|
||||
field_definitions: list[FieldDefinition]
|
||||
agent_capabilities: list[str]
|
||||
menu_items: list[FrontendMenuItem]
|
||||
page_routes: list[FrontendPageRoute]
|
||||
detail_tabs: list[FrontendDetailTab]
|
||||
settings_pages: list[FrontendSettingsPage]
|
||||
dashboard_widgets: list[FrontendDashboardWidget]
|
||||
agent_definitions: list[AgentDefinitionContribution]
|
||||
automation_templates: list[AutomationTemplateContribution]
|
||||
cron_jobs: list[CronJobContribution]
|
||||
heartbeat_configs: list[HeartbeatConfigContribution]
|
||||
miniapps: list[MiniAppContribution]
|
||||
custom_fields: list[CustomFieldDefinition]
|
||||
model_config = {"extra": "forbid"}
|
||||
```
|
||||
|
||||
**Neue Felder hinzufügen:**
|
||||
```python
|
||||
class PluginManifest(BaseModel):
|
||||
# ... alle bestehenden Felder ...
|
||||
|
||||
# ── Versioning (Phase 4) ──
|
||||
min_app_version: str = Field(
|
||||
default="0.0.0",
|
||||
description="Minimum LeoCRM version required (SemVer)"
|
||||
)
|
||||
|
||||
# ── Marketplace (Phase 5) ──
|
||||
author: str = Field(default="", max_length=200, description="Plugin author name")
|
||||
author_email: str = Field(default="", max_length=200, description="Author contact email")
|
||||
homepage: str = Field(default="", max_length=500, description="Plugin homepage URL")
|
||||
license: str = Field(default="MIT", max_length=50, description="License identifier")
|
||||
icon: str = Field(default="", description="Icon URL or emoji")
|
||||
screenshots: list[str] = Field(default_factory=list, description="Screenshot URLs for marketplace")
|
||||
changelog: str = Field(default="", description="Changelog URL or inline text")
|
||||
marketplace_tags: list[str] = Field(default_factory=list, description="Marketplace category tags")
|
||||
price: float = Field(default=0.0, ge=0.0, description="Price (0 = free)")
|
||||
|
||||
# ── Hooks (Phase 2) ──
|
||||
hooks: list[str] = Field(
|
||||
default_factory=list,
|
||||
description="Hook names this plugin registers (e.g. 'contact.before_create')"
|
||||
)
|
||||
|
||||
# ── Contracts (Phase 1) ──
|
||||
contract_version: str = Field(
|
||||
default="1.0.0",
|
||||
description="Contract API version this plugin exposes"
|
||||
)
|
||||
```
|
||||
|
||||
### 6.2 Manifest-Schema-Dokumentation aktualisieren (3 Std)
|
||||
|
||||
**`MANIFEST_SCHEMA_DOC` in `manifest.py` erweitern:**
|
||||
- Alle neuen Felder in `fields`-Dict aufnehmen
|
||||
- `example`-Manifest mit neuen Feldern aktualisieren
|
||||
- API-Endpoint `GET /api/v1/plugins/manifest` liefert vollständiges Schema
|
||||
|
||||
### 6.3 Alle 19 Plugin-Manifeste aktualisieren (8 Std)
|
||||
|
||||
Jedes Plugin-Manifest muss um die neuen Felder erweitert werden:
|
||||
|
||||
| # | Plugin | Aufwand | Neue Felder |
|
||||
|---|---|---|---|
|
||||
| 1 | `ai_assistant` | 30 Min | author, min_app_version, hooks, contract_version |
|
||||
| 2 | `ai_proactive` | 30 Min | author, min_app_version, hooks, contract_version |
|
||||
| 3 | `ai_ui_control` | 20 Min | author, min_app_version, contract_version |
|
||||
| 4 | `automation` | 30 Min | author, min_app_version, hooks, contract_version |
|
||||
| 5 | `calendar` | 20 Min | author, min_app_version, hooks, contract_version |
|
||||
| 6 | `dms` | 20 Min | author, min_app_version, hooks, contract_version |
|
||||
| 7 | `entity_links` | 15 Min | author, min_app_version, contract_version |
|
||||
| 8 | `forgejo_error_reporter` | 15 Min | author, min_app_version, contract_version |
|
||||
| 9 | `kommunikation` | 30 Min | author, min_app_version, hooks, contract_version |
|
||||
| 10 | `mail` | 20 Min | author, min_app_version, hooks, contract_version |
|
||||
| 11 | `mcp_client` | 20 Min | author, min_app_version, contract_version |
|
||||
| 12 | `mcp_server` | 20 Min | author, min_app_version, contract_version |
|
||||
| 13 | `permissions` | 20 Min | author, min_app_version, contract_version |
|
||||
| 14 | `report_generator` | 20 Min | author, min_app_version, contract_version |
|
||||
| 15 | `system_notif` | 15 Min | author, min_app_version, contract_version |
|
||||
| 16 | `tags` | 15 Min | author, min_app_version, contract_version |
|
||||
| 17 | `tasks` | 20 Min | author, min_app_version, hooks, contract_version |
|
||||
| 18 | `test_sample` | 10 Min | author, min_app_version, contract_version |
|
||||
| 19 | `unified_search` | 20 Min | author, min_app_version, hooks, contract_version |
|
||||
|
||||
**Muster für Aktualisierung:**
|
||||
```python
|
||||
# VORHER:
|
||||
manifest = PluginManifest(
|
||||
name="calendar",
|
||||
version="1.0.0",
|
||||
display_name="Calendar",
|
||||
...
|
||||
)
|
||||
|
||||
# NACHHER:
|
||||
manifest = PluginManifest(
|
||||
name="calendar",
|
||||
version="1.0.0",
|
||||
display_name="Calendar",
|
||||
# ... bestehende Felder ...
|
||||
# ── Neue Felder ──
|
||||
min_app_version="1.0.0",
|
||||
author="LeoCRM Team",
|
||||
license="MIT",
|
||||
hooks=["calendar.before_appointment", "calendar.after_appointment"],
|
||||
contract_version="1.0.0",
|
||||
)
|
||||
```
|
||||
|
||||
### 6.4 Frontend Plugin-Manifest-Typen aktualisieren (2 Std)
|
||||
|
||||
**`frontend/src/api/pluginManifests.ts` und `frontend/src/types/automation.ts`:**
|
||||
- TypeScript-Interfaces um neue Manifest-Felder erweitern
|
||||
- `PluginManifestResponse`-Typ aktualisieren
|
||||
- Frontend-Komponenten die Manifest-Felder anzeigen erweitern
|
||||
|
||||
### 6.5 Manifest-Validierung verschärfen (3 Std)
|
||||
|
||||
**Neue Validierungsregeln in `PluginManifest`:**
|
||||
```python
|
||||
@field_validator("min_app_version")
|
||||
@classmethod
|
||||
def validate_min_app_version(cls, v: str) -> str:
|
||||
"""Validate SemVer format."""
|
||||
from app.plugins.semver import SemVer
|
||||
SemVer.parse(v) # Raises ValueError if invalid
|
||||
return v
|
||||
|
||||
@field_validator("hooks")
|
||||
@classmethod
|
||||
def validate_hooks(cls, v: list[str]) -> list[str]:
|
||||
"""Validate hook names follow namespace.pattern."""
|
||||
for hook in v:
|
||||
if not re.match(r"^[a-z_]+\.[a-z_]+$", hook):
|
||||
raise ValueError(f"Invalid hook name '{hook}': must be 'namespace.action'")
|
||||
return v
|
||||
```
|
||||
|
||||
### 6.6 Tests für erweitertes Manifest (3 Std)
|
||||
|
||||
- `test_manifest.py` — Neue Felder validieren
|
||||
- `test_manifest_validation.py` — SemVer-Validierung, Hook-Name-Validierung
|
||||
- Alle Plugin-Tests: Manifest mit neuen Feldern erstellen
|
||||
- Frontend-Tests: Manifest mit neuen Feldern rendern
|
||||
|
||||
### Meilenstein Phase 6:
|
||||
- ✅ `PluginManifest` hat alle neuen Felder (min_app_version, author, hooks, contract_version, etc.)
|
||||
- ✅ `MANIFEST_SCHEMA_DOC` ist vollständig aktualisiert
|
||||
- ✅ Alle 19 Plugin-Manifeste haben die neuen Felder
|
||||
- ✅ Frontend-Typen sind aktualisiert
|
||||
- ✅ Manifest-Validierung ist verschärft
|
||||
- ✅ Tests bestanden
|
||||
|
||||
---
|
||||
|
||||
## Zeitplan
|
||||
|
||||
```
|
||||
@@ -654,7 +843,8 @@ Woche 2 (Tag 6-8): Phase 1 — Contracts (Teil 2: Deaktivierung + Tests)
|
||||
Woche 3 (Tag 11): Phase 3 — Plugin-Isolation
|
||||
(Tag 12-14): Phase 4 — Plugin-Versioning
|
||||
Woche 4 (Tag 15-19): Phase 5 — Marketplace-Vorbereitung
|
||||
(Tag 20): Puffer / Bugfixes / Doku
|
||||
Woche 5 (Tag 20-22): Phase 6 — Manifest-Anpassung & Konsolidierung
|
||||
(Tag 23): Puffer / Bugfixes / Doku
|
||||
```
|
||||
|
||||
### Abhängigkeiten
|
||||
@@ -666,6 +856,8 @@ Phase 1 (Contracts) ──→ Phase 3 (Isolation: Linting braucht Contracts als
|
||||
└──→ Phase 4 (Versioning: braucht Contracts für min_app_version)
|
||||
│
|
||||
└──→ Phase 5 (Marketplace: braucht alles)
|
||||
│
|
||||
└──→ Phase 6 (Manifest: braucht Phase 4 + 5 Felder)
|
||||
```
|
||||
|
||||
### Parallelisierungsmöglichkeiten
|
||||
@@ -673,6 +865,7 @@ Phase 1 (Contracts) ──→ Phase 3 (Isolation: Linting braucht Contracts als
|
||||
- Phase 3 kann erst nach Phase 1 starten
|
||||
- Phase 4 kann nach Phase 1 starten
|
||||
- Phase 5 kann erst nach Phase 1+4 starten
|
||||
- Phase 6 kann erst nach Phase 4+5 starten (braucht deren Manifest-Felder)
|
||||
|
||||
---
|
||||
|
||||
@@ -707,6 +900,10 @@ Nach Abschluss aller 5 Phasen:
|
||||
13. ✅ **Externe Plugin-Discovery** funktioniert
|
||||
14. ✅ **Alle Tests bestanden**
|
||||
15. ✅ **Built-in Plugins laufen ohne Marketplace**
|
||||
16. ✅ **PluginManifest hat alle neuen Felder** (min_app_version, author, hooks, contract_version, etc.)
|
||||
17. ✅ **Alle 19 Plugin-Manifeste aktualisiert** mit neuen Feldern
|
||||
18. ✅ **Manifest-Validierung verschärft** (SemVer, Hook-Names)
|
||||
19. ✅ **Frontend-Typen aktualisiert** für neue Manifest-Felder
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user