Storage
REST API per project on S3 storage (MinIO), on-the-fly image transformations with derivative cache, HMAC signed URLs, public or private buckets, trash and restore.
One bucket, one origin, one CDN
The aura-storage service manages your binary files: upload, download, image transformations, signed URLs, trash. It exposes its own REST API under /v1/storage/{project_id} and relies on S3 storage (MinIO) internally — the S3 tools (rclone, boto3) do not connect to it directly.
Objects are organized into buckets. Each bucket has a policy (public or private), size limits, an optional TTL, and a set of RLS policies that control who can read/write each path.
The metadata lives in the project schema: storage_buckets, storage_objects, storage_derivatives, storage_project_settings, storage_audit_log. The bytes are in S3 storage.
Path → RLS → CDN → origin
During a read, the service checks for access to the requested path and then serves the bytes from storage. If the query carries transformation parameters, the corresponding derivative is reused if it already exists, otherwise calculated and then cached. In upload, the flow is reversed: client → service → storage, after writing control and bucket limits.
Six native abilities
REST API per project
Routes /v1/storage/{project_id}/… on S3 storage (MinIO) — this is not an S3 API: S3 SDKs do not plug into it.
Transforms on the fly
width, height, fit, format (jpeg/png/webp/gif), quality, rotate, flip. Each combination is hidden as a derivative.
Signed URLs
HMAC signature on method + bucket + key + expiration. TTL 3600 s by default, secret rotation per project.
Multipart upload
Simple upload in multipart/form-data, or init / part / complete for large files.
Trash and restoration
Soft deletion: /trash lists deleted objects, /restore/{key} restores them.
Public or private buckets
The bucket carries the access policy, size limits and the list of authorized MIME types.
Four basic operations
Transformation URLs are immutable by parameters. ?width=240&format=png and ?width=240&format=webp are two distinct URLs, therefore two distinct derivatives: each combination is only calculated once, then reread from the derivative cache.
RLS on object paths
Object metadata lives in the storage_objects table of the project schema (columns bucket_name, key, owner_id, metadata, deleted_at), with RLS enabled. There is no storage schema nor storage.foldername() function: policies are written on the columns.