Files
nexarch/mail/docs/ARC-03-PRUEFPROTOKOLL.md
sysopsandClaude Sonnet 5 704b64fe27 ARC-03: dublettenerkennung-e-mail
- mail/internal/dedup/hash.go: HashAndBuffer, SHA-256 auf Klartext VOR
  Verschluesselung (ARC-02), liefert erneut lesbaren Reader zurueck.
- mail/internal/dedup/store.go: Store (Postgres, tenant_slug fest im
  Primaerschluessel gebunden), Register: Duplikat referenziert Original
  statt redundant zu speichern.
- Alle 3 Pflichtpruefungen real bestanden (siehe
  mail/docs/ARC-03-PRUEFPROTOKOLL.md): Duplikat aus zwei Quellen
  erkannt, zwei Mandanten mit identischem Inhalt nicht verknuepft,
  knapp unterschiedliche Nachricht korrekt nicht erkannt.
- Kein Umbau: internal/storage, internal/crypto, internal/encstorage
  unveraendert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 00:12:43 +02:00

3.0 KiB
Raw Permalink Blame History

ARC-03 Prüfprotokoll: Dublettenerkennung E-Mail

Voraussetzung ARC-01 (Mail, Fertig).

Umsetzung

  • mail/internal/dedup/hash.goHashAndBuffer(plaintext io.Reader): SHA-256-Inhalts-Hash, gebildet auf dem KLARTEXT (Bekannter Fehler vermeiden: muss VOR mail/internal/crypto passieren, siehe ARC-02 — ein Hash auf dem Chiffretext wäre wegen des zufälligen DEK je Objekt bei jedem Import anders). Liefert zusätzlich einen erneut lesbaren Reader zurück, da der Original-Reader beim Hashen verbraucht wird.
  • mail/internal/dedup/store.goStore.Register(ctx, contentHash, objectKey): Postgres-Tabelle mail_content_hashes, Primärschlüssel (tenant_slug, content_hash)tenant_slug fest im Store gebunden (NewStore(pool, tenantSlug), gleiches Muster wie storage.Service/encstorage.Service), nicht nur Konvention. ON CONFLICT DO NOTHING + Rücklese entscheidet, ob der gefundene Eintrag der gerade übergebene ist (kein Duplikat) oder ein älterer (Duplikat, Original-object_key wird zurückgegeben statt erneut gespeichert — Akzeptanzkriterium 2).
  • Kein Umbau: mail/internal/storage/mail/internal/crypto/ mail/internal/encstorage unverändert (git diff --stat bleibt für alle drei leer). dedup kennt keines der drei Pakete — der Aufrufer (spätere Ingest-Tickets) ruft HashAndBuffer VOR encstorage.Put auf.

Prüfungen

# Prüfung Ergebnis
1 Test: dieselbe Nachricht aus zwei Quellen wird als Duplikat erkannt bestanden TestRegister_SameMessageFromTwoSourcesIsDuplicate: gleicher Hash, zwei verschiedene object_key ("quelle-1/objekt", "quelle-2/objekt") — zweite Registrierung liefert real isDuplicate=true und referenziert das Original quelle-1/objekt
2 Test: zwei Mandanten mit identischem Mailinhalt werden nicht fälschlich verknüpft bestanden TestRegister_SameContentTwoTenantsNotLinked: zwei Store-Instanzen mit unterschiedlichem tenantSlug, IDENTISCHER Hash — beide Registrierungen liefern real isDuplicate=false, keine Verknüpfung über die Mandantengrenze
3 Test mit knapp unterschiedlichen Nachrichten bestätigt korrekte Nicht-Erkennung bestanden TestHashAndBuffer_SlightlyDifferentContentDifferentHash: zwei Nachrichten, die sich nur im letzten Zeichen unterscheiden (. vs ,) — real unterschiedlicher SHA-256-Hash

Build/Test-Ergebnis (192.168.1.131)

go build ./...  -> clean
go vet ./...    -> clean
golangci-lint run ./...  -> 0 issues
TEST_TENANT_DSN=postgresql://nexarch_test:***@localhost:5432/tenant_acme?sslmode=disable \
  go test ./... -v -p 1  -> alle Pakete bestanden, inkl. internal/dedup (5 Tests)

Testdaten (mail_content_hashes, Zeilen mit tenant_slug beginnend mandant-arc03-) werden von den Tests selbst über t.Cleanup entfernt.

Gesamtergebnis

Bestanden. Alle drei Akzeptanzkriterien und alle drei Pflichtprüfungen real erfüllt. Entsperrt SRC-01, SRC-02, SRC-07.