mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-25 06:16:38 +02:00
Backend (CRM expert): Custom field definitions CRUD, bulk value upsert, 7 endpoints, Prisma schema with CustomFieldDef + CustomFieldValue tables. Frontend: Types, API, hooks, admin settings page with field management, CustomFieldsDisplay for detail pages, CustomFieldsForm for edit modals. Also fix Vite allowedHosts for insight.xinion.lan. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
12 KiB
12 KiB
CRM-Service - Zusammenfassung
Stand: 2026-03-12
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, Shared DTOs (contact-info, owner)
custom-fields/ — Custom Fields System (Phase 2.1): Definitionen + Werte CRUD, Entity-Integration
companies/ — CRUD: Unternehmen (Multi-Value emails/phones, Owner m:n, Status, Lexware ERP-Push, Custom Fields)
contacts/ — CRUD: Kontakte (Multi-Value emails/phones, Owner m:n, Status, Events, Custom Fields)
activities/ — CRUD: Aktivitaeten (NOTE, CALL, EMAIL, MEETING, TASK, FOLLOWUP; contactId+companyId optional)
pipelines/ — CRUD: Sales-Pipelines mit Stages (inkl. Stage-Update)
deals/ — CRUD: Vorgaenge mit Pipeline/Stage/Contact/Company + DealVouchers + LostReason + Owner m:n + Events + Custom Fields
owners/ — Shared Owner-Service (Contact/Company/Deal Owners, Upsert, Rollen)
events/ — CRM Event Publisher (Redis Pub/Sub) + Activity Due-Soon Scheduler
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, Multi-Value emails/phones, Owner m:n, EntityStatus, vatId/taxId/tradeRegisterNumber/companySize, Lexware-Verknuepfung
- Contact — Kontakte mit Multi-Value emails/phones, Owner m:n, EntityStatus, linkedinUrl/birthday/source/department, Lexware-Verknuepfung
- Activity — Aktivitaeten verknuepft mit Kontakten UND/ODER Companies (contactId + companyId beide optional, min. 1) + FOLLOWUP-Typ
- Pipeline — Konfigurierbare Sales-Pipelines pro Tenant
- PipelineStage — Stufen innerhalb einer Pipeline
- Deal — Vorgaenge mit dealVouchers-Relation, Owner m:n, LostReason/LostReasonText, Events
- ContactEmail — Multi-Value E-Mail-Adressen (Contact/Company, Typ: WORK/PERSONAL/OTHER)
- ContactPhone — Multi-Value Telefonnummern (Contact/Company, Typ: OFFICE/MOBILE/FAX)
- ContactOwner — Owner m:n fuer Contacts (Rollen: OWNER/MEMBER/WATCHER)
- CompanyOwner — Owner m:n fuer Companies
- DealOwner — Owner m:n fuer Deals
- 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)
- CustomFieldDef — Benutzerdefinierte Feld-Definitionen (Phase 2.1): entityType, name (Slug), label, fieldType, options (JSONB), isRequired, position. Unique: [tenantId, entityType, name]
- CustomFieldValue — Gespeicherte Werte (Phase 2.1): fieldDefId, entityId (generisch), valueText/valueNumber/valueDate/valueBoolean/valueJson. Unique: [fieldDefId, entityId]. CASCADE Delete bei Definition-Loeschung
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
CustomFieldDef (1) --< (n) CustomFieldValue — fieldDefId (Cascade)
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 |
| POST | /api/v1/crm/contacts/:id/owners | Owner hinzufuegen |
| DELETE | /api/v1/crm/contacts/:id/owners/:userId | Owner entfernen |
| POST | /api/v1/crm/companies/:id/owners | Owner hinzufuegen |
| DELETE | /api/v1/crm/companies/:id/owners/:userId | Owner entfernen |
| POST | /api/v1/crm/deals/:id/owners | Owner hinzufuegen |
| DELETE | /api/v1/crm/deals/:id/owners/:userId | Owner entfernen |
| 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) |
| Custom Fields | ||
| POST | /api/v1/crm/custom-fields | Feld-Definition erstellen |
| GET | /api/v1/crm/custom-fields?entityType=PERSON | Definitionen auflisten (nach Entity-Typ) |
| GET | /api/v1/crm/custom-fields/:id | Definition abrufen |
| PATCH | /api/v1/crm/custom-fields/:id | Definition aktualisieren |
| DELETE | /api/v1/crm/custom-fields/:id | Definition loeschen (CASCADE) |
| PUT | /api/v1/crm/custom-fields/:entityId/values | Werte setzen (Bulk-Upsert) |
| GET | /api/v1/crm/custom-fields/:entityId/values | Werte lesen |
| 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.ymlim 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: siehe Abschnitt "Migrationen" oben
Migrationen
20260310163211_init— Initiales Schema20260310183117_add_companies— Company-Entity20260310_add_lexware_integration— Lexware Office Integration20260311_add_company_detail_overhaul— Company Detail Overhaul20260312_phase1_schema_expansion— Phase 1: Enums, Multi-Value, Owner, LostReason20260312_phase2_custom_fields— Phase 2.1: Custom Fields (Definitionen + Werte)
Naechste Schritte
- Migration
20260312_phase2_custom_fieldsauf Server anwenden - Container neu bauen und deployen
- Frontend: Custom Fields Admin-UI + Entity-Integration
- Phase 2.2: Kontakt-Import (CSV, Excel, vCard)
- Phase 2.3: Forecast-Endpoint (Probability-Feld auf PipelineStage)
- Phase 2.4: Firmendaten-Anreicherung (Data Enrichment)
- Phase 2.5: Berechtigungsmodell (Sichtbarkeitsfilter)