# CRM-Service - Zusammenfassung ## Stand: 2026-03-10 ### 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) 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 src/ main.ts — Bootstrap (Port 3100, Prefix: api/v1/crm, Swagger) app.module.ts — Root Module mit globalem JwtAuthGuard + ExceptionFilter config/ — Umgebungsvariablen-Validierung prisma/ — CrmPrismaService (eigener Client) redis/ — RedisService (Token-Blocklist, Cache) auth/ — JWT Strategy (RS256), JwtAuthGuard, RolesGuard, TenantGuard common/ — Decorators (@Public, @Roles, @CurrentUser), Pagination, ExceptionFilter contacts/ — CRUD: Kontakte (PERSON, ORGANIZATION) activities/ — CRUD: Aktivitaeten (NOTE, CALL, EMAIL, MEETING, TASK) pipelines/ — CRUD: Sales-Pipelines mit Stages deals/ — CRUD: Deals mit Pipeline/Stage-Zuordnung ``` ### Datenbank-Modelle (app_crm Schema) - **Contact** — Kontakte mit Typen, Adresse, Tags, Audit-Trail - **Activity** — Aktivitaeten verknuepft mit Kontakten - **Pipeline** — Konfigurierbare Sales-Pipelines pro Tenant - **PipelineStage** — Stufen innerhalb einer Pipeline - **Deal** — Verkaufschancen mit Wert, Status, Pipeline-Zuordnung ### API-Endpunkte | Methode | Pfad | Beschreibung | |---------|------|-------------| | 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 | | GET/PATCH/DELETE | /api/v1/crm/activities/:id | Detail / Update / Delete | | 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 | | GET/POST | /api/v1/crm/deals | Liste / Erstellen | | GET/PATCH/DELETE | /api/v1/crm/deals/:id | Detail / Update / Delete | | GET | /health | Health-Check (public) | ### Docker-Integration - `docker-compose.crm.yml` im Projekt-Root - Port: 3100 - Netzwerke: insight-web, insight-db, insight-cache - Traefik-Route: `Host(172.20.10.59) && PathPrefix(/api/v1/crm)` mit Priority 100 - JWT Public Key als Read-Only Volume (.keys/jwt-public.pem) - Direkte PostgreSQL-Verbindung (PgBouncer unterstuetzt kein search_path fuer Schema-Auswahl) ### Sicherheit - JWT RS256 Validierung mit shared Public Key - Token-Revocation via Redis (blocked:{jti}) - Multi-Tenancy: Alle Queries filtern nach tenantId - TenantGuard sichert mandantenbezogenen Zugriff - Globaler ValidationPipe (whitelist + forbidNonWhitelisted) - Strict TypeScript, kein `any` - 401 bei fehlendem/ungueltigem Token ### Deployment-Status **Erfolgreich deployed auf insight-dev-01 (172.20.10.59) am 2026-03-10** - Container: insight-crm (Development-Mode) - Prisma Migration `20260310163211_init` angewendet - Alle API-Endpunkte getestet und funktionsfaehig - Traefik-Routing aktiv: http://172.20.10.59/api/v1/crm/* - Swagger-Docs: nicht ueber Traefik erreichbar (nur Container-intern) ### Getestete Endpunkte | Test | Ergebnis | |------|----------| | GET /contacts (leere Liste) | 200 OK, pagination korrekt | | POST /contacts (Kontakt erstellen) | 201 Created, UUID generiert | | GET /contacts/:id | 200 OK, Detail korrekt | | PATCH /contacts/:id | 200 OK, Update + Tags | | GET /contacts?search=Muster | 200 OK, Suche funktioniert | | POST /activities (Notiz) | 201 Created, contactId verknuepft | | POST /pipelines (mit 4 Stages) | 201 Created, Stages korrekt | | POST /deals | 201 Created, Pipeline/Stage/Contact verknuepft | | PATCH /deals/:id (WON) | 200 OK, closedAt automatisch gesetzt | | GET /deals (Liste) | 200 OK, pagination korrekt | | GET /contacts ohne Token | 401 Unauthorized | | Validierung (falsche Felder) | 400 Bad Request, Details korrekt | ### Bekannte Einschraenkungen - PgBouncer kann nicht genutzt werden (search_path nicht kompatibel mit transaction pooling) - Swagger-Docs nur Container-intern erreichbar (kein Traefik-Route fuer /api/v1/crm/docs) ### Naechste Schritte 1. DELETE-Endpunkte testen (Kontakte, Deals, Pipelines) 2. Swagger-Docs ueber Traefik erreichbar machen (optional) 3. Integration mit Frontend (CRM-Modul im Admin-Bereich) 4. E2E-Tests schreiben 5. Production-Build testen (multi-stage Dockerfile)