feat(kontakte): Einverständnis für Mails und Mailingliste

Am Kontakt gibt es unter der E-Mail-Adresse das Kästchen "Einverständnis
für Mails". Ohne Adresse ist es gesperrt. Der Zeitpunkt wird in
`mail_consent_at` mitgeschrieben und im Kontakt angezeigt: bei einer
Beschwerde ist nicht die Frage, ob ein Einverständnis vorliegt, sondern
seit wann. Beim Widerruf wird er geleert; ein erneutes Speichern
verschiebt ihn nicht.

Der Knopf "Mailingliste erstellen" in der Kontaktleiste sammelt alle
Adressen mit Haken, durch Komma getrennt, mit Zähler am Knopf. Rechts im
Feld ein Kopiersymbol (Zwischenablage, mit Fallback für Browser ohne die
Schnittstelle) und ein Mailsymbol.

Zum Mailsymbol zwei Entscheidungen:

- Die Adressen gehen ins BCC, nicht ins An-Feld. Im An-Feld sähe jeder
  Empfänger die vollständige Kundenliste.
- Windows gibt an das Mailprogramm nur rund 2000 Zeichen weiter. Ab 1900
  Zeichen ist das Symbol deshalb gesperrt und der Dialog erklärt es -
  sonst wäre die Empfängerliste unbemerkt abgeschnitten.

Nur für richtige Kontakte: Der Vorbereich "Aus Mails" hat das Kästchen
nicht, und beim Übernehmen wird der Haken nicht mitgesetzt - dass jemand
eine Mail geschrieben hat, ist keine Einwilligung in Werbung. Das Backend
weist ein `mail_consent` für Einträge mit `mail_pool = 1` ab.

Sichtbar ohne Öffnen: grünes Briefsymbol in der Kachel, Häkchen hinter der
Adresse in der Liste.

Geprüft im Browser gegen das Stub-Backend: Haken setzen und widerrufen,
Zähler, Komma-Liste, Zwischenablage, mailto mit BCC, kein Kästchen im
Vorbereich (15 Prüfungen).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sascha Wolf
2026-08-11 14:45:36 +02:00
co-authored by Claude Opus 5
parent 9a4266ae7e
commit 41e9f6898f
14 changed files with 463 additions and 18 deletions
+2
View File
@@ -15,6 +15,8 @@ Quelltext.
| **Delta Query** | Graph-Abfrage, die beim nächsten Aufruf nur noch die Änderungen liefert. Der Fortschritt steckt in einem Verweis (`delta_link`), der in `crm_mail_sync_state` liegt. |
| **Kontakt** / Lead | Person im Netzwerk: Firma, Position, Status, Verbindungen. Tabelle `crm_leads` mit `mail_pool = 0`. Im Code durchgängig `lead`. |
| **Aus Mails** / Vorbereich | Zeilen in `crm_leads` mit `mail_pool = 1`: Personen, die der Postfachabgleich gefunden hat. Eigener Menüpunkt unter *Kontakte*, taucht in keiner Auswahlliste auf. Erst das Übernehmen macht daraus einen Kontakt. |
| **Einverständnis für Mails** | Haken am Kontakt (`crm_leads.mail_consent`, Zeitpunkt in `mail_consent_at`). Nur damit kommt die Adresse in die **Mailingliste**. Im Vorbereich *Aus Mails* gibt es ihn nicht, und beim Übernehmen wird er nicht mitgesetzt. |
| **Mailingliste** | Alle Adressen mit Einverständnis, durch Komma getrennt. Über die Zwischenablage oder als `mailto:` mit den Adressen im BCC. Nichts wird versendet - das CRM hat keinen Postausgang. |
| **Dublette** (Aus Mails) | Ein Fund, zu dem es in den Kontakten schon eine Person gibt - erkannt an der E-Mail-Adresse, sonst am vollen Namen. In der Liste **gold** markiert, abweichende Felder hervorgehoben. |
| **Kontakt-Vorschlag** | Aus einer Mail gelesene Person, die noch kein Kontakt ist. Tabelle `crm_mail_contact_candidates`. Wird übernommen, ergänzt oder verworfen. |
| **Match** / Treffer | Die Bewertung **eines** Projekts für **einen** Agenten: Prozentwert, Pro-Liste, Contra-Liste, Status. Tabelle `matches`. Ein Projekt erzeugt so viele Treffer, wie es aktive Agenten gibt. |