47 KiB
ARCHIV seit 2026-08-27: Plan als ABGESCHLOSSEN erklaert (Bloecke 0/H/A-G done). Verbleibende offene Punkte liegen verifiziert in PROGRESS.md.
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)
- Statistik korrigiert (siehe oben), alle Duplikate entfernt.
- Phase 0 (Agent Zero Config) gestrichen — deepseek-v4-pro/ministral/Vision gehören nicht in diesen Plan.
- Reihenfolge gedreht: Plattformbasis ist jetzt Block A (zuerst), Einzelbugs folgen in D.
- Contacts-Ansatz korrigiert: NICHT "NUR Plugin" (v1-Fehler), sondern Core-Plugin (is_core=True, nicht deaktivierbar) OHNE Core-Hardcoding.
- Workspace ARCH-004 hat jetzt eine konkrete Fixphase (C2) mit verifizierter Ursache.
- Checker-Fix erweitert: nicht nur Default, sondern ZWEI Bugs (Default + ValueError-Crash bei relativen Pfaden).
- Regel aufgenommen: KEINE globalen commit→flush-Transformationen; nur nachgewiesene Einzelfälle.
- Regel aufgenommen: Integration/Install-Tests ausschließlich über Alembic-Migrationen, kein pauschales
Base.metadata.create_all. - Frontend-Permission-Reihenfolge fixiert: ERST Backend-Felder
FrontendPageRoute.permission+FrontendMenuItem.permission(C1), DANN statische Routes abbauen (C4) — sonst Permission-Verlust. - Settings + Dashboard als eigene Fixpunkte ergänzt (C6/C7) — fehlten in v1 komplett.
- Lifecycle-Findings konkret eingeplant: ARCH-012, 013, 015, 033–037, 042 jetzt einzeln in Block A aufgeführt.
- God Objects raus aus dem Pflichtumbau → separater Track S1.
- i18n raus aus dem Basisumbau → separater Track S2.
- Secrets/SQL-Injection = TRIAGE statt Pauschalfix (D4): jede Stelle klassifizieren, nur echte Findings fixen.
- Marathon-Zahlen = Triage-Cluster (D5), keine Bug-Anzahl, Root-Cause-Clustering.
- 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(...)undexcept Exception:im Cron-Job-Block auf die neue Einrücktiefe heben (innerhalbif 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
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()vorrelative_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=Trueerst 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_taskKlassenvariable → Instanzvariable (sonst teilen sich Instanzen den Task-State). - ARCH-037: graph_rag on_activate —
super().on_activate()VOR eigenemregistry.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 (Flagunregistered=Trueprü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 uuidergä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:readstattcore: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)
- Import-Test: jedes Modul in app/ lädt (kein NameError/ImportError).
- Activate → Permissions/Entities sofort registriert; Deactivate → sauber deregistriert (Runtime-Test).
- Multi-Tenant-Startup: on_activate genau 1× im Log.
- Contract roundtrip: register → get_contract liefert registrierte Instanz → unregister → get_contract liefert None (kein Lazy-Resurrect).
- 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.
main.py:549app.include_router(contacts.router)entfernen — NACHDEM der Plugin-Route-Mechanismus identische Endpoints bereitstellt (Endpoint-Diff-Test davor!).- Plugin manifest:
routes=[]-Kommentar beseitigen; Contacts-Routes über Plugin registrieren mitrequire_active_plugin("contacts")-Dependency (schützt bei versehentlicher Deaktivierung + klarer Fehler). CORE_FIELD_DEFINITIONS(Contact-Feldmassen) → Plugin-Field-Contribution migrieren.- Sidebar-Sonderfall ("Only non-plugin items: dashboard, contacts, settings") → contacts über pluginNavItems.
- Restore/History/Entity-Links: Contacts-Entity über EntityRegistry (B3), nicht über Core-Annahmen.
- 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-manifestsfür eingeloggte User freigeben (eigene Permissionplugins:view_manifests, Default-Rollen erhalten sie). Frontend braucht das für C.
Gate B (vor Block C)
- Neues-Plugin-Test: Minimal-Plugin mit Route+Entity+Menü — OHNE Änderung einer Core-Datei funktionsfähig.
- Fresh-DB-Install: leere DB → ausschließlich Alembic → Admin-Seed → Contacts/Companies voll funktional.
- Contacts-Vertrag: Endpoint-Vergleich alt (core route) vs. neu (plugin route) — identische Pfade/Statuscodes.
- Dependency-Test: A hängt an B → B deaktivieren wird blockiert.
- 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 (C4–C7) → 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 | Nonein app/plugins/manifest.py ergänzen (aktuell nurprotected: 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-ignoreDynamic-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.permissionaus 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
- Production Build (
npm run build) + Playwright GEGEN DEN BUILD (nicht dev-server). - Workspace: is_visible=false wirklich unsichtbar (Sidebar + Direktaufruf geblockt).
- Normaler User (kein Admin): sieht Plugin-Menüs/Routes gemäß Permission; 403 wo keine.
- Permission-Diff-Test: jede ehemals statische Route hatte Permission X → dynamische Route fordert dieselbe X (KEIN Absinken auf auth-only).
- 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, 092–096, 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-074–078)
- 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:
- Import-Test aller app/-Module (framework runtime).
- Cross-Plugin-Vollscan: 0 Verstöße der jeweiligen Kategorie.
npx tsc --noEmit+ ruff + mypy (Ziel-Regelwerk) bei jedem Touch.- 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):
- Kein direkter Import aus anderem Plugin — nur get_contract (Checker läuft in CI)
- on_activate/on_deactivate symmetrisch: alles was registriert wird, wird auch deregistriert
- Jede Route hat Permission (kein auth-only), jede Menü-Route hat permission-Feld im Manifest
- depends_on deklariert, wenn Plugin andere nutzt
- Entities über Plugin-Registrierung, keine Core-Annahmen
- Frontend-Components über Manifest-Contribution, keine hardcoded Loader-Einträge
- Migrationen folgen Namenskonvention, RLS für eigene Tabellen
- Audit-Log bei allen Mutationen
- datetime nur mit UTC
- 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)
- Agent-Tools sind hardcoded:
app/ai/integration_tools.pyregistriert 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. - Agent-Laufzeit hängt an einem Plugin:
ToolRegistryliegt unterapp/plugins/builtins/ai_assistant/tool_registry.py. Ist ai_assistant deaktiviert, existiert keine Registry mehr — Agent-Betrieb ohne dieses Plugin unmöglich. - Manifest hat Contribution-Ansätze (
agent_capabilitiesmanifest.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_loopgehören inapp/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
- Core-Registry nach app/core/ ziehen (Move + Alias-Import für Übergangszeit), ai_assistant nutzt sie wie jedes andere Plugin.
integration_tools.pyauflösen: Die 4 Hardcoded-Tools werden zu regulären Contributions ihrer Quell-Plugins (workflows, knowledge, unified_search) via Manifest/Hook — Core-Datei verschwindet.- Plugin-Guide: neues Kapitel 'Agent-Tools beitragen' mit Schema + Beispiel + Test-Pflicht (Tool ohne Permission verboten).
- 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
- Neues Fachmodul-Testplugin bringt ein Agent-Tool MIT OHNE Änderung einer Core-Datei; Agent führt es aus (Tenant-scoped, permission-geprüft).
- ai_assistant deaktivieren → Agent-Laufzeit läuft weiter; dessen eigene Tools sind weg, alles andere bleibt.
- Deactivate/Activate-Zyklus: Tools sauber ab-/angemeldet, keine Duplikate (EventBus-Duplikatfix greift hier analog).
- 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 C4–C7 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).
- E2–E6 parallel zu Block C/D, spätestens VOR Go-Live-Kandidat.
ARBEITSREGELN (aus Review abgeleitete Verbote/Gebote)
- ❌ KEINE globalen
commit()→flush()-Transformationen. Nur nachgewiesene Einzelfälle mit Transaktionsbegründung (BUG-003-Muster). - ❌ KEIN pauschales
Base.metadata.create_allin conftest. Unit-Fixtures ok; Integration/Install ausschließlich Alembic. - ✅ Erst Backend-Feld (
permission), dann Frontend-Consumption. Nie umgekehrt. - ✅ Alte Wege (Routes/Sidebar/Settings/Dashboard-Hardcodes) erst nach Production-Build-Verify löschen.
- ✅ Scanner-Zahlen sind Triage-Queues, keine Bugcounts.
- ✅ Pro Task: Forgejo-Issue + PROGRESS.md-Update (AGENTS.md §9). Conventional Commits mit Finding-ID (
fix(arch-004): ...). - ✅ 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 S1–S3: 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-085–092 (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-027–035: 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 (~2–3 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/093–096: 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)
Konsolidiert 2026-08-25: Jede Spezifikation existiert genau einmal — DSGVO und Session-Revocation sind NUR in BLOCK G definiert (G1/G2), Monitoring/Performance NUR in I-H („E4 konkret“/„E5 konkret“). Diese Sektion ist ein reiner Verantwortlichkeits-Index ohne Doppelspezifikation:
- I5 Credential-Rotation (PFLICHT, User): 7 kompromittierte Credentials rotieren (Anleitung deploy-guide.md § Credential-Rotation); SECRET_KEY zuletzt.
- G1 DSGVO Art. 15/17/20 → Umsetzung, Tests und Verarbeitungsübersicht laufen unter BLOCK G / G1 (volle Spezifikation dort; Status: system_settings.py dsar/export existiert teilweise, Rest der Art. 15/17/20-Endpunkte fehlt).
- G2 Session-Revocation bei Passwortänderung → BLOCK G / G2.
- G3 Hygiene-Funde aus Final-Check → BLOCK G / G3.
- E4/E5 → BLOCK I / I-H („E4 konkret“/„E5 konkret“) — hier bewusst nicht wiederholt.
I-G Qualität/Hygiene S-Tracks einplanen (~2–3 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-Ivor Start; ab hier Branchfix/block-imit 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'
- pytest tests/ komplett durchgelaufen (kein Timeout, kein --ignore): 0 F, 0 E.
- trace_api_contracts gegen Live-OpenAPI: 0 echte Findings.
- grep '⏳' docs/test-bugs.md: nur noch bewusst akzeptierte Ausnahmen MIT Begründung.
- 0 Geister-Komponenten; Production-Build + Smoke-Crawl der Navigation ohne ErrorBoundary.
- Credentials rotiert (alle 7); CI-Gate aktiv (Runner + Branch-Protection).
- DSGVO Art. 15/17/20 implementiert und getestet; Session-Revocation aktiv.
- ruff/tsc/mypy clean; npm/pip audits clean.