Der "Stressfrei wechseln Adressen"-Link (sowie "Postfach öffnen")
war nur im Normal-Zweig sichtbar, nicht aber wenn der Kunde noch
gar kein Mailbox-Konto hat. cardTitle in einer gemeinsamen Variable
extrahiert und in beiden Branches verwendet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ContractEmailsSection (Vertragsansicht): Zusätzlich zu "Postfach
öffnen" gibt es jetzt "Stressfrei wechseln Adressen" → Tab in der
Kundenakte.
ContractForm (Bearbeiten): Kleine ExternalLink-Icons neben den
Select-Labels:
- Lieferadresse + Rechnungsadresse → Kundenakte/Adressen
- Bankkarte → Kundenakte/Bankkarten
- Ausweis → Kundenakte/Ausweise
- Anbieter + Tarif → Settings/Anbieter & Tarife
- Vertriebsplattform → Settings/Vertriebsplattformen
Select-Komponente nimmt jetzt ReactNode als label (statt nur string),
um JSX-Labels mit eingebettetem Link zu erlauben. Rückwärts-
kompatibel zu allen bestehenden String-Aufrufen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neben dem "E-Mails"-Titel der Card im Vertragsdetail jetzt ein
kleiner Link mit ExternalLink-Icon, der den Tab "E-Mail-Postfach"
in der Kundenakte in einem neuen Tab öffnet (target="_blank",
rel="noopener noreferrer"). Greift auf das bereits unterstützte
?tab=emails-Deep-Link-Pattern in CustomerDetail zurück.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Zwei Aktionen, die der existierende Reply-Pfad bisher nicht abdeckte:
1. Weiterleiten (Compose-Modal-Forward-Modus):
- Neuer Button im EmailDetail, neben "Antworten"
- ComposeEmailModal akzeptiert jetzt einen `forwardOf` prop und
füllt das Formular im Forward-Stil vor:
* To leer (User trägt selbst ein)
* Subject mit "Fwd:"-Prefix
* Body mit zitierten Headern (Von, An, Datum, Betreff) +
Original-Text
- Titel des Modals reagiert ("Antworten" / "Weiterleiten" /
"Neue E-Mail")
2. Erneut senden (One-Click-Resend):
- Neuer Button im EmailDetail; schickt die Mail nochmal an die
ursprüngliche toAddresses (= die Stressfrei-Adresse selbst).
Plesk routet dann gemäß der HEUTE hinterlegten Forwards –
Use-Case: die Stressfrei-Forward-Adresse wurde nach Empfang
umgestellt, der Empfang soll beim neuen Forward-Empfänger
landen.
- Confirm-Dialog erklärt den Vorgang und warnt explizit, dass
Anhänge nicht erneut mit gesendet werden (Anhänge wären
IMAP-Refetch, dafür "Weiterleiten" nutzen).
- Toast-Feedback für Erfolg/Fehler.
- Im TRASH-Folder wird der Resend-Button bewusst nicht
eingeblendet (kein sinnvoller Use-Case dort).
Backend braucht keine neuen Endpoints – beide Aktionen nutzen die
bestehenden `stressfreiEmailApi.sendEmail` + `cachedEmailApi.getById`
(letztere für den Body, der ohnehin schon im Detail-View geladen ist).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Variante B aus der Trade-off-Diskussion: Suchleiste über der Email-Liste
plus eine ausklappbare Box mit Detail-Filtern, alle AND-verknüpft.
Backend:
- EmailListOptions um search + 9 Detail-Filter erweitert (fromFilter,
toFilter, subjectFilter, bodyFilter, attachmentNameFilter,
hasAttachments, isRead, isStarred, receivedFrom, receivedTo)
- getCachedEmails baut die where-Klausel:
* `search` → OR über Subject/From-Address/From-Name/Body (Volltext-
Quicksearch)
* Feldspezifische Filter werden AND-verknüpft an die where gehängt;
From-/Body-Filter intern als kleine OR-Subqueries (Match in
Adresse ODER Name; Match in textBody ODER htmlBody)
- Controller-Parser akzeptiert die Filter als Query-Parameter
(parseBoolParam/parseDateParam tolerieren leere/invalide Werte)
Frontend:
- Suchleiste mit X-Button zum Leeren + Filter-Toggle mit Badge (zeigt
Anzahl aktiver Filter)
- Ausklappbare Filter-Box: Von, An, Betreff, Inhalt, Datum von/bis,
Anhang-Dateiname, Mit/Ohne Anhang, Gelesen-Status, Markiert-Status
- Filter-State fließt via useMemo + queryKey in den useQuery → React
Query macht automatisch ein Re-Fetch bei jeder Änderung
- "Alle zurücksetzen"-Button räumt komplett auf
- Nicht für TRASH-Folder eingeblendet (eigener Pfad ohne Filter-API)
Bewusst nicht gebaut: voller AND/OR-Builder mit Plus-Button und
Bool-Verschachtelung. Reale Such-Use-Cases im Email-Kontext sind
quasi immer AND-verknüpft; Bool-Builder bringt mehr Bedienprobleme
als Mehrwert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Beim automatischen Status-Wechsel wird jetzt auch das passende Datum gesetzt,
damit Status und Datumsfeld konsistent sind (Cockpit-Warnung "Datum fehlt"
verschwindet sofort nach Upload).
Backend:
- Upload-Handler für Kündigungsbestätigung(s-Optionen) nimmt optional
`confirmationDate` aus multipart an, speichert als
cancellationConfirmationDate / cancellationConfirmationOptionsDate.
Fallback: heute (nur falls Feld noch leer war).
- maybeActivateOnDeliveryConfirmation nimmt optional deliveryDate, setzt
Contract.startDate falls leer. Fallback: heute.
Frontend:
- ContractDetail: neues kleines Modal beim Kündigungsbestätigungs-Upload
fragt das Bestätigungs-Datum ab (Default: heute oder bereits gesetzter
Wert). Der bestehende inline-Datums-Editor bleibt für spätere Korrekturen.
- ContractDocumentsSection: Datums-Input erscheint conditional im
Upload-Bereich, sobald Typ "Lieferbestätigung" gewählt ist.
- SaveAttachmentModal (E-Mail-Anhang → Vertragsdokument): gleicher
Datums-Input conditional für "Lieferbestätigung".
- API-Methoden uploadCancellationConfirmation / uploadDocument /
saveAttachmentAsContractDocument nehmen optional Datum entgegen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Alle hardcoded Referenzen auf 'stressfrei-wechseln.de' und 'Stressfrei-Wechseln'
durch dynamische Werte aus der EmailProviderConfig ersetzt. Notwendig für
Multi-Mandanten-Betrieb, wenn das CRM an Dritte vermietet wird.
Schema:
- Neues Feld EmailProviderConfig.customerEmailLabel (String?)
- Wenn leer, wird Label aus Domain abgeleitet ('stressfrei-wechseln.de' → 'Stressfrei-Wechseln')
Backend:
- Neuer Endpoint GET /api/email-providers/public-settings liefert { domain, customerEmailLabel }
- Neue Service-Funktionen: getProviderPublicSettings(), deriveLabelFromDomain()
- create/updateProviderConfig erweitert um customerEmailLabel
Frontend:
- Neuer Hook useProviderSettings() mit Auto-Caching
- Neues Eingabefeld 'Bezeichnung für Kunden-E-Mails' im Provider-Modal
- Dynamische Domain-Suffix im Adress-Hinzufügen-Dialog (@<domain>)
- Tab-Label 'Stressfrei-Wechseln' im Kunden-Detail → dynamisch
- 'Stressfrei-Wechseln Adresse' in ContractForm → dynamisch
- '(Stressfrei-Wechseln)' Badge in ContractDetail → dynamisch
- 'Stressfrei-Wechseln E-Mail' im Generate-Modal → dynamisch
- Leere-Zustand-Meldungen in Tab und E-Mail-Client → dynamisch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bisher blieb ein fehlgeschlagener IMAP-Sync oder E-Mail-Versand still – der User
sah nur im Browser-Devtools, dass etwas schief lief. Jetzt erscheint eine rote
Toast-Benachrichtigung (8 Sekunden) mit der konkreten Fehlermeldung des Servers,
z.B. 'Sync fehlgeschlagen: IMAP-Authentifizierung fehlgeschlagen: NO [AUTHENTICATIONFAILED]'.
EmailClientTab (Synchronisieren-Button):
- toast.success bei erfolgreichem Sync
- toast.error bei Fehler + bei Backend-Response mit success=false
ComposeEmailModal (Senden):
- toast.success bei erfolgreichem Versand
- toast.error bei SMTP-Fehler mit Server-Response (zusätzlich zum Inline-Fehler)
Außerdem im imapService.testImapConnection:
- Roh-Error wird jetzt geloggt (code, response, responseStatus, authenticationFailed)
- ImapFlow-spezifische Felder werden in die Fehlermeldung übernommen, sodass
z.B. '2 NO [AUTHENTICATIONFAILED] Authentication failed.' direkt sichtbar wird
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Der SaveAttachmentModal hat jetzt drei Modi (wenn E-Mail einem Vertrag zugeordnet ist):
1. Als Dokument – in feste Slots (Kündigungsschreiben etc.), unverändert
2. Als Vertragsdokument – NEU: flexible ContractDocument-Tabelle mit Typ-Dropdown
(Auftragsformular, Lieferbestätigung, Vertragsunterlagen, Vollmacht,
Widerrufsbelehrung, Preisblatt, Sonstiges) + optionalen Notizen
3. Als Rechnung – jetzt für ALLE Vertragstypen (vorher nur Strom/Gas)
Backend:
- Neuer Endpoint POST /api/emails/:id/attachments/:filename/save-as-contract-document
- saveAttachmentAsInvoice + saveEmailAsInvoice: ELECTRICITY/GAS-Einschränkung entfernt,
nutzt jetzt addInvoiceByContract als Fallback für Nicht-Energie-Verträge
Frontend:
- cachedEmailApi.saveAttachmentAsContractDocument hinzugefügt
- SaveAttachmentModal: neuer Mode 'contractDocument' mit Typ+Notizen
- Mode-Toggle zeigt jetzt alle drei Optionen wenn Vertrag zugeordnet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>