Ein Driver-Interface, zwei austauschbare Treiber: LocalDriver (Entwicklung, Dateisystem, HMAC-signierte URLs) und S3Driver (Produktion, S3-kompatibel via aws-sdk-go-v2, echte presigned URLs). Pfadschema documents/<id>/ revisions/<id> innerhalb des mandantenspezifischen Buckets. Service verbindet Driver mit Nutzungsmeldung an Core LIC-05 (HTTPUsageReporter, Vertrag von internal/resync.Handler nachgebildet, DMS kann Cores internal/- Pakete als eigenes Modul nicht importieren). Auf 192.168.1.131 verifiziert, S3-Treiber gegen echtes lokal installiertes MinIO (kein Mock): Round-Trip beide Treiber, abgelaufene presigned URL real mit 403 abgewiesen (manuell zusaetzlich zum Unit-Test verifiziert), klare ErrNotFound bei fehlendem Objekt beide Treiber, Nutzungsmeldung mit korrektem Tenant/Metrik/Delta bei Put/Delete. Befund dokumentiert: Cores internal/resync.Handler (Gegenstelle fuer die Nutzungsmeldung) ist noch in keinem cmd/*/main.go verdrahtet (dieselbe Fehlerklasse wie QA-05/AUD-06) - HTTPUsageReporter daher gegen den dokumentierten Vertrag getestet, nicht gegen eine laufende Core-Instanz. Siehe dms/docs/FDN-03-PRUEFPROTOKOLL.md. golangci-lint auf v2.1.6 aktualisiert (v1.63.4 konnte go1.24-Zielstand nicht linten), .golangci.yml auf v2-Konfigurationsformat migriert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
46 lines
2.0 KiB
Go
46 lines
2.0 KiB
Go
// Package storage implementiert FDN-03: eine einheitliche Objekt-Storage-
|
|
// Abstraktion mit zwei austauschbaren Treibern (lokal fuer Entwicklung,
|
|
// S3-kompatibel fuer Produktion). Verschluesselung at rest ist NICHT
|
|
// Bestandteil dieser Kachel (siehe FDN-09) — dieses Paket legt Bytes
|
|
// unveraendert ab.
|
|
package storage
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
// ErrNotFound wird geliefert, wenn ein angefragtes Objekt nicht existiert
|
|
// (Akzeptanzkriterium/Pruefung 3: klarer Fehler statt treiberspezifischer
|
|
// Fehlertypen, die der Aufrufer sonst je Treiber unterschiedlich behandeln
|
|
// muesste).
|
|
var ErrNotFound = errors.New("storage: objekt nicht gefunden")
|
|
|
|
// Driver ist die EINE Schnittstelle, gegen die der Rest von DMS arbeitet
|
|
// (Akzeptanzkriterium 1). Zwei Implementierungen: LocalDriver (Entwicklung)
|
|
// und S3Driver (Produktion, S3-kompatibel).
|
|
type Driver interface {
|
|
// Put legt die Bytes aus r unter key ab und liefert die tatsaechlich
|
|
// geschriebene Groesse in Bytes.
|
|
Put(ctx context.Context, key string, r io.Reader, size int64, contentType string) (int64, error)
|
|
// Get liefert die Bytes unter key. Existiert key nicht, liefert Get
|
|
// ErrNotFound.
|
|
Get(ctx context.Context, key string) (io.ReadCloser, error)
|
|
// Delete entfernt das Objekt unter key. Existiert key nicht, liefert
|
|
// Delete ErrNotFound.
|
|
Delete(ctx context.Context, key string) error
|
|
// SignedURL liefert eine zeitlich begrenzte, signierte URL zum Lesen des
|
|
// Objekts (Akzeptanzkriterium 2: konfigurierbare Gueltigkeit ueber ttl).
|
|
SignedURL(ctx context.Context, key string, ttl time.Duration) (string, error)
|
|
}
|
|
|
|
// ObjectKey liefert das Pfadschema fuer ein Dokument/Revision INNERHALB des
|
|
// Mandanten-Buckets (Akzeptanzkriterium 3) — die Bucket-Trennung selbst ist
|
|
// Sache von Core TEN-01, hier geht es nur um den Pfad innerhalb eines
|
|
// bereits mandantenspezifischen Buckets.
|
|
func ObjectKey(documentID, revisionID string) string {
|
|
return "documents/" + documentID + "/revisions/" + revisionID
|
|
}
|