Storage Module
The Storage module manages user-owned storage provider configurations (S3 buckets, GCS buckets, local-FS roots, Dropbox, Google Drive, etc.) and bridges them to the storage.Provider runtime backends used by the Media module. The module owns configuration — credentials, OAuth tokens, encryption — and delegates byte movement to the pkg/storage provider implementations. Each user can have multiple configured providers and exactly one default.
Class Diagram
Request Flow
- CRUD path → Standard Controller → Service → Repository chain for storage-provider records.
- OAuth path → For providers that need delegated auth (Google Drive, Dropbox),
InitiateOAuthreturns an authorization URL;OAuthCallbackexchanges the code for tokens, encrypts the refresh token, and stores it on the provider record. - TestConnection → Service builds a transient
Providervia the factory and runs a no-opStat/Listto validate credentials before persisting. - Runtime resolution → The Media module calls
GetProviderForUser(orGetDefaultProviderfor system uploads) to obtain a ready-to-streamstorage.Provider.
Key Components
Controller
- Pure CRUD plus three operational endpoints:
GetCurrent(which provider this user uses by default),GetUsage(quota/used bytes), andTestConnection(round-trip credential check). - OAuth endpoints are isolated to providers that require it — direct-credential providers (S3 access keys, local FS) bypass these.
Service
GetProviderForUseris the runtime bridge: it loads the user’s chosen storage-provider config, decrypts secrets, and returns astorage.Providerinstance the Media module can stream to.GetDefaultProviderreturns the system-wide fallback (typically local FS) used when a user hasn’t configured one yet.
Repository
Stores storage_providers rows: ID, owner, type slug, encrypted config JSON, OAuth token reference, last-tested timestamp.
Special Behaviors
Encrypted-at-rest credentials
Every persisted provider config (S3 secret keys, OAuth refresh tokens, etc.) is encrypted with the platform’s pkg/crypto AEAD before hitting the database. Decryption happens lazily — only when GetProviderForUser is called to instantiate a runtime Provider. Reads of the bare config JSON via GET /storage-providers/{id} redact secret fields.
OAuth flow isolation
Providers that need OAuth (Google Drive, Dropbox) go through InitiateOAuth → OAuthCallback. The state token is HMAC-signed (binds the redirect to the calling user) and short-lived (5 minutes). Direct-credential providers (S3 access key + secret, local FS root) bypass these endpoints entirely. The OAuth code path is fully separate from the CRUD code path so a future provider that uses neither (e.g. mTLS-authed object stores) can land without disturbing existing flows.
Runtime bridge to Media
GetProviderForUser(ctx, userID, providerType) is the only way the rest of the platform obtains a storage.Provider instance. The Blobs module wires this in via the StorageProviderGetter interface (a deliberate inversion to break the circular import). The Media module calls it directly. This single chokepoint means future cross-cutting concerns (rate limiting per provider, quota enforcement, audit logging on byte movement) all land in one place.
SDK Surface
StorageService—create,getById,list,update,delete,getCurrent,getUsage,testConnection,initiateOAuth.StorageProvider,StorageProviderType— wire shapes.InitiateOAuthRequest/InitiateOAuthResponse— for delegated-auth providers.actions/storage— undo/redo-aware actions.
Cross-Module Integration
| Module | Relationship |
|---|---|
| Media | Calls GetProviderForUser to obtain a runtime backend; never touches storage_providers directly. |
| Blobs | Holds a StorageProviderGetter set post-construction; uses it to clean up files on blob hard-delete. |
| Users | Each storage_providers row is owned by a user; deletes cascade. |
API Reference
See the interactive API reference /storage-providers tag for live examples, including the OAuth handshake.