Files
leocrm/docs/fix-plan-v3.md
T

637 lines
47 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LeoCRM — Reparaturplan v3 (komplett überarbeitet)
> Erstellt: 2026-08-23 · v3 nach Plattform-Klarstellung
> Basis: v1 (leocrm-fix-plan.zip gesichert) + ChatGPT-Review (16 Punkte) + eigene Code-Verifizierung
> Grundsatz: Erst Plattformbasis reparieren, dann Plugin-Grenze, dann Frontend, DANACH erst Einzelbugs.
> Alle ARCH-IDs + neue Findings sind explizit einem Block zugeordnet. Nichts hängt mehr in der Luft.
## LEITBILD (bindend für alle Blöcke)
Dieses Projekt ist KEINE CRM-Anwendung, sondern eine **Business- & Agenten-Plattform**:
- Der Core ist ein **Plattform-Kernel**: Multi-Tenant, Auth/Permissions, Plugin-System, Events, Workflows, AI-Agent-Laufzeit.
- **Fachmodule (CRM heute, ERP-Module später) sind ausschließlich Plugins** — nachrüstbar, deaktivierbar, ohne Core-Änderung.
- **Agenten sollen die Software VOLL bedienen können** — jede Plugin-Funktion muss automatisch agenten-bedienbar werden, ohne dass der Core angefasst wird.
- Konsequenz als Prüfregel für JEDEN Task: *"Kann ein neues Fachmodul diese Funktion nutzen, ohne eine Core-Datei zu ändern?"* — Wenn nein, ist der Task falsch geschnitten.
---
## 0. Korrigierte Statistik (v1 war falsch)
| Angabe | v1 (falsch) | v2 (korrekt) |
|---|---|---|
| Bugs gesamt | 148 | **139 eindeutige IDs** |
| Offen | 113 | **108 eindeutig** (31 High / 56 Medium / 21 Low nach Duplikat-Entfernung) |
| Gefixt | 20 | **19** (BUG-073 war doppelt) |
| Kein Bug | 12 | 12 |
Entfernte Duplikate: BUG-073 (Gefixt-Liste), BUG-074/075/076/077 (Phase 2 doppelt), BUG-078 (Phase 3 doppelt).
## 1. Was gegenüber v1 geändert wurde (ChatGPT-Review, alle 16 Punkte)
1. **Statistik korrigiert** (siehe oben), alle Duplikate entfernt.
2. **Phase 0 (Agent Zero Config) gestrichen** — deepseek-v4-pro/ministral/Vision gehören nicht in diesen Plan.
3. **Reihenfolge gedreht**: Plattformbasis ist jetzt Block A (zuerst), Einzelbugs folgen in D.
4. **Contacts-Ansatz korrigiert**: NICHT "NUR Plugin" (v1-Fehler), sondern **Core-Plugin (is_core=True, nicht deaktivierbar) OHNE Core-Hardcoding**.
5. **Workspace ARCH-004 hat jetzt eine konkrete Fixphase** (C2) mit verifizierter Ursache.
6. **Checker-Fix erweitert**: nicht nur Default, sondern ZWEI Bugs (Default + ValueError-Crash bei relativen Pfaden).
7. **Regel aufgenommen**: KEINE globalen commit→flush-Transformationen; nur nachgewiesene Einzelfälle.
8. **Regel aufgenommen**: Integration/Install-Tests ausschließlich über Alembic-Migrationen, kein pauschales `Base.metadata.create_all`.
9. **Frontend-Permission-Reihenfolge fixiert**: ERST Backend-Felder `FrontendPageRoute.permission` + `FrontendMenuItem.permission` (C1), DANN statische Routes abbauen (C4) — sonst Permission-Verlust.
10. **Settings + Dashboard als eigene Fixpunkte ergänzt** (C6/C7) — fehlten in v1 komplett.
11. **Lifecycle-Findings konkret eingeplant**: ARCH-012, 013, 015, 033037, 042 jetzt einzeln in Block A aufgeführt.
12. **God Objects raus** aus dem Pflichtumbau → separater Track S1.
13. **i18n raus** aus dem Basisumbau → separater Track S2.
14. **Secrets/SQL-Injection = TRIAGE statt Pauschalfix** (D4): jede Stelle klassifizieren, nur echte Findings fixen.
15. **Marathon-Zahlen = Triage-Cluster** (D5), keine Bug-Anzahl, Root-Cause-Clustering.
16. **Verifikations-Gates in JEDEN Block integriert** (nicht erst am Ende) + 10 verpflichtende Integrationstests vor dem Löschen alter Wege.
## 2. Neue Findings (nicht in v1, heute code-verifiziert)
| ID | Finding | Ort | Block |
|---|---|---|---|
| SYNTAX-001 | **SyntaxError Zeile 413** (`expected 'except' or 'finally'`) in UNCOMMITTED Änderung — App startet mit aktuellem Working-Tree nicht. Einrückung von `logger.info` + `except` wurde beim if-Guard-Verschub nicht mitgenommen | app/plugins/builtins/automation/plugin.py | 0 |
| CHECK-002 | Checker crasht mit `ValueError: 'app/ai/action_mapper.py' is not in the subpath` bei relativen Pfaden — `check_file()` ruft `relative_to(PROJECT_ROOT)` ohne Resolution | scripts/check_cross_plugin_imports.py:113 | 0 |
| DT-001 | Naive `datetime.utcnow()` in mcp_client routes (fehlte in allen v1-Listen) | app/plugins/builtins/mcp_client/routes.py:173 | D2 |
| SQLITE-001 | SQLite in-memory Fixture — Forbidden Pattern (PostgreSQL only) | app/plugins/builtins/automation/tests/test_automation.py:35 | D2 |
Vollscan-Ergebnis (nach CHECK-002-Fix): **14 Cross-Plugin-Verstöße**, davon Core→Plugin: `ai/integration_tools.py` (3×), `core/worker.py` (2×), `routes/compliance.py`, `workflows/engine.py`, `routes/compliance.py`; Plugin→Plugin: 5× (Details in Block B).
---
# BLOCK 0 — Sofortmaßnahmen (Blocker, vor allem anderen)
### 0.1 SYNTAX-001: automation/plugin.py reparieren
- `logger.info(...)` und `except Exception:` im Cron-Job-Block auf die neue Einrücktiefe heben (innerhalb `if default_tenant_id is not None:``for``try`).
- Verify: `/opt/venv/bin/python -m py_compile app/plugins/builtins/automation/plugin.py` → OK, dann App-Start smoke testen.
- Danach entscheiden: committen (nach Review) oder reverten. Zustand nicht so lassen.
### 0.2 ARCH-010 + CHECK-002: Cross-Plugin-Checker doppelt fixen
```python
parser.add_argument("--path", default=None)
...
search_path = Path(args.path).resolve() if args.path else None
files = find_python_files(search_path) # None -> Vollscan app/
```
- In `check_file()`: `filepath = Path(filepath).resolve()` vor `relative_to(PROJECT_ROOT)`.
- Verify: ohne Argument → ~450+ Dateien, 14 Verstöße; `--path app` (relativ) → kein Crash, identisches Ergebnis.
### 0.3 Gate
- `python -c "import app.main"` lädt sauber (mit framework runtime).
- Checker-Ausgabe (14 Findings) wird Arbeitsliste für Block A/B.
---
# BLOCK A — Plattformbasis: Lifecycle, Contracts, Events, Runtime
Ziel: Plugin activate/deactivate deterministisch, Contracts stabil, keine Laufzeit-Namen Fehler.
### A1 Activation-Reihenfolge & Tenant-Logik
- **ARCH-001**: plugin_service.py:94 — Permissions registrieren VOR `on_activate()`; `active=True` erst nach erfolgreichem on_activate setzen.
- **ARCH-002**: main.py:292-302 — `on_activate()` einmal pro Prozess (global scope), nicht pro Tenant. Tenant-Seed bleibt separat.
- **ARCH-043**: automation register_plugin_contributions — `Tenant.limit(1)` ersetzen durch definierten Default-Tenant-Mechanismus (konfigurierter System-Tenant), dokumentieren.
### A2 Deactivation & Cleanup (vollständige Liste, war in v1 ungeplant)
- **ARCH-012**: knowledge/wiki on_deactivate vervollständigen (Search-Provider, Event-Handler, Entities deregistrieren).
- **ARCH-013**: self_improvement services.py:586-588 — Fallback auf direkten kommunikation-Import entfernen, Contract-only.
- **ARCH-015**: registry.py:181-244,622-623 — Notification-Type Sync in deactivate-Sequence einordnen.
- **ARCH-033**: kommunikation on_deactivate → service_container.remove() für alle registrierten Services.
- **ARCH-034**: self_improvement on_deactivate → contract unregister.
- **ARCH-035**: marketplace on_deactivate → contract unregister.
- **ARCH-036**: mail `_auto_sync_task` Klassenvariable → Instanzvariable (sonst teilen sich Instanzen den Task-State).
- **ARCH-037**: graph_rag on_activate — `super().on_activate()` VOR eigenem `registry.register()`.
- **ARCH-044**: ai_ui_control on_deactivate — service_container.remove() VOR super().on_deactivate().
- **BasePlugin erzwingt Symmetrie**: activate was du registered, deactivate must remove (Checkliste in base.py dokumentieren).
### A3 Contracts
- **ARCH-014**: contracts.py:88-89 — Lazy-Load nach `unregister()` deaktivieren (Flag `unregistered=True` prüfen).
- **ARCH-042**: calendar/dms contracts — `get_contract()` darf neue Instanz erzeugen; registrierte Instanz aus Registry zurückgeben.
- **ARCH-030**: step_handlers.py:221,261,306,351,394 — `get_function()` existiert nicht; tatsächliche Contract-API verwenden (oder Methode sauber ergänzen).
- **ARCH-047**: SearchContract → UnifiedSearchContract (Import + Usage).
### A4 Events & Worker
- **ARCH-020**: event_bus.py:38 — Duplikat-Check vor append.
- **ARCH-038**: BasePlugin.register_event_handlers() definieren (Hook-Punkt), worker.py:168 nutzt ihn.
- **ARCH-048**: engine.py:663 — payload key "event" → "event_name" (Outbox-Envelope-Kontrakt).
- **ARCH-050**: engine.py acquire_lock — `await get_redis()` auf nicht-async Funktion; konsistent machen (async oder await entfernen).
### A5 Runtime-Namen & None-Fehler
- **ARCH-029/041**: trigger_dispatcher.py:125 — None-Check VOR Verwendung.
- **ARCH-031**: knowledge/plugin.py — `import uuid` ergänzen.
- **ARCH-032**: knowledge:66 + wiki:41 — `unregister_actions_by_owner(hook_name, owner_tag)` mit 2 Argumenten.
- **ARCH-054**: entity_permissions.py:114/259 — `ENTITY_MODELS.get(entity_type)` direkt, nicht model_info["model"].
- **ARCH-052**: storage.py get_file_metadata — kein `asyncio.new_event_loop()` im async Kontext; korrekt awaiten.
### A6 Default-Permissions-Basis
- **ARCH-009**: alembic/0019 + permissions.py:46-50 — Wildcard-Pattern an 2-Segment-Schema angleichen (`contacts:read` statt `core:contacts:read`) + Datenmigration für Bestandsrollen.
- **ARCH-008**: Permission-Namen vereinheitlichen (kommunikation plugin.py:44 vs dashboard.py:23) — Namensschema festlegen und durchsetzen (Konstanten aus registry).
### Gate A (muss grün sein vor Block B)
1. Import-Test: jedes Modul in app/ lädt (kein NameError/ImportError).
2. Activate → Permissions/Entities sofort registriert; Deactivate → sauber deregistriert (Runtime-Test).
3. Multi-Tenant-Startup: on_activate genau 1× im Log.
4. Contract roundtrip: register → get_contract liefert registrierte Instanz → unregister → get_contract liefert None (kein Lazy-Resurrect).
5. pytest-Smoke der Plugin-Tests (ohne die in D geschobenen Suiten).
---
# BLOCK B — Plugin-Grenze vollständig ziehen
Ziel: Core kennt Plugins nicht als Sonderfall. Plugins deklarieren alles.
### B1 Contacts: Core-Plugin statt Core-Hardcoding ⚠️ Kernstück
**Prinzip:** `is_core=True` bedeutet *nicht deaktivierbar* — NICHT *im Core hardcoded*. Contacts bleibt immer aktiv, aber 100% über den Plugin-Mechanismus.
1. `main.py:549` `app.include_router(contacts.router)` entfernen — NACHDEM der Plugin-Route-Mechanismus identische Endpoints bereitstellt (Endpoint-Diff-Test davor!).
2. Plugin manifest: `routes=[]`-Kommentar beseitigen; Contacts-Routes über Plugin registrieren mit `require_active_plugin("contacts")`-Dependency (schützt bei versehentlicher Deaktivierung + klarer Fehler).
3. `CORE_FIELD_DEFINITIONS` (Contact-Feldmassen) → Plugin-Field-Contribution migrieren.
4. Sidebar-Sonderfall ("Only non-plugin items: dashboard, contacts, settings") → contacts über pluginNavItems.
5. Restore/History/Entity-Links: Contacts-Entity über EntityRegistry (B3), nicht über Core-Annahmen.
6. Acceptance: `grep -rn "contacts" app/main.py` → keine fachliche Referenz mehr; alle Contact-E2E-Tests grün.
### B2 Core→Plugin Imports via Contracts (alle 6 Core-Stellen des Vollscans)
- `app/ai/integration_tools.py`: tool_registry/knowledge/provider_registry → get_contract("ai_assistant"/"knowledge"/"unified_search").
- `app/ai/agent_loop.py`: analog prüfen und umstellen.
- `app/core/worker.py:175,460`: provider_registry + KnowledgeExtraction (**deckt ARCH-040 ab**) → Contract/Service-Interface.
- `app/routes/compliance.py:22` (**ARCH-046**): AgentDefinition → Contract oder gemeinsames Core-Schema.
- `app/workflows/engine.py:94-95` (**ARCH-049**): CommConversation → kommunikation-Contract.
- Regel: Wenn ein Contract fehlt, Contract im Plugin definieren und exportieren — NIEMALS Model-Import behalten.
### B3 Entity-Registry & Custom Fields dynamisch
- **ARCH-016**: ENTITY_PERMISSIONS-Liste aus registrierten Plugin-Entities generieren (entity_permission_service.py:54, entity_permissions.py:252).
- **ARCH-017**: custom_field_definitions.py:25,42 — von contacts-Permission entkoppeln (plugin-eigene Permission je entity_type).
- **ARCH-022**: deps.py _WRITE_PERMISSIONS aus permission_registry generieren (nicht hardcoded).
### B4 Dependencies deklarieren
- **ARCH-026**: Manifest `depends_on`; Aktivierungsreihenfolge topologisch; Abhängiges nicht deaktivierbar solange Abhängiges aktiv (Fehlermeldung statt stiller Bruch).
- **ARCH-021-Vorbereitung**: Menü/Routen-Daten kommen vollständig aus active-manifests (siehe C).
### B5 ARCH-003 (früh, weil Frontend es braucht)
- plugins.py:97 — `/plugins/active-manifests` für eingeloggte User freigeben (eigene Permission `plugins:view_manifests`, Default-Rollen erhalten sie). Frontend braucht das für C.
### Gate B (vor Block C)
1. **Neues-Plugin-Test**: Minimal-Plugin mit Route+Entity+Menü — OHNE Änderung einer Core-Datei funktionsfähig.
2. **Fresh-DB-Install**: leere DB → ausschließlich Alembic → Admin-Seed → Contacts/Companies voll funktional.
3. **Contacts-Vertrag**: Endpoint-Vergleich alt (core route) vs. neu (plugin route) — identische Pfade/Statuscodes.
4. Dependency-Test: A hängt an B → B deaktivieren wird blockiert.
5. Cross-Plugin-Vollscan: 0 Core→Plugin-Verstöße.
---
# BLOCK C — Frontend + Workspace (erst nach A+B)
⚠️ Reihenfolge innerhalb C ist verbindlich: Backend-Felder (C1) → Store-Filter (C2) → Loader (C3) → erst DANN Route-/Menu-Umbau (C4C7) → Production-Verify (C8) → alte Wege löschen (C9).
### C1 Backend: Permission-Felder liefern (VORAUSSETZUNG für alles Weitere)
- `FrontendPageRoute.permission: str | None` + `FrontendMenuItem.permission: str | None` in app/plugins/manifest.py ergänzen (aktuell nur `protected: bool` — verifiziert).
- active-manifests liefert die Felder aus; TypeScript-Typen (PluginMenuItem erwartet bereits `permission?` — Backend zieht nach).
- Migration der vorhandenen Plugin-Manifeste: jede Route/Menü bekommt ihre Permission.
### C2 Workspace is_visible (ARCH-004, verifizierte Ursache)
- workspaceStore.ts:103-105: `visibleModuleKeys()` filtert aktuell gar nicht:
`new Set((ctx?.modules ?? []).filter(m => m.is_visible !== false).map(m => m.module_key))`
- Server-Seite prüfen: liefert WorkspaceContext modules ohne is_visible? Falls ja, Feld ergänzen.
- Test: `is_visible=false` → Modul unsichtbar in Sidebar + Route guard; Toggle im WorkspaceManager wirkt sofort.
### C3 PluginLoader Production-Build (ARCH-019)
- `@vite-ignore` Dynamic-Import-Problem lösen: Plugin-Frontends als bekannte Chunk-Map (build-time generiertes Manifest) oder importmap. Ziel: Production-Build lädt Plugin-Module wirklich.
### C4 Dynamische Routes mit Permission (ARCH-006 + ARCH-007)
- PluginRouteRenderer: PermissionGate mit `route.permission` aus C1 wrappen (gleiches Verhalten wie heutige statische `<PermissionRoute permission="calendar:read">`).
- Statische Plugin-Routes in routes/index.tsx markieren (deprecated), parallel betreiben bis C8 grün.
- **ARCH-061** gleich mit: leeres Route-Objekt (index.tsx:58-59) entfernen.
### C5 Sidebar (ARCH-021)
- singleItems reduzieren auf dashboard/login/settings(+profil). Alles andere aus pluginStore (Manifest-Menü inkl. permission, order, icon).
- Sortierreihenfolge aus Manifest `order`.
### C6 Settings-Doppelarchitektur auflösen (NEU, fehlte in v1)
- Settings.tsx:33-61: `hardcodedNavItems` + `pluginNavItems` + Dedup → EINE Quelle: Settings-Seiten als Manifest-Contribution (`parent: "/settings"` existiert bereits in FrontendPageRoute). Core behält nur Profil/Security-Basis.
### C7 Dashboard entkoppeln (NEU, fehlte in v1)
- DashboardWidgetLoader.tsx:13-20: statische Widget-Map → Widget-Registry aus Plugin-Manifest (component + permission + dashboard-slot).
- dashboard.py:14,60-66: Contact-Count nicht hardcoded — Count-Endpoint je Entity über Contract/Registry (Contacts-Plugin liefert seinen Count; Core aggregiert).
- RecentContacts/TasksSummary/CalendarUpcoming → Contributions ihrer Plugins.
### C8 Kleinere Frontend-Dedupes (funktional begründet, KEIN Refactor-Programm)
- **ARCH-062**: TeamPanel → components/shared/TeamPanel.tsx (echte Duplikation, 50 Zeilen).
- **ARCH-063**: SortableMenuItem.tsx:4 `import * as LucideIcons` → ICON_MAP-Pattern (behebt OOM in Tests — funktional, nicht kosmetisch).
### C9 Alte Wege löschen (NUR nach C8-Verify)
- Statische Plugin-Routes + Sidebar-singleItems + Settings-hardcodes entfernen.
### Gate C
1. **Production Build** (`npm run build`) + Playwright GEGEN DEN BUILD (nicht dev-server).
2. Workspace: is_visible=false wirklich unsichtbar (Sidebar + Direktaufruf geblockt).
3. Normaler User (kein Admin): sieht Plugin-Menüs/Routes gemäß Permission; 403 wo keine.
4. Permission-Diff-Test: jede ehemals statische Route hatte Permission X → dynamische Route fordert dieselbe X (KEIN Absinken auf auth-only).
5. tsc --noEmit clean.
---
# BLOCK D — Produktbugs & Triage (JETZT erst, auf stabiler Basis)
### D1 pytest-Suiten reparieren (die v1-„Phase 1"-Massen)
- Reihenfolge nach Basisabhängigkeit: conftest/fixtures → test_auth → test_abac → test_companies → test_calendar → test_ai_proactive → test_api_tokens → test_backend_coverage_gaps → test_phase_h_wiki (BUG-097, 091, 087, 088, 089, 090, 086, 085, 092096, 098, 099, 067).
- Pro Suite: Root-Cause zuerst (meist Fixtures/RLS/Permission-Setup), keine Test-Anpassung um grün zu werden (AGENTS.md §2).
### D2 DateTime & Forbidden Patterns (abgeschlossen, konkrete Liste)
- `datetime.utcnow()``datetime.now(UTC)` an: core/worker.py:365,409,468 · routes/audit.py:170 · services/webhook_service.py:221 · services/backup_service.py:159 · plugins/mcp_client/routes.py:173 (**DT-001, neu**). (Deckt ARCH-039, 053, 058, 060.)
- **SQLITE-001** (neu): automation test fixture auf ephemeres PostgreSQL (projekt-Konvention) umstellen.
### D3 API-/Testpfad-Korrekturen (Low, mechanisch)
- BUG-027, 028, 029, 031, 032, 033, 034, 035, 071 (Test-Pfade/Payloads an reale API anpassen — Docs prüfen, nicht Tests verbiegen falls API falsch: dann API fixen).
- **ARCH-051**: dict-body-Routes auf Pydantic-Schemas (Liste aus test-bugs abarbeiten).
- **ARCH-055**: errors.py:124 user_agent. **ARCH-056/057**: roles.py SYSTEM_PERMISSIONS aus registry importieren; `_plugins` → öffentliche Methode. **ARCH-061** falls nicht schon in C4.
### D4 Security-TRIAGE (nicht pauschal fixen)
- BUG-019 „453 hardcoded secrets“: Klassifizieren (echtes Secret / Testdaten / Konstante / false positive) → nur echte Findings: Secret in env/Secretstore, Referenz einfügen. Ergebnis als Triage-Tabelle dokumentieren.
- BUG-020 „288 SQL-Injection-Risiken“: Nur Stellen mit User-Input-Fluss in String-SQL prüfen; parameterisieren. Scan-Finding ≠ Bug.
- **ARCH-027** hier einsortieren: config.py Default SECRET_KEY in Production hart failen lassen.
### D5 Marathon-Scanner-Triage (BUG-074078)
- trace_api_contracts (859), stores (323), hooks (70), plugins (27), functions (3): Cluster-Analyse → wahrscheinliche Root-Causes zählen (Erfahrungswert: deutlich weniger als Issue-Zahl) → Cluster fixen, Scanner erneut laufen lassen, Delta dokumentieren.
### D6 Legacy-Migration (umsichtig)
- **ARCH-059** (+ ARCH-018-Familie): AIConversation/AIMessage → kommunikation-Conversations migrieren ODER Modul als deprecated markieren + Abschaltplan. Kein Big-Bang: erst Parität herstellen, dann Quellen umstellen, dann Tabellen droppen (eigene Migration).
- **ARCH-023**: service_container.initialize() vervollständigen.
---
# SEPARATE TRACKS (bewusst NICHT Teil dieses Umbaus)
| Track | Inhalt | Warum geschoben |
|---|---|---|
| S1 Code-Hygiene | God Objects (36 Py + 9 FE, BUG-018/081), weitere >500-Zeilen-Splits | Kein nachgewiesener Basisdefekt; Risiko von Big-Refactors bekannt |
| S2 i18n | BUG-021, ARCH-024, 025, 028, 045 | UI-Qualitätsarbeit, kein Architekturproblem |
| S3 Dependency-Audits | BUG-022/070 npm, pip-audit-Routine | Routineaufgabe, automatisierbar (CI), kein Umbau |
---
# VERIFIKATIONS-GATES (gültig in ALLEN Blöcken)
Nach jedem Block, vor dem nächsten:
1. Import-Test aller app/-Module (framework runtime).
2. Cross-Plugin-Vollscan: 0 Verstöße der jeweiligen Kategorie.
3. `npx tsc --noEmit` + ruff + mypy (Ziel-Regelwerk) bei jedem Touch.
4. pytest-Smoke der betroffenen Suites.
## 10 verpflichtende Integrationstests VOR dem Löschen alter Doppelwege (C9/B1-final)
| # | Test | Muss bestehen |
|---|---|---|
| 1 | Runtime Plugin Activation | Permissions + Entities sofort registriert |
| 2 | Runtime Deactivation | sauber deregistriert (Contracts/Services/Events) |
| 3 | Multi-Tenant Startup | on_activate genau 1× |
| 4 | Normaler User | Plugin-Manifeste/Menüs ohne Adminrecht (ARCH-003-Fix wirksam) |
| 5 | Workspace | is_visible=false wirklich unsichtbar |
| 6 | Dependency | A→B geladen; B nicht deaktivierbar solange A aktiv |
| 7 | Neues Plugin | keine Core-Dateiänderung nötig |
| 8 | Frontend Production Build | dynamische Plugin-Routes laden wirklich (nicht dev) |
| 9 | Fresh DB | Editor/Viewer-Permissions funktionieren nach reiner Migration+Seed |
| 10 | Contacts Core-Plugin | funktioniert ohne Contacts-Hardcodings im Core |
---
# BLOCK F — Sicherheit des Umbaus selbst + Wissenssicherung
Ziel: Der Umbau darf selbst nichts kaputt machen, und die neue Architektur muss so dokumentiert sein, dass die Fehlerklasse NIE wieder entsteht.
### F1 Rollback- & Branch-Strategie (schützt vor 'Plan macht was kaputt')
- Pro Block ein eigener Git-Branch (`fix/block-a`, `fix/block-b`, ...). Merge in main NUR nach bestandenem Block-Gate.
- Pro Task ein Commit (Conventional Commits mit Finding-ID) — jeder Commit ist einzeln revertierbar.
- DB-Migrationen additiv-first: neue Spalten/Tabellen hinzufügen, alte NICHT droppen, solange der neue Weg nicht durch Gate verifiziert ist. Drop-Migrationen erst in einem eigenen 'Cleanup-Release' nach C9.
- Feature-Flags wo machbar: dynamische Routes/Sidebar hinter einem Toggle (`DYNAMIC_PLUGIN_UI=true/false`), Default=false bis Gate C grün. Sofortiger Rollback = Flag off, kein Code-Revert.
- Deploy-Reihenfolge: Staging-Container (docker compose profile test) VOR Production. Production-Deploy nur mit grünem Gate.
- Vor jedem Block-Start: git tag `pre-block-<X>` als Restore-Punkt.
### F2 Was der Plan bewusst NICHT anfasst (Explosions-Schutz)
- Keine Schema-Änderungen an bestehenden 130 Tabellen (nur additive neue Felder: permission in Manifests ist Code, kein DB-Schema).
- Keine API-Path-Änderungen für bestehende Endpoints (Contacts-Entkopplung muss identische Pfade liefern — Endpoint-Diff-Test in B1 erzwingt das).
- Keine Auth-/Session-Logik-Änderungen (Security-Basics sind verifiziert gut — nicht anfassen).
- Keine gleichzeitige Änderung von Backend + Frontend im selben Commit (Backend erst, dann Frontend — C-Reihenfolge).
### F3 Plugin-Development-Guide aktualisieren (VERHINDERT RÜCKFALL) ⚠️ Pflicht
**Befund:** docs/plugin-development-guide.md existiert (2549 Zeilen, gut strukturiert: Manifest, Lifecycle, UI-Registration, Events, Permissions, Migrations). ABER verifizierte Lücken:
- Contracts: nur 3 Erwähnungen — der zentrale Mechanismus der neuen Architektur fehlt fast komplett
- `depends_on`: 0 Erwähnungen — ARCH-026 führt es ein, der Guide kennt es nicht
- Kein 'Plugin-Checkliste'-Abschnitt, der die Fehlerklasse (Cross-Plugin-Imports, Lifecycle-Asymmetrie, fehlende Permissions) strukturell verhindert
**Pflicht: Der Guide wird MIT jedem Block aktualisiert — ein Block gilt erst als done, wenn der Guide den neuen Zustand beschreibt.**
| Nach Block | Guide-Update |
|---|---|
| A | Kapitel 'Contracts' vollständig: get_contract, register/unregister, Symmetrie-Pflicht activate/deactivate, register_event_handlers-Hook, EventBus-Duplikat-Regel |
| B | Kapitel 'Dependencies': depends_on im Manifest, topologische Aktivierung, Deaktivier-Schutz. Kapitel 'Entity-Registrierung': dynamische ENTITY_PERMISSIONS, Field-Contributions (statt CORE_FIELD_DEFINITIONS) |
| C | Kapitel 'Frontend-Contributions' aktualisieren: permission-Feld in FrontendPageRoute/FrontendMenuItem (PFLICHT, nicht optional), Widget-Registry statt statischem Loader, Workspace is_visible |
| D | Kapitel 'Konventionen': datetime.now(UTC) statt utcnow, Pydantic-Schemas statt dict-bodies, Audit-Log-Pflicht bei Mutationen |
**Neuer Guide-Abschnitt 'Plugin-Checkliste' (Muss-Bestehen vor Merge jedes neuen Plugins):**
1. Kein direkter Import aus anderem Plugin — nur get_contract (Checker läuft in CI)
2. on_activate/on_deactivate symmetrisch: alles was registriert wird, wird auch deregistriert
3. Jede Route hat Permission (kein auth-only), jede Menü-Route hat permission-Feld im Manifest
4. depends_on deklariert, wenn Plugin andere nutzt
5. Entities über Plugin-Registrierung, keine Core-Annahmen
6. Frontend-Components über Manifest-Contribution, keine hardcoded Loader-Einträge
7. Migrationen folgen Namenskonvention, RLS für eigene Tabellen
8. Audit-Log bei allen Mutationen
9. datetime nur mit UTC
10. E2E-Smoke gegen Production-Build
**Enforcement:** Die Checkliste wird als CI-Template-Check + Review-Checkliste referenziert. AGENTS.md §0 (Auf bestehendem Code aufbauen) bleibt die übergeordnete Regel.
### Gate F
- Guide-Review: Jeder neue Mechanismus (Contracts, depends_on, permission-Felder, Widget-Registry) hat ein Kapitel mit Code-Beispiel aus einem REAL existierenden Plugin (nicht fiktiv).
- Checkliste als Datei (docs/plugin-checklist.md) existiert und ist in PR-Template verlinkt.
- Test: Ein Entwickler (oder Agent) baut ein Minimal-Plugin NUR mit dem Guide — ohne Fragen an den Architekten. Gelingt das nicht, ist der Guide nicht fertig.
---
# BLOCK G — Compliance & Account-Security (NEU aus Final-Check 2026-08-23)
Ziel: Rechtliche Pflichten (DSGVO) und Account-Sicherheit, die im Final-Check ans Licht kamen. Diese Punkte waren in v1, v2 UND dem ChatGPT-Review nicht enthalten.
### G1 DSGVO-Compliance ⚠️ KRITISCH (verifiziert: grep 'gdpr' in app/routes + app/services = 0 Treffer)
Ein CRM mit Personendaten ohne DSGVO-Funktionen darf in DE nicht produktiv gehen:
- **Art. 15 Auskunft**: Endpunkt `GET /api/v1/me/data-export` — alle Daten einer natürlichen Person, maschinenlesbar (JSON).
- **Art. 17 Löschung**: Der von AGENTS.md geforderte Hard-Delete (`?gdpr=true`) existiert als Regel, aber KEIN Endpunkt implementiert ihn. Implementieren: anonymisiere/lösche Personendaten inkl. aller verknüpften Entities (Contacts, Addresses, Notes, Files, Mail-Verknüpfungen), respektiere Aufbewahrungspflichten (Buchhaltung), protokolliere die Löschung selbst im Audit.
- **Art. 20 Portabilität**: Strukturierter Export (JSON/CSV) der Kontaktdaten eines Tenants/Users.
- **Verarbeitungsübersicht**: doc (welche Daten, wo, wie lange) als Grundlage für den AVV.
- Aufwand: mittelgroßes Feature-Paket, eigener Track mit Tests; NICHT in die Architekturblöcke mischen.
### G2 Session-Revocation bei Passwortänderung (verifiziert: nur Logout invalidiert)
- Befund: app/routes/auth.py:105 invalidiert NUR die eigene Session beim Logout. Eine Passwortänderung löscht NICHT andere aktive Sessions des Accounts.
- Risiko: kompromittierter Account bleibt nach PW-Wechsel kompromittiert (Angreifer-Session lebt weiter).
- Fix: Nach erfolgreichem Passwortwechsel/-reset alle Sessions des Users löschen (außer der aktuellen); optional E-Mail-Benachrichtigung über den Vorgang.
- Klein, wichtig, sofort machbar — gehört in Block 0 oder A.
### G3 Hygiene-Funde (klein)
- dump.rdb im Repo-Root: git-ignored (kein Leak, verifiziert), aber aufräumen und Redis-Workdir sauber konfigurieren.
- scripts/test_migrations.sh:70 testet `alembic downgrade base`, ignoriert aber Fehler bewusst ('not always lossless'). Entscheidung dokumentieren: Downgrade-Fähigkeit ist KEIN Release-Kriterium — dann Kommentar so lassen und in docs/test-strategy.md festhalten.
### Verifiziert GUT (nichts zu tun — explizit geprüft im Final-Check)
- Webhook-Signaturen: HMAC-SHA256 vorhanden (webhook_service.py:200-231)
- API-Token-Expiry-Prüfung vorhanden (api_token.py:91-95)
- Content-based MIME-Detection via python-magic (storage.py:32-34)
- CORS konfigurierbar über Settings (main.py:468-469)
- Redis: Passwort-Pflicht, Named Volume, Healthcheck (docker-compose.yaml:50-59)
---
# BLOCK H — Agent-Plattform-Kern (NEU v3: Kernprodukt, war unsichtbar)
⚠️ Höchste Priorität nach Block 0 — VOR bzw. zusammen mit Block B.
Kontext: Die Plattform soll ERP-Fachmodule per Plugin nachrüsten und Agenten müssen die Software VOLL bedienen. Code-Verifizierung zeigt: Dieser Kernanspruch ist aktuell architektonisch NICHT erfüllt.
### H1 Befunde (verifiziert 2026-08-23)
1. **Agent-Tools sind hardcoded**: `app/ai/integration_tools.py` registriert Workflow/Knowledge-Tools fest und importiert direkt aus Plugins (Core→Plugin, ARCH-011-Familie). Ein neues Fachmodul könnte seine Funktionen NICHT agenten-bedienbar machen, ohne diese Core-Datei zu ändern — direkter Verstoß gegen das Plattform-Prinzip.
2. **Agent-Laufzeit hängt an einem Plugin**: `ToolRegistry` liegt unter `app/plugins/builtins/ai_assistant/tool_registry.py`. Ist ai_assistant deaktiviert, existiert keine Registry mehr — Agent-Betrieb ohne dieses Plugin unmöglich.
3. **Manifest hat Contribution-Ansätze** (`agent_capabilities` manifest.py:200, `AgentDefinitionContribution.tool_ids` :88-94), aber keinen vollständigen Weg: BasePlugin kennt keinen register_tools-Hook; die Hardcodes umgehen das Manifest komplett.
### H2 Architektur-Entscheidung (zuerst klären, dann bauen)
- **Agent-Laufzeit = Core**: `tool_registry`, `skill_registry`, `llm_client`, `agent_loop` gehören in `app/core/` bzw. `app/ai/` (Core-Layer), NICHT ins ai_assistant-Plugin. Das ai_assistant-Plugin wird zum normalen Fachplugin, das NUR seine eigenen Tools beiträgt.
- **Tool-Contribution-API**: Manifest-Feld `tools: list[ToolContribution]` (name, description, input_schema, handler_ref, required_permission) + BasePlugin-Lifecycle: on_activate registriert Tools beim Core-Registry, on_deactivate meldet sie ab (Symmetrie-Pflicht wie alle Contributions).
- **Permission-Gebundenheit**: Jedes Agent-Tool trägt die Permission des darunterliegenden Endpoints; der Agent kann nur handeln, was der ausführende User darf (bestehendes agent_permissions.py nutzen/konsolidieren).
### H3 Umbau
1. Core-Registry nach app/core/ ziehen (Move + Alias-Import für Übergangszeit), ai_assistant nutzt sie wie jedes andere Plugin.
2. `integration_tools.py` auflösen: Die 4 Hardcoded-Tools werden zu regulären Contributions ihrer Quell-Plugins (workflows, knowledge, unified_search) via Manifest/Hook — Core-Datei verschwindet.
3. Plugin-Guide: neues Kapitel 'Agent-Tools beitragen' mit Schema + Beispiel + Test-Pflicht (Tool ohne Permission verboten).
4. ARCH-011-Core-Imports (ai/integration_tools, ai/agent_loop) lösen sich dadurch STRUKTURELL auf — nicht durch Contract-Surrogate an dieser Stelle.
### Gate H
1. Neues Fachmodul-Testplugin bringt ein Agent-Tool MIT OHNE Änderung einer Core-Datei; Agent führt es aus (Tenant-scoped, permission-geprüft).
2. ai_assistant deaktivieren → Agent-Laufzeit läuft weiter; dessen eigene Tools sind weg, alles andere bleibt.
3. Deactivate/Activate-Zyklus: Tools sauber ab-/angemeldet, keine Duplikate (EventBus-Duplikatfix greift hier analog).
4. Jeder Tool-Call landet im Audit-Log mit actor=agent, acting_user, permission.
### H4 Weitere Hardcoding-Systeme (gründlicher Nachscan 2026-08-23, alle code-verifiziert)
Gleiche Fehlerklasse wie H1 — Systeme, die Fachmodule hardcodieren statt Contribution anzubieten:
| ID | System | Ort | Befund | Fix-Richtung |
|---|---|---|---|---|
| HC-A | NL→Aktions-Mapping | app/ai/action_mapper.py:52-128 | map_query_to_actions() hat FESTE API-Pfade per Regex — neue Fachmodul-Endpunkte sind für Agenten-Vorschläge UNSICHTBAR | Aktions-Katalog aus Plugin-Manifest generieren (Endpoint-Registry existiert schon via OpenAPI) |
| HC-B | Workflow-Schritte | app/workflows/step_handlers.py:221,261,306,351,394 | Importiert 5 Contract-KLASSEN direkt (MailContract, CalendarContract, DmsContract, SearchContract, AutomationContract) statt get_contract() — neue Module können KEINE eigenen Step-Types beitragen | Step-Handler-Registry: Plugins registrieren Step-Types per Manifest; Core kennt nur Interface |
| HC-C | AI-Chat & Workflow-Notifications an kommunikation | app/ai/agent_loop.py:397 + app/workflows/engine.py:95 | CommConversation-Model direkt importiert — AI-Konversationspersistenz und Workflow-Benachrichtigung hängen am kommunikation-Plugin | Über kommunikation-Contract (besteht laut Checker-Output teilweise) oder Notification-Abstraktion |
| HC-D | Knowledge-Worker | app/core/worker.py:460 | KnowledgeExtraction-Model direkt importiert (deckt ARCH-040) | Contract oder generischer Extraction-Job über Plugin-Hook |
| HC-E | Compliance-Route | app/routes/compliance.py:22 | AgentDefinition-Model direkt importiert | Contract auf automation oder Model in Core-Schema überführen |
**POSITIV-VORBILD im eigenen Code:** `unified_search/provider_registry.py` macht es RICHTIG — dynamisches register()/unregister()/get(), graph_rag contributet seinen Provider per Contract (graph_rag/plugin.py:44-58). Dieses Muster ist die Blaupause für ALLE H-Fixes.
**Inkonsistenz gleich mitfixen:** knowledge/services.py:110 importiert provider_registry DIREKT statt den eigenen unified_search-Contract zu nutzen (Plugin→Plugin-Verstoß aus dem Vollscan).
### H5 Frontend-Hardcodings (Nachscan Frontend 2026-08-23, code-verifiziert)
| ID | System | Ort | Befund | Fix-Richtung |
|---|---|---|---|---|
| HC-F | Message-Block-Typen | frontend/src/components/comm/blocks/BlockRenderer.tsx:3-15,34+ | 14 Block-Typen hart im switch, darunter FACHMODUL-Blocks (TaskCardBlock, WorkflowCardBlock, KnowledgeCardBlock, ContactCardBlock, AgentResultBlock, ApprovalRequestBlock). Keine dynamische Registry (grep registerBlock/BLOCK_REGISTRY = leer). Ein ERP-Modul kann keine eigenen Message-Blocks beitragen | Block-Registry: Plugins registrieren Block-Component per Manifest-Contribution (component + block_type + permission); Core behält nur text/markdown/html/file/image/audio/video als Basis |
| HC-G | AISidebar-Tabs | frontend/src/components/layout/AISidebar.tsx:137-141 | 5 Tabs hardcodiert (chat/proactive/notifications/team/chatroom), Fachmodule können keine eigenen Sidebar-Tabs beitragen | Tab-Contribution über Manifest (wie Menü/Routes); Core behält Basis-Tabs, Plugin-Tabs kommen aus pluginStore |
**Geprüft und sauber (Frontend):** Core-Layout-Komponenten (App.tsx, routes/, components/layout/, components/common/) importieren KEINE Plugin-API-Clients direkt. Die Doppelarchitektur-Probleme (Routes, Sidebar-Menü, Settings, Dashboard) sind bereits als C4C7 geplant.
**Gate H erweitert:**
5. Testplugin registriert einen eigenen Workflow-Step-Type OHNE Core-Änderung; Workflow führt ihn aus.
6. Agent-Query auf einen Fachmodul-Begriff schlägt dessen Aktionen vor (HC-A wirksam).
7. grep-Beweis: Keine der Dateien integration_tools/step_handlers/agent_loop/engine enthält noch Plugin-Model-Imports.
8. Testplugin contributet einen eigenen Message-Block-Typ; BlockRenderer rendert ihn dynamisch (HC-F wirksam).
9. Testplugin contributet einen AISidebar-Tab; Tab erscheint dynamisch (HC-G wirksam).
---
# BLOCK E — Production-Härtung (NEU aus Deep-Dive 2026-08-23)
Ziel: Der Unterschied zwischen 'Architektur repariert' und 'produktiv betreibbar'. Diese Punkte fehlten in v1 UND v2 komplett.
### E1 Audit-Logging-Vollständigkeit
- Befund: Nur 1 Service-Datei referenziert AuditLog (grep-verified). AGENTS.md verbietet Mutationen OHNE Audit-Eintrag.
- Fix: Systematische Prüfung ALLER schreibenden Routes/Services auf Audit-Aufruf; Lücke schließen (Middleware-/Repository-Pattern statt handgestreut); Test: jede POST/PATCH/DELETE-Route erzeugt Audit-Zeile.
### E2 E2E-Test-Realität
- Befund: BUG-012 — Playwright helpers.ts nutzt Mock-Daten. Die E2E-'Abdeckung' ist teilweise Schein.
- Fix: helpers.ts auf echte API umstellen; E2E gegen Production-Build + echte Backend-Instanz (docker compose profile test). Erst danach zählt E2E als Verifikations-Gate.
### E3 Backup/Restore-Drill
- Vorhanden: backup.py, restore.py, restore_test.sh — aber ungeprüft, ob Restore auf FRISCHER DB wirklich reproduzierbar funktioniert.
- Fix: Automatisierten Restore-Drill in CI aufnehmen (Dump → leere DB → Restore → Smoke-Checks). Monatlicher manuell getriggerte Drill zusätzlich.
### E4 Monitoring-Reality-Check
- Docs vorhanden (monitoring.md, incident-response-runbook.md) — tatsächliche Aktivierung ungeprüft.
- Fix: Health-Endpunkte extern erreichbar + Alerting konfiguriert? Metrics-Endpoint gefüllt? Einmal durchspielen und dokumentieren, was WIRKLICH alarmiert.
### E5 Performance-Baseline
- Keine Lasttests erkennbar; bereits ein Search-Perf-Bug (6.34s) aufgetreten.
- Fix: Baseline-Messung der Top-10-Endpoints (p95), seed_perf_data.py nutzen, Schwellwerte dokumentieren. Kein Voll-Lasttest-Programm — nur Baseline + Regressionsschwelle.
### E6 Secrets & Credential-Hygiene
- Befund: Sensible Credentials liegen lt. Projektanweisungen in docs/deploy-guide.md (privates Repo, aber Repo-Datei ≠ Secretstore).
- Fix: Triage wie D4; Ziel: Deploy-Guide referenziert Secretstore statt Werte zu enthalten. pip-audit/npm-audit-Routine in CI (aus S3 vorziehen: nur die AUTOMATISIERUNG, nicht die Altlasten).
### E7 CI als hartes Gate
- Vorhanden aber ungeprüft: ci_pipeline.sh, .forgejo/workflows, .pre-commit-cross-plugin.yaml.
- Fix: Pipeline zum Pflicht-Gate machen: Import-Check + Cross-Plugin-Vollscan (nach 0.2-Fix) + ruff (85 Auto-Fixes zuerst bereinigen, dann Regel scharf) + tsc + pytest-Smoke. Merge ohne grün = unmöglich.
### Reihenfolge von E
- E7 sofort nach Block 0 (CI braucht den funktionierenden Checker).
- E1 nach Block B (Audit braucht stabile Service-Schicht).
- E2E6 parallel zu Block C/D, spätestens VOR Go-Live-Kandidat.
---
# ARBEITSREGELN (aus Review abgeleitete Verbote/Gebote)
1. ❌ KEINE globalen `commit()→flush()`-Transformationen. Nur nachgewiesene Einzelfälle mit Transaktionsbegründung (BUG-003-Muster).
2. ❌ KEIN pauschales `Base.metadata.create_all` in conftest. Unit-Fixtures ok; Integration/Install ausschließlich Alembic.
3. ✅ Erst Backend-Feld (`permission`), dann Frontend-Consumption. Nie umgekehrt.
4. ✅ Alte Wege (Routes/Sidebar/Settings/Dashboard-Hardcodes) erst nach Production-Build-Verify löschen.
5. ✅ Scanner-Zahlen sind Triage-Queues, keine Bugcounts.
6. ✅ Pro Task: Forgejo-Issue + PROGRESS.md-Update (AGENTS.md §9). Conventional Commits mit Finding-ID (`fix(arch-004): ...`).
7. ✅ Jede Änderung: minimal focused, bestehender Stil, Tests beweisen Wirkung.
# AUSFÜHRUNGSREIHENFOLGE (kurz)
```
Block 0 (Sofort: SYNTAX-001, CHECKER-FIX) ~ halber Tag
Block A (Lifecycle/Contracts/Runtime) → Gate A
Block B (Plugin-Grenze, Contacts-Entkopplung) → Gate B (inkl. Fresh-DB)
Block C (Backend permission-Felder → Workspace →
Routes/Sidebar/Settings/Dashboard → Verify → Löschen) → Gate C
Block D (pytest-Massen, DateTime, API-Pfade,
Security-Triage, Marathon-Triage, Legacy) → Full Regression
Separate Tracks S1S3: danach, unabhängig
```
# BLOCK I — Keine bekannten Fehler mehr (NEU 2026-08-24, VOLLSTÄNDIG überarbeitet)
Ziel: Nach Abarbeitung dieses Blocks gibt es KEINEN bekannten Fehler mehr.
Grundlage: Vollständiger Abgleich aller Quellen — test-bugs.md (73 ⏳-Findings,
davon einige stale), Suite v2 (brach bei 77% ab, Restzone nie gemessen),
Blöcke F/G aus diesem Plan, S-Tracks S1/S2/S3.
## I-A Stale-Status korrigieren (~1 Std)
Folgende Findings sind in dieser Reparatur-Serie bereits gefixt, aber die
Status-Markierung in test-bugs.md fehlt. Erst Dokumentation nachziehen:
- ARCH-051 (dict-body → Pydantic, c32e4bb), ARCH-055 (user_agent),
ARCH-056 (SYSTEM_PERMISSIONS), ARCH-057 (_plugins→public API),
ARCH-027 (verifiziert implementiert + strenger),
BUG-085092 (D1-Ziel-Suites alle grün verifiziert).
## I-B Suite v2 Restzone messen und triagieren (~1 Tag)
Suite v2 brach bei 77% ab (EEEE-Kette, vermutlich Mail-artige Hänger in einer
weiteren Suite). Die Suiten DANACH wurden nie gemessen:
- Hängende Suite identifizieren (--timeout pro Test setzen), mocken oder fixen.
- Voll-Lauf v3 OHNE Ausschlüsse mit per-Test-Timeout → definitive Failure-Liste.
- Jede Failure klassifizieren (Produktionsbug / Test-Harness / Vorbestand) und fixen.
Gate: pytest tests/ komplett durchgelaufen, 0 Failures, 0 Errors.
## I-C Produktionsrelevante offene Bugs fixen (~2 Tage)
Aus dem Abgleich wirklich offen (nicht stale):
- BUG-024: GET /api/v1/plugins/{name} → 404 (Plugin-Detail-Route fehlt).
- BUG-036: GET /api/v1/workflows/instances → 500.
- BUG-071: Merge-API braucht source_contact_id/target_contact_id.
- ARCH-042: calendar/dms get_contract() erzeugt NEUE Instanz statt registrierte.
- ARCH-048: register_workflow_event_handlers nutzt falschen payload key.
- ARCH-050: engine.py acquire_lock awaitet nicht-async get_redis().
- ARCH-032: knowledge/wiki unregister_actions_by_owner falsche Signatur.
- BUG-015: Cross-Plugin Imports — 6 verbleibende Violations (nach Block B waren es
14→6; die 6 Restlichen fixen oder als erlaubte Ausnahmen whitelisten).
- BUG-006: wiki/plugin.py verbotene Cross-Plugin Imports (prüfen ob Block B sie
bereits eliminierte; sonst fixen).
- BUG-017/ARCH-011: Core-to-Plugin Imports (10 + 27) — prüfen welche durch Block B
entfielen, Rest fixen oder dokumentiert whitelisten (Contract-only).
- BUG-009/010/011/013/014/016/023: Einzelfixes laut test-bugs.md Details.
- BUG-027035: Test-/Doku-Pfad-Korrekturen (teils in D3 als obsolet verifiziert —
Status-Markierung nachziehen, Rest korrigieren).
- BUG-039: entity-links API Pfad in Tests korrigieren.
- BUG-078: 3 dead functions entfernen oder aufrufen.
- BUG-100: 4 spike_i_integration_flow Failures triagen.
- BUG-068: Field-Level Permissions in contacts routes implementieren (Medium,
echtes Feature-Gap).
- ARCH-026: Plugin Cross-Dependencies deklarieren (Manifest dependencies Feld).
Gate: grep '⏳' docs/test-bugs.md = nur noch bewusst akzeptierte Ausnahmen
(mit Begründung), alles andere ✅.
## I-D Frontend-Konsistenz (~1 Tag)
- Geister-Komponenten: @/pages/AIAssistant + 5 Contact-Detail-Tabs bauen oder
Manifest-Einträge entfernen.
- D5-Rest-API-Brüche ×12: ai/sessions ×5, policies ×4, mail signatures/drafts/
labels ×4, notifications DELETE, agents/skills (Frontend umstellen auf echte
Endpoints oder Backend-Shims).
- ARCH-061: routes/index.tsx leeres Route-Objekt entfernen.
- ARCH-028: PluginRouteRenderer 'Page Not Found' i18n.
- ARCH-025: ProtectedRoute.tsx hardcoded deutscher Pfad i18n.
- ARCH-062: MessageSidebar TeamPanel-Duplikat auf SharedTeamPanel (aus C8) umstellen.
- ARCH-063: SortableMenuItem LucideIcons-Wildcard → ICON_MAP (OOM-Fix aus C8 prüfen).
- ARCH-021: Sidebar statische UND dynamische Menüs konsolidieren (Rest nach C5/C6).
- ARCH-004: Workspace/Sidebar is_visible Konsistenz final verifizieren (C2 done,
Regressionstest ergänzen).
Gate: tsc --noEmit clean + Production-Build + keine ErrorBoundary-Fallbacks im
Smoke-Crawl der Hauptnavigation.
## I-E Test-Hygiene Runde 2 (~23 Tage)
- Mail-Suite: IMAP/SMTP konsequent mocken (AsyncMock-Pattern) → ~28 Tests deterministisch.
- PluginLoader-Tests: erwartete UI-Texte angleichen (de/en, 5 Failures).
- BUG-099: workstream-Tests löschen oder umbauen (4 Failures, Modul Phase 2 entfernt).
- BUG-097/098/093096: Rest-Failures dieser Suiten triagen (D1 deckte nur Teil ab).
- BUG-012/E2: Playwright helpers.ts auf echte API umstellen; E2E gegen Production-Build.
Gate: pytest tests/ komplett ohne --ignore durchgelaufen, 0 Failures/Errors.
## I-F Sicherheit & Compliance abschließen (User + Agent, ~1 Tag)
- I5 Credential-Rotation (PFLICHT, User): 7 kompromittierte Credentials rotieren
(Anleitung deploy-guide.md § Credential-Rotation); SECRET_KEY zuletzt.
- G1 DSGVO (KRITISCH): Art. 15/17/20 Endpoints existieren teilweise (system_settings.py
dsar/export), aber grep 'gdpr' in app/routes+services war leer → vollständige
Implementierung + Tests + Verarbeitungsübersicht.
- G2 Session-Revocation bei Passwortänderung (aktuell nur Logout invalidiert).
- G3 Hygiene-Funde aus Final-Check umsetzen.
- E4 Monitoring-Reality-Check: Alerting einmal real durchspielen, dokumentieren was alarmiert.
- E5 Performance-Baseline: Top-10-Endpoints p95 mit seed_perf_data.py; Schwellwerte dokumentieren.
## I-G Qualität/Hygiene S-Tracks einplanen (~23 Tage, kann parallel)
- BUG-018: 36 Python God Objects >500 Zeilen — Split-Programm priorisiert nach
Hotspots (nicht Big-Bang; je Datei eigener Commit + Tests).
- BUG-081: 9 Frontend God Objects >500 Zeilen — gleiche Methodik.
- BUG-021/ARCH-024/045: i18n — 165 hardcoded Strings auf t() umstellen.
- BUG-022/070: npm audit fix (3+3 Vulnerabilities) + pip-audit-Routine in CI.
- ARCH-026: Plugin Cross-Dependencies deklarieren (falls nicht schon in I-C).
Gate: keine Datei >500 Zeilen in den priorisierten Hotspots; npm audit clean;
pip-audit clean; i18n-Scanner <10 Treffer.
## I-H Prozess- & Rest-Lücken aus Originalplan (~1 Tag)
Diese Punkte waren in der ersten Block-I-Fassung nicht enthalten:
- F1-Restprozess: git tag `pre-block-I` vor Start; ab hier Branch `fix/block-i` mit
Merge erst nach Gate I; Deploy-Reihenfolge Staging vor Production.
- F3-Gate-F nachziehen: Ein Minimal-Plugin NUR mit Guide+Checkliste bauen
(docs/plugin-checklist.md existiert) — gelingt das ohne Rückfragen an den
Architekten, gilt der Guide als fertig. Sonst Guide-Lücken schließen.
- G3-a: dump.rdb aus Repo-Root entfernen (git-ignored, kein Leak) + Redis workdir
sauber konfigurieren.
- G3-b: Downgrade-Fähigkeit als NICHT-Release-Kriterium in docs/test-strategy.md
festhalten (test_migrations.sh ignoriert downgrade-Fehler bewusst).
- E2 konkret: Playwright BASE_URL auf Production-Build-Preview + docker compose
profile test; helpers.ts auf echte API umstellen (BUG-012).
- E4 konkret: Monitoring einmal real durchspielen (Alerting-Pfad verifizieren,
was WIRKLICH alarmiert dokumentieren); metrics-Endpoint füllen prüfen.
- E5 konkret: Baseline Top-10-Endpoints p95 (seed_perf_data.py + spike_e_benchmark.py);
Regressionsschwelle dokumentieren.
Gate-Ergänzung: dump.rdb entfernt, Downgrade-Entscheidung dokumentiert,
Guide-Test bestanden, E2/E4/E5 jeweils mit Beweis abgeschlossen.
## Reihenfolge von I
```
I-A (Stale-Status, sofort — ehrliche Basis)
I-B (Suite v2 Restzone messen — definitive Zahlen)
I5/I-F Rotation (User, sofort parallel — Sicherheit)
I4 (CI-Gate scharf, parallel — Driftschutz)
I-C (Produktionsbugs) → I-D (Frontend-Konsistenz)
I-E (Test-Hygiene Runde 2) → I-F Compliance → I-G S-Tracks
```
## Gate I — Definition von 'keine bekannten Fehler mehr'
1. pytest tests/ komplett durchgelaufen (kein Timeout, kein --ignore): 0 F, 0 E.
2. trace_api_contracts gegen Live-OpenAPI: 0 echte Findings.
3. grep '⏳' docs/test-bugs.md: nur noch bewusst akzeptierte Ausnahmen MIT Begründung.
4. 0 Geister-Komponenten; Production-Build + Smoke-Crawl der Navigation ohne ErrorBoundary.
5. Credentials rotiert (alle 7); CI-Gate aktiv (Runner + Branch-Protection).
6. DSGVO Art. 15/17/20 implementiert und getestet; Session-Revocation aktiv.
7. ruff/tsc/mypy clean; npm/pip audits clean.