ARC-01: objekt-speicher-anbindung-fuer-mails-anhaenge

- mail/internal/storage: LocalDriver/S3Driver (bewaehrtes Muster aus
  DMS FDN-03, bewusste Neuimplementierung - Mail kann DMS nicht
  importieren), ObjectKey mit festem Pfadschema
- Service.Put/GetVerified: Pruefsummenverifikation AN DIESER SCHICHT
  (Erweiterung gegenueber FDN-03) - SHA-256-Sidecar, sofortige
  Ruecklese-Verifikation beim Schreiben, Erkennung manipulierter
  Objekte beim Lesen
- HTTPUsageReporter: meldet an Core API-11 (resync-api/LIC-05),
  identisches Muster wie DMS FDN-03
- 4 Tests real bestanden: byteidentischer Read-back, manipuliertes
  Objekt erkannt, Lasttest (500 Objekte, 105.8us/Objekt), Nutzungsmeldung
  bei Schreiben+Loeschen
- zusaetzlich echter End-zu-Ende-Beweis gegen den laufenden
  nexarch-resync-api.service: reales Service-Credential provisioniert,
  Put->GetVerified->Delete komplett durchlaufen, usage_counters zeigt
  reales +29/-29-Delta (beide Meldungen real angewendet)

Pruefungen siehe mail/docs/ARC-01-PRUEFPROTOKOLL.md
This commit is contained in:
sysops
2026-08-30 23:43:12 +02:00
parent dff6b8b7a4
commit ee98efb51e
9 changed files with 669 additions and 1 deletions
+49
View File
@@ -0,0 +1,49 @@
// Package storage implementiert ARC-01: die Objekt-Speicher-Anbindung
// für archivierte Mails und Anhänge. Baut auf demselben bewährten
// Muster wie DMS FDN-03 auf (austauschbare Driver, LocalDriver für
// Entwicklung, S3Driver für Produktion) — Mail kann DMS' internal/
// nicht importieren (eigenständiges Go-Modul), daher eine bewusste,
// angepasste Neuimplementierung statt eines Cross-Modul-Imports.
//
// Erweiterung gegenüber FDN-03: ARC-01 verlangt Prüfsummenverifikation
// AN DIESER SCHICHT (Akzeptanzkriterium 2), nicht erst an einer
// späteren DB-Schicht — siehe service.go.
package storage
import (
"context"
"errors"
"io"
"strconv"
)
// ErrNotFound wird geliefert, wenn ein angefragtes Objekt nicht
// existiert.
var ErrNotFound = errors.New("storage: objekt nicht gefunden")
// Driver ist die EINE Schnittstelle, gegen die der Rest von Mail
// arbeitet (Akzeptanzkriterium 1). Zwei Implementierungen: LocalDriver
// (Entwicklung) und S3Driver (Produktion, S3-kompatibel).
type Driver interface {
Put(ctx context.Context, key string, r io.Reader, size int64, contentType string) (int64, error)
Get(ctx context.Context, key string) (io.ReadCloser, error)
Delete(ctx context.Context, key string) error
}
// ObjectKey liefert das feste, dokumentierte Pfadschema für einen
// Mail-Anhang/-Teil INNERHALB des bereits mandantenspezifischen
// Buckets (Akzeptanzkriterium 1) — Bucket-Trennung selbst ist Sache
// von Core TEN-01. Lesezugriff hängt NUR von messageID+partIndex ab,
// nicht vom ursprünglichen Importpfad (IMAP/SMTP/manueller Import —
// Akzeptanzkriterium 3): derselbe Key wird unabhängig davon berechnet,
// über welchen Weg die Nachricht ins System kam.
func ObjectKey(messageID string, partIndex int) string {
return "messages/" + messageID + "/parts/" + strconv.Itoa(partIndex)
}
// checksumKey ist der Sidecar-Objektschlüssel für die beim Schreiben
// berechnete Prüfsumme (siehe service.go) — liegt bewusst im selben
// Driver/Bucket wie der Inhalt, keine separate DB-Abhängigkeit nötig.
func checksumKey(key string) string {
return key + ".sha256"
}