---
name: project-sap-mock-fixtures
description: SAP-Abgleich-Testfixtures + symmetrische Mail-Rettung — FERTIG inkl. E2E (Stand 2026-06-02).
metadata: 
  node_type: memory
  type: project
  originSessionId: ff64bed0-7915-4ef2-bc0d-c7c4af6a44ac
---

**Erledigt 2026-06-02** — Branch `test/migration-sap-fixtures` (3 Commits: a92ba63 Rehydrator-Spec-Nachzug zu 0aab04e, 7bd0727 Fixtures+Rescue, d2b9475 E2E). Alle 61 Tests in plato-customer-be grün.

**Was gebaut wurde:**
- `data/master-20.json` — 20 saubere Originale aus `data/customer.db` (echte Namen/Mails/craft_seller), erzeugt mit `scripts/build-master.mjs` (skalierbar: `node scripts/build-master.mjs 500`).
- `scripts/build-fixtures.mjs` → `data/fixtures/migration-source.sqlite` (20, Legacy-Schema, Fall-Marker in `opt1` ausgeschrieben) + `sap-master.sqlite` (10 SAP-Matches) + `expectations.json` (Test-Vertrag je customer_number).
- Aufteilung der 10 SAP-Seite: 2 abw. E-Mail (Fall A/B), 2 abw. Adresse, 1 beides, 2 Stammdaten-Korrektur, 3 identisch. Die anderen 10 sind reine Migrationssätze (origin=PlaTo). Match läuft NUR über `customer_number` → echte Nummer bleibt, Testfall steckt in `opt1` (nicht in der Nummer!).

**Logik-Änderung (Wegwerf-Code) `sap-adapter.ts overwriteWithSap`:** verdrängte Kunden-Mail wird als Kontakt gerettet; liegt sie schon an einem Kontakt → stattdessen die SAP-Mail retten (`origin='SAP'`). So überleben beide Mails immer als Kontakt. (Marcus' Wunsch: Trigger am Kunden, Kontakt-Check sinnvoll, dann SAP-Mail restaurieren.)

**Zwei Knackpunkte (nicht offensichtlich):**
- SAP-Query liefert `verband_nummer = customer_number` IMMER mit + baut craft_seller aus der kv neu → sonst ist jeder Match fälschlich `changed`. Quelle setzt für die 10 deshalb `verband_nummer = customer_number` und craft_seller = Original (round-trippt).
- E2E-Seam: `getFromSap` mocken, dahinter `SapMockService.buildCustomerXml` + `sapXmlToCustomer` (jetzt exportiert), `SAP_MOCK_DB`-Env auf die Fixture-DB. So läuft SAP echt durch, nur HTTP raus. Test: `apps/plato-customer-be/src/migration/sap-fixtures.e2e.spec.ts`.

**Hinweis:** Fixtures enthalten echte Kunden-/Außendienst-PII, liegen dauerhaft in der Historie (war so gewollt). Nächste Prio bleibt Sync-Tests/Refactoring, siehe [[project-naechste-schritte]].

**Update 2026-06-08:**
- `test/migration-sap-fixtures` ist Vorfahr von `development` → Fixtures + E2E + Lift liegen alle auf `development` (dort fixen, nicht auf dem alten Branch).
- **mobile-Gap gefixt** (commit `8001207` auf `development`): `liftSingleContactPhoneToMobile` (Wegwerf, util `contact-phone.util.ts`, kam in `8e98c10` NACH den Fixtures) hebt die einzige gepflegte Kontaktnummer auf `customer.mobile` — der E2E prüfte das Feld nicht. Jetzt `expectedMobile` je importiertem Satz in `expectations.json` (7 geliftet, 10 leer) + Assertion. Test grün (26 in der spec, 80 gesamt).
- **DEV-Mock = fixer Stamm (dauerhaft, NICHT im Repo):** Live gegen DEV verifiziert (Browser-Import → echte Postgres, alle Erwartungen grün: 17/10-SAP/7-PlaTo/20/20/3). Dafür das geteilte `backend`-Deployment (ns `1401-plato-development`) so umgebaut und **bewusst stehen gelassen** (Marcus: „fixer bekannter Stamm"): ConfigMap `sap-mock-master` (= `sap-master.sqlite`, 40 KB) als Volume gemountet unter `/app/apps/sap-mock/sap-master.sqlite` + env `SAP_MOCK_DB` darauf. `SAP_MOCK_ENABLED=true` ohnehin gesetzt. Die Image-`crm.sqlite` (30 MB generisch) bleibt daneben ungenutzt. Image war `backend:0.28.2`.
