refactor: audit and reduce HetznerStorageClient wrapper duplication
Summary
app/utils/hetzner_storage.py is a 626-line wrapper over the MinIO Python SDK. A significant portion of this code duplicates functionality already provided by the SDK — presigned URL generation, bucket creation, object existence checks, and metadata attachment. This creates a maintenance surface that must track SDK changes.
Problem
- Presigned URL generation (GET and PUT) is re-implemented when
minio.Client.presigned_get_object/presigned_put_objectalready exist - Bucket existence and auto-creation logic reimplements
minio.Client.bucket_exists+make_bucket - A custom
ProgressLoggingThreadclass is used for upload progress — the MinIO SDK'sprogressparameter accepts athreading.Threadsubclass natively - Object metadata attachment mirrors the SDK's
metadataparameter input_object - Global singleton pattern with manual initialization is unnecessary — dependency injection via FastAPI's
Dependsis idiomatic
Long-term consideration: boto3 (Apache 2.0) is the industry-standard S3 SDK. Hetzner Object Storage is S3-compatible, so boto3 with endpoint_url works directly. boto3 has broader tooling, more active maintenance, and a larger community than the MinIO SDK for client-side use.
Proposed Actions
-
Immediate: Audit each method in
HetznerStorageClientagainst the MinIO SDK docs and remove any method that directly wraps an existing SDK call without adding logic -
Short-term: Replace the singleton pattern with a FastAPI dependency (
Depends(get_storage_client)) -
Medium-term: Evaluate migrating from
minioSDK toboto3for portability and ecosystem breadth
Impact
| Dimension | Current | After (Step 1+2) |
|---|---|---|
| LOC | 626 lines | Est. 200–300 lines |
| SDK drift risk | High (manual reimplementation) | Low (delegate to SDK) |
| Testability | Requires mocking entire class | Mock at SDK boundary |
| Portability | MinIO SDK only | boto3 path opens S3-compatible options |
| FastAPI integration | Global singleton | Idiomatic Depends injection |
Files Affected
-
app/utils/hetzner_storage.py— audit and reduce - Any service/task files importing
HetznerStorageClient— update instantiation if DI pattern is adopted -
pyproject.toml— optionally addboto3if migration is chosen