opencrm/README.md

31 KiB
Raw Blame History

OpenCRM

Web-basiertes CRM-System für Kundenverwaltung mit Verträgen (Energie, Telekommunikation, KFZ-Versicherung).

Features

  • Kundenverwaltung: Privat- und Geschäftskunden mit Stammdaten
  • Adressen: Mehrere Liefer-/Melde- und Rechnungsadressen pro Kunde
  • Bankkarten: Mit Ablaufdatum, Aktiv-Status und Dokument-Upload (PDF)
  • Ausweise: Personalausweis, Reisepass, etc. mit Ablaufdatum und Dokument-Upload (PDF)
  • Zähler: Strom-/Gaszähler mit Zählerstandhistorie
  • Rechnungen: Rechnungsverwaltung für Energieverträge mit Dokumenten-Upload
  • Vertrags-Cockpit: Dashboard zur Überwachung offener Aufgaben (fehlende Dokumente, Rechnungen)
  • Verträge:
    • Energie (Strom, Gas)
    • Telekommunikation (DSL, Glasfaser, Mobilfunk, TV)
    • KFZ-Versicherung
  • Folgeverträge: Automatische Datenübernahme bei Anbieterwechsel
  • Vertriebsplattformen: Verwaltbar über WebUI
  • Email-Provisionierung: Automatische E-Mail-Weiterleitung bei Plesk/cPanel/DirectAdmin
  • Berechtigungssystem: Admin, Mitarbeiter, Nur-Lesen, Kundenportal
  • Verschlüsselte Zugangsdaten: Portal-Passwörter AES-256-GCM verschlüsselt
  • DSGVO-Compliance: Audit-Logging, Einwilligungsverwaltung, Datenexport, Löschanfragen
  • Developer-Tools: Datenbank-Browser und interaktives ER-Diagramm

Tech Stack

  • Frontend: React 18, TypeScript, Tailwind CSS, React Query
  • Backend: Node.js, Express 4.x, TypeScript
  • Datenbank: MariaDB
  • ORM: Prisma
  • Auth: JWT mit Rollen-basierter Zugriffskontrolle

Hinweis zu Express 5: Das Projekt verwendet bewusst Express 4.x (nicht 5.x). Express 5 ist seit Jahren in der Beta-Phase und noch nicht offiziell stable. Bei der Installation darauf achten, dass @types/express zur Express-Version passt:

  • Express 4.x → @types/express@^4.17.x
  • Express 5.x → @types/express@^5.x (erst bei offiziellem Release empfohlen)

Voraussetzungen

  • Node.js 18+ (empfohlen: 20+)
  • Docker & Docker Compose
  • npm

Installation

1. Repository klonen

git clone <repository-url>
cd opencrm

2. MariaDB-Datenbank starten

docker-compose up -d

Dies startet einen MariaDB-Container mit:

  • Port: 3306
  • Datenbank: opencrm
  • Root-Passwort: rootpassword
  • Benutzer: opencrm / opencrm123

Warte ca. 10 Sekunden bis die Datenbank bereit ist.

3. Backend einrichten

cd backend

# Dependencies installieren
npm install

# .env-Datei erstellen (falls noch nicht vorhanden)
cp .env.example .env

Die .env-Datei sollte folgende Werte enthalten:

# Database
DATABASE_URL="mysql://root:rootpassword@localhost:3306/opencrm"

# JWT
JWT_SECRET="change-this-to-a-very-long-random-secret-in-production"
JWT_EXPIRES_IN="7d"

# Encryption (for portal credentials) - generate with: openssl rand -hex 32
ENCRYPTION_KEY="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"

# Server
PORT=3001
NODE_ENV=development

4. Datenbank initialisieren

# Prisma Client generieren und Migrationen ausführen
npx prisma migrate dev

# Seed-Daten einspielen (Admin-User, Rollen, Berechtigungen)
npm run db:seed

5. Frontend einrichten

cd ../frontend

# Dependencies installieren
npm install

Anwendung starten

Backend starten (Terminal 1)

cd backend
npm run dev

Das Backend läuft auf http://localhost:3001

Frontend starten (Terminal 2)

cd frontend
npm run dev

Das Frontend läuft auf http://localhost:5173

Erster Login

Nach dem Seed sind folgende Zugangsdaten verfügbar:

Developer-Tools aktivieren

Die Developer-Tools (Datenbankstruktur, ER-Diagramm) sind standardmäßig für Admins verfügbar. Falls der Menüpunkt nicht erscheint:

  1. Einmalig im Browser-Console ausführen:
    fetch('/api/developer/setup', { method: 'POST' })
    
  2. Ausloggen und neu einloggen

Alternativ können Developer-Rechte pro Benutzer vergeben werden:

  • Benutzer bearbeiten > "Entwicklerzugriff" aktivieren

Email-Provisionierung

Das System unterstützt die automatische Erstellung von E-Mail-Weiterleitungen auf Hosting-Servern für Stressfrei-Wechseln Adressen.

Unterstützte Provider

  • Plesk (implementiert)
  • cPanel (vorbereitet)
  • DirectAdmin (vorbereitet)

Konfiguration

  1. EinstellungenEmail-Provisionierung öffnen
  2. Neuen Provider hinzufügen:
    • Name: Bezeichnung (z.B. "Plesk Hauptserver")
    • Typ: Plesk/cPanel/DirectAdmin
    • API-URL: Server-URL (z.B. https://server.de:8443)
    • Benutzername/Passwort: API-Zugangsdaten
    • Domain: E-Mail-Domain (z.B. stressfrei-wechseln.de)
    • Standard-Weiterleitung: Zusätzliche Weiterleitungsadresse (optional)
  3. Provider als "Standard" und "Aktiv" markieren
  4. Verbindung testen

Verwendung

Beim Anlegen einer Stressfrei-Wechseln Adresse im Kundenbereich erscheint die Checkbox "Beim E-Mail-Provider anlegen", wenn:

  • Ein aktiver Standard-Provider konfiguriert ist
  • Der Kunde eine E-Mail-Adresse hat

Bei aktivierter Checkbox wird automatisch:

  1. Geprüft, ob die E-Mail-Adresse bereits existiert
  2. Falls nicht: E-Mail-Adresse beim Provider angelegt mit Weiterleitung an:
    • Kunden-E-Mail-Adresse
    • Standard-Weiterleitungsadresse (falls konfiguriert)

Befehle

Backend

npm run dev          # Entwicklungsserver starten
npm run build        # Produktions-Build erstellen
npm run db:studio    # Prisma Studio (Datenbank-GUI)
npm run db:migrate   # Neue Migration erstellen
npm run db:seed      # Seed erneut ausführen

Frontend

npm run dev      # Entwicklungsserver starten
npm run build    # Produktions-Build erstellen
npm run preview  # Build-Vorschau

Docker (Entwicklung)

docker-compose up -d       # Container starten
docker-compose down        # Container stoppen
docker-compose down -v     # Container stoppen + Daten löschen
docker-compose logs -f     # Logs anzeigen

Docker (Produktion)

Im docker/ Verzeichnis liegt ein komplettes Produktions-Setup:

cd docker

# Image bauen
docker-compose build

# Container starten
docker-compose up -d

# Logs anzeigen
docker-compose logs -f app

Komponenten:

  • MariaDB 10.11: Datenbank
  • App: Backend + Frontend in einem Container
  • Caddy: Reverse-Proxy mit automatischem SSL

Umgebungsvariablen (docker/.env):

MYSQL_ROOT_PASSWORD=sicheres-root-passwort
MYSQL_DATABASE=opencrm
MYSQL_USER=opencrm
MYSQL_PASSWORD=sicheres-passwort
JWT_SECRET=sehr-langer-zufaelliger-string
ENCRYPTION_KEY=64-zeichen-hex-string
DOMAIN=crm.example.com
RUN_SEED=true  # Nur beim ersten Start

Projektstruktur

opencrm/
├── backend/
│   ├── src/
│   │   ├── controllers/    # Request-Handler
│   │   │   ├── auditLog.controller.ts   # Audit-Log API
│   │   │   └── gdpr.controller.ts       # DSGVO API
│   │   ├── middleware/     # Auth, Validation
│   │   │   ├── audit.ts              # Automatisches API-Logging
│   │   │   └── auditContext.ts       # Before/After Context
│   │   ├── routes/         # API-Endpunkte
│   │   │   ├── auditLog.routes.ts    # Audit-Log Routes
│   │   │   └── gdpr.routes.ts        # DSGVO Routes
│   │   ├── services/       # Business-Logik
│   │   │   ├── audit.service.ts      # Hash-Kette, Logging
│   │   │   ├── consent.service.ts    # Einwilligungen
│   │   │   └── gdpr.service.ts       # Export, Löschung
│   │   ├── lib/
│   │   │   └── prisma.ts             # Prisma mit Audit-Middleware
│   │   ├── types/          # TypeScript-Typen
│   │   └── index.ts        # Server-Einstiegspunkt
│   ├── prisma/
│   │   ├── schema.prisma   # Datenbank-Schema
│   │   └── seed.ts         # Seed-Daten
│   ├── uploads/            # Hochgeladene Dokumente
│   │   ├── bank-cards/     # Bankkarten-Dokumente
│   │   ├── documents/      # Ausweis-Scans
│   │   ├── invoices/       # Rechnungsdokumente (Strom/Gas)
│   │   ├── gdpr/           # DSGVO-Löschnachweise
│   │   ├── business-registrations/    # Gewerbeanmeldungen
│   │   ├── commercial-registers/      # Handelsregisterauszüge
│   │   ├── privacy-policies/          # Datenschutzerklärungen
│   │   ├── cancellation-letters/      # Kündigungsschreiben
│   │   ├── cancellation-confirmations/ # Kündigungsbestätigungen
│   │   └── cancellation-*-options/    # Kündigungsdokumente Optionen
│   └── package.json
├── frontend/
│   ├── src/
│   │   ├── components/     # UI-Komponenten
│   │   ├── pages/          # Seiten
│   │   │   └── settings/
│   │   │       ├── AuditLogs.tsx      # Audit-Protokoll
│   │   │       └── GDPRDashboard.tsx  # DSGVO-Dashboard
│   │   ├── hooks/          # Custom Hooks
│   │   ├── services/       # API-Client
│   │   ├── types/          # TypeScript-Typen
│   │   └── App.tsx         # Haupt-Komponente
│   └── package.json
├── docker/                  # Docker-Deployment
│   ├── Dockerfile          # Multi-Stage Build
│   ├── docker-compose.yml  # Produktion (MariaDB, App, Caddy)
│   ├── Caddyfile           # Reverse-Proxy mit SSL
│   └── entrypoint.sh       # Container-Startup
├── docker-compose.yml      # MariaDB-Container (Entwicklung)
└── README.md

Berechtigungen

Rolle Kunden Verträge Benutzer Plattformen Audit/DSGVO Developer
Admin CRUD CRUD CRUD CRUD Vollzugriff Optional
Mitarbeiter CRUD CRUD - Lesen Lesen -
Mitarbeiter (Lesen) Lesen Lesen - Lesen - -
Kunde Eigene Eigene - - - -

Troubleshooting

Datenbank-Verbindungsfehler

  1. Prüfe ob Container läuft: docker ps
  2. Prüfe die DATABASE_URL in .env
  3. Warte nach Container-Start ca. 10 Sekunden

Prisma-Fehler

# Prisma Client neu generieren
npx prisma generate

# Schema zur Datenbank pushen (ohne Migration)
npx prisma db push

Port bereits belegt

  • Backend: PORT in .env ändern
  • Frontend: In vite.config.ts anpassen

Developer-Menü fehlt

# In der Browser-Console:
fetch('/api/developer/setup', { method: 'POST' }).then(r => r.json()).then(console.log)
# Danach ausloggen und neu einloggen

Vertragstypen

Standard-Vertragstypen

Folgende Vertragstypen werden bei Installation/Factory-Reset automatisch angelegt:

Code Name Icon Farbe
ELECTRICITY Strom Zap #FFC107
GAS Gas Flame #FF5722
DSL DSL Wifi #2196F3
FIBER Glasfaser Cable #9C27B0
CABLE Kabel Internet (Coax) Cable #00BCD4
MOBILE Mobilfunk Smartphone #4CAF50
TV TV Tv #E91E63
CAR_INSURANCE KFZ-Versicherung Car #607D8B

Hinweis: Vertragstypen können nur von Benutzern mit Entwicklerzugriff geändert werden, da Änderungen auch Anpassungen an den Formularen erfordern.

Vertragstyp-spezifische Felder

Je nach Vertragstyp werden unterschiedliche Felder im Formular angezeigt:

Strom & Gas (ELECTRICITY, GAS)

  • Zähler-Auswahl
  • Jahresverbrauch (kWh/m³)
  • Grundpreis, Arbeitspreis
  • Bonus
  • Vorversorger, Kundennummer beim Vorversorger

Internet (DSL, CABLE, FIBER)

  • Download/Upload (Mbit/s)
  • Router Modell, Seriennummer
  • Installationsdatum
  • Benutzername, Passwort
  • Rufnummern mit SIP-Zugangsdaten
Vertragstyp Zusatzfeld
Glasfaser (FIBER) Home-ID

Mobilfunk (MOBILE)

  • Datenvolumen (GB)
  • Inklusiv-Minuten, Inklusiv-SMS
  • Gerät-Modell, IMEI
  • Multisim-Checkbox
  • SIM-Karten (dynamisch erweiterbar):
    • Rufnummer, SIM-Kartennummer (ICCID)
    • PIN, PUK (verschlüsselt)
    • Multisim-Flag, Hauptkarte-Flag

Hinweis Multisim: Nicht buchbar bei Klarmobil, Congstar, Otelo. Benötigt Freenet oder vergleichbar.

TV

  • Receiver Modell
  • Smartcard-Nummer
  • Paket/Angebot

KFZ-Versicherung (CAR_INSURANCE)

  • Kennzeichen, HSN, TSN, FIN/VIN
  • Fahrzeugtyp, Erstzulassung
  • SF-Klasse (Schadenfreiheitsklasse)
  • Versicherungsart (Haftpflicht/Teilkasko/Vollkasko)
  • Selbstbeteiligungen (Teilkasko, Vollkasko)
  • Versicherungsscheinnummer
  • Vorversicherer

Standard-Anbieter

Folgende Anbieter werden bei Installation/Factory-Reset automatisch angelegt:

Anbieter Portal-URL
Vodafone https://www.vodafone.de/meinvodafone/account/login
Klarmobil https://www.klarmobil.de/login
Otelo https://www.otelo.de/mein-otelo/login
Congstar https://www.congstar.de/login/
Telekom https://www.telekom.de/kundencenter/startseite
O2 https://www.o2online.de/ecare/selfcare
1&1 https://control-center.1und1.de/

Anbieter-spezifische Felder

Einige Felder werden nur bei bestimmten Anbietern angezeigt:

Anbieter Vertragstyp Zusatzfeld
Vodafone DSL, Kabel Internet Aktivierungscode

Hinweis Multisim: Bei Klarmobil, Congstar und Otelo ist Multisim nicht buchbar. Dafür wird Freenet oder ein vergleichbarer Anbieter benötigt.

Rechnungsverwaltung (Energieverträge)

Für Strom- und Gas-Verträge können Rechnungen verwaltet werden, um den Abrechnungsstatus zu tracken.

Rechnungstypen

Typ Beschreibung
Zwischenrechnung (INTERIM) Reguläre Jahresrechnung während der Vertragslaufzeit
Schlussrechnung (FINAL) Endabrechnung nach Vertragskündigung/Deaktivierung
Nicht verfügbar (NOT_AVAILABLE) Rechnung ist nicht mehr zu bekommen (z.B. Anbieter existiert nicht mehr)

Funktionen

  • Rechnungen hinzufügen/bearbeiten/löschen in der Vertragsdetailansicht
  • Dokument-Upload (PDF) - Pflicht, außer bei Typ "Nicht verfügbar"
  • Statusanzeige: Grünes Badge bei Schlussrechnung, Orange bei fehlender Schlussrechnung
  • E-Mail-Anhänge als Rechnung speichern: Direkt aus dem E-Mail-Client

E-Mail-Integration

Bei E-Mails, die einem Energievertrag zugeordnet sind:

  1. Toggle zwischen "Als Dokument" und "Als Rechnung" im Speichern-Dialog
  2. Rechnungsdatum und Typ auswählen
  3. Anhang wird automatisch als Rechnungsdokument gespeichert

Vertrags-Cockpit

Dashboard zur Überwachung offener Aufgaben und fehlender Dokumente.

Kategorien

Kategorie Prüfungen
Fehlende Dokumente Kündigungsschreiben, Kündigungsbestätigung (wenn Kündigung markiert)
Fehlende Rechnungen Schluss-/Zwischenrechnungen für Energieverträge
Ablaufende Dokumente Ausweise, Bankkarten (nächste 30 Tage)

Rechnungsprüfung für Energieverträge

Schlussrechnung (gekündigte/deaktivierte Verträge)

Status Prüfung
CANCELLED / DEACTIVATED Schlussrechnung oder "Nicht verfügbar" erforderlich

Zwischenrechnung (laufende Verträge)

Bedingung Warnung
Vertrag > 12 Monate alt, keine Rechnung "Zwischenrechnung fehlt"
Letzte Rechnung > 12 Monate her "Zwischenrechnung überfällig"

Hinweis Status-Logik:

  • EXPIRED = Laufzeit abgelaufen, aber Vertrag läuft ohne Kündigung weiter → Zwischenrechnung prüfen
  • CANCELLED = Aktive Kündigung → Schlussrechnung prüfen
  • DEACTIVATED = Manuell beendet → Schlussrechnung prüfen

Vertrag zurückstellen (Snooze)

Wenn ein Vertrag EXPIRED ist (Laufzeit vorbei, läuft aber weiter), erscheint er im Cockpit. Manchmal ist Bleiben günstiger als Wechseln - aber der Vertrag soll nicht dauerhaft im Cockpit erscheinen.

Lösung: Vertrag temporär zurückstellen mit Datum für erneute Prüfung.

Snooze aktivieren

Im Cockpit hat jeder Vertrag einen Snooze-Button (Glocke mit Uhr). Optionen:

  • +3 Monate
  • +6 Monate (Empfohlen)
  • +12 Monate
  • Eigenes Datum (Datepicker)

Unterdrückte Warnungen (bei aktivem Snooze)

Warnung Beschreibung
Kündigungsfrist Frist läuft ab
Vertrag läuft ab Enddatum naht
Kündigungsschreiben fehlt Bei markierter Kündigung
Kündigungsbestätigung fehlt Bei markierter Kündigung

NICHT unterdrückte Warnungen

Diese Warnungen werden auch bei aktivem Snooze angezeigt:

Warnung Beschreibung
Schlussrechnung fehlt Beendeter Vertrag ohne Endabrechnung
Zwischenrechnung fehlt/überfällig Laufender Vertrag ohne Jahresrechnung
Zählerstand fehlt Fehlende Zählerstände bei Energieverträgen
Zugangsdaten fehlen Portal-Passwort, SIP-Daten, etc.

Snooze aufheben

Im Cockpit: Bei Verträgen in der Kategorie "Erneute Prüfung fällig" erscheint ein "Snooze aufheben"-Button.

In Vertragsdetails: Bei zurückgestellten Verträgen erscheint ein bernsteinfarbenes Badge "Zurückgestellt bis [Datum]" mit X-Button zum Aufheben.

Erneute Prüfung fällig

Wenn das Snooze-Datum in der Vergangenheit liegt, erscheint der Vertrag in der neuen Kategorie "Erneute Prüfung fällig" mit Angabe, seit wie vielen Tagen die Prüfung fällig ist.

Status-Info Modal

An verschiedenen Stellen (Vertragsformular, Vertragsdetails, Vertragsübersicht, Kundenansicht) zeigt ein -Icon neben dem Status eine Erklärung aller Vertragsstatus:

Status Bedeutung
Entwurf Vertrag wird noch vorbereitet
Ausstehend Wartet auf Aktivierung
Aktiv Vertrag läuft normal
Abgelaufen Laufzeit vorbei, läuft aber ohne Kündigung weiter
Gekündigt Aktive Kündigung eingereicht, Vertrag endet
Deaktiviert Manuell beendet/archiviert

E-Mail-Client

Ein vollständig integrierter E-Mail-Client pro Kunde mit IMAP-Empfang und SMTP-Versand.

Funktionen

E-Mails lesen & verwalten

  • E-Mail-Tab in Kundenansicht mit Ordnern: Posteingang, Gesendet, Papierkorb
  • Mehrere E-Mail-Konten pro Kunde (Dropdown zur Auswahl)
  • E-Mail-Detailansicht mit HTML/Text-Body, Absender, Empfänger, CC, Datum
  • Gelesen/Ungelesen markieren
  • Favoriten (Stern) für wichtige E-Mails
  • Papierkorb mit Wiederherstellen und endgültigem Löschen

E-Mails schreiben

  • Neue E-Mail verfassen mit An, CC, Betreff, Text
  • Antworten mit zitiertem Originaltext
  • Dateianhänge (max. 10 MB pro Datei, 25 MB gesamt)
  • SMTP-Versand über die gewählte StressfreiEmail-Adresse

Vertragszuordnung

  • E-Mails zu Verträgen zuordnen für bessere Nachverfolgung
  • E-Mail-Tab in Vertragsansicht zeigt nur zugeordnete E-Mails
  • Automatische Zuordnung bei Versand aus Vertragskontext
  • Manuelle Zuordnung über Suchfeld und Vertragsauswahl

Anhänge

  • Anhangsliste in E-Mail-Detail
  • Download einzelner Anhänge
  • Inline-Ansicht (im Browser öffnen)

Technische Details

Backend-Services

Service Beschreibung
imapService.ts IMAP-Client (ImapFlow) für E-Mail-Empfang
smtpService.ts SMTP-Client (Nodemailer) für E-Mail-Versand
cachedEmail.service.ts E-Mail-Caching, Synchronisation, Zuordnung

API-Endpunkte

GET  /api/customers/:id/emails              # E-Mails für Kunde
GET  /api/contracts/:id/emails              # E-Mails für Vertrag
GET  /api/emails/:id                        # Einzelne E-Mail mit Body
POST /api/stressfrei-emails/:id/sync        # IMAP-Synchronisation
POST /api/stressfrei-emails/:id/send        # E-Mail senden
POST /api/emails/:id/assign                 # Vertrag zuordnen
DELETE /api/emails/:id/assign               # Zuordnung aufheben
PATCH /api/emails/:id/read                  # Gelesen/Ungelesen
POST /api/emails/:id/star                   # Favorit umschalten
DELETE /api/emails/:id                      # In Papierkorb
POST /api/emails/:id/restore                # Aus Papierkorb wiederherstellen
DELETE /api/emails/:id/permanent            # Endgültig löschen
GET  /api/emails/:id/attachments/:filename  # Anhang herunterladen

# Rechnungen (Invoices)
GET    /api/invoices/ecd/:ecdId              # Rechnungen für EnergyContractDetails
POST   /api/invoices/ecd/:ecdId              # Rechnung hinzufügen
PUT    /api/invoices/ecd/:ecdId/:invoiceId   # Rechnung bearbeiten
DELETE /api/invoices/ecd/:ecdId/:invoiceId   # Rechnung löschen
POST   /api/invoices/:invoiceId/upload       # Rechnungsdokument hochladen

# Cockpit
GET    /api/contracts/cockpit                # Offene Aufgaben abrufen

Datenbank-Modell

model CachedEmail {
  id                Int              @id @default(autoincrement())
  stressfreiEmailId Int
  stressfreiEmail   StressfreiEmail  @relation(...)
  folder            String           // INBOX, SENT
  messageId         String           // RFC 5322 Message-ID
  uid               Int              // IMAP UID
  subject           String?
  fromAddress       String
  fromName          String?
  toAddresses       String           @db.Text  // JSON Array
  ccAddresses       String?          @db.Text
  receivedAt        DateTime
  textBody          String?          @db.LongText
  htmlBody          String?          @db.LongText
  hasAttachments    Boolean          @default(false)
  attachmentNames   String?          @db.Text  // JSON Array
  contractId        Int?             // Vertragszuordnung
  assignedAt        DateTime?
  assignedBy        Int?
  isAutoAssigned    Boolean          @default(false)
  isRead            Boolean          @default(false)
  isStarred         Boolean          @default(false)
  isDeleted         Boolean          @default(false)
  deletedAt         DateTime?

  @@unique([stressfreiEmailId, messageId, folder])
}

Sicherheit

  • Passwort-Verschlüsselung: AES-256-GCM für Mailbox-Passwörter
  • Passwort-Reset: Neues Passwort generieren und beim Provider setzen
  • Verschlüsselungsmodi: SSL, STARTTLS, oder unverschlüsselt
  • Selbstsignierte Zertifikate: Konfigurierbar pro Provider

Berechtigungen

Aktion Berechtigung
E-Mails lesen customers:read
E-Mails senden, markieren customers:update
Anhänge in Dokumente speichern customers:update
Vertrag zuordnen contracts:update
Löschen, Papierkorb emails:delete

Frontend-Komponenten

Komponente Beschreibung
EmailClientTab.tsx Haupt-Tab mit Konto-Auswahl und Ordnern
EmailList.tsx E-Mail-Liste mit Aktionen
EmailDetail.tsx E-Mail-Ansicht mit Anhängen
ComposeEmailModal.tsx Neue E-Mail / Antworten
TrashEmailList.tsx Papierkorb-Verwaltung
AssignToContractModal.tsx Vertragszuordnung
ContractEmailsSection.tsx E-Mails in Vertragsansicht
SaveAttachmentModal.tsx Anhänge in Dokumentfelder speichern
SaveEmailAsPdfModal.tsx E-Mail als PDF in Dokumentfelder speichern
InvoicesSection.tsx Rechnungsverwaltung in Vertragsdetails

Anhänge als Dokumente speichern

E-Mail-Anhänge können direkt in Dokumentfelder des CRM gespeichert werden. Über den blauen Speichern-Button (💾) neben jedem Anhang öffnet sich ein Modal mit allen verfügbaren Zielen.

Verfügbare Ziele

Kategorie Dokumentfelder
Kunde Datenschutzerklärung
Kunde (Gewerbe) + Gewerbeanmeldung, Handelsregisterauszug
Ausweisdokumente Dokumentscan (pro Ausweis)
Bankkarten Kartenscan (pro Karte)
Vertrag Kündigungsschreiben, Kündigungsbestätigung, Kündigungsschreiben (Optionen), Kündigungsbestätigung (Optionen)

Hinweis: Vertragsdokumente sind nur verfügbar, wenn die E-Mail einem Vertrag zugeordnet ist.

Dynamische Konfiguration

Die Dokumentziele werden zentral in backend/src/config/documentTargets.config.ts konfiguriert. Neue Dokumentfelder werden automatisch im Modal angezeigt, ohne Frontend-Änderungen.

// Beispiel: Neues Feld hinzufügen
{
  key: 'newDocument',
  label: 'Neues Dokument',
  field: 'newDocumentPath',      // Prisma-Feld
  condition: null,                // oder 'BUSINESS' für Geschäftskunden
  directory: 'new-documents'      // Upload-Verzeichnis
}

Warnung bei Überschreiben

Wenn bereits ein Dokument im Zielfeld vorhanden ist, wird eine Warnung angezeigt. Das vorhandene Dokument wird beim Speichern automatisch ersetzt und die alte Datei gelöscht.

Vertragszuordnung aufheben (X-Button)

Der X-Button zum Aufheben der Vertragszuordnung erscheint nur bei manuell zugeordneten E-Mails. E-Mails, die direkt aus dem Vertragskontext gesendet wurden (isAutoAssigned = true), bleiben dauerhaft mit dem Vertrag verknüpft.

Ansicht Vertrags-Badge X-Button sichtbar
Kundenakte - Posteingang immer
Kundenakte - Gesendet nur manuell zugeordnet
Kundenakte - Papierkorb je nach Original-Ordner
Vertrag - Posteingang immer
Vertrag - Gesendet nur manuell zugeordnet
Vertrag - Papierkorb je nach Original-Ordner
Detail-Ansicht (beide) nur manuell zugeordnet

Hinweis: Bei gesendeten E-Mails gilt:

  • isAutoAssigned = true: E-Mail wurde direkt aus dem Vertragskontext gesendet → X-Button ausgeblendet
  • isAutoAssigned = false: E-Mail wurde manuell dem Vertrag zugeordnet → X-Button sichtbar

Vertragsbaum in Kundenansicht

In der Kundendetailansicht werden Verträge als Baumstruktur mit Vorgänger-Verknüpfung dargestellt:

▼ GAS-ML781A4FYXU  │ Gas │ ACTIVE │ 01.01.2025 - 31.12.2026
  └─ GAS-ML24GKR...│ Gas │ EXPIRED│ 05.05.2023 - 05.05.2025  (Vorgänger)
     └─ GAS-OLD123 │ Gas │ EXPIRED│ 01.01.2021 - 04.05.2023  (Vorgänger)

▶ MOB-ML77W560A73  │ Mobil│ DRAFT  │ 02.01.2024 - 02.01.2026

Funktionsweise:

  • Aktuellste Verträge oben - Verträge ohne Nachfolger werden als Wurzelknoten angezeigt
  • Standardmäßig eingeklappt - Klick auf ▶ zeigt die Vorgängerkette
  • Vorgänger eingerückt - Mit grauem Rand und "(Vorgänger)" Label
  • Verknüpfung über previousContractId - Wird beim Erstellen eines Folgevertrags automatisch gesetzt

Hinweis: In der Hauptvertragsliste (/contracts) wird weiterhin die flache Ansicht ohne Baumstruktur verwendet.

DSGVO-Compliance & Audit-Logging

Umfassendes Audit-Logging-System mit DSGVO-Compliance-Features.

Audit-Protokoll

Automatische Protokollierung aller API-Zugriffe mit:

Feld Beschreibung
Benutzer User-ID, E-Mail, Rolle
Aktion CREATE, READ, UPDATE, DELETE, EXPORT, ANONYMIZE, LOGIN, LOGOUT
Ressource Tabelle + ID + lesbare Bezeichnung
Kontext Endpoint, HTTP-Methode, IP-Adresse, User-Agent
Änderungen Vorher/Nachher-Werte (bei Updates)
Sensitivität LOW, MEDIUM, HIGH, CRITICAL
Integrität SHA-256 Hash-Kette für Manipulationsschutz

Sensitivitätsstufen

Stufe Ressourcen
LOW Einstellungen, Plattformen, Tarife
MEDIUM Verträge, Provider
HIGH Kundendaten, Benutzerdaten
CRITICAL Authentifizierung, Bankdaten, Ausweisdokumente

Zugriff

  • EinstellungenAudit-Protokoll
  • Filter nach: Datum, Benutzer, Aktion, Ressource, Sensitivität
  • Detail-Ansicht mit Vorher/Nachher-Diff
  • Export als JSON
  • Integritätsprüfung (Hash-Kette verifizieren)

DSGVO-Dashboard

Zentrale Verwaltung für DSGVO-Anfragen unter EinstellungenDSGVO-Dashboard.

Dashboard-Statistiken

  • Offene Löschanfragen
  • Abgeschlossene Löschungen (letzte 30 Tage)
  • Datenexporte (letzte 30 Tage)
  • Aktive Einwilligungen

Einwilligungsverwaltung (Consents)

Consent-Typ Beschreibung
DATA_PROCESSING Grundlegende Datenverarbeitung
MARKETING_EMAIL E-Mail-Marketing
MARKETING_PHONE Telefonmarketing
DATA_SHARING_PARTNER Datenweitergabe an Partner

Einwilligungen können pro Kunde im Tab "Einwilligungen" verwaltet werden.

Löschanfragen (Art. 17)

Workflow für DSGVO-Löschanfragen:

Status Beschreibung
PENDING Anfrage eingegangen
IN_PROGRESS Wird bearbeitet
COMPLETED Vollständig gelöscht/anonymisiert
PARTIALLY_COMPLETED Teildaten behalten (z.B. aktive Verträge)
REJECTED Abgelehnt mit Begründung

Anonymisierung statt Löschung:

  • Kundendaten werden anonymisiert (nicht gelöscht)
  • Aktive Verträge werden beibehalten
  • PDF-Löschnachweis wird generiert

Datenexport (Art. 15)

Kunden können alle gespeicherten Daten als JSON exportieren:

  • Stammdaten
  • Adressen, Bankdaten, Ausweise
  • Verträge mit Details
  • Zähler und Ablesungen
  • Einwilligungen
  • Zugriffsprotokolle

API-Endpunkte

# Audit-Logs
GET    /api/audit-logs                    # Logs mit Filtern
GET    /api/audit-logs/:id                # Einzelnes Log
GET    /api/audit-logs/customer/:id       # Logs für Kunde
GET    /api/audit-logs/export             # Export (JSON/CSV)
POST   /api/audit-logs/verify             # Hash-Kette prüfen
GET    /api/audit-logs/retention-policies # Aufbewahrungsfristen
PUT    /api/audit-logs/retention-policies/:id
POST   /api/audit-logs/cleanup            # Manuelle Bereinigung

# DSGVO
GET    /api/gdpr/dashboard                # Dashboard-Statistiken
GET    /api/gdpr/customer/:id/export      # Kundendaten-Export
GET    /api/gdpr/deletions                # Löschanfragen
POST   /api/gdpr/deletions                # Löschanfrage erstellen
PUT    /api/gdpr/deletions/:id/process    # Löschanfrage bearbeiten
GET    /api/gdpr/customer/:id/consents    # Einwilligungen abrufen
PUT    /api/gdpr/customer/:id/consents/:type  # Einwilligung ändern
GET    /api/gdpr/consents/overview        # Consent-Übersicht

Aufbewahrungsfristen

Ressource Frist Rechtsgrundlage
Standard 10 Jahre AO §147, HGB §257
Authentifizierung 2 Jahre Sicherheit
Kundendaten (HIGH) 10 Jahre Steuerrecht
Verträge 10 Jahre Steuerrecht
Allgemein (LOW) 3 Jahre Verjährung

Berechtigungen

Aktion Berechtigung
Audit-Logs lesen audit:read
Audit-Logs exportieren audit:export
Audit-Administration audit:admin
DSGVO-Export gdpr:export
Löschanfrage erstellen gdpr:delete
DSGVO-Administration gdpr:admin

Technische Details

Hash-Kette

Jeder Audit-Log-Eintrag enthält einen SHA-256-Hash über:

  • Alle Felder des Eintrags
  • Hash des vorherigen Eintrags

Dies ermöglicht die Erkennung von Manipulationen.

Sensitive Daten

Folgende Felder werden in Audit-Logs gefiltert:

  • password, passwordHash
  • portalPasswordHash, portalPasswordEncrypted
  • emailPasswordEncrypted, internetPasswordEncrypted
  • sipPasswordEncrypted, pin, puk, apiKey

Performance

  • Logging erfolgt asynchron (setImmediate)
  • API-Response wird nicht blockiert
  • Before/After-Werte über Prisma Middleware

Lizenz

MIT