mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-24 23:56:40 +02:00
docs(crm): document Company entity for frontend developer
Update INSIGHT-CRM.md with complete Company API documentation, Contact/Deal changes (companyId, position), and frontend integration suggestions. Update Summarize.md with current test results. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ab4898210e
commit
a13cca054b
2 changed files with 218 additions and 23 deletions
|
|
@ -208,4 +208,175 @@ Alle user-facing Strings wurden umbenannt:
|
|||
|
||||
---
|
||||
|
||||
## 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)
|
||||
|
||||
```typescript
|
||||
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):
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
```json
|
||||
{
|
||||
"company": { "id": "...", "name": "Xinion GmbH", "industry": "Enterprise Software" }
|
||||
}
|
||||
```
|
||||
|
||||
**Contact-Detail** liefert:
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
```json
|
||||
{
|
||||
"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/
|
||||
|
||||
---
|
||||
|
||||
*Bitte neue Eintraege unten anfuegen. Format: `## YYYY-MM-DD | Absender: Betreff`*
|
||||
|
|
|
|||
|
|
@ -25,24 +25,40 @@ packages/crm-service/
|
|||
redis/ — RedisService (Token-Blocklist, Cache)
|
||||
auth/ — JWT Strategy (RS256), JwtAuthGuard, RolesGuard, TenantGuard
|
||||
common/ — Decorators (@Public, @Roles, @CurrentUser), Pagination, ExceptionFilter
|
||||
contacts/ — CRUD: Kontakte (PERSON, ORGANIZATION)
|
||||
companies/ — CRUD: Unternehmen (uebergeordnete Entity)
|
||||
contacts/ — CRUD: Kontakte (PERSON, ORGANIZATION) mit Company-Verknuepfung
|
||||
activities/ — CRUD: Aktivitaeten (NOTE, CALL, EMAIL, MEETING, TASK)
|
||||
pipelines/ — CRUD: Sales-Pipelines mit Stages
|
||||
deals/ — CRUD: Deals mit Pipeline/Stage-Zuordnung
|
||||
pipelines/ — CRUD: Sales-Pipelines mit Stages (inkl. Stage-Update)
|
||||
deals/ — CRUD: Vorgaenge mit Pipeline/Stage/Contact/Company-Zuordnung
|
||||
```
|
||||
|
||||
### Datenbank-Modelle (app_crm Schema)
|
||||
|
||||
- **Contact** — Kontakte mit Typen, Adresse, Tags, Audit-Trail
|
||||
- **Company** — Unternehmen mit Branche, Adresse, Tags, Audit-Trail. Eltern-Entity fuer Contacts und Deals.
|
||||
- **Contact** — Kontakte (Person/Organisation) mit optionaler Company-Zuordnung (companyId, position)
|
||||
- **Activity** — Aktivitaeten verknuepft mit Kontakten
|
||||
- **Pipeline** — Konfigurierbare Sales-Pipelines pro Tenant
|
||||
- **PipelineStage** — Stufen innerhalb einer Pipeline
|
||||
- **Deal** — Verkaufschancen mit Wert, Status, Pipeline-Zuordnung
|
||||
- **PipelineStage** — Stufen innerhalb einer Pipeline (Name, Farbe, Reihenfolge editierbar)
|
||||
- **Deal** — Vorgaenge mit Wert, Status, Pipeline/Stage/Contact/Company-Zuordnung
|
||||
|
||||
### Entity-Beziehungen
|
||||
|
||||
```
|
||||
Company (1) --< (n) Contact — companyId (optional, SetNull bei Loeschung)
|
||||
Company (1) --< (n) Deal — companyId (optional, SetNull bei Loeschung)
|
||||
Contact (1) --< (n) Activity — contactId (Cascade bei Loeschung)
|
||||
Contact (1) --< (n) Deal — contactId (optional, SetNull bei Loeschung)
|
||||
Pipeline (1) --< (n) PipelineStage — pipelineId (Cascade bei Loeschung)
|
||||
Pipeline (1) --< (n) Deal — pipelineId (Cascade bei Loeschung)
|
||||
PipelineStage (1) --< (n) Deal — stageId
|
||||
```
|
||||
|
||||
### 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 |
|
||||
|
|
@ -50,6 +66,7 @@ packages/crm-service/
|
|||
| 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 (Name, Farbe, Reihenfolge) |
|
||||
| GET/POST | /api/v1/crm/deals | Liste / Erstellen |
|
||||
| GET/PATCH/DELETE | /api/v1/crm/deals/:id | Detail / Update / Delete |
|
||||
| GET | /health | Health-Check (public) |
|
||||
|
|
@ -59,7 +76,8 @@ packages/crm-service/
|
|||
- `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
|
||||
- Traefik HTTP-Route: `Host(172.20.10.59) && PathPrefix(/api/v1/crm)` mit Priority 100
|
||||
- Traefik HTTPS-Route: `crm-secure` mit `entrypoints=websecure`, `tls=true`, Priority 100
|
||||
- JWT Public Key als Read-Only Volume (.keys/jwt-public.pem)
|
||||
- Direkte PostgreSQL-Verbindung (PgBouncer unterstuetzt kein search_path fuer Schema-Auswahl)
|
||||
|
||||
|
|
@ -78,37 +96,43 @@ packages/crm-service/
|
|||
**Erfolgreich deployed auf insight-dev-01 (172.20.10.59) am 2026-03-10**
|
||||
|
||||
- Container: insight-crm (Development-Mode)
|
||||
- Prisma Migration `20260310163211_init` angewendet
|
||||
- Prisma Migrationen angewendet:
|
||||
- `20260310163211_init` — Initiales Schema (Contact, Activity, Pipeline, PipelineStage, Deal)
|
||||
- `20260310183117_add_companies` — Company-Entity, Contact.companyId/position, Deal.companyId
|
||||
- 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)
|
||||
- Traefik-Routing aktiv (HTTP + HTTPS): http(s)://172.20.10.59/api/v1/crm/*
|
||||
- Swagger-Docs: http://172.20.10.59/api/v1/crm/docs/
|
||||
|
||||
### 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 /companies (Erstellen mit allen Feldern) | 200 OK, UUID + _count korrekt |
|
||||
| GET /companies (Liste) | 200 OK, pagination + _count korrekt |
|
||||
| GET /companies/:id (Detail) | 200 OK, contacts[] + deals[] + _count |
|
||||
| PATCH /companies/:id (Update) | 200 OK, updatedBy + tags korrekt |
|
||||
| GET /companies?search=Xinion | 200 OK, Suche funktioniert |
|
||||
| POST /contacts (mit companyId + position) | 201 Created, Company-Verknuepfung korrekt |
|
||||
| GET /contacts/:id (mit Company) | 200 OK, company-Objekt enthalten |
|
||||
| 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 /pipelines/:id/stages/:stageId | 200 OK, Stage-Update korrekt |
|
||||
| POST /deals (mit companyId + contactId) | 200 OK, Company + Contact verknuepft |
|
||||
| GET /deals/:id (mit Company) | 200 OK, company + pipeline.stages enthalten |
|
||||
| GET /deals?companyId=... | 200 OK, Filter nach Company funktioniert |
|
||||
| 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)
|
||||
1. Frontend: Company-Modul (Seiten, Formulare, Sidebar-Link)
|
||||
2. Frontend: Contact/Deal-Formulare um Company-Selektor erweitern
|
||||
3. Activity-Liste komplett laden (UI-Button "Alle anzeigen")
|
||||
4. Kanban-Board fuer Vorgaenge (Drag & Drop Stage-Wechsel)
|
||||
5. E2E-Tests schreiben
|
||||
6. Production-Build testen (multi-stage Dockerfile)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue