Capability surfaces

Storage as a capability surface.

One IStorageProvider contract. 14 sub-interfaces declare capability granularly — Core, Stream, Urls, Copy, Metadata, Directory, MultiPart, Query, Version, Batch, Move, AccessControl, ProviderIdentity. Vadyl branches on declared caps, never assumes feature parity. Signed URLs for browser-direct uploads. Multi-part for large files. Quota enforcement and metering ride canonical events.

Five vendors. One contract.

Switch by changing the binding. Your code does not change.

S3 · Azure Blob · GCS

Three cloud providers shipped. Vendor-neutral upload / download / copy / move / signed URL / multi-part. Capability declarations expose what each one does natively vs runtime-supplemented.

Local Disk · MinIO

Local for development and self-hosted. MinIO for S3-compatible storage on your own infrastructure. Same canonical surface — your code does not branch.

14 sub-interface declarations

Core / Stream / Urls / Copy / Metadata / Directory / MultiPart / Query / Version / Batch / Move / AccessControl / ProviderIdentity. Capability mismatches surface explicitly, never silent.

Signed URLs

Per-object pre-signed URLs for browser-direct uploads and downloads. Time-bounded, capability-gated, audited through canonical observability.

Multi-part uploads

Large-file resumable uploads via canonical IMultiPartOperations. Chunked, parallel, fail-resumable. Same client API across vendors.

Quota + metering

StorageEventEmitter routes through IUsageMeteringService for billing attribution and IQuotaEnforcementService for hard caps. Rides the canonical event substrate; no second metering pipeline.

Realtime + audit

Object create / update / delete fan out to realtime subscribers (field names only). Every storage mutation surfaces in the canonical observability relay.

Per-tenant path isolation

ProjectStorageNamespace.PhysicalPrefix derives from immutable project IDs (anti-pattern #32). No slug-based paths. Storage namespaces are forever stable.

Branchable bindings

Storage provider bindings are scope-chain inherited. A staging branch can point S3 at a different bucket without touching production. Branch and environment, not feature flags.

5
Vendors

S3 · Azure Blob · GCS · Local Disk · MinIO

14
Sub-interface declarations

Granular capability

Immutable IDs
Path isolation

Anti-pattern #32 codified

Built-in
Quota + metering

Through canonical events

Object storage without lock-in.

Bind a vendor. Upload through signed URLs. Multi-part for large files. Switch the binding for staging. Vadyl handles the wiring, the audit, the quota.