Goal
Uploaded files (GeoJSON, CSV, Shapefile, …) are written to a local UPLOAD_DIR. This forces the API and worker to share a filesystem, which is awkward as soon as they run on different hosts or in different containers. Switching to an S3-compatible backend removes that constraint and enables horizontal scaling of workers.
Scope
- A
FileStorage interface with two implementations:
LocalFileStorage (current behaviour, default)
S3FileStorage (any S3-compatible: AWS S3, MinIO, Cloudflare R2, Scaleway, OVH Object Storage)
- Backend selected via
STORAGE_BACKEND=local|s3 env var
- S3 config via env:
S3_BUCKET, S3_ENDPOINT, S3_REGION, S3_ACCESS_KEY, S3_SECRET_KEY, S3_FORCE_PATH_STYLE
- API stores the file via the
FileStorage, queues a job carrying the storage URI; worker reads it back through the same interface
Acceptance criteria
Out of scope
- Automatic migration of files already on disk (one-time operator task)
- Pre-signed URLs for direct browser uploads (could come later)
Goal
Uploaded files (GeoJSON, CSV, Shapefile, …) are written to a local
UPLOAD_DIR. This forces the API and worker to share a filesystem, which is awkward as soon as they run on different hosts or in different containers. Switching to an S3-compatible backend removes that constraint and enables horizontal scaling of workers.Scope
FileStorageinterface with two implementations:LocalFileStorage(current behaviour, default)S3FileStorage(any S3-compatible: AWS S3, MinIO, Cloudflare R2, Scaleway, OVH Object Storage)STORAGE_BACKEND=local|s3env varS3_BUCKET,S3_ENDPOINT,S3_REGION,S3_ACCESS_KEY,S3_SECRET_KEY,S3_FORCE_PATH_STYLEFileStorage, queues a job carrying the storage URI; worker reads it back through the same interfaceAcceptance criteria
FileStorageinterface andLocalFileStoragerefactor (no behavioural change)S3FileStorageusing@aws-sdk/client-s3v3STORAGE_BACKENDenv vardocs/guide/configuration.mdand a deployment example (compose with MinIO)Out of scope