# CRM-Service - Zusammenfassung ## Stand: 2026-03-11 ### Was wurde erstellt Der CRM-Service als eigenstaendiges NestJS-Package unter `packages/crm-service/`. ### Struktur ``` packages/crm-service/ package.json — Dependencies (NestJS 10, Prisma, Passport, ioredis, @nestjs/axios, @nestjs/schedule) tsconfig.json — Strict TypeScript nest-cli.json — NestJS CLI Config Dockerfile — Multi-Stage (base, deps, development, build, production) .dockerignore — Excludes prisma/ crm.schema.prisma — Eigenes Schema (app_crm) mit eigenem Client-Output migrations/ — SQL-Migrationen src/ main.ts — Bootstrap (Port 3100, Prefix: api/v1/crm, Swagger) app.module.ts — Root Module mit globalem JwtAuthGuard + ExceptionFilter + ScheduleModule config/ — Umgebungsvariablen-Validierung (inkl. LEXWARE_*) prisma/ — CrmPrismaService (eigener Client) redis/ — RedisService (Token-Blocklist, Cache, Distributed Locks) auth/ — JWT Strategy (RS256), JwtAuthGuard, RolesGuard, TenantGuard common/ — Decorators (@Public, @Roles, @CurrentUser), Pagination, ExceptionFilter companies/ — CRUD: Unternehmen (mit Lexware ERP-Push, industryId, accountTypeId, ownerId) contacts/ — CRUD: Kontakte (mit Lexware ERP-Push bei Update) activities/ — CRUD: Aktivitaeten (NOTE, CALL, EMAIL, MEETING, TASK; contactId+companyId optional) pipelines/ — CRUD: Sales-Pipelines mit Stages (inkl. Stage-Update) deals/ — CRUD: Vorgaenge mit Pipeline/Stage/Contact/Company + DealVouchers industries/ — CRUD: Branchen (admin-konfigurierbar, mit Farbe) account-types/ — CRUD: Kontotypen (admin-konfigurierbar) relationship-types/ — CRUD: Beziehungstypen (admin-konfigurierbar) company-relationships/ — Company-zu-Company Beziehungen (N:M, bidirektional) health/ — Health-Check (DB, Redis, Lexware) lexware/ — Lexware Office Integration lexware.module.ts — Feature Module (HttpModule + ScheduleModule) lexware-client.service.ts — Rate-limitierter HTTP Client (Token Bucket, 2 req/s) lexware-contacts.service.ts — Kontakt-Suche, Link, Import, Push, Sync lexware-vouchers.service.ts — Beleg-Abruf, Cache, Deal-Verknuepfung lexware-sync.service.ts — Cron-Jobs (Beleg-Sync 4h, ERP-Push 30min) lexware-contacts.controller.ts — REST Endpoints Kontakt-Operationen lexware-vouchers.controller.ts — REST Endpoints Beleg-Operationen dto/ — Validierungs-DTOs interfaces/ — TypeScript Interfaces fuer Lexware API utils/ rate-limiter.ts — Token Bucket (max 2, 2/s Refill) lexware-mapper.ts — Bidirektionales Mapping CRM <-> Lexware ``` ### Datenbank-Modelle (app_crm Schema) - **Company** — Unternehmen mit industryId, accountTypeId, ownerId, Lexware-Verknuepfung - **Contact** — Kontakte mit optionaler Lexware-Verknuepfung - **Activity** — Aktivitaeten verknuepft mit Kontakten UND/ODER Companies (contactId + companyId beide optional, min. 1) - **Pipeline** — Konfigurierbare Sales-Pipelines pro Tenant - **PipelineStage** — Stufen innerhalb einer Pipeline - **Deal** — Vorgaenge mit dealVouchers-Relation zu Lexware-Belegen - **Industry** — Admin-konfigurierbare Branchen mit Farbe (unique pro Tenant) - **AccountType** — Admin-konfigurierbare Kontotypen (unique pro Tenant) - **RelationshipType** — Admin-konfigurierbare Beziehungstypen (unique pro Tenant) - **CompanyRelationship** — N:M Company-zu-Company Beziehungen mit Typ und Notizen - **Contract** — Vertraege (DB-Modell vorhanden, UI-Platzhalter) - **LexwareVoucher** — Gecachte Belege aus Lexware Office - **DealVoucher** — Join-Table Deal <-> Beleg (m:n mit Audit-Trail) ### Entity-Beziehungen ``` Company (1) --< (n) Contact — companyId (optional, SetNull) Company (1) --< (n) Deal — companyId (optional, SetNull) Company (1) --< (n) Activity — companyId (optional, SetNull) Company (1) --< (n) LexwareVoucher — companyId (optional, SetNull) Company (n) >--< (n) Company — via CompanyRelationship (bidirektional) Company (1) --< (n) Contract — companyId (Cascade) Company (n) --> (1) Industry — industryId (optional, SetNull) Company (n) --> (1) AccountType — accountTypeId (optional, SetNull) Contact (1) --< (n) Activity — contactId (optional, SetNull) Contact (1) --< (n) Deal — contactId (optional, SetNull) Contact (1) --< (n) LexwareVoucher — contactId (optional, SetNull) Pipeline (1) --< (n) PipelineStage — pipelineId (Cascade) Pipeline (1) --< (n) Deal — pipelineId (Cascade) PipelineStage (1) --< (n) Deal — stageId Deal (1) --< (n) DealVoucher — dealId (Cascade) LexwareVoucher (1) --< (n) DealVoucher — voucherId (Cascade) RelationshipType (1) --< (n) CompanyRelationship — relationshipTypeId ``` ### API-Endpunkte | Methode | Pfad | Beschreibung | |---------|------|-------------| | GET/POST | /api/v1/crm/companies | Liste / Erstellen | | GET/PATCH/DELETE | /api/v1/crm/companies/:id | Detail / Update / Delete | | GET/POST | /api/v1/crm/contacts | Liste / Erstellen | | GET/PATCH/DELETE | /api/v1/crm/contacts/:id | Detail / Update / Delete | | GET/POST | /api/v1/crm/activities | Liste / Erstellen (companyId+includeContacts fuer aggregierten Feed) | | GET/PATCH/DELETE | /api/v1/crm/activities/:id | Detail / Update / Delete | | GET/POST | /api/v1/crm/industries | Branchen verwalten | | PATCH/DELETE | /api/v1/crm/industries/:id | Branche bearbeiten / loeschen | | GET/POST | /api/v1/crm/account-types | Kontotypen verwalten | | PATCH/DELETE | /api/v1/crm/account-types/:id | Kontotyp bearbeiten / loeschen | | GET/POST | /api/v1/crm/relationship-types | Beziehungstypen verwalten | | PATCH/DELETE | /api/v1/crm/relationship-types/:id | Beziehungstyp bearbeiten / loeschen | | GET/POST | /api/v1/crm/companies/:id/relationships | Beziehungen verwalten | | DELETE | /api/v1/crm/companies/:id/relationships/:relId | Beziehung loeschen | | GET | /api/v1/crm/users | Tenant-User fuer Owner-Dropdown | | GET/POST | /api/v1/crm/pipelines | Liste / Erstellen | | GET/PATCH/DELETE | /api/v1/crm/pipelines/:id | Detail / Update / Delete | | POST/DELETE | /api/v1/crm/pipelines/:id/stages | Stage hinzufuegen/entfernen | | PATCH | /api/v1/crm/pipelines/:id/stages/:stageId | Stage bearbeiten | | GET/POST | /api/v1/crm/deals | Liste / Erstellen | | GET/PATCH/DELETE | /api/v1/crm/deals/:id | Detail / Update / Delete | | GET | /health | Health-Check (DB, Redis, Lexware) | | **Lexware Kontakte** | | | | GET | /api/v1/crm/lexware/contacts/search | Lexware-Kontakte suchen | | POST | /api/v1/crm/lexware/contacts/link-company | Company verknuepfen | | POST | /api/v1/crm/lexware/contacts/link-contact | Contact verknuepfen | | DELETE | /api/v1/crm/lexware/contacts/unlink-company/:id | Verknuepfung loesen | | DELETE | /api/v1/crm/lexware/contacts/unlink-contact/:id | Verknuepfung loesen | | POST | /api/v1/crm/lexware/contacts/import-company | Company aus Lexware importieren | | POST | /api/v1/crm/lexware/contacts/import-contact | Contact aus Lexware importieren | | POST | /api/v1/crm/lexware/contacts/push/:type/:id | CRM -> Lexware pushen | | POST | /api/v1/crm/lexware/contacts/sync/:type/:id | Lexware -> CRM synchronisieren | | **Lexware Belege** | | | | GET | /api/v1/crm/lexware/vouchers/company/:id | Belege fuer Unternehmen | | GET | /api/v1/crm/lexware/vouchers/contact/:id | Belege fuer Kontakt | | GET | /api/v1/crm/lexware/vouchers/deal/:id | Belege fuer Vorgang | | POST | /api/v1/crm/lexware/vouchers/deal/:id/link | Beleg mit Vorgang verknuepfen | | DELETE | /api/v1/crm/lexware/vouchers/deal/:id/unlink/:vid | Verknuepfung loesen | | POST | /api/v1/crm/lexware/vouchers/refresh/company/:id | Cache aktualisieren | | POST | /api/v1/crm/lexware/vouchers/refresh/contact/:id | Cache aktualisieren | ### Lexware Office Integration — Details - **Rate Limiter**: In-Memory Token Bucket, 2 Requests/Sekunde (Lexware API Limit) - **Beleg-Caching**: PostgreSQL-Tabelle `lexware_vouchers`, alle 4h Cron-Refresh + manueller Refresh - **ERP-Push**: Companies/Contacts mit Tag "ERP" werden automatisch (30min Cron) + bei Update nach Lexware gepusht - **Distributed Locks**: Redis SET NX EX verhindert Doppelausfuehrung von Cron-Jobs - **Optimistic Locking**: lexwareContactVersion fuer sichere Updates - **Graceful Degradation**: Ohne LEXWARE_API_KEY → Modul deaktiviert, Health = "unconfigured" ### Docker-Integration - `docker-compose.crm.yml` im Projekt-Root - Port: 3100 - Neue Env-Variablen: `LEXWARE_API_KEY`, `LEXWARE_API_URL` - Traefik HTTP + HTTPS Routing: `/api/v1/crm/*` ### Sicherheit - JWT RS256 Validierung mit shared Public Key - Token-Revocation via Redis - Multi-Tenancy: Alle Queries filtern nach tenantId - Globaler ValidationPipe (whitelist + forbidNonWhitelisted) - Strict TypeScript, kein `any` ### Deployment-Status **Erfolgreich deployed auf insight-dev-01 (172.20.10.59) am 2026-03-10** - Prisma Migrationen: - `20260310163211_init` — Initiales Schema - `20260310183117_add_companies` — Company-Entity - `20260310_add_lexware_integration` — Lexware Office Integration - `20260311_add_company_detail_overhaul` — Company Detail Overhaul (Industry, AccountType, RelationshipType, CompanyRelationship, Contract, Activity companyId) ### Naechste Schritte 1. Migration `20260311_add_company_detail_overhaul` auf Server anwenden 2. Seed-Data (Industries, AccountTypes, RelationshipTypes) ausfuehren 3. Container neu bauen und deployen 4. Frontend testen: CompanyDetailPage 3-Spalten Layout 5. CRM-Einstellungen: Branchen/Kontotypen/Beziehungstypen verwalten 6. CompanyFormModal: Dropdowns testen 7. Activity Feed: Aggregierten Feed testen 8. Kanban-Board fuer Vorgaenge 9. Vertraege-UI implementieren (DB-Modell bereits vorhanden)