package filesvc import ( "context" "errors" "time" ) /*** Domain ***/ type ID = int64 type File struct { ID ID `json:"id"` Name string `json:"name"` // weitere Metadaten optional: Size, Hash, Owner, Tags, ... UpdatedAt int64 `json:"updatedAt"` // UnixNano für LWW Deleted bool `json:"deleted"` // Tombstone für Mesh-Delete } /*** Fehler ***/ var ( ErrNotFound = errors.New("file not found") ErrBadInput = errors.New("bad input") ErrConflict = errors.New("conflict") ErrForbidden = errors.New("forbidden") ErrTransient = errors.New("transient") ) /*** Basis-API (lokal nutzbar) ***/ type Store interface { // Lesen & Auflisten Get(ctx context.Context, id ID) (File, error) List(ctx context.Context, next ID, limit int) (items []File, nextOut ID, err error) // Mutationen mit LWW-Semantik (UpdatedAt wird intern gesetzt, außer bei ApplyRemote) Create(ctx context.Context, name string) (File, error) Rename(ctx context.Context, id ID, newName string) (File, error) Delete(ctx context.Context, id ID) (File, error) } /*** Mesh-Replikation ***/ type Snapshot struct { Items []File `json:"items"` } type Replicable interface { // Snapshot liefert den vollständigen aktuellen Stand (inkl. Tombstones). Snapshot(ctx context.Context) (Snapshot, error) // ApplyRemote wendet LWW an. next-ID wird dabei korrekt fortgeschrieben. ApplyRemote(ctx context.Context, s Snapshot) error } /*** Events (optional) ***/ // ChangeEvent kann genutzt werden, um proaktive Mesh-Pushes zu triggern. // Bei deiner Pull-basierten Anti-Entropy ist es optional. type ChangeEvent struct { At time.Time Item File } // Watch gibt Änderungen aus; close(stop) beendet den Stream. // Eine Noop-Implementierung ist erlaubt, wenn Pull-Sync genügt. type Watchable interface { Watch(stop <-chan struct{}) <-chan ChangeEvent } /*** Kombiniertes Interface ***/ type MeshStore interface { Store Replicable Watchable // optional – kann Noop sein }