opencrm/README.md

714 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
- **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
```bash
git clone <repository-url>
cd opencrm
```
### 2. MariaDB-Datenbank starten
```bash
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
```bash
cd backend
# Dependencies installieren
npm install
# .env-Datei erstellen (falls noch nicht vorhanden)
cp .env.example .env
```
Die `.env`-Datei sollte folgende Werte enthalten:
```env
# 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
```bash
# 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
```bash
cd ../frontend
# Dependencies installieren
npm install
```
## Anwendung starten
### Backend starten (Terminal 1)
```bash
cd backend
npm run dev
```
Das Backend läuft auf `http://localhost:3001`
### Frontend starten (Terminal 2)
```bash
cd frontend
npm run dev
```
Das Frontend läuft auf `http://localhost:5173`
## Erster Login
Nach dem Seed sind folgende Zugangsdaten verfügbar:
- **E-Mail:** admin@admin.com
- **Passwort:** admin
## 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:
```javascript
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. **Einstellungen****Email-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
```bash
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
```bash
npm run dev # Entwicklungsserver starten
npm run build # Produktions-Build erstellen
npm run preview # Build-Vorschau
```
### Docker
```bash
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
```
## Projektstruktur
```
opencrm/
├── backend/
│ ├── src/
│ │ ├── controllers/ # Request-Handler
│ │ ├── middleware/ # Auth, Validation
│ │ ├── routes/ # API-Endpunkte
│ │ ├── services/ # Business-Logik
│ │ ├── 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)
│ │ ├── 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
│ │ ├── hooks/ # Custom Hooks
│ │ ├── services/ # API-Client
│ │ ├── types/ # TypeScript-Typen
│ │ └── App.tsx # Haupt-Komponente
│ └── package.json
├── docker-compose.yml # MariaDB-Container
└── README.md
```
## Berechtigungen
| Rolle | Kunden | Verträge | Benutzer | Plattformen | Developer |
|-------|--------|----------|----------|-------------|-----------|
| Admin | CRUD | CRUD | CRUD | CRUD | Optional |
| Mitarbeiter | CRUD | CRUD | - | 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
```bash
# 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
```bash
# 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
```prisma
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.
```typescript
// 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.
## Lizenz
MIT