714 lines
24 KiB
Markdown
714 lines
24 KiB
Markdown
# 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
|