Files
leocrm/docs/ABSCHLUSSBERICHT_PHASE0_PHASE1.md
T
Agent Zero be20a8545e docs: Abschlussbericht Phase 0+1 und vollständiger Sanierungsplan
- Kompletter Statusbericht mit allen 5 Gates
- Datenbankrollen-Architektur dokumentiert
- RLS-Architektur dokumentiert
- Verifizierte Sicherheitsnachweise
- Durchgeführte Code-Änderungen und Migrationen
- Offene Risiken
- Vollständiger Sanierungsplan Phase 2-10
- Gesamtschätzung: 120-210h verbleibend
- Empfohlene Reihenfolge
2026-08-01 07:28:11 +02:00

19 KiB
Raw Blame History

LeoCRM — Abschlussbericht Phase 0 + Phase 1 und vollständiger Sanierungsplan

Datum: 2026-08-01 Git-Commit: 733fa1c (main) Alembic-Head: 0090 Produktion: https://crm.media-on.de — healthy


1. Aktueller Stand

1.1 Abgenommene Gates

Gate Beschreibung Status
Gate 1 Reproduzierbares Coolify-Deployment Bestanden
Gate 2 Neuinstallation auf leerer Datenbank Bestanden
Gate 3 Vollständiger Restore-Test Bestanden
Gate 4 Passwort-Reset end-to-end Bestanden
Gate 5 Worker und Eventhandler Bestanden

1.2 Produktionsstand

Komponente Wert
Git-Commit 733fa1c
Docker-Image stvabl4vaqru7jclx4ittzr3:733fa1c
API-Container stvabl4vaqru7jclx4ittzr3-201530032526 — healthy
Worker-Container leocrm-worker — healthy
Alembic-Head 0090
Tabellen 124
RLS-Tabellen 108 (alle Tenant-Tabellen)
RLS-Policies 112
Legacy app.tenant_id Policies 0
DB-Rollen 5 (crm_platform_admin, crm_migration, crm_auth, crm_api, crm_worker)
crm_api NOSUPERUSER, NOBYPASSRLS — API-Laufzeit
crm_auth NOSUPERUSER, NOBYPASSRLS — Login/Authentifizierung
crm_worker NOSUPERUSER, NOBYPASSRLS — Worker-Laufzeit
crm_migration NOSUPERUSER, BYPASSRLS — Migrationen und DDL
crm_runtime Gelöscht

1.3 Datenbankrollen-Architektur

┌─────────────────────────────────────────────────────────────┐
│                    PostgreSQL (crm_db)                        │
├─────────────────────────────────────────────────────────────┤
│  crm_user (POSTGRES_USER, SUPERUSER)                         │
│  └── Nur für Bootstrap und DB-Initialisierung                │
│                                                              │
│  crm_migration (NOSUPERUSER, BYPASSRLS, Tabellenowner)       │
│  ├── Alembic-Migrationen (00010090)                         │
│  ├── Plugin-Migrationen (DDL)                                │
│  └── Datenmigrationen (tenantübergreifend)                   │
│                                                              │
│  crm_auth (NOSUPERUSER, NOBYPASSRLS)                         │
│  ├── Login/Logout                                            │
│  ├── Tenant-Auflösung                                        │
│  ├── User/Tenant-Membership                                  │
│  └── Password-Reset-Token                                     │
│                                                              │
│  crm_api (NOSUPERUSER, NOBYPASSRLS, kein Owner)              │
│  ├── Normale API-Abfragen (SELECT, INSERT, UPDATE, DELETE)   │
│  ├── Audit-Log (über separate Session mit Tenant-Kontext)    │
│  └── Keine DDL-Rechte                                        │
│                                                              │
│  crm_worker (NOSUPERUSER, NOBYPASSRLS, kein Owner)            │
│  ├── ARQ-Background-Jobs                                     │
│  ├── Outbox-Processing (per-Tenant mit RLS-Kontext)           │
│  ├── Cron-Jobs (scheduler_tick, tasks_due_reminder)          │
│  └── Event-Handler für aktive Plugins                        │
└─────────────────────────────────────────────────────────────┘

1.4 RLS-Architektur

  • Fail-closed: Kein Tenant-Kontext = kein Zugriff auf Tenant-Daten
  • Policy: USING/WITH CHECK (tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')::uuid)
  • FORCE ROW LEVEL SECURITY auf allen 108 Tenant-Tabellen
  • Scoped to: crm_api, crm_worker (nicht PUBLIC)
  • 21 globale Tabellen ohne RLS: users, tenants, sessions, plugins, etc.
  • 0 legacy Policies mit app.tenant_id (alle durch app.current_tenant_id ersetzt)

1.5 Verifizierte Sicherheitsnachweise

Test Ergebnis
RLS ohne Tenant-Kontext 0 rows (fail-closed)
RLS mit Tenant A Nur Tenant-A-Daten
RLS mit Tenant B Nur Tenant-B-Daten
Cross-Tenant INSERT Blockiert (RLS violation)
Cross-Tenant UPDATE 0 rows affected
Cross-Tenant DELETE 0 rows affected
WITH CHECK (tenant_id ändern) Blockiert
DDL durch crm_api Blockiert (permission denied)
Login über crm_auth 200 OK
Passwort-Reset end-to-end Email zugestellt, Token einmalig, Session widerrufen
Leere DB-Installation 124 Tabellen, 0090, keine manuellen Eingriffe
Restore + Upgrade 0086 → 0090, Datenintegrität erhalten

1.6 Durchgeführte Code-Änderungen (Phase 0 + Phase 1)

Commit Beschreibung
v-phase0-baseline Git-Baseline bei 11d6faa
4a5c905 P0-Fix: Plugin-Migrationen über Migrations-Engine
1029613 Migration 0085: crm_runtime DROP ROLE Fix
48ddd78 Mail Plugin Migration 0009 Fix
569476b prestart.sh: DB-Rollen-Passwörter setzen
b5191f0 Migration 0089: sessions.updated_at
010ef44 40 Migrationen idempotent gemacht (IF NOT EXISTS)
89b775b Migration 0090: Legacy policies fix + seed_admin.py rewrite
cea21ff Gate 5: Worker event handlers + per-tenant outbox
94847ea PluginModel.active Fix (worker crash)
733fa1c Gate 3: Restore-Test Doku

1.7 Migrationen

Migration Beschreibung
0085 RLS-Restore: Rollen, Policies, Grants, FORCE RLS auf 108 Tabellen
0086 Globaltabellen-Korrektur: FORCE RLS entfernt von 5 globalen Tabellen
0087 password_reset_tokens: created_at, updated_at
0088 Auth RLS policies: password_reset_tokens, audit_log für crm_auth
0089 sessions: updated_at Spalte
0090 Legacy app.tenant_id policies auf _old Tabellen fixen

1.8 Offene Risiken

# Risiko Bewertung
1 Coolify-API-Token im Chat verwendet Mittel — Token widerrufen und neu erstellen
2 Test-DB-Passwort (TestDbPass2026) Niedrig — nur in Testumgebung verwendet
3 Worker-Env-Variablen manuell gesetzt Mittel — bei Coolify-Rebuild verloren, muss in Coolify .env dokumentiert werden
4 pg_restore --no-acl überspringt Grants Niedrig — Restore-Prozedur muss Grants neu anwenden
5 DMS-Dateien nicht im Restore-Test Niedrig — Storage-Volume separat sichern
6 Bootstrap über crm_user (SUPERUSER) Niedrig — akzeptiert für Gate 2, später auf crm_migration umstellen

2. Vollständiger Sanierungsplan — Verbleibende Phasen

Phase 2 — Datenintegrität

Ziel: Konsistente Fremdschlüssel, keine verwaisten Datensätze, saubere Sequenzen.

Aufgaben:

  1. Fremdschlüssel-Constraints prüfen und fehlende ergänzen
  2. Verwaiste Datensätze identifizieren und bereinigen
  3. Sequenzen synchronisieren (sync mit MAX(id))
  4. ON DELETE CASCADE prüfen und dokumentieren
  5. Datenbank-Integritäts-Test-Suite erstellen
  6. Migration für fehlende FK-Constraints erstellen

Abnahmekriterien:

  • Alle FK-Constraints vorhanden und gültig
  • Keine verwaisten Datensätze
  • Alle Sequenzen synchron
  • Integritäts-Tests grün

Aufwand: 816 Stunden


Phase 3 — Plugin-Lifecycle

Ziel: Saubere Plugin-Aktivierung, Deaktivierung und Migration ohne Race-Conditions.

Aufgaben:

  1. Plugin-Aktivierung: Prüfen ob bereits aktiv, idempotent machen
  2. Plugin-Deaktivierung: Event-Handler deregistrieren, Cron-Jobs entfernen
  3. Plugin-Migration: Versionierung und Rollback
  4. Tenant-Plugin-Aktivierung: Per-Tenant mit Tenant-Kontext
  5. Plugin-Abhängigkeiten: Load-Order respektieren
  6. Plugin-Router: Nur in API registrieren, nicht im Worker
  7. Plugin-Event-Handler: Nur für aktive Plugins registrieren
  8. Test: Plugin aktivieren → deaktivieren → reaktivieren

Abnahmekriterien:

  • Plugin-Aktivierung ist idempotent
  • Plugin-Deaktivierung deregistriert Event-Handler
  • Plugin-Migrationen haben Versionierung
  • Tenant-Plugin-Aktivierung funktioniert mit RLS
  • Keine Race-Conditions bei paralleler Aktivierung

Aufwand: 610 Stunden


Phase 4 — Sichere KI-Delegation

Ziel: KI-Agenten können sicher und kontrolliert Aufgaben ausführen.

Aufgaben:

  1. Delegation-Contract definieren (Input, Output, Permissions)
  2. KI-Agent-Permissions: Tenant-scoped, keine Cross-Tenant
  3. KI-Agent-Session: Separate Session mit Tenant-Kontext
  4. KI-Agent-Limits: Max executions, timeout, rate-limit
  5. KI-Agent-Audit: Alle Aktionen protokollieren
  6. KI-Agent-Rollback: Fehlerhafte Aktionen zurückrollen
  7. KI-Agent-Approval: Menschliche Freigabe für kritische Aktionen
  8. Test: KI-Agent erstellt Kontakt → aktualisiert → löscht (nur im eigenen Tenant)

Abnahmekriterien:

  • KI-Agent kann nur im zugewiesenen Tenant arbeiten
  • KI-Agent-Aktionen sind auditiert
  • KI-Agent-Timeout und Rate-Limit funktionieren
  • KI-Agent kann keine Cross-Tenant-Daten lesen/schreiben
  • Kritische Aktionen erfordern Freigabe

Aufwand: 1224 Stunden


Phase 5 — Transactional Outbox

Ziel: Zuverlässige Event-Zustellung ohne Events zu verlieren.

Aufgaben:

  1. Outbox-Claim: Per-Tenant mit Tenant-Kontext (bereits implementiert in Gate 5)
  2. Outbox-Event-Consumer: Erwartete Consumer pro Event registrieren
  3. Outbox-Dead-Letter: Events nach max_attempts in DLQ
  4. Outbox-Monitoring: Backlog-Metriken, Failed-Jobs-Alert
  5. Outbox-Retry: Exponentieller Backoff (bereits implementiert)
  6. Outbox-Idempotency: consumer_inbox Check (bereits implementiert)
  7. Outbox-Delivery-Guarantee: At-least-once, consumer must be idempotent
  8. Test: Event erzeugen → Worker verarbeitet → Consumer ausführen → Idempotency prüfen

Abnahmekriterien:

  • Events gehen nicht verloren (auch bei Worker-Crash)
  • Events werden mindestens einmal zugestellt
  • Consumer sind idempotent
  • Dead-Letter-Queue funktioniert
  • Backlog-Monitoring funktioniert

Aufwand: 1424 Stunden


Phase 6 — Workspaces

Ziel: Mehrere unabhängige Workspaces pro Benutzer, pro Browser-Tab.

Aufgaben:

  1. Workspace-Model: UUID, Name, Owner, Tenant, Config
  2. Workspace-Widget-Config: Eigene UUID, Position, Größe, Konfiguration
  3. Workspace-Store: Zentraler React/Zustand-Store
  4. Workspace-Switcher: Sofortiger Wechsel ohne Page-Reload
  5. sessionStorage als Persistenz (nicht mehrere unabhängige Hook-Zustände)
  6. Sidebar reagiert sofort auf Workspace-Wechsel
  7. Leerer Workspace zeigt keine Module
  8. Direkte Links auf berechtigte Fachobjekte funktionieren
  9. Mehrfach-Widgets: Gleicher widget_key kann mehrfach vorkommen
  10. Workspace-Manager: Kann nur eigenen Workspace konfigurieren
  11. Cross-Tenant-Zuweisungen unmöglich
  12. Ausgeblendetes Modul erscheint nicht in Navigation

Abnahmekriterien:

  1. Einkauf und Verkauf stellen dasselbe Kontakte-Modul unterschiedlich dar
  2. Kalender unterscheiden sich pro Workspace
  3. Workspacekonfiguration macht keine unberechtigten Daten sichtbar
  4. Zwei Browser-Tabs können unterschiedliche Workspaces verwenden
  5. Derselbe Widget-Typ kann mehrfach vorkommen
  6. Workspace-Manager kann nur seinen Workspace konfigurieren
  7. Workspace-Manager kann keine Rechte ändern
  8. Cross-Tenant-Zuweisungen sind unmöglich
  9. Ein ausgeblendetes Modul erscheint nicht in der Navigation
  10. Direkte berechtigte Objektlinks bleiben erreichbar

Aufwand: 3050 Stunden


Phase 7 — DMS und Attachments

Ziel: Konsistenter Storage- und Berechtigungspfad für alle Dateiabläufe.

Aufgaben:

  1. Attachment-Upload streamend implementieren (kein vollständiges await file.read())
  2. Download über Storage-Streaming
  3. Alte Attachments nach files + entity_attachments migrieren
  4. Deduplikation nur tenantlokal
  5. Physische Datei nur löschen wenn keine Referenzen existieren
  6. Technische Felder (storage_path, Hashwerte) nicht an Clients ausgeben
  7. Entity-Typen konsistent registrieren
  8. Größenlimit, MIME-Prüfung und Hashing zentralisieren
  9. Lokales Storage und S3 identisch behandeln
  10. Keine Cross-Tenant-Dateireferenzen
  11. Optional: Malware-Scan

Abnahmekriterien:

  • Große Dateien verursachen keine mehrfache RAM-Belegung
  • Lokaler und S3-Storage funktionieren
  • Bestehende Attachments bleiben erhalten
  • Tenantfremde Dateien können nicht referenziert werden
  • Aktive Dateien werden nicht versehentlich physisch gelöscht

Aufwand: 1220 Stunden


Phase 8 — Verbleibende Sicherheits- und Betriebsfehler

HTML:

  1. Alle Mail-, Signatur- und HTML-Pfade serverseitig mit derselben Sanitization behandeln

Gäste: 2. Tenant-Slug verpflichtend oder eindeutige Tenant-Auswahl 3. Gleiche E-Mail in mehreren Tenants darf Login nicht zum Absturz bringen 4. Sofortiger Session-Widerruf 5. Einladungstoken nur gehasht, einmalig, mit Ablaufzeit und Widerruf

Webhooks: 6. SSRF-Schutz beibehalten 7. DNS-Ziel beim tatsächlichen Connect erneut prüfen 8. Redirects begrenzen oder deaktivieren 9. Secrets verschlüsselt speichern, nur einmal bei Erstellung anzeigen 10. Interne und private Netze blockieren 11. Retry und Fehlerstatus implementieren

Healthchecks: 12. Trennen: /health/live, /health/ready, /metrics 13. Readiness muss bei nicht verfügbaren Abhängigkeiten HTTP 503 liefern

Build: 14. Entfernen: npm ci || npm install → Verwenden: RUN npm ci 15. Python-Abhängigkeiten exakt pinnen oder über Lockdatei verwalten

Report-Worker: 16. Keine direkten Cross-Plugin-Imports 17. DMS nur über Contract oder Core-Service 18. PDF-Erstellung nur im Worker 19. Synchronen API-Reportpfad entfernen oder stark begrenzen 20. Read-only-Dateisystem, CPU- und RAM-Limits, kein allgemeiner Netzwerkzugriff

Aufwand: 1018 Stunden


Phase 9 — CI und verbindliche Quality Gates

Ziel: Jeder Merge muss folgende Gates bestehen:

# Gate
1 Python Compile
2 Ruff
3 Python Typecheck
4 Vollständige Testcollection
5 Pytest
6 Frontend Typecheck
7 Vitest
8 Frontend Production Build
9 Cross-Plugin-Importprüfung
10 SQL-Injection-Prüfung
11 Jinja-Sandbox-Test
12 RLS-Variablenprüfung
13 RLS-Abdeckungsprüfung
14 Cross-Tenant-Integrationstest
15 Test mit echter crm_api-Rolle
16 Login-Test mit crm_auth
17 Alembic auf leerer Datenbank
18 Upgrade von vorherigem Release
19 Container Smoke Test
20 API- und Worker-Healthcheck
21 Dependency Scan
22 Prüfung auf unerlaubte Bootstrap-RLS-Policies
23 Prüfung der Tabellenowner
24 Prüfung auf genau einen Alembic-Head

Kein Gate darf über || true, allow_failure oder continue-on-error ignoriert werden.

Aufwand: 1628 Stunden


Phase 10 — Backup, Restore, Monitoring und Pilotfreigabe

Backup:

  1. PostgreSQL, DMS/Object Storage, Secrets, Verschlüsselungsschlüssel, Anwendungsversion, Alembic-Stand

Restore: 2. PostgreSQL wiederherstellen → DMS wiederherstellen → Secrets → alembic current → alembic upgrade head → App/Worker starten → Login testen → Datensatzanzahlen vergleichen → RLS testen → Dateien stichprobenartig öffnen → Outbox/Worker testen → Workspace prüfen

Monitoring: 3. Externes Monitoring für: API Liveness, API Readiness, Worker Heartbeat, Redis, PostgreSQL, Outbox-Rückstau, Failed Jobs, Fehlerrate, Antwortzeit, DB-Pool-Auslastung, Storage-Erreichbarkeit

Pilotfreigabe: 4. Erst freigeben wenn:

  • alle P0- und P1-Tests grün
  • Cross-Tenant-Tests mit echter Runtime-Rolle grün
  • Backup und Restore praktisch getestet
  • KI-Delegation auditiert funktioniert
  • mindestens ein kompletter Geschäftsablauf getestet
  • keine offenen kritischen Findings
  • App, Worker und Migrationen getrennte Rollen verwenden
  • RLS auf allen Fachtabellen aktiv und erzwungen

Aufwand: 1220 Stunden


3. Gesamtschätzung

Reine Codeänderungen

Phase Beschreibung Aufwand
0+1 Ausgangsbasis, Login, DB-Rollen, RLS Abgeschlossen
2 Datenintegrität 816 h
3 Plugin-Lifecycle 610 h
4 Sichere KI-Delegation 1224 h
5 Transactional Outbox 1424 h
6 Workspaces 3050 h
7 DMS und Attachments 1220 h
8 Sicherheitsreste und Build 1018 h
9 CI und Quality Gates 1628 h
10 Backup, Restore, Monitoring 1220 h
Gesamt Verbleibend 120210 h

Einschließlich Migrationen, Tests und Deployment

Bereich Aufwand
Verbleibende Codeänderungen 120210 h
Tests, Fehlerkorrekturen, Deployment +3050 h
Gesamt verbleibend 150260 h

Pilotfähiger technischer Kern (ohne vollständige Workspaces)

Bereich Aufwand
Datenintegrität 816 h
Plugin-Lifecycle 610 h
Sichere KI-Delegation 1224 h
Outbox 1424 h
DMS und Attachments 1220 h
Sicherheitsreste und Build 1018 h
CI 1628 h
Backup, Restore, Monitoring 1220 h
Gesamt (ohne Workspaces) 90160 h

Vollständige Workspaces zusätzlich

Bereich Aufwand
Workspaces 3050 h
Gesamt einschließlich Workspaces 120210 h

4. Empfohlene Reihenfolge

  1. Phase 2 (Datenintegrität) — Fundament für alle weiteren Phasen
  2. Phase 3 (Plugin-Lifecycle) — Saubere Basis für Plugin-Funktionen
  3. Phase 5 (Outbox) — Bereits teilweise implementiert, fertigstellen
  4. Phase 4 (KI-Delegation) — Baut auf Outbox auf
  5. Phase 7 (DMS) — Unabhängig, parallel möglich
  6. Phase 8 (Sicherheitsreste) — Unabhängig, parallel möglich
  7. Phase 9 (CI) — Nach allen Code-Phasen, vor Pilot
  8. Phase 6 (Workspaces) — Größter Aufwand, nach Kern-Stabilität
  9. Phase 10 (Backup, Monitoring, Pilot) — Als Abschluss

5. Nächste Schritte

  1. Freigabe Phase 2 — Nach Abnahme dieses Berichts
  2. Coolify-API-Token widerrufen — Token wurde im Chat verwendet
  3. Produktions-Passwörter rotieren — Falls noch nicht geschehen
  4. Coolify .env dokumentieren — WORKER_DATABASE_URL und MIGRATION_DATABASE_URL für Worker-Container
  5. Restore-Prozedur dokumentieren — Grants müssen nach pg_restore neu angewendet werden

Dieser Bericht wurde am 2026-08-01 erstellt und entspricht dem Stand Commit 733fa1c auf main.