fix(quick-260909-ab3): kollidierende AD-Konten werden angelegt, nur ohne Adresse

- User.email auf optional gestellt (Migration geschrieben, NICHT
  ausgefuehrt); Eindeutigkeitsindex unangetastet, NULL bleibt in Postgres
  je verschieden
- Neuer Kollisionsentscheider (resolveEmailForWrite) in ldap.service.ts:
  eine bereits vergebene Adresse wird nie umgehaengt (T-Q3-01) — das
  zuerst angelegte Konto behaelt sie, jedes weitere Konto entsteht ohne
  Adresse (gesperrte Nutzerentscheidung 2026-09-09, WINDOWS #15)
- Entscheider in upsertMappedUser (Sync) UND importUsersByDn (Handimport)
  verdrahtet, damit der zweite Anlageweg nicht als Luecke bestehen bleibt
- LdapSyncResult um emailConflicts/skippedNoLogin/entryFailures erweitert;
  rohe ORM-Ausnahmetexte gehen nur noch an logger.error, nie in den
  Bericht (T-Q3-02)
- UserService.create nimmt die Adresse optional entgegen; Tender-Digest
  und Instant-Alert ueberspringen Empfaenger ohne Adresse (continue)
- Fuenf neue Testfaelle vorab gegen den unveraenderten Bestand rot
  gelaufen (erwartete Ursachen bestaetigt); 651/651 API-Tests gruen,
  prisma validate und type-check sauber

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
This commit is contained in:
2026-09-09 07:48:37 +02:00
parent e8c2411e60
commit 1222951af6
7 changed files with 324 additions and 15 deletions
@@ -0,0 +1,18 @@
-- WINDOWS #15: der AD-Sync liess Konten, deren Adresse bereits einem anderen
-- Konto gehoert (vier Funktionskonten mit geteilter mail-Adresse gemessen),
-- wegen der Pflicht auf "User.email" komplett unimportiert liegen -- ohne
-- verstaendliche Rueckmeldung.
--
-- Gesperrte Nutzerentscheidung vom 2026-09-09 (nicht verhandelbar): ein
-- Konto mit bereits belegter Adresse wird trotzdem angelegt, nur eben OHNE
-- Adresse. Die Anmeldung laeuft ueber den Benutzernamen, nicht ueber die
-- Adresse -- das Konto bleibt voll funktionsfaehig, lediglich
-- Benachrichtigungen per E-Mail erreichen es nicht. Wer eine Adresse zuerst
-- belegt, behaelt sie unveraendert.
--
-- Der Eindeutigkeitsindex auf "email" wird NICHT angefasst: PostgreSQL
-- behandelt NULL-Werte in einer Eindeutigkeitsregel als jeweils verschieden,
-- mehrere Konten ohne Adresse sind also weiterhin erlaubt. Bestandszeilen
-- bleiben unangetastet -- jedes bereits angelegte Konto behaelt seine
-- heutige Adresse.
ALTER TABLE "User" ALTER COLUMN "email" DROP NOT NULL;
+1 -1
View File
@@ -29,7 +29,7 @@ enum Role {
model User {
id String @id @default(uuid())
username String @unique
email String @unique
email String? @unique
passwordHash String?
displayName String?
role Role @default(USER)