docs: update INSIGHT-CRM.md with architect requirements from Konzept v1.0

Extract and categorize new requirements from updated CLAUDE_BRIEFING.docx
and INSIGHT_Konzept_v1.0.docx. Add comprehensive CRM task breakdown
(Kap 22: full CRM spec, Kap 24: Office 365 integration) with prioritized
action items for the CRM backend developer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas Reitz 2026-03-12 14:39:18 +01:00
parent a85634a906
commit 69f032a3d8
3 changed files with 467 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View file

@ -1052,4 +1052,471 @@ Wenn ein User mit Rolle `PLATFORM_ADMIN` keiner Tenant-Membership zugeordnet war
---
## 2026-03-12 | Architekt: Neue Anforderungen aus Konzeptdokument v1.0 + Briefing
Der Architekt hat das Konzeptdokument (INSIGHT_Konzept_v1.0.docx) und das Claude Briefing (CLAUDE_BRIEFING.docx) aktualisiert. Folgende Kapitel sind neu oder erweitert und betreffen den CRM-Service direkt:
- **Kapitel 22** — CRM-Modul (vorher nur Platzhalter, jetzt vollstaendig spezifiziert)
- **Kapitel 24** — Office 365 Integration (neu, CRM-relevante Teile)
- **Kapitel 14 im Briefing** — Office 365 Kurzreferenz (neu)
### Hinweis: CORE vs CRM
Folgende Teile sind **CORE-Aufgaben** (NICHT fuer den CRM-Entwickler):
- Kap 24.1: OAuth-Flow + `user_integrations` Tabelle in `platform_core`
- Kap 24.8: Azure App-Registrierung im Azure Portal
- `.env`-Variablen: `MS_CLIENT_ID`, `MS_CLIENT_SECRET`, `MS_REDIRECT_URI`, `MS_INTEGRATION_ENCRYPTION_KEY`
Alles Folgende ist **CRM-Arbeit**.
---
### A) CRM-Modul Spezifikation (Kap 22) — Neue/Erweiterte Anforderungen
#### A.1 Kontakttypen & Felder (Kap 22.1)
Die vollstaendige Felddefinition fuer Person und Unternehmen liegt jetzt vor:
**Kontakttyp: Person**
| Feld | Typ | Pflicht | Bemerkung |
|------|-----|---------|-----------|
| Vorname | String | Ja | |
| Nachname | String | Ja | |
| Jobtitel | String | Nein | |
| Unternehmen | Relation -> Unternehmen | Nein | |
| Abteilung | String | Nein | |
| E-Mail | Array (String) | Nein | Mehrere, Typ: Arbeit / Privat / Sonstige |
| Telefon | Array (String) | Nein | Mehrere, Typ: Buero / Mobil / Fax |
| Adresse | Objekt | Nein | Strasse, PLZ, Stadt, Land |
| LinkedIn-URL | String (URL) | Nein | |
| Geburtsdatum | Date | Nein | Optional, kann ausgeblendet werden |
| Quelle | Enum | Nein | Messe, Empfehlung, Website, Kaltakquise, Import, Visitenkarte, Sonstige |
| Tags | Array (String) | Nein | Frei vergebbar, tenant-weit geteilt |
| Status | Enum | Ja | Aktiv / Inaktiv / Gesperrt (Default: Aktiv) |
| Notizen | Text (Markdown) | Nein | |
| Benutzerdefinierte Felder | Dynamisch | Nein | Siehe A.6 |
**Kontakttyp: Unternehmen**
| Feld | Typ | Pflicht | Bemerkung |
|------|-----|---------|-----------|
| Firmenname | String | Ja | |
| Branche | String | Nein | Freitext oder vordefinierte Kategorien |
| Website | String (URL) | Nein | |
| Telefon | Array (String) | Nein | Mehrere Nummern |
| Adresse Hauptsitz | Objekt | Nein | Strasse, PLZ, Stadt, Land |
| Adresse Lieferung | Objekt | Nein | Optional abweichende Lieferadresse |
| USt-IdNr. | String | Nein | |
| Steuernummer | String | Nein | |
| Handelsregisternummer | String | Nein | z.B. HRB 12345 — befuellbar via Datenanreicherung |
| Registergericht | String | Nein | z.B. Amtsgericht Muenchen — befuellbar via Datenanreicherung |
| Unternehmensgroesse | Enum | Nein | 1-10, 11-50, 51-200, 201-500, 500+ |
| Ansprechpartner | Relation -> Personen | Nein | Verknuepfte Personen |
| Tags | Array (String) | Nein | |
| Status | Enum | Ja | Aktiv / Inaktiv / Gesperrt |
| Notizen | Text (Markdown) | Nein | |
| Datenanreicherung | Automatisch | Nein | data_enriched_at + data_enriched_source |
| Benutzerdefinierte Felder | Dynamisch | Nein | Siehe A.6 |
**Backend-Aufgabe**: Abgleich mit bestehenden Prisma-Modellen. Fehlende Felder (LinkedIn, Geburtsdatum, Quelle, Unternehmensgroesse, USt-IdNr, Steuernummer, Handelsregisternummer, Registergericht, Adresse Lieferung, data_enriched_at/source) muessen ergaenzt werden.
#### A.2 Firmendaten-Anreicherung / Data Enrichment (Kap 22.2) — NEU
"Firmendaten laden"-Button im Unternehmenformular. Stammdaten aus externen Registern abrufen und als Vorschlag in einem Modal anzeigen.
**Quellen:**
1. **Unternehmensregister.de** (kostenlos, oeffentlich) — HR-Nummer, Registergericht, Rechtsform, Sitz, Eintragsdatum
2. **North Data API** (kommerziell, API-Key pro Tenant) — Adresse, Branche, Umsatz, Mitarbeiterzahl, Gesellschafter, Verflechtungen
**Backend-Aufgaben:**
- [ ] `POST /crm/companies/:id/enrich` oder `POST /crm/data-enrichment/company` Endpoint
- [ ] Paralleler Abruf: Unternehmensregister.de + North Data API (Timeout je 10 Sek.)
- [ ] Ergebnisse normalisieren und zusammenfuehren
- [ ] `data_enriched_at` + `data_enriched_source` in Company speichern
- [ ] Admin-Einstellung: North Data API-Key pro Tenant (Admin > CRM > Integrationen)
**Frontend-Aufgaben:**
- [ ] "Firmendaten laden" Button im Unternehmenformular
- [ ] Anreicherungs-Modal: Linke Spalte = aktueller Wert, Rechte Spalte = Vorschlag (Quelle), Checkbox pro Feld
- [ ] "Auswahl uebernehmen" -> Felder im Formular setzen (Speichern erst bei explizitem Speichern)
- [ ] CRM-Settings-Seite: North Data API-Key Konfiguration
#### A.3 Zustaendigkeit / Account Owner (Kap 22.3) — NEU
Jeder Kontakt/Unternehmen kann mit mehreren internen Mitarbeitern verknuepft werden (m:n).
| Aspekt | Entscheidung |
|--------|-------------|
| Modell | m:n — ein Kontakt hat mehrere Owner, ein Mitarbeiter hat mehrere Kontakte |
| Rollen pro Zuweisung | `OWNER`, `MEMBER`, `WATCHER` (unterschiedliche Bearbeitungsrechte) |
| Mitarbeiter-Referenz | `user_id` aus `platform_core` (kein Kopieren von User-Daten) |
| Anzeige | Avatare der zugewiesenen Mitarbeiter in der Kontaktkarte |
| Pflicht-Owner | Mindestens 1 Owner pro Kontakt bei Erstellung (Default: erstellender User) |
**DB-Tabelle:** `crm_contact_owners (contact_id, user_id, role: OWNER|MEMBER|WATCHER)`
**Backend-Aufgaben:**
- [ ] Contact-Owner CRUD: `POST/DELETE /crm/contacts/:id/owners`
- [ ] Bei Kontakt-Erstellung automatisch erstellenden User als OWNER setzen
- [ ] Owner-Info in Contact-Detail-Response mitliefern
**Frontend-Aufgaben:**
- [ ] Avatare der Owner in der Kontaktkarte anzeigen
- [ ] Owner-Zuweisung UI (User suchen + Rolle waehlen)
#### A.4 Pipeline & Deal-Management — Erweiterte Spec (Kap 22.4)
Ergaenzungen zur bestehenden Implementierung:
- **Forecast-Ansicht**: Aggregierter Dealwert pro Stage gewichtet mit Wahrscheinlichkeit
- **Lost-Grund**: Enum + Freitext bei Status Lost: Preis, Timing, Wettbewerber, Kein Bedarf, Sonstige
- **Pipeline-Sichtbarkeit**: Enum — Alle Tenant-User / Nur zugewiesene Teams
- **Deal-Owner**: m:n analog zu Kontakt-Owner (crm_deal_owners)
**Backend-Aufgaben:**
- [ ] `lost_reason` Enum + `lost_reason_text` Freitext in Deals
- [ ] Deal-Owner CRUD (analog Contact-Owner)
- [ ] Forecast-Endpoint: `GET /crm/deals/forecast` (Wert x Wahrscheinlichkeit pro Stage)
**Frontend-Aufgaben:**
- [ ] Lost-Grund Modal bei Stage-Wechsel zu "Lost"
- [ ] Kanban-Board (Drag & Drop)
- [ ] Forecast-Ansicht
#### A.5 Aktivitaeten & Aufgaben (Kap 22.5) — Erweiterte Spec
6 Aktivitaetstypen sind definiert:
| Typ | Icon | Bemerkung |
|-----|------|-----------|
| Anruf (Call) | Telefon | Kann Gespraechsnotizen enthalten |
| Meeting | Kalender | Datum, Uhrzeit, Ort / Videolink |
| E-Mail | Brief | Freitext-Notiz, KEINE echte E-Mail-Integration in MVP |
| Aufgabe (Task) | Checkbox | Faelligkeitsdatum, Zuweisung an Mitarbeiter |
| Notiz | Stift | Freitext ohne Faelligkeitsdatum |
| Follow-Up | Pfeil | Erinnerung zu einem definierten Zeitpunkt |
**Hinweis**: E-Mail-Integration (Outlook) kommt erst mit Office 365 (Kap 24).
#### A.6 Benutzerdefinierte Felder / Custom Fields (Kap 22.6) — NEU
Pro Kontakttyp (Person, Unternehmen) und pro Deal koennen eigene Felder definiert werden.
**Unterstuetzte Feldtypen:**
| Typ | Beschreibung | Beispiel |
|-----|-------------|---------|
| Text | Einzeiliger Freitext | Kundennummer |
| Textarea | Mehrzeiliger Freitext | Besondere Hinweise |
| Zahl | Integer oder Decimal | Umsatz, Vertragslaufzeit |
| Datum | Datumspicker | Vertragsbeginn |
| Auswahl (Dropdown) | Vordefinierte Werte | Kundensegment: A / B / C |
| Mehrfachauswahl | Mehrere Werte waehlbar | Interessensgebiete |
| Checkbox | Boolean Ja/Nein | DSGVO-Einwilligung |
| URL | Validierter Link | Portal-Link |
**DB-Tabellen:**
```sql
crm_custom_field_defs (id, entity_type: PERSON|COMPANY|DEAL, name, label, field_type,
options jsonb, is_required, position)
crm_custom_field_values (id, field_def_id, entity_id, value_text, value_number,
value_date, value_boolean, value_json)
```
**Backend-Aufgaben:**
- [ ] CRUD fuer Field-Definitions: `GET/POST/PATCH/DELETE /crm/custom-fields`
- [ ] Wert-Speicherung bei Entity-Create/Update
- [ ] Custom Fields in Entity-Detail-Response mitliefern
**Frontend-Aufgaben:**
- [ ] Admin-Bereich: Custom Fields Verwaltung (Drag & Drop Reihenfolge, Pflichtfeld-Flag)
- [ ] Dynamische Formular-Felder in Contact/Deal-Formularen
- [ ] Custom Fields als optionale Spalten in Listen-Ansichten
- [ ] Custom Fields als Filter in der Suche
#### A.7 Kontakt-Import (Kap 22.7) — NEU
**Import via Datei:**
- [ ] CSV-Import mit visuellem Spalten-Mapper
- [ ] Excel-Import (.xlsx)
- [ ] vCard-Import (.vcf, einzeln und ZIP)
- [ ] Vorschau der ersten 10 Datensaetze + Validierungsfehler anzeigen
- [ ] Duplikat-Erkennung via E-Mail: ueberspringen / zusammenfuehren / als Duplikat markieren
**Visitenkarten-Scan (Anthropic Vision API):**
- [ ] "Visitenkarte scannen" — Kamera-/Datei-Dialog
- [ ] Bild base64-kodiert an CRM-Backend senden
- [ ] Backend ruft Anthropic Vision API auf (strukturierter Prompt)
- [ ] Vorausgefuelltes Kontaktformular zur Bestaetigung
- [ ] Rate Limit: max. 50 Scans pro Tenant pro Tag (konfigurierbar)
- [ ] Bild wird NICHT dauerhaft gespeichert
#### A.8 Berechtigungsmodell (Kap 22.8) — NEU
Ownership-basiertes Sichtbarkeitsmodell:
| Stufe | Beschreibung | Sieht was? |
|-------|-------------|-----------|
| Eigene | User sieht nur eigene Datensaetze (Owner) | Eigene Kontakte, Deals, Aktivitaeten |
| Team | User sieht alle Datensaetze der eigenen Abteilung | Kontakte aller Kollegen |
| Alle | User sieht alle Datensaetze des Tenants | Vollzugriff (lesend) |
**Berechtigungen nach Rolle:**
| Rolle | Sichtbarkeit | Erstellen | Bearbeiten | Loeschen |
|-------|-------------|-----------|------------|----------|
| tenant_admin | Alle | Ja | Alle | Alle |
| team_lead | Team | Ja | Team + Eigene | Eigene |
| tenant_member | Konfigurierbar | Ja | Eigene + zugewiesene | Eigene |
| tenant_readonly | Konfigurierbar | Nein | Nein | Nein |
**Backend-Aufgaben:**
- [ ] Sichtbarkeitsfilter in allen List-Queries (Contacts, Deals, Activities)
- [ ] Tenant-Admin Einstellung: Default-Sichtbarkeit pro Rolle
- [ ] Per-User Override moeglich
**Frontend-Aufgaben:**
- [ ] Admin > CRM-Einstellungen > Berechtigungen: Sichtbarkeitsstufe konfigurieren
#### A.9 Reporting & Dashboards (Kap 22.9) — NEU
5 Reports/Dashboards sind definiert:
| Dashboard | Inhalt | Aktualisierung |
|-----------|--------|---------------|
| Pipeline-Uebersicht | Deals pro Stage, Gesamtvolumen, gewichteter Forecast | Echtzeit |
| Aktivitaeten-Uebersicht | Offene Aufgaben, ueberfaellige Aktivitaeten, Volumen/Woche | Echtzeit |
| Kontaktwachstum | Neue Kontakte/Monat, aufgeschluesselt nach Quelle | Taeglich |
| Win/Loss-Analyse | Won vs Lost Deals, Lost-Gruende als Torte, Durchschnittliche Deal-Dauer | Taeglich |
| Mitarbeiter-Performance | Deals pro Mitarbeiter, Aktivitaeten-Anzahl, Response-Zeit | Taeglich |
- Alle Reports als CSV exportierbar
- Datumsbereiche: letzte 7 / 30 / 90 Tage, benutzerdefiniert
- Mitarbeiter-Performance nur fuer tenant_admin und team_lead sichtbar
**Backend-Aufgaben:**
- [ ] Reporting-Endpoints: `GET /crm/reports/pipeline`, `/reports/activities`, `/reports/contacts-growth`, `/reports/win-loss`, `/reports/performance`
- [ ] CSV-Export fuer alle Reports
**Frontend-Aufgaben:**
- [ ] CRM Dashboard-Seite mit den 5 Report-Widgets
- [ ] Datumbereich-Selektor
- [ ] CSV-Export Buttons
#### A.10 CRM Datenbankschema (Kap 22.10)
Vollstaendiges Schema laut Architekt:
```sql
-- Kernentitaeten
crm_contacts (id, type: PERSON|COMPANY, status, source, created_by, created_at, updated_at)
crm_persons (id, contact_id, first_name, last_name, job_title, department, birthday, notes)
crm_companies (id, contact_id, name, industry, website, vat_id, tax_id, size_class, notes)
crm_contact_emails (id, contact_id, email, type: WORK|PERSONAL|OTHER, is_primary)
crm_contact_phones (id, contact_id, phone, type: OFFICE|MOBILE|FAX, is_primary)
crm_contact_addresses (id, contact_id, type: MAIN|DELIVERY, street, zip, city, country)
-- Beziehungen
crm_person_company (person_contact_id, company_contact_id)
crm_contact_owners (contact_id, user_id, role: OWNER|MEMBER|WATCHER)
crm_contact_tags (contact_id, tag)
-- Pipeline & Deals
crm_pipelines (id, name, is_default, visibility)
crm_pipeline_stages (id, pipeline_id, name, color, position, probability, is_won_stage, is_lost_stage)
crm_deals (id, contact_id, pipeline_id, stage_id, title, value, currency,
probability_override, expected_close_date, status: OPEN|WON|LOST,
lost_reason, lost_reason_text, notes, created_by)
crm_deal_owners (deal_id, user_id, role: OWNER|MEMBER|WATCHER)
-- Aktivitaeten
crm_activities (id, type: CALL|MEETING|EMAIL|TASK|NOTE|FOLLOWUP,
contact_id nullable, deal_id nullable,
title, body, due_date, completed_at, assigned_to_user_id, created_by)
-- Custom Fields
crm_custom_field_defs (id, entity_type: PERSON|COMPANY|DEAL, name, label, field_type,
options jsonb, is_required, position)
crm_custom_field_values (id, field_def_id, entity_id, value_text, value_number,
value_date, value_boolean, value_json)
```
**Hinweis**: Das aktuelle Prisma-Schema im CRM-Service weicht teilweise ab (z.B. `app_crm` Schema-Prefix statt `crm_` Tabellen-Prefix, flaches Company/Contact-Modell statt Contact+Person+Company Split). Der Architekt hat das Ziel-Schema definiert — Abgleich und Migration sind Backend-Aufgaben.
#### A.11 CRM Events (Kap 22.11)
| Event | Ausgeloest von | Empfaenger/Zweck |
|-------|---------------|-----------------|
| `crm.contact.created` | CRM-Service | Zukuenftige Module (Marketing etc.) |
| `crm.contact.updated` | CRM-Service | Zukuenftige Module |
| `crm.deal.stage_changed` | CRM-Service | Reporting, Automatisierungen |
| `crm.deal.won` | CRM-Service | Reporting, Modul-Integrationen |
| `crm.deal.lost` | CRM-Service | Reporting |
| `crm.activity.due_soon` | CRM-Service (Scheduler) | Benachrichtigungs-Service |
| `core.user.deactivated` | Core-Service | CRM prueft Owner-Reassignment |
**Backend-Aufgabe:**
- [ ] Redis Pub/Sub Events bei Kontakt/Deal/Activity-Aenderungen publishen
---
### B) Office 365 Integration — CRM-relevante Teile (Kap 24)
Die OAuth-Verbindung (Kap 24.1) und Azure App-Registrierung (Kap 24.8) sind **CORE-Aufgaben**. Der CRM-Service nutzt die bestehende MS-Verbindung des Users fuer folgende Features:
#### B.1 E-Mail Tab im CRM-Kontakt (Kap 24.2) — Read-only
Pro CRM-Kontakt wird ein "E-Mails"-Tab angezeigt mit allen Outlook-Mails von/an die Kontakt-E-Mail-Adresse.
**Graph API Abfrage:**
```
GET /me/messages
?$filter=from/emailAddress/address eq '{kontakt_email}'
or toRecipients/any(...)
&$select=id,subject,from,toRecipients,receivedDateTime,bodyPreview,isRead
&$orderby=receivedDateTime desc
&$top=25
```
| Feature | Detail |
|---------|--------|
| Anzeige | Absender, Betreff, Datum, Vorschautext (max. 255 Zeichen) |
| Sortierung | Neueste zuerst, 25 pro Seite |
| Caching | Redis 5 Min (Key: `user:{id}:mails:contact:{id}`) |
| Kein Volltext | Nur bodyPreview, kein vollstaendiger E-Mail-Body |
| Kein Senden | Read-only |
**Backend-Aufgaben:**
- [ ] `GET /crm/contacts/:id/emails` Endpoint (Proxy zu Graph API)
- [ ] MS Access Token aus Redis / Refresh via Core
- [ ] Redis-Caching (5 Min TTL)
**Frontend-Aufgaben:**
- [ ] "E-Mails" Tab in ContactDetailPage (nur wenn MS-Verbindung aktiv)
- [ ] Ausgegraut wenn keine MS-Verbindung, Hinweis "Microsoft 365 verbinden"
#### B.2 Kalender Tab im CRM-Kontakt (Kap 24.3) — Read-only
Outlook-Termine bei denen der CRM-Kontakt als Teilnehmer eingetragen ist.
**Graph API Abfrage:**
```
GET /me/calendarView
?startDateTime={heute}T00:00:00Z
&endDateTime={heute+90Tage}T23:59:59Z
&$filter=attendees/any(a: a/emailAddress/address eq '{kontakt_email}')
&$select=id,subject,start,end,location,attendees,bodyPreview,onlineMeetingUrl
```
| Feature | Detail |
|---------|--------|
| Anzeige | Kommende 90 Tage + vergangene 90 Tage |
| Felder | Titel, Datum/Uhrzeit, Ort, Online-Meeting-Link, Teilnehmer |
| Caching | Redis 5 Min |
| Kein Schreiben | Read-only |
**Backend-Aufgaben:**
- [ ] `GET /crm/contacts/:id/calendar` Endpoint
- [ ] Redis-Caching
**Frontend-Aufgaben:**
- [ ] "Kalender" Tab in ContactDetailPage
#### B.3 Aufgaben Sync — Bidirektional mit Microsoft To Do (Kap 24.4)
CRM-Aufgaben koennen optional nach Microsoft To Do synchronisiert werden.
**Richtung INSIGHT -> To Do:**
- Trigger: Aufgabe erstellt/geaendert im CRM
- Action: `POST /me/todo/lists/{defaultListId}/tasks` (oder PATCH wenn ms_task_id bekannt)
- `ms_task_id` wird in `crm_activities` gespeichert
**Richtung To Do -> INSIGHT:**
- NestJS `@Cron` Polling alle 5 Min fuer User mit aktiver MS-Verbindung
- `GET /me/todo/lists/{listId}/tasks?$filter=lastModifiedDateTime gt {letzter_sync}`
- Status-Aenderungen (erledigt/offen) werden uebernommen
- Redis-Lock pro User verhindert parallele Sync-Jobs
- Nur INSIGHT-erstellte Aufgaben werden synchronisiert (die eine ms_task_id haben)
**DB-Aenderungen an crm_activities:**
```sql
+ ms_task_id VARCHAR(255) -- To Do Aufgaben ID
+ ms_task_list_id VARCHAR(255) -- To Do Listen ID
+ ms_synced_at TIMESTAMPTZ -- Letzter erfolgreicher Sync
```
**Backend-Aufgaben:**
- [ ] ms_task_id, ms_task_list_id, ms_synced_at Felder in Activity-Model
- [ ] Graph API Integration: POST/PATCH Tasks
- [ ] @Cron Scheduler (alle 5 Min) fuer To Do -> INSIGHT Sync
- [ ] Redis-Lock pro User
- [ ] Konfliktbehandlung: INSIGHT gewinnt (Last Write Wins mit Timestamp)
#### B.4 Kontakte Export nach Outlook (Kap 24.5) — Manuell
Button "Nach Outlook exportieren" im CRM-Kontakt (Person).
**Ablauf:**
1. User klickt "Nach Outlook exportieren"
2. Pruefung: MS-Verbindung aktiv? -> Wenn nein: Hinweis
3. Existiert Kontakt in Outlook (ms_contact_id)? -> PATCH (Update) / POST (Neu)
4. ms_contact_id wird in crm_persons gespeichert
**Feldzuordnung CRM -> Outlook:**
| CRM Feld | Outlook Contacts (Graph API) |
|----------|------------------------------|
| Vorname + Nachname | givenName + surname |
| Jobtitel | jobTitle |
| Unternehmen | companyName |
| Abteilung | department |
| E-Mails | emailAddresses[] |
| Telefone | businessPhones[] / mobilePhone |
| Adresse | businessAddress |
| LinkedIn-URL | businessHomePage |
| Notizen | personalNotes |
**DB-Aenderung an crm_persons:**
```sql
+ ms_contact_id VARCHAR(255) -- Outlook Kontakt ID
```
**Backend-Aufgaben:**
- [ ] `POST /crm/contacts/:id/export-to-outlook` Endpoint
- [ ] ms_contact_id Feld in Person-Model
- [ ] Bei 404 (Kontakt in Outlook geloescht): neuen Kontakt erstellen, ms_contact_id aktualisieren
**Frontend-Aufgaben:**
- [ ] "Nach Outlook exportieren" Button in Kontakt-Header (nur fuer Personen)
- [ ] Ausgegraut wenn keine MS-Verbindung
---
### C) Zusammenfassung: Priorisierte Aufgabenliste fuer CRM-Entwickler
**Prio 1 — Kurzfristig (bestehende Features erweitern):**
- [ ] Fehlende Kontakt-/Unternehmens-Felder im Prisma-Schema ergaenzen (LinkedIn, Geburtsdatum, Quelle, USt-IdNr etc.)
- [ ] Lost-Grund (Enum + Freitext) bei Deals
- [ ] Contact/Deal-Owner m:n Modell (crm_contact_owners, crm_deal_owners)
- [ ] Redis Pub/Sub Events bei Entity-Aenderungen
**Prio 2 — Mittelfristig (neue Features):**
- [ ] Custom Fields (Definition + Wert-Speicherung + Admin-UI)
- [ ] Firmendaten-Anreicherung (Unternehmensregister.de + North Data)
- [ ] Kontakt-Import (CSV, Excel, vCard) mit Spalten-Mapper + Duplikat-Erkennung
- [ ] Berechtigungsmodell (Eigene/Team/Alle Sichtbarkeit)
- [ ] Kanban-Board fuer Deals (Drag & Drop)
- [ ] Forecast-Ansicht
**Prio 3 — Spaeter (abhaengig von Core-Vorarbeiten):**
- [ ] Office 365: E-Mail Tab (benoetigt OAuth-Infrastruktur im Core)
- [ ] Office 365: Kalender Tab
- [ ] Office 365: Aufgaben Sync mit Microsoft To Do
- [ ] Office 365: Kontakte Export nach Outlook
- [ ] Visitenkarten-Scan (Anthropic Vision API)
- [ ] CRM Reporting & Dashboards (5 Reports + CSV-Export)
---
*Bitte neue Eintraege unten anfuegen. Format: `## YYYY-MM-DD | Absender: Betreff`*