ADR 0001: Large file upload/download support for magda-storage-api

Context

magda-storage-api is an authorization proxy in front of a MinIO gateway. The original upload paths (POST /v0/storage/upload/... and PUT /v0/storage/:bucket/*) buffered the entire file into memory before writing to MinIO (capped at uploadLimit, default 100mb), and downloads (GET /v0/storage/:bucket/*) streamed but ignored the Range header. This meant: memory pressure scaling with file size, a hard ~100 MB ceiling, single non-resumable requests, and no resumable/seekable downloads.

We needed to support files up to ~10 GB (with headroom) while preserving the existing OPA + record-linked authorization model and without forcing an ingress body-size increase on every deployment.

Decision

Two additive changes; all existing routes preserved.

  1. Download: add HTTP Range support to the existing GET /v0/storage/:bucket/* route (Accept-Ranges: bytes; 206 + Content-Range for a satisfiable single range via minio.getPartialObject; 416 for unsatisfiable; full 200 otherwise). Authorization unchanged.

  2. Upload: add S3 multipart upload proxy endpoints under /v0/storage/multipart/{initiate,part,parts,complete,abort}/:bucket/* that relay one bounded part at a time through storage-api to MinIO.

Key sub-decisions:

Consequences

Alternatives considered

Implementation notes / non-obvious decisions

Verification

Unit/integration tests (Mocha, against a local MinIO) cover range parsing, the signed token, the MinIO client multipart methods, the Range download route, and the multipart endpoints. End-to-end verification against a minikube deployment — through the gateway, authenticated with an API key, as both the default admin and a freshly-created admin user — is scripted in magda-storage-api/scripts/verify-large-file.mjs (see E2E test case: Large file storage).