Add S3-compatible storage backend (B2, MinIO, AWS S3)
Introduces a StorageBackend interface with local filesystem and S3 implementations. The StorageService delegates raw I/O to the backend while keeping validation, encryption, and URL generation unchanged. Backend selection is config-driven: set B2_ENDPOINT + B2_KEY_ID + B2_APP_KEY + B2_BUCKET_NAME for S3 mode, or STORAGE_UPLOAD_DIR for local mode. STORAGE_USE_SSL=false for in-cluster MinIO (HTTP). All existing tests pass unchanged — the local backend preserves identical behavior to the previous direct-filesystem implementation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -138,15 +138,33 @@ type SecurityConfig struct {
|
||||
TokenRefreshDays int // Token must be at least this many days old before refresh (default 60)
|
||||
}
|
||||
|
||||
// StorageConfig holds file storage settings
|
||||
// StorageConfig holds file storage settings.
|
||||
// When S3Endpoint is set, files are stored in S3-compatible storage (B2, MinIO).
|
||||
// When S3Endpoint is empty, files are stored on the local filesystem using UploadDir.
|
||||
type StorageConfig struct {
|
||||
UploadDir string // Directory to store uploaded files
|
||||
BaseURL string // Public URL prefix for serving files (e.g., "/uploads")
|
||||
// Local filesystem settings
|
||||
UploadDir string // Directory to store uploaded files (local mode)
|
||||
BaseURL string // Public URL prefix for serving files (e.g., "/uploads")
|
||||
|
||||
// S3-compatible storage settings (B2, MinIO)
|
||||
S3Endpoint string // S3 endpoint (e.g., "s3.us-west-004.backblazeb2.com" or "minio:9000")
|
||||
S3KeyID string // Access key ID
|
||||
S3AppKey string // Secret access key
|
||||
S3Bucket string // Bucket name
|
||||
S3UseSSL bool // Use HTTPS (true for B2, false for in-cluster MinIO)
|
||||
S3Region string // Region (optional, defaults to "us-east-1")
|
||||
|
||||
// Shared settings
|
||||
MaxFileSize int64 // Max file size in bytes (default 10MB)
|
||||
AllowedTypes string // Comma-separated MIME types
|
||||
EncryptionKey string // 64-char hex key for file encryption at rest (optional)
|
||||
}
|
||||
|
||||
// IsS3 returns true if S3-compatible storage is configured
|
||||
func (c *StorageConfig) IsS3() bool {
|
||||
return c.S3Endpoint != "" && c.S3KeyID != "" && c.S3AppKey != "" && c.S3Bucket != ""
|
||||
}
|
||||
|
||||
// FeatureFlags holds kill switches for major subsystems.
|
||||
// All default to true (enabled). Set to false via env vars to disable.
|
||||
type FeatureFlags struct {
|
||||
@@ -270,6 +288,12 @@ func Load() (*Config, error) {
|
||||
Storage: StorageConfig{
|
||||
UploadDir: viper.GetString("STORAGE_UPLOAD_DIR"),
|
||||
BaseURL: viper.GetString("STORAGE_BASE_URL"),
|
||||
S3Endpoint: viper.GetString("B2_ENDPOINT"),
|
||||
S3KeyID: viper.GetString("B2_KEY_ID"),
|
||||
S3AppKey: viper.GetString("B2_APP_KEY"),
|
||||
S3Bucket: viper.GetString("B2_BUCKET_NAME"),
|
||||
S3UseSSL: viper.GetString("STORAGE_USE_SSL") == "" || viper.GetBool("STORAGE_USE_SSL"),
|
||||
S3Region: viper.GetString("B2_REGION"),
|
||||
MaxFileSize: viper.GetInt64("STORAGE_MAX_FILE_SIZE"),
|
||||
AllowedTypes: viper.GetString("STORAGE_ALLOWED_TYPES"),
|
||||
EncryptionKey: viper.GetString("STORAGE_ENCRYPTION_KEY"),
|
||||
|
||||
Reference in New Issue
Block a user