feat: add S3-compatible storage backend #6

Merged kenneth.nym.sh
targeting main from t3/s3-compatible-storage
Merged opened by and assigned to kenneth.nym.sh
targeting main from t3/s3-compatible-storage

Selecting S3 storage now starts the backend and supports uploads, downloads, metadata updates, moves, renames, and deletion through a configurable S3-compatible endpoint.

Supports flat and hierarchical keys, configurable regions and path-style addressing, AWS credentials/profiles/roles, and a separate public endpoint for signed URLs. Direct uploads use temporary keys and are promoted before metadata finalization, preventing signed URL replay from overwriting ready files. The API content endpoint rejects proxied uploads for direct-upload stores.

Failed S3 moves restore missing source objects before removing their copies. Failed batch items retain their original database parent and are excluded from Moved; successful items still commit. Configuration, bucket permissions, CORS, and staging lifecycle setup are documented in dev/docs/s3-storage.md.

Validation: Go unit tests and vet; MinIO/Postgres integration tests for both storage modes, signed URL expiry, multipart transfers, finalization/replay, moves/deletion, injected copy/delete failures, compensation, and API-level partial-move retries; frontend Biome and TypeScript checks.

Limits: other S3 providers have not been tested directly. S3 and database changes are not atomic; process crashes, database commit failures, or failed compensation can require reconciliation. Pending upload sessions remain in memory.

Implements https://linear.app/drexa/issue/DRE-20/implement-s3-storage-backend

Commits 0