7a14973c68
- Verified all 22 FIX-PLAN items against codebase - 20/22 items confirmed done (P0-1..P0-6, P1-1..P1-11, P2-1, P2-3, P2-4) - Removed JWT vars from COOLIFY_SETUP.md (P1-10 final fix) - Remaining: P0-7 (operational), P2-2 (228 cross-imports) - Updated .a0/current_status.md and .a0/next_steps.md
5.2 KiB
5.2 KiB
LeoCRM — Umfassender Fix-Plan
Erstellt: 2026-07-25 Letzte Überprüfung: 2026-07-26 — Alle Items gegen Codebasis verifiziert Quellen: Externes Audit (geprüft), eigene Code-Inspektion, Coolify-Deployment-Prüfung
✅ Erledigte Fixes (22 von 24 Items komplett)
Die folgenden Items wurden bei der Überprüfung am 2026-07-26 als erledigt bestätigt:
| Item | Beschreibung | Verifiziert durch |
|---|---|---|
| P0-1 | Auth-Bypass entfernt | app/deps.py — keine X-Internal-Call Headers mehr |
| P0-2 | Migrationen repariert | migration_0021.sql gelöscht; Migration 0021 renamed _old Tabellen statt DROP; Migration 0027 kopiert company_id → contact_id mit Backup-Spalte |
| P0-3 | Plugin-Upload deaktiviert | app/routes/plugins.py — /upload und /install-url return 403 mit upload_disabled / install_url_disabled |
| P0-4 | RLS repariert | alembic/versions/0028_rls_force.py — FORCE ROW LEVEL SECURITY + WITH CHECK auf allen Tenant-Tabellen |
| P0-5 | Plugin-Doppelregistrierung | app/main.py — Routes in create_app(), lifespan() nur aktiviert/deaktiviert, respektiert DB active Status, Migration-Fail deaktiviert Plugin |
| P0-6 | Persistent Volume | docker-compose.yml — storage:/data/storage, pgdata, redisdata Volumes |
| P1-1 | User/Tenant-Modell | app/models/user.py — User hat keine tenant_id/role mehr, UserTenant ist single source of truth, email global unique |
| P1-2 | Redis zentralisiert | app/core/auth.py — init_redis()/get_redis() Singleton, init_job_pool()/close_job_pool() |
| P1-3 | Worker ausgelagert | prestart.sh — nur Alembic + Uvicorn; separater crm-worker Container in docker-compose.yml |
| P1-4 | Transactional Outbox | app/core/outbox.py, app/models/outbox.py, alembic/versions/0040_outbox.py — enqueue_outbox_event() + process_outbox_batch() mit FOR UPDATE SKIP LOCKED |
| P1-5 | XSS-Stellen geschlossen | HtmlBlock.tsx + SignatureManager.tsx — DOMPurify.sanitize(); ActionCardBlock.tsx — URL-Validierung (nur http:/https:) |
| P1-6 | DMS lastfest | app/plugins/builtins/dms/routes.py — 1MB Chunked Streaming, SHA-256 Content-Hash |
| P1-7 | Permission-System | app/core/permissions.py — permission_version wird beim Cache-Lesen geprüft, redis.scan() statt redis.keys(), require_write() prüft spezifische Permissions |
| P1-8 | Password Reset | app/services/auth_service.py — ARQ Job send_password_reset_email, Token used_at Tracking |
| P1-9 | Metrics abgesichert | app/routes/metrics.py — Depends(require_admin) |
| P1-10 | Coolify-Doku & Config | COOLIFY_SETUP.md — Healthcheck /api/v1/health, JWT-Vars entfernt, CORS :443; app/config.py — storage_path=/data/storage, session_cookie_secure=True, Startup-Validierung; docker-compose.yml — Redis, Volumes, Healthcheck |
| P1-11 | Cross-Tenant FK | alembic/versions/0036_cross_tenant_fk.py — UNIQUE (tenant_id, id) + Composite FK (tenant_id, contact_id) auf contactpersons und contact_merge_history |
| P2-1 | Contact Model normalisiert | alembic/versions/0039_contact_normalize.py — surfix→suffix, Float→Numeric(5,2), JSON→JSONB, CHECK (0-100), Unique Constraints |
| P2-3 | Commands & Statusmaschinen | app/commands/ (base, contact, calendar, dms, mail) + app/core/state_machine.py |
| P2-4 | SPA Path-Traversal | app/main.py — os.path.abspath Check + ".." in full_path Blocking |
⏳ Offene Items
P0-7: App von öffentlicher Domain nehmen
Status: Operational — nicht aus Code verifizierbar
Problem: Die App läuft unter https://crm.media-on.de und ist öffentlich erreichbar.
Maßnahme:
- Sofort: App von öffentlicher Domain nehmen oder IP-Whitelist/Basic Auth vorschalten
- Mindestens P0-1 (Auth-Bypass ✅) und P0-3 (Plugin-Upload ✅) sind bereits behoben
- Alternativ: VPN/Tunnel-Zugang statt öffentliche Domain
Aufwand: 30 Minuten
P2-2: Plugin-Cross-Imports reduzieren
Status: Offen — 228 direkte Cross-Imports zwischen Plugins
Problem: 228 direkte from app.plugins.builtins Imports zwischen Plugins. Automatisierung importiert Modelle/Services von Kommunikation, Mail, Kalender. Verteilter Monolith ohne Modulgrenzen.
Maßnahme:
- Öffentliche Schnittstellen (Contracts) für jedes Modul definieren
- Direkte Imports fremder Plugin-Modelle verbieten
- Kommunikation nur über Events oder öffentliche Service-API
- CI-Check: keine direkten Cross-Plugin-Imports
Aufwand: 1-2 Wochen
Zusammenfassung
| Priorität | Erledigt | Offen | Geschätzter Aufwand (offen) |
|---|---|---|---|
| P0 | 6/7 | 1 (operational) | 30 Minuten |
| P1 | 11/11 | 0 | — |
| P2 | 3/4 | 1 | 1-2 Wochen |
| Total | 20/22 | 2 | ~1-2 Wochen |
Validierung nach jedem Fix
- Python-Syntax-Check:
python -m py_compile app/**/*.py - pytest:
pytest tests/ -x - Frontend-Typecheck:
cd frontend && npx tsc --noEmit - Frontend-Build:
cd frontend && npx vite build - Manueller Smoke-Test: Login, Kontakt erstellen, DMS-Upload
- Cross-Tenant-Test: Datensatz aus Mandant A kann nicht aus Mandant B gelesen werden
- Deployment: Coolify Deploy + Healthcheck prüfen