// 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 }