Neue Datei storage/archivekey.go: ArchiveKey(mailbox, sentAt, messageID, partIndex) liefert den Objektschlüssel nach dem Schema Postfach/Jahr innerhalb des bereits mandantenspezifischen Buckets (ARC-06) — additiv neben dem bestehenden, flachen ObjectKey (ARC-01), das für bestehende Aufrufer (mailapi/INT-01) unverändert bleibt. ArchiveYearPrefix(mailbox, year) ist der eigenständig berechenbare Präfix eines Postfach-Jahrs — Grundlage für spätere Retention-Regeln ohne Migration. Fehlendes Postfach bzw. Null-Sendedatum führen zu dokumentierten Fallback-Segmenten statt einem Ablagefehler; ArchiveKey liefert bewusst keinen error, da es strukturell keinen Fehlerfall gibt. Alle drei Pflichtprüfungen: mehrjähriger Import erzeugt nachweislich getrennte Jahresordner, fehlendes Postfach/Sendedatum nutzt den dokumentierten Fallback (inkl. Test gegen mehrere ungewöhnliche Eingaben), sowie ergänzend ein Nachweis für Akzeptanzkriterium 2 (Retention-Präfix trifft exakt die zuvor abgelegten Schlüssel desselben Postfach-Jahrs). Pflichtprüfung 3 (Stichprobenreview durch zweite Person) bleibt strukturell offen, im Prüfprotokoll dokumentiert (analog zu ING-10/QA-04/QA-02). go build/go vet/golangci-lint clean, gesamtes Mail-Modul regressionsfrei getestet.
96 lines
4.1 KiB
Markdown
96 lines
4.1 KiB
Markdown
# 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).
|