# 📋 OpenCRM – Todo-Liste --- ## 🔜 Offen ### Manuelle Tests (vor Release durchklicken) Checklisten für Security + Email-Log-System stehen in **[TESTING.md](./TESTING.md)**. Einmal komplett durchlaufen vor v1.0.0-Release. ### 🚀 SaaS-Ausbau: Instance-per-Customer + Admin-Portal + GoCardless **Vision:** OpenCRM als SaaS anbieten. Jeder Kunde bekommt seine eigene isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung über ein zentrales Admin-Portal. **Architektur-Entscheidung:** Weg C (Instance-per-Customer) - Pro Kunde eine eigene Docker-Instanz mit eigener DB - Keine `tenantId` im CRM-Code → keine Security-Risiken durch vergessene Filter - Komplette Datenisolation (DSGVO-freundlich) - Updates können gestaffelt ausgerollt werden (erst 10% testen) - Bei Kündigung: Docker-Image + DB-Export als "Mitnehm-Paket" **Bewusst NICHT dabei:** eigener Mailserver. Stattdessen Plesk-Integration (die wir schon haben) – Kunde bekommt Mail-Zugang über unseren Plesk bei Bedarf. --- **Admin-Portal (separate App, neben den CRM-Instanzen):** - Kundenverwaltung: wer hat welchen Plan, Status (Trial/Active/Suspended/Cancelled) - "Neuen Kunden anlegen" → Provisioning-Script - DB anlegen (Master-DB kennt die Mapping) - Docker-Container starten - Subdomain konfigurieren (`kundenname.deincrm.de` via Caddy/Traefik) - Initial-Admin-Account erstellen + Einladungs-Email senden - Optional: Factory-Defaults für Stammdaten einspielen - GoCardless-Integration (Webhook + Dashboard) - Instanz-Management: Pause/Resume bei Zahlungsproblemen - Logs & Metriken pro Instanz (optional) - Support-Bereich (Tickets? oder einfach E-Mail) --- **Abrechnung mit GoCardless (gocardless.com):** - Zahlungsmethoden: SEPA-Lastschrift (Hauptfokus) + Kreditkarte (über GoCardless Embedded/Success) - 30 Tage kostenlose Testphase ohne Zahlungsmittel - Nach Trial: Mandats-Erfassung → regelmäßige Abbuchung - Mehrere Pläne (z.B. Basic / Pro / Enterprise) mit unterschiedlichen Features - Webhook-Endpoint im Admin-Portal: - `payment_confirmed` → Instanz aktiv lassen - `payment_failed` → Banner im CRM, nach X Tagen pausieren - `mandate_cancelled` → Kündigungs-Flow - Rechnungsstellung: GoCardless liefert Zahlungsbelege, aber **echte Rechnungen** (mit USt-ID, Rechnungsnummer etc.) müssen wir selbst generieren (evtl. über das existierende PDF-Template-System aus dem CRM nutzen) --- **Provisioning-Flow (grober Entwurf):** 1. Kunde registriert sich auf Landing Page (Name, Firma, E-Mail, Wunsch-Subdomain) 2. Admin-Portal: Trial-Instanz starten - DB erstellen, Docker-Container hochfahren, Caddy-Config für Subdomain - Einladungs-Email mit Admin-Login + Passwort-Reset-Link 3. Tag 25: Erinnerungs-Email "Deine Trial läuft bald ab" 4. Tag 30: Banner im CRM "Jetzt bezahlen oder pausieren" 5. Kunde erfasst GoCardless-Mandat im Admin-Portal-Login 6. Bei erfolgreicher Zahlung: Instanz bleibt aktiv 7. Bei fehlender Zahlung nach 7 Tagen: Instanz pausiert (DB bleibt, UI zeigt Hinweis) --- **Technische Bausteine für später:** - Master-DB mit Tenant-Tabelle (Name, Subdomain, DB-Name, Plan, Status, GoCardlessIDs) - Caddy oder Traefik als Reverse-Proxy mit Auto-SSL (Let's Encrypt) - Docker-Orchestrierung: einzelne `docker-compose.yml` pro Kunde oder Docker-Swarm/K8s - Backup-Strategie: pro Tenant separate Backups + zentrale Master-DB-Backups - Monitoring: ein Fail macht nicht alle down, aber wir müssen es mitbekommen - Logs zentral: z.B. Loki + Grafana für aggregierte Logs aller Instanzen --- **Grobe Zeitschätzung:** - Admin-Portal (MVP): ~1 Woche - GoCardless-Integration + Webhooks: ~3-5 Tage - Provisioning-Automatisierung (Docker + Caddy): ~1 Woche - Landing Page + Checkout: ~3-5 Tage - Tests + Polishing: ~1 Woche - **Gesamt: ~3-4 Wochen** **Vorbereitung JETZT (einfach, macht später Arbeit leichter):** - ✅ Factory-Defaults System (schon erledigt, hilft beim Provisioning) - ✅ Domain/Label dynamisch per Provider (schon erledigt) - Docker-Compose aufräumen, Env-Variablen dokumentieren (klein, ein Tag) - Backup-Script robust + wiederherstellbar (haben wir schon weitgehend) --- ## ✅ Erledigt - [x] **🔄 Automatische Vertrags-Status-Übergänge** - Nightly-Cron (02:00 + Catch-up 60s nach Start): alle Verträge mit `status=ACTIVE` und `endDate < heute` → `EXPIRED` (mit Audit-Log). - Beim Upload der Kündigungsbestätigung (`cancellationConfirmationPath`): wenn Vertrag aktuell `ACTIVE` → auf `CANCELLED` setzen (Audit-Log). Frontend fragt per Modal das Bestätigungs-Datum ab (Default: heute), wird direkt als `cancellationConfirmationDate` gespeichert. Der "Optionen"-Upload löst den Status-Wechsel bewusst NICHT aus, da er für Vertragsänderungen (nicht echte Kündigungen) gedacht ist, setzt aber `cancellationConfirmationOptionsDate` analog. - Beim Upload einer `Lieferbestätigung` (ContractDocument via direkt-Upload oder Email-Anhang-Import): wenn Vertrag aktuell `DRAFT` → auf `ACTIVE` setzen + `startDate` auf das erfasste Lieferdatum (falls leer). Frontend zeigt Datums-Input conditional, wenn Typ "Lieferbestätigung" ausgewählt ist. - Keine neuen Status eingeführt: `cancellationSentDate` vs. `cancellationConfirmationDate` genügen, um "gesendet vs. bestätigt" abzubilden. `ACTIVE` bleibt bis zur Bestätigung. - [x] **🛡️ Security-Hardening vor Production-Deployment (8 Runden)** - Vollständige Story inkl. aller Live-Test-Tabellen + Trade-offs: **[SECURITY-HARDENING.md](./SECURITY-HARDENING.md)** - Erste 2 Runden zusätzlich ausführlich in [SECURITY-REVIEW.md](./SECURITY-REVIEW.md) - Highlights: - Runde 1–3: CORS, Helmet, JWT-Fallback, IDOR-Welle 1, XSS, Mass Assignment, Zip-Slip, Path-Traversal, JWT-Algorithm, Rate-Limiter - Runde 4: 9 Live-IDORs (customer.\*/gdpr.\*) + Error-Handler - Runde 5: `/api/uploads`-Auth (DSGVO-GAU), Login-Timing, Privacy-Policy-XSS - Runde 6: Customer-List-Leak, XFF-Rate-Limit-Bypass, Self-Grant + Existence-Disclosure - Runde 7: SSRF-Schutz (Cloud-Metadata-Block), Logout-Endpoint - Runde 8: DNS-Rebinding-Schutz, Per-File-Ownership-Check - Deployment-Checkliste komplett (in HARDENING.md) - [x] **🎉 Version 1.0.0 Feinschliff: Passwort-Reset + Rate-Limiting + Auto-Geburtstagsgrüße** - **Passwort vergessen-Flow** (Login → "Passwort vergessen?" Link) - Email-Reset-Token mit 2h Gültigkeit (kryptografisch sicher: 32 Byte Random) - Funktioniert für Mitarbeiter UND Portal-Kunden (Typ-Auswahl) - User-Enumeration-Schutz: immer 200 OK, egal ob Email existiert - Reset-Link per Email mit schönem HTML-Template - Nach Reset: alle bestehenden Sessions werden gekickt - **Rate-Limiting** gegen Brute-Force - Login: 10 Versuche pro 15 Min pro IP (erfolgreiche zählen nicht) - Passwort-Reset-Anfrage: 5 Versuche pro Stunde pro IP - **Cron-Job für automatische Geburtstagsgrüße** - Täglich 08:00 Uhr: alle Kunden mit heutigem Geburtstag + autoBirthdayGreeting=true - Email-Versand über System-E-Mail, Du/Sie-abhängiger Text - Catch-up 30s nach Server-Start (falls Server am Geburtstag kurz down war) - Marker lastBirthdayGreetingYear verhindert Doppel-Versand - [x] **Mandantenfähigkeit: Domain + Kunden-E-Mail-Label dynamisch pro Provider** - Neues Feld `customerEmailLabel` am EmailProviderConfig (z.B. "Stressfrei-Wechseln", "Meine-Firma") - Wenn leer, wird das Label automatisch aus der Domain abgeleitet ("stressfrei-wechseln.de" → "Stressfrei-Wechseln") - Neuer Frontend-Hook `useProviderSettings()` liefert Domain + Label - Alle hardcoded "Stressfrei-Wechseln" und `@stressfrei-wechseln.de` Strings durch dynamische Werte ersetzt (CustomerDetail, ContractForm, ContractDetail, EmailClientTab, Settings) - Modal-Eingabefeld "Bezeichnung für Kunden-E-Mails" in Provider-Einstellungen - Notwendig für Multi-Mandanten-Betrieb wenn das CRM an Dritte vermietet wird - [x] **Factory-Defaults: Export + Import von Stammdaten-Katalogen** - Enthält: Anbieter, Tarife, Kündigungsfristen, Laufzeiten, Vertragskategorien, PDF-Auftragsvorlagen (+ PDF-Dateien) - Enthält NICHT: Kundendaten, Verträge, Dokumente, Emails, Einstellungen (dafür gibt es den Datenbank-Backup) - Neue Einstellungsseite „Factory-Defaults" mit Übersicht (Anzahl pro Kategorie) und Export-Button - Export: ZIP mit manifest.json + Kategorie-JSONs + PDF-Dateien, Download über Browser - Import-Script: `npm run seed:defaults` liest `backend/factory-defaults/`, merged mehrere JSONs pro Kategorie, upsertet idempotent + kopiert PDFs in uploads/ - Ordner `backend/factory-defaults/` gitignoriert (außer .gitkeep + README), damit firmen-spezifische Kataloge nicht ins Repo kommen - [x] **Email-Anhänge → Vertragsdokumente + Rechnungen für alle Vertragstypen** - Im SaveAttachmentModal (bei einem per Email zugeordneten Vertrag) gibt es jetzt drei Modi: 1. **Als Dokument** (in feste Slots wie Kündigungsschreiben) – wie bisher 2. **Als Vertragsdokument** – neu, mit Typ-Dropdown (Auftragsformular, Lieferbestätigung, Vertragsunterlagen, Vollmacht, Widerrufsbelehrung, Preisblatt, Sonstiges) + Notizen 3. **Als Rechnung** – jetzt für **alle** Vertragstypen (vorher nur Strom/Gas) - Gleiches gilt für das Speichern der gesamten Email als PDF-Rechnung - Neuer Backend-Endpoint `saveAttachmentAsContractDocument` für die flexible ContractDocument-Tabelle - [x] **Geburtstag-Management-Modal in Kundenstammdaten** - Neuer Button (Cake-Icon) neben Geburtsdatum öffnet Modal - **Gruß zurücksetzen:** setzt `lastBirthdayGreetingYear` auf null zurück (fürs Debugging + Fallback) - **Gruß jetzt senden:** per Email (direkt), WhatsApp/Telegram/Signal (öffnet vorbefülltes Fenster) - Beide Aktionen mit Ja/Nein-Bestätigungsdialog (kein versehentliches Klicken) - Text respektiert Du/Sie-Einstellung des Kunden - Checkbox "Automatisch senden" mit Kanal-Dropdown (neue Felder am Customer) - Audit-Log für Reset + Send - [x] **Anrede-Verhältnis Du/Sie pro Kunde** - Neues Feld `useInformalAddress` in Stammdaten (auch bei Firmenkunden) - Default: Sie (formell) - Geburtstagsgruß im Portal nutzt die Anrede: "Du"-Kunden bekommen "Herzlichen Glückwunsch, Max!", "Sie"-Kunden "Herzlichen Glückwunsch, Herr Müller!" - Komplett konsistent auch bei nachträglichen Glückwünschen ("hattest" vs "hatten") - [x] **Geburtsdatum + Geburtsort auch bei Firmenkunden** - Felder werden jetzt unabhängig vom Kundentyp angezeigt - Ermöglicht z.B. Geburtstage für Ansprechpartner bei Firmen - [x] **Geburtstagskalender + Geburtstagsgruß-Modal** - Admin: Section im Vertrags-Cockpit mit Kunden, die in den nächsten 30 Tagen oder letzten 7 Tagen Geburtstag haben - Portal: Modal mit Gruß am Geburtstag (inkl. nachträglichem Glückwunsch bis 7 Tage danach) - Wird pro Jahr nur einmal angezeigt - [x] **Typspezifische Zusatzinfos in Vertragslisten** - Strom/Gas → "Lieferadresse: ..." - DSL/Glasfaser/Kabel → "Anschlussadresse: ..." - Mobilfunk → "Rufnummer: ..." - KFZ → "Kennzeichen: ..." - Sichtbar in Admin-Liste, Portal-Liste und Kunden-Tab - [x] **Datenschutzerklärung PDF ↔ Online-Einwilligungen synchronisieren** - PDF hochgeladen → alle 4 Consents auf GRANTED - Haken entfernt im Portal → PDF löschen + Tabs sperren - Entsperrung nur durch alle Haken oder neues PDF - [x] **Zweitarif-Zähler (HT/NT)** bei Strom + Verbrauchsberechnung - [x] **Datumsformate vereinheitlichen** (01.01.2026 statt 1.1.2026) - [x] **Audit-Log aussagekräftig** (Vorher/Nachher bei allen Änderungen) - [x] **Impressum + Website-Datenschutzerklärung** im Kundenportal - Editor in Einstellungen - Vorschlagstexte - [x] **Consent-Bestätigungs-Flow per Email** - Alle Hebel müssen gesetzt sein - Bestätigungsbutton + Bestätigungsemail - [x] **Vertragsdokumente-Upload** (Auftragsformular, Lieferbestätigung, Vertragsunterlagen als PDF/PNG) - [x] **Bug: Stressfrei-Email im Auftragsgenerator** (funktioniert jetzt im Vertrag) - [x] **PDF-Auftragsvorlagen-System** - Template-Editor in Einstellungen - PDF hochladen, Formularfelder automatisch auslesen - CRM-Felder zuordnen (visuell mit Vorschau) - Seitenweise Sortierung der Felder - Dynamische Rufnummern-Felder mit Vorwahl-Extraktion - Nicht zugeordnete Felder bleiben editierbar - Auftrag generieren aus Vertragsdaten (Button im Vertrags-Detail) - [x] **Eigentümer-Verwaltung** - An Adresse gehängt (Firma, Vorname, Nachname, Anschrift, Kontakt) - Fallback auf Kundendaten wenn leer - Nur bei Liefer-/Meldeadressen (nicht Rechnung) - Namens-Kombinationen (Firma + Vorname + Nachname etc.) - [x] **Gruppenauswahl Liefer-/Rechnungs-/Eigentümer-Adresse** im Auftragsgenerator - [x] **Objekttyp + Lage + Lage des Anschlusses** bei Festnetz-Verträgen (DSL/Glasfaser/Kabel) - [x] **Bankverbindung-Fallback** im PDF-Generator (neueste aktive Bankverbindung des Kunden)