From a55643a0dd9a885c982ed1e54a426fbbe2ab80dd Mon Sep 17 00:00:00 2001 From: Thomas Reitz Date: Thu, 12 Mar 2026 21:09:16 +0100 Subject: [PATCH] docs(crm): Phase 2.2-2.4 Frontend-TODOs abgehakt + Summarize.md aktualisiert Co-Authored-By: Claude Sonnet 4.6 --- Summarize.md | 40 +++++++ docs/INSIGHT-CRM.md | 261 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+) diff --git a/Summarize.md b/Summarize.md index 7463d12..fecdf15 100644 --- a/Summarize.md +++ b/Summarize.md @@ -2,6 +2,46 @@ ## Stand: 2026-03-12 +### Aktueller Sprint: CRM Phase 2 (Feature-Branch: feature/crm-service) + +--- + +### Aenderungen 2026-03-12: CRM Phase 2 — Forecast, Import, Enrichment (Frontend komplett) + +#### Phase 2.3: Forecasting +- `crm/forecast/ForecastPage.tsx` — Prognose-Dashboard unter `/crm/forecast` + - Pipeline-Filter (Dropdown) + Zeitraum-Toggle (Monat/Quartal/Jahr) + - Summary-Cards: Offene Vorgaenge, Gesamtwert, Gewichteter Wert, Zeitraum + - Tabelle: Stage | Wahrscheinlichkeit | Vorgaenge | Gesamtwert | Gewichteter Wert +- `crm/pipelines/PipelinesPage.tsx` — Probability-Feld (0–100%) pro Pipeline-Stage + +#### Phase 2.2: CSV/Excel Import +- `crm/import/ImportPage.tsx` — 3-Schritt-Wizard in CRM-Einstellungen → Tab "Import" + - Schritt 1: Typ-Auswahl (Kontakte/Unternehmen/Vorgaenge) + Datei-Upload (CSV, XLSX, max 10MB) + - Schritt 2: Spalten-Mapping (Auto-Match + manuell), Duplikat-Strategie, Kopfzeilen-Option + - Schritt 3: Ergebnis (created/updated/skipped/errors + Fehlerdetails) +- API-Konvertierungen: `PERSON→contact`, mapping `Record→Array [{sourceColumn,targetField}]` + +#### Phase 2.4: Datenanreicherung +- `crm/companies/CompanyDetailPage.tsx` — "Anreichern"-Button im Header + - POST /companies/:id/enrich → Suggestions-Modal + - Tabelle: Feld | Aktuell | Vorschlag | Quelle + "Uebernehmen"-Button (PATCH) + - suggestions-Konvertierung: Backend-Record → UI-Array +- `crm/settings/CrmSettingsPage.tsx` — North Data API-Key in Tab "Integrationen" + +#### Kontakt-Entity UI/UX Redesign (aus dieser Sprint-Session) +- `components/Drawer.tsx` + `Drawer.module.css` — Wiederverwendbarer Right-Side-Drawer +- `crm/contacts/ContactFormModal.tsx` — Modal → Drawer, Zwei-Tab-Struktur (Allgemein/Details) +- `crm/contacts/ContactDetailPage.tsx`: + - Header: Name (Unternehmen) in Klammern, Aktiv/Inaktiv-Badge (Pill mit farbigem Dot) + - Kontaktdaten-Card: immer alle Allgemein-Felder (leere Felder = "—"), 2 Sub-Spalten + - Lexware-Section entfernt (Kontakte werden nicht separat in Lexware gepflegt) + +#### TypeScript +- `npx tsc --noEmit` in packages/frontend: 0 Fehler (alle Commits) + +--- + ### Aktueller Sprint: Sprint 1 (Alpha) --- diff --git a/docs/INSIGHT-CRM.md b/docs/INSIGHT-CRM.md index bcfbcad..135e13b 100644 --- a/docs/INSIGHT-CRM.md +++ b/docs/INSIGHT-CRM.md @@ -2858,3 +2858,264 @@ Sie werden **NICHT** vom Enrich-Endpoint aktualisiert. Stattdessen setzt das Fro 4. **Tests:** Import-Edge-Cases besonders gruendlich testen (leere Zeilen, Sonderzeichen, fehlende Pflichtfelder, doppelte E-Mails) 5. **DSGVO:** Import-Temp-Dateien MUESSEN nach Verarbeitung geloescht werden 6. **Completion-Report:** Nach jeder Phase einen Eintrag in dieser Datei ergaenzen (wie bei Phase 2.1) + +--- + +## Phase 2.3 Backend — Forecast (DONE) + +**Implementiert am:** 2026-03-12 + +### Schema-Aenderung + +- `PipelineStage.probability` — Decimal(3,2), Default 0, Bereich 0.00–1.00 +- Migration: `prisma/migrations/20260312_phase23_forecast/migration.sql` + +### Neue Endpoints + +| Methode | Pfad | Beschreibung | +|---------|------|-------------| +| GET | /api/v1/crm/deals/forecast?pipelineId=&period= | Umsatz-Forecast (gewichtete Pipeline) | + +### Forecast Response + +```json +{ + "success": true, + "data": { + "period": "quarter", + "periodStart": "2026-01-01T00:00:00.000Z", + "periodEnd": "2026-03-31T23:59:59.999Z", + "currency": "EUR", + "stages": [ + { + "stageId": "uuid", + "stageName": "Qualifiziert", + "stageColor": "#3B82F6", + "probability": 0.25, + "sortOrder": 1, + "pipelineId": "uuid", + "pipelineName": "Sales", + "dealCount": 5, + "totalValue": 50000, + "weightedValue": 12500 + } + ], + "totals": { + "dealCount": 15, + "totalValue": 150000, + "weightedValue": 67500 + } + } +} +``` + +### Query-Parameter + +- `pipelineId` (optional, UUID) — Filter nach Pipeline +- `period` (optional, enum: month|quarter|year, default: quarter) + +### DTO-Updates + +- `CreatePipelineStageDto.probability` — Optional, @IsNumber, @Min(0), @Max(1) +- `UpdateStageDto.probability` — Optional, gleiche Validierung + +### Geaenderte Dateien + +- `prisma/crm.schema.prisma` — probability auf PipelineStage +- `src/pipelines/dto/create-pipeline.dto.ts` — probability-Feld +- `src/pipelines/dto/update-stage.dto.ts` — probability-Feld +- `src/pipelines/pipelines.service.ts` — probability in create/addStage/updateStage +- `src/pipelines/pipelines.controller.ts` — probability durchreichen +- `src/deals/dto/forecast-query.dto.ts` — NEU: ForecastQueryDto + ForecastPeriod Enum +- `src/deals/deals.service.ts` — NEU: forecast() + getPeriodBounds() +- `src/deals/deals.controller.ts` — NEU: GET /deals/forecast (vor :id Route) + +### TODO Frontend + +- [x] Forecast-Seite (`/crm/forecast`) — Pipeline-Filter, Zeitraum-Toggle (Monat/Quartal/Jahr), Tabelle mit gewichteten Werten + Summary-Cards +- [x] probability-Feld in Pipeline-Stage-Editor (0–100% Input in PipelinesPage) + +--- + +## Phase 2.2 Backend — CSV/Excel Import (DONE) + +**Implementiert am:** 2026-03-12 + +### Neue Dependencies + +- `csv-parser: ^3.0.0` — CSV-Parser mit Stream-Support +- `xlsx: ^0.18.5` — Excel-Parser (XLSX/XLS) +- `@types/multer: ^1.4.12` (devDep) + +### Neue Endpoints + +| Methode | Pfad | Beschreibung | +|---------|------|-------------| +| POST | /api/v1/crm/import/preview | Datei-Vorschau (Multipart, CSV/XLSX) | +| POST | /api/v1/crm/import/execute | Import ausfuehren | + +### Preview (Multipart POST) + +- **File-Upload**: `file` Feld, max 10MB, MIME: text/csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet +- **Query-Params**: `entityType` (contact|company), `delimiter` (optional) +- **Max Rows**: 5000 +- **Preview Rows**: Erste 10 + +```json +{ + "success": true, + "data": { + "importId": "uuid", + "format": "csv", + "columns": ["Vorname", "Nachname", "E-Mail", "Telefon"], + "rows": [{"Vorname": "Max", "Nachname": "Muster", ...}], + "totalRows": 250, + "availableTargetFields": ["firstName", "lastName", "email", ...] + } +} +``` + +### Execute (JSON POST) + +```json +{ + "importId": "uuid-from-preview", + "entityType": "contact", + "mapping": [ + {"sourceColumn": "Vorname", "targetField": "firstName"}, + {"sourceColumn": "E-Mail", "targetField": "email"} + ], + "duplicateStrategy": "SKIP" +} +``` + +**Duplikat-Strategien** (E-Mail-Abgleich, case-insensitive): +- `SKIP` — Zeile ueberspringen +- `UPDATE` — Bestehenden Datensatz aktualisieren +- `MARK` — Neuen Datensatz mit Tag "DUPLIKAT" erstellen + +**Response:** +```json +{ + "success": true, + "data": { + "created": 230, + "updated": 0, + "skipped": 15, + "errors": 5, + "totalProcessed": 250, + "errorDetails": [{"row": 42, "field": "", "value": "", "message": "..."}] + } +} +``` + +### Target Fields + +- **Contact**: firstName, lastName, email, phone, mobile, companyName, position, department, website, street, zip, city, state, country, notes, tags, source, linkedinUrl +- **Company**: name, email, phone, website, industry, street, zip, city, state, country, vatId, taxId, tradeRegisterNumber, registerCourt, notes, tags + +### GDPR + +- Temp-Dateien werden unter `/tmp/crm-import-{uuid}{ext}` gespeichert +- Nach Execute werden Temp-Dateien IMMER geloescht (finally-Block) +- Owner wird automatisch auf den importierenden User gesetzt + +### Neue Dateien + +- `src/import/import.module.ts` +- `src/import/import.controller.ts` +- `src/import/import.service.ts` +- `src/import/dto/import-preview.dto.ts` +- `src/import/dto/import-execute.dto.ts` + +### TODO Frontend + +- [x] Import-Wizard (3 Schritte: Upload → Spalten-Mapping → Ergebnis) in CRM-Einstellungen → Tab "Import" +- [x] Import-Ergebnis-Anzeige (created/updated/skipped/errors mit Fehlerdetails) +- [x] entityType-Konvertierung: PERSON→contact, COMPANY→company +- [x] mapping-Konvertierung: Record→Array [{sourceColumn, targetField}] + +--- + +## Phase 2.4 Backend — Datenanreicherung / Enrichment (DONE) + +**Implementiert am:** 2026-03-12 + +### Neue Endpoints + +| Methode | Pfad | Beschreibung | +|---------|------|-------------| +| POST | /api/v1/crm/companies/:id/enrich | Unternehmensdaten anreichern (Suggestion-Only!) | +| GET | /api/v1/crm/settings/integrations/north-data | North Data Einstellungen abrufen | +| PUT | /api/v1/crm/settings/integrations/north-data | North Data Einstellungen aktualisieren | + +### Datenquellen + +1. **Unternehmensregister.de** (kostenfrei) — Handelsregister-Daten: registerNumber, registerCourt, Adresse +2. **North Data API** (kostenpflichtig, optional) — Erweiterte Daten: name, vatId, website, phone, Adresse, industry + +Beide Quellen werden **parallel** abgefragt (`Promise.allSettled`). Graceful Degradation: Wenn eine Quelle fehlschlaegt, werden Ergebnisse der anderen zurueckgegeben. + +### Enrich Response (Suggestion-Only, KEIN Auto-Write) + +```json +{ + "success": true, + "data": { + "companyId": "uuid", + "companyName": "Muster GmbH", + "sources": ["unternehmensregister.de", "northdata.de"], + "suggestions": { + "tradeRegisterNumber": { + "current": null, + "suggested": "HRB 12345", + "source": "unternehmensregister.de" + }, + "vatId": { + "current": null, + "suggested": "DE123456789", + "source": "northdata.de" + } + }, + "enrichedAt": "2026-03-12T14:30:00.000Z", + "warnings": [] + } +} +``` + +### North Data Settings + +- Gespeichert in Redis: `crm:{tenantId}:integrations:north_data` +- Fallback: Env-Variable `NORTH_DATA_API_KEY` +- API-Key wird in GET-Response maskiert: `****xxxx` + +### Env-Variablen (optional) + +- `NORTH_DATA_API_KEY` — Globaler API-Key +- `NORTH_DATA_API_URL` — Base-URL (Default: https://www.northdata.de/_api) + +### Health-Check + +- `/health` Response enthaelt neuen Service: `enrichment: 'up' | 'down' | 'unconfigured'` +- Version auf `0.3.0` erhoeht + +### Neue Dateien + +- `src/enrichment/enrichment.module.ts` +- `src/enrichment/enrichment.controller.ts` +- `src/enrichment/enrichment.service.ts` +- `src/enrichment/dto/enrich-response.dto.ts` +- `src/enrichment/dto/enrichment-settings.dto.ts` + +### Geaenderte Dateien + +- `src/app.module.ts` — EnrichmentModule registriert +- `src/config/env.validation.ts` — NORTH_DATA_API_KEY + _URL +- `src/health/health.module.ts` — EnrichmentModule importiert +- `src/health/health.controller.ts` — enrichment Health-Check + +### TODO Frontend + +- [x] "Anreichern"-Button auf Company-Detail — POST /enrich, Suggestions-Modal (Tabelle mit Feld/Aktuell/Vorschlag/Quelle), "Uebernehmen" per PATCH +- [x] suggestions-Konvertierung: Record → Array fuer UI +- [x] North Data API-Key in CRM-Einstellungen → Tab "Integrationen"