INSIGHT-MVP/docs/INSIGHT-CRM.md
Thomas Reitz 028364cd7d docs(crm): document Company module frontend implementation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:13:28 +01:00

17 KiB

INSIGHT CRM - Kommunikation Frontend <-> Backend

Dieses Dokument dient als Kommunikationskanal zwischen dem Frontend- und dem CRM-Backend-Entwickler.


2026-03-10 | Frontend: Erster Stand der CRM-Integration

Was wurde umgesetzt

Das komplette CRM-Frontend-Modul ist implementiert und auf dem Server deployed (feature/crm-service Branch, Commit c739dce).

Neue Dateien (16 Dateien, ~4.800 Zeilen)

packages/frontend/src/crm/
  types.ts                              -- Zentrale Interfaces (alle Entitaeten + API-Wrapper)
  api.ts                                -- API-Funktionen (Axios, baseURL /api/v1/crm/*)
  hooks.ts                              -- React Query Hooks + Query Key Factory
  contacts/
    ContactsPage.tsx + .module.css      -- Liste mit Suche, Typ-Filter, Paginierung
    ContactFormModal.tsx                -- Create/Edit Modal (Person/Organisation)
    ContactDetailPage.tsx + .module.css -- 2-Spalten: Info+Deals links, Aktivitaeten rechts
  deals/
    DealsPage.tsx + .module.css         -- Liste mit Pipeline/Stage/Status-Filter
    DealFormModal.tsx                   -- Create/Edit mit Kontakt-Suche + Pipeline/Stage-Selektor
    DealDetailPage.tsx + .module.css    -- Detail mit Stage-Fortschrittsbalken
  pipelines/
    PipelinesPage.tsx + .module.css     -- Verwaltung mit klappbaren Cards + Stage-Management
  activities/
    ActivityFormModal.tsx               -- Formular fuer Notiz/Anruf/E-Mail/Meeting/Aufgabe

Geaenderte Dateien (3)

Datei Aenderung
src/shell/App.tsx 5 CRM-Routen (/crm/contacts, /crm/contacts/:id, /crm/deals, /crm/deals/:id, /crm/pipelines)
src/shell/AppLayout.tsx CRM-Sektion in Sidebar (aufklappbar, 3 NavLinks mit SVG-Icons)
vite.config.ts Proxy /api/v1/crm -> localhost:3100 fuer lokale Entwicklung

Welche API-Endpoints werden genutzt

Modul Endpoints Methoden
Contacts /crm/contacts, /crm/contacts/:id GET (list+detail), POST, PATCH, DELETE
Deals /crm/deals, /crm/deals/:id GET (list+detail), POST, PATCH, DELETE
Pipelines /crm/pipelines, /crm/pipelines/:id, /crm/pipelines/:id/stages, /crm/pipelines/:id/stages/:stageId GET (list+detail), POST, PATCH, DELETE
Activities /crm/activities, /crm/activities/:id GET (list), POST, PATCH, DELETE

Erwartete Response-Formate

Liste (paginiert):

{
  "success": true,
  "data": [...],
  "pagination": { "page": 1, "pageSize": 25, "total": 42, "totalPages": 2 },
  "meta": { "timestamp": "..." }
}

Einzelobjekt:

{
  "success": true,
  "data": { ... },
  "meta": { "timestamp": "..." }
}

Fehler:

{
  "success": false,
  "error": { "code": "NOT_FOUND", "message": "...", "details": [] },
  "meta": { "timestamp": "..." }
}

Annahmen / Abhaengigkeiten ans Backend

  1. Contact-Detail liefert Activities mit -- GET /crm/contacts/:id gibt die letzten 10 Aktivitaeten im Feld activities zurueck. Das Frontend zeigt diese in der Timeline an.

  2. Deal-Detail liefert Relations mit -- GET /crm/deals/:id gibt pipeline, stage und contact als verschachtelte Objekte zurueck.

  3. Pipeline-List liefert Stages mit -- GET /crm/pipelines gibt jede Pipeline inkl. stages[] Array zurueck. Das Frontend nutzt diese fuer die Stage-Selektoren im Deal-Formular.

  4. Deal.value ist ein String -- Decimal kommt als String vom Backend (z.B. "24000.00"). Das Frontend parst mit parseFloat().

  5. Sortierung -- Contacts: createdAt, firstName, lastName, companyName, email. Deals: createdAt, title, value, expectedCloseDate.

  6. Suche -- Contacts: Substring-Match in firstName, lastName, companyName, email. Deals: Substring-Match in title.

Bekannte Offene Punkte

  • Traefik HTTPS-Router fuer CRM: Aktuell hat der CRM-Service nur einen HTTP-Router (web Entrypoint). Fuer HTTPS (websecure) muesste ein zweiter Router mit tls=true angelegt werden (wie bei core-api-secure).
  • Activity-Liste komplett laden: Die Contact-Detail-Seite zeigt nur die letzten 10 Aktivitaeten (aus dem Contact-Objekt). Fuer eine "Alle anzeigen"-Funktion wuerde ein separater GET /crm/activities?contactId=... Aufruf benoetigt (Hook existiert bereits).
  • Kanban-Board fuer Deals: Aktuell nur Tabellenansicht. Ein Drag-and-Drop Kanban-Board waere ein sinnvolles Feature fuer spaeter.
  • Pipeline-Stages bearbeiten: Derzeit kann man Stages nur hinzufuegen und loeschen, nicht den Namen/Farbe/Reihenfolge aendern (kein PATCH-Endpoint fuer Stages vorhanden).

2026-03-10 | Backend: Antwort auf Frontend-Integrationsbericht

Status der Annahmen

Alle 6 Annahmen des Frontend-Entwicklers sind korrekt und werden vom Backend unterstuetzt:

# Annahme Status Hinweise
1 Contact-Detail liefert Activities mit Bestaetigt GET /crm/contacts/:id liefert activities[] (letzte 10, sortiert nach createdAt desc)
2 Deal-Detail liefert Relations mit Bestaetigt GET /crm/deals/:id liefert pipeline (inkl. aller Stages!), stage, contact
3 Pipeline-List liefert Stages mit Bestaetigt GET /crm/pipelines liefert jede Pipeline inkl. stages[] + _count.deals
4 Deal.value ist ein String Bestaetigt Decimal wird als String geliefert (z.B. "24000")
5 Sortierung Bestaetigt Contacts: createdAt, firstName, lastName, companyName, email. Deals: createdAt, updatedAt, title, value, expectedCloseDate
6 Suche Bestaetigt Contacts: case-insensitive Substring in firstName, lastName, companyName, email. Deals: case-insensitive Substring in title

Erledigte Offene Punkte

  • Traefik HTTPS-Router: crm-secure Router angelegt mit entrypoints=websecure, tls=true, Priority 100. Deployed in Commit c9e2c4a.

  • Pipeline-Stages bearbeiten: Neuer Endpoint PATCH /crm/pipelines/:id/stages/:stageId hinzugefuegt. Akzeptiert:

    {
      "name": "Neuer Name",     // optional, max 200
      "sortOrder": 2,            // optional, int >= 0
      "color": "#EF4444"         // optional, Hex #RRGGBB
    }
    

Noch offene Punkte (Backend-Sicht)

  • Activity-Liste komplett laden: GET /crm/activities?contactId=... ist bereits implementiert und funktioniert. Das Frontend kann den bestehenden Hook direkt nutzen.
  • Kanban-Board: Backend-seitig kein Handlungsbedarf - PATCH /crm/deals/:id mit { stageId: "..." } genuegt fuer Drag & Drop.

Hinweis zu Pipeline-Detail bei Deals

GET /crm/deals/:id liefert die Pipeline inklusive aller Stages (nicht nur die aktuelle Stage). Das ist nuetzlich fuer den Stage-Fortschrittsbalken im DealDetailPage.tsx:

{
  "pipeline": {
    "id": "...",
    "name": "Standard Sales",
    "stages": [
      { "id": "...", "name": "Qualifizierung", "sortOrder": 0, "color": "#3B82F6" },
      { "id": "...", "name": "Angebot", "sortOrder": 1, "color": "#F59E0B" },
      { "id": "...", "name": "Verhandlung", "sortOrder": 2, "color": "#EF4444" },
      { "id": "...", "name": "Abschluss", "sortOrder": 3, "color": "#10B981" }
    ]
  },
  "stage": { "id": "...", "name": "Angebot", "color": "#F59E0B" }
}

Deployment-Info

  • Branch: feature/crm-service, Commit: c9e2c4a
  • Server: insight-dev-01 (172.20.10.59)
  • Container: insight-crm (neu gebuildet und deployed)
  • Swagger-Docs: http://172.20.10.59/api/v1/crm/docs/

2026-03-10 | Frontend: Update nach Backend-Feedback

Umgesetzte Verbesserungen

Basierend auf der Backend-Antwort wurden folgende Aenderungen umgesetzt (Commit 0b78160):

1. Pipeline-Stages inline bearbeitbar

Die PipelinesPage.tsx nutzt jetzt den neuen PATCH /crm/pipelines/:id/stages/:stageId Endpoint:

  • Jede Stage kann per Doppelklick oder Stift-Icon bearbeitet werden
  • Inline-Formular mit Name-Input und Color-Picker
  • Speichern mit Enter oder Haekchen, Abbrechen mit Escape oder X
  • Neuer Hook: useUpdateStage() mit automatischer Query-Invalidierung

2. DealDetailPage optimiert

DealDetailPage.tsx nutzt jetzt direkt deal.pipeline.stages aus dem Deal-Objekt fuer den Stage-Fortschrittsbalken. Der vorherige separate usePipeline() API-Call wurde entfernt.

3. UI-Umbenennung: "Deals" -> "Vorgaenge"

Alle user-facing Strings wurden umbenannt:

  • Sidebar: "Deals" -> "Vorgaenge"
  • Seitentitel: "Deals" -> "Vorgaenge"
  • Buttons: "Neuer Deal" -> "Neuer Vorgang"
  • Modals: "Deal bearbeiten/loeschen" -> "Vorgang bearbeiten/loeschen"
  • Fehlermeldungen und Leer-Zustaende angepasst

Hinweis: API-Pfade (/crm/deals), TypeScript-Typen (Deal, DealStatus) und Komponentennamen (DealsPage, DealFormModal) bleiben unveraendert — nur die UI-Texte wurden geaendert.

Aktualisierte Offene Punkte

  • Pipeline-Stages bearbeiten — Frontend nutzt den neuen PATCH-Endpoint
  • DealDetail separater Pipeline-Call — Nutzt jetzt deal.pipeline.stages
  • Activity-Liste komplett laden — Hook existiert, UI-Button "Alle anzeigen" fehlt noch
  • Kanban-Board fuer Vorgaenge — Feature fuer spaeter geplant

Deployment-Info

  • Branch: feature/crm-service, Commit: 0b78160
  • Server: insight-dev-01 (172.20.10.59)
  • Container: insight-frontend neu gebaut und deployed

2026-03-10 | Backend: Neues Company-Modul + Aenderungen an Contact und Deal

Neue Entity: Company (Unternehmen)

Unternehmen sind jetzt als eigenstaendige Entity implementiert. Sie dienen als uebergeordnete Ebene fuer Kontakte und Vorgaenge. Ein Unternehmen kann mehrere Kontakte und Vorgaenge haben.

Neue API-Endpoints

Methode Pfad Beschreibung
GET /crm/companies Liste (paginiert, filterbar, suchbar)
POST /crm/companies Unternehmen erstellen
GET /crm/companies/:id Detail (inkl. Kontakte + Vorgaenge)
PATCH /crm/companies/:id Unternehmen aktualisieren
DELETE /crm/companies/:id Unternehmen loeschen

Company-Objekt (Felder)

interface Company {
  id: string;            // UUID
  tenantId: string;      // UUID
  name: string;          // Pflichtfeld, max 200
  industry?: string;     // max 100
  email?: string;        // max 255
  phone?: string;        // max 50
  website?: string;      // max 500
  street?: string;       // max 200
  zip?: string;          // max 20
  city?: string;         // max 100
  state?: string;        // max 100
  country?: string;      // Default "DE", 2-Zeichen ISO
  notes?: string;        // Freitext
  tags: string[];        // Default []
  isActive: boolean;     // Default true
  createdBy: string;     // UUID
  updatedBy?: string;    // UUID
  createdAt: string;     // ISO DateTime
  updatedAt: string;     // ISO DateTime
  _count: { contacts: number; deals: number };
}

Company-Liste: Query-Parameter

Parameter Typ Beschreibung
page number Seite (default: 1)
pageSize number Eintraege pro Seite (default: 25)
search string Substring-Match in name, industry, email, city
industry string Exakter Filter nach Branche
sort string createdAt, updatedAt, name, industry, city
order string asc oder desc (default: desc)

Company-Detail: Verschachtelte Daten

GET /crm/companies/:id liefert zusaetzlich:

  • contacts[] — Top 20 aktive Kontakte mit: id, firstName, lastName, email, phone, position, isActive
  • deals[] — Top 10 Vorgaenge mit: alle Deal-Felder + pipeline + stage Objekte
  • _count — Zaehler fuer contacts und deals

Beispiel-Response (gekuerzt):

{
  "data": {
    "id": "...",
    "name": "Xinion GmbH",
    "industry": "Enterprise Software",
    "contacts": [
      {
        "id": "...",
        "firstName": "Thomas",
        "lastName": "Reitz",
        "email": "treitz@xinion.de",
        "position": "Geschaeftsfuehrer",
        "isActive": true
      }
    ],
    "deals": [
      {
        "id": "...",
        "title": "INSIGHT Platform Lizenz",
        "value": "48000",
        "status": "OPEN",
        "pipeline": { "id": "...", "name": "Standard Sales" },
        "stage": { "id": "...", "name": "Qualifizierung", "color": "#3B82F6" }
      }
    ],
    "_count": { "contacts": 1, "deals": 1 }
  }
}

Aenderungen an Contact

Kontakte haben zwei neue Felder:

Feld Typ Beschreibung
companyId string? (UUID) Verknuepfung zum Unternehmen (optional)
position string? Position/Rolle im Unternehmen (max 200)

Contact-Liste liefert jetzt zusaetzlich:

{
  "company": { "id": "...", "name": "Xinion GmbH", "industry": "Enterprise Software" }
}

Contact-Detail liefert:

{
  "company": { "id": "...", "name": "Xinion GmbH", "industry": "Enterprise Software", "city": "Berlin", "website": "https://xinion.de" }
}

Aenderungen an Deal (Vorgang)

Vorgaenge haben ein neues Feld:

Feld Typ Beschreibung
companyId string? (UUID) Verknuepfung zum Unternehmen (optional)

Deal-Liste und Detail liefern jetzt zusaetzlich:

{
  "company": { "id": "...", "name": "Xinion GmbH" }
}

Deal-Liste Filter: Neuer Query-Parameter companyId (UUID) zum Filtern nach Unternehmen.

Vorschlaege fuer das Frontend

  1. Neue Seiten/Routen:

    • /crm/companies — Unternehmensliste (wie Kontakte, mit Suche/Filter/Paginierung)
    • /crm/companies/:id — Unternehmensdetail (2-Spalten: Info links, Kontakte+Vorgaenge rechts)
  2. Sidebar: Neuer NavLink "Unternehmen" in der CRM-Sektion (zwischen Kontakte und Vorgaenge oder davor)

  3. Contact-Formular: companyId Dropdown (Unternehmen-Suche) + position Textfeld hinzufuegen

  4. Contact-Liste: Company-Name als Spalte anzeigen (kommt aus contact.company.name)

  5. Deal-Formular: companyId Dropdown (Unternehmen-Suche) hinzufuegen

  6. Deal-Liste: Company-Name als Spalte anzeigen

  7. Verlinkung: Company-Name in Contact- und Deal-Listen als Link zu /crm/companies/:id

Swagger-Aenderung

Der Swagger-Tag fuer Deals/Vorgaenge ist jetzt Vorgaenge (Deals) statt Deals.

Datenbank-Verhalten bei Loeschung

  • Company loeschen: Kontakte und Vorgaenge behalten ihre Daten, aber companyId wird auf null gesetzt (SetNull)
  • Pipeline loeschen: Alle verknuepften Vorgaenge werden geloescht (Cascade)
  • Kontakt loeschen: Vorgaenge behalten ihre Daten, contactId wird null (SetNull)

Deployment-Info

  • Branch: feature/crm-service, Commit: 56a9ed9
  • Prisma Migration 20260310183117_add_companies angewendet
  • Alle Endpoints getestet und funktionsfaehig
  • Swagger-Docs aktualisiert: http://172.20.10.59/api/v1/crm/docs/

2026-03-10 | Frontend: Company-Modul implementiert

Was wurde umgesetzt

Das komplette Company-Frontend-Modul ist implementiert und deployed (Commit 36f571f).

Neue Dateien (5 Dateien)

packages/frontend/src/crm/companies/
  CompaniesPage.tsx + .module.css      -- Liste mit Suche, Paginierung, CRUD-Modals
  CompanyFormModal.tsx                 -- Create/Edit Modal (Name, Branche, Kontakt, Adresse, Tags)
  CompanyDetailPage.tsx + .module.css  -- 2-Spalten: Info links, Kontakte+Vorgaenge rechts

Geaenderte Dateien (11 Dateien)

  • types.ts: Company-Interface, CreateCompanyPayload, UpdateCompanyPayload, CompaniesQueryParams; Contact erweitert um companyId, position, company-Relation; Deal erweitert um companyId, company-Relation
  • api.ts: companiesApi mit 5 CRUD-Methoden
  • hooks.ts: crmKeys.companies + 5 Hooks (useCompanies, useCompany, useCreateCompany, useUpdateCompany, useDeleteCompany); Cross-Invalidation (Contact/Deal-Mutations invalidieren Companies-Cache)
  • AppLayout.tsx: NavLink "Unternehmen" mit Gebaeude-Icon zwischen Kontakte und Vorgaenge
  • App.tsx: 2 Routen (/crm/companies, /crm/companies/:id)
  • ContactsPage.tsx: Neue Spalte "Unternehmen" mit Link zu Company
  • ContactFormModal.tsx: Unternehmen-Suche (debounced Dropdown) + Position-Feld
  • ContactDetailPage.tsx: Unternehmen-Link + Position in Info-Card
  • DealsPage.tsx: Neue Spalte "Unternehmen" mit Link zu Company
  • DealFormModal.tsx: Unternehmen-Suche (debounced Dropdown)
  • DealDetailPage.tsx: Unternehmen-Link in Info-Card

Funktionsumfang Company-Modul

  1. CompaniesPage: Tabelle mit Name, Branche, Stadt, E-Mail, Kontakte-Anzahl, Vorgaenge-Anzahl, Status, Aktionen; Suchfeld (debounced 300ms); Paginierung; Erstellen/Bearbeiten/Loeschen-Modals
  2. CompanyFormModal: Name*, Branche, E-Mail, Telefon, Website, Adresse (Strasse, PLZ/Stadt, Land), Notizen, Tags (kommasepariert), Aktiv-Checkbox
  3. CompanyDetailPage: Links Info-Card (alle Felder + Tags + Notizen), Rechts Kontakte-Tabelle + Vorgaenge-Tabelle mit Navigation zu Detail-Seiten

Company-Integration in bestehende Module

  • Kontakte: Unternehmen-Spalte in Liste, Dropdown-Suche im Formular, Link+Position im Detail
  • Vorgaenge: Unternehmen-Spalte in Liste, Dropdown-Suche im Formular, Link im Detail
  • Pattern: Identisch zur Kontakt-Suche in DealFormModal (debounced, dropdown, click-outside)

Deployment

  • Branch: feature/crm-service, Commit: 36f571f
  • TypeScript-Check + Build: erfolgreich
  • Frontend Container neu gebaut und deployed

Bitte neue Eintraege unten anfuegen. Format: ## YYYY-MM-DD | Absender: Betreff