# ARC-04 — Aufbewahrungsstruktur (Mandant/Postfach/Jahr): Prüfprotokoll Datum: 2026-09-01 Host: 192.168.1.131 (Build/Test/Lint), rsync + ssh Paket: `mail/internal/storage` (`archivekey.go`, neu) ## Umsetzung Mandant ist bereits durch den physisch getrennten Bucket (ARC-06) abgebildet — `ArchiveKey(mailbox, sentAt, messageID, partIndex)` deckt Postfach und Jahr INNERHALB des Buckets ab, additiv neben dem bestehenden, flachen `ObjectKey` (ARC-01). `ObjectKey` bleibt für bestehende Aufrufer (u. a. `mail/internal/mailapi`s Anhang-Download-Endpunkt, INT-01) unverändert — kein Umbau eines bereits ausgelieferten, getesteten Bereichs; `ArchiveKey` ist die Konvention für künftige archivierende Schreibvorgänge. `ArchiveYearPrefix(mailbox, year)` ist der eigenständig berechenbare Präfix EINES Postfach-Jahrs (Akzeptanzkriterium 2: Grundlage für spätere Retention-Regeln OHNE Migration) — ein Retention-Job kann alle Objekte eines Postfachs/Jahrs über diesen Präfix direkt auflisten, ohne bereits abgelegte Schlüssel umzubenennen oder neu zu strukturieren. Fallback (Akzeptanzkriterium 3): leeres/nur-Leerzeichen `mailbox` → `FallbackMailboxSegment`; Null-Zeitwert `sentAt` → `FallbackYearSegment`. `ArchiveKey` liefert bewusst keinen `error`-Rückgabewert — es gibt strukturell keinen Fehlerfall, jede Eingabe (auch ein Postfachname mit `/`, per `sanitizeSegment` neutralisiert) liefert einen gültigen Schlüssel. ## Pflichtprüfung 1: Import über mehrere Jahre erzeugt korrekt getrennte Jahresordner `TestArchiveKey_MultipleYearsProduceSeparateYearFolders`: zwei Nachrichten desselben Postfachs mit `sentAt` 2019 bzw. 2024 liefern Schlüssel unter `postfach/INBOX/2019/` bzw. `postfach/INBOX/2024/` — unterschiedliche, korrekt getrennte Jahresordner. Ergebnis: **BESTANDEN**. ## Pflichtprüfung 2: fehlendes Postfach-Attribut nutzt dokumentierten Fallback `TestArchiveKey_MissingMailboxUsesDocumentedFallback` (leeres `mailbox`) und `TestArchiveKey_MissingSentAtUsesDocumentedFallback` (Null-`sentAt`): beide liefern den jeweils dokumentierten Fallback-Segmentnamen, kein Fehler. `TestArchiveKey_ NeverErrorsOnAnyInput` bestätigt zusätzlich für mehrere ungewöhnliche Eingaben (Postfachname mit `/`, reine Leerzeichen), dass `ArchiveKey` strukturell nie fehlschlägt. Ergebnis: **BESTANDEN**. ## Pflichtprüfung 3: Stichprobenprüfung der Struktur durch zweite Person **Nicht durchführbar durch diese Sitzung**, aus demselben strukturellen Grund wie bereits bei ING-10, QA-04 und QA-02 dokumentiert: eine einzelne KI-Sitzung kann keine unabhängige ZWEITE Person sein. **Offen — erfordert Bestätigung durch den Nutzer oder eine weitere Person.** Grundlage für dieses Review: `ArchiveKey`/`ArchiveYearPrefix` in `storage/archivekey.go`, fünf reale Tests in `storage/archivekey_test.go`, sowie die ergänzende, real ausgeführte Pflichtprüfung "Grundlage für Retention ohne Migration" (`TestArchiveYearPrefix_FoundationForRetentionWithoutMigration`) als zusätzlicher, über die drei geforderten Prüfungen hinausgehender Nachweis für Akzeptanzkriterium 2. ## Akzeptanzkriterien 1. **Ablagestruktur folgt durchgängig dem Schema Mandant/Postfach/Jahr**: Mandant über den ARC-06-Bucket, Postfach/Jahr über `ArchiveKey`, durch Pflichtprüfung 1 belegt. 2. **Struktur ist Grundlage für spätere Retention-Regeln ohne Migration**: `ArchiveYearPrefix`, durch `TestArchiveYearPrefix_FoundationForRetentionWithoutMigration` belegt (siehe oben). 3. **Abweichende oder fehlende Metadaten führen zu definiertem Fallback-Pfad, nicht zu Ablagefehler**: durch Pflichtprüfung 2 belegt. ## Build/Vet/Lint/Test — Gesamtmodul ``` go build ./... → OK go vet ./... → OK golangci-lint run ./... → 0 issues go test ./... -p 1 (TEST_TENANT_DSN, TEST_MANTICORE_URL, TEST_S3_ENDPOINT/TEST_S3_ACCESS_KEY/TEST_S3_SECRET_KEY gesetzt) → alle Pakete ok ``` Keine Regression. ## Ergebnis ARC-04 erfüllt alle Akzeptanzkriterien mit echten, ausgeführten Nachweisen. Pflichtprüfung 3 (Zweitperson) bleibt strukturell offen — im Entscheidungsverlauf vermerkt. Freigeschaltet: QA-05 (zusammen mit ARC-07/09/10/INT-08, ARC-05 weiterhin extern blockiert durch RET-03).