---
name: project_kontakt_adress_spec
description: "Geplante Spec Kontakte/Adressen — SAP-Schutz, Validierung-bei-Änderung, M:N-Removal (noch NICHT implementiert)"
metadata: 
  node_type: memory
  type: project
  originSessionId: 9ea3a233-d124-48d2-bcbd-df83326a7e21
---

Soll-Funktionen für Kontakte/Adressen, am 2026-06-09 mit Marcus festgeklopft und im Wesentlichen UMGESETZT auf `development`: 282698f Relation-Removal, f423c8f Server-Guard, 5473a2b FE-Anrede-Pflicht, 140c09f Delete-Integrationstest (Kaskade+SAP-Block), 2b16384 Orphan-Delete-Fix+Test (createOrUpdate mergte Collections falsch -> Einzel-Löschen verpuffte; jetzt Skalare mergen, Kind-Arrays explizit setzen wie batchImport). OFFEN nur noch: `deleteAll` auf eigenem Branch entfernen (s.u.); MS-EXCEL-vs-Mehrgesellschaften vertagt. Commits noch ungepusht (Push macht Marcus).

**Adressen NUR auf Kundenebene.** Kontakt↔Adresse-M:N (`contact_addresses`, JoinTable auf Contact-Seite) wird ENTFERNT — toter Code, nie befüllt, auch in Alt-DB `_contacts2addresses` = 0 Einträge. Evtl. später wieder (geringer Aufwand); dann ist offen, wie eine Adresse bei Kontakt-Neuanlage zugeordnet wird. Removal braucht Entity-Edits + TypeORM-Migration; bringt die latente `addressId ON DELETE NO ACTION`-Falle weg.

**SAP-Schutz (origin === 'SAP' = read-only, „aus SAP hinterfragen wir gar nichts"):**
- UI schützt schon: `canEditCustomer` (CustomerDetails.vue:163), `canEditItem` (useCardListManageer.ts:49) — disabled Edit+Delete für Nicht-PlaTo/Excel.
- Server hat KEINEN Guard (nur `enforceOwnership` für owner_country). Zu bauen: `enforceSapProtection` in `CustomerCoreService.createOrUpdate` (NICHT in `batchImport` — das ist die Migration), Delete-Guard in `delete()` (SAP-Kunde nicht löschbar).
- origin der Kinder aus DB-Stand ableiten (by id), nicht aus Payload — sonst spooft FE `origin: 'PlaTo'`. SAP-Kind verändert/fehlend → Reject.

**Cascade:** Plato-Kunde löschen → Kontakte+Adressen mit (existiert via OneToMany `cascade`/`orphanedRowAction`, nichts zu tun). `deleteAll()`/`customer.delete.list` ist reines Test-Werkzeug → auf PROD raus/nicht erreichbar, KEIN Guard nötig.

**Contact-Felder (ALLE bleiben):** contact_type, form(=Anrede), title, firstname, lastname, fullname, position, department, phone, mobile, fax, mail, website, contact_number, comment. `addresses` RAUS.
- `fullname` wird abgeleitet = `firstname + " " + lastname`, nicht editierbar (heute freies Feld CustomerContacts.vue:39).

**Validierung:**
- Pflicht = Anrede(form)/firstname/lastname/mail. Keine DB-NOT-NULL, nur Validierungslayer.
- Greift NUR für origin PlaTo. SAP nie. MS EXCEL = vorerst PlaTo (Mehrgesellschaften später klären).
- PlaTo entsteht auch beim SAP-Import (Rettungskontakt aus abweichender Mail, `guessNameFromEmail`) → u.U. unvollständig. Daher: Pflicht NICHT bei Anlage, sondern erst bei ÄNDERUNG erzwingen — nur neue (FE) oder ggü. DB veränderte Kontakte prüfen.
- „Verändert" = gleicher Diff wie SAP-Guard, via `contactProjection`/`addressProjection` aus `content-hash` (eine Wahrheit).

Beispiel-Stores (Klartext) für Tests: `ressources/outbox.v1.json`, `ressources/inflight.v1.json`. Siehe auch [[project_naechste_schritte]].
