API REST par projet sur un stockage S3 (MinIO), transformations d’image à la volée avec cache des dérivés, URLs signées HMAC, buckets publics ou privés, corbeille et restauration.
6 min de lecture·Niveau intermédiaire·Révisé le 15 avr. 2026
Le service aura-storage gère vos fichiers binaires : upload, download, transformations d'image, URLs signées, corbeille. Il expose sa propre API REST sous /v1/storage/{project_id} et s'appuie sur un stockage S3 (MinIO) en interne — les outils S3 (rclone, boto3) ne s'y connectent pas directement.
Les objets sont organisés en buckets. Chaque bucket a une politique (public ou privé), des limites de taille, un TTL optionnel, et un ensemble de policies RLS qui contrôlent qui peut lire/écrire chaque chemin.
Info
Les métadonnées vivent dans le schéma du projet : storage_buckets, storage_objects, storage_derivatives, storage_project_settings, storage_audit_log. Les octets, eux, sont dans le stockage S3.
Lors d'une lecture, le service vérifie l'accès au chemin demandé, puis sert les octets depuis le stockage. Si la requête porte des paramètres de transformation, le dérivé correspondant est réutilisé s'il existe déjà, sinon calculé puis mis en cache. En upload, le flux est inversé : client → service → stockage, après contrôle d'écriture et des limites du bucket.
schema
TEXT
┌───── cache dérivés ─────┐
GET /v1/storage/{pid}/… ─▶ │ dérivé déjà calculé ? │
// Sans upsert, un chemin déjà occupé échoue en 409 (code CONFLICT)
Astuce
Les URLs de transformation sont immuables par paramètres. ?width=240&format=png et ?width=240&format=webp sont deux URLs distinctes, donc deux dérivés distincts : chaque combinaison n'est calculée qu'une fois, puis relue depuis le cache de dérivés.
Les métadonnées d'objets vivent dans la table storage_objects du schéma du projet (colonnes bucket_name, key, owner_id, metadata, deleted_at), avec RLS activée. Il n'existe pas de schéma storage ni de fonction storage.foldername() : les policies s'écrivent sur les colonnes.
policies livrées par défaut
SQL
-- Lecture : son propre objet, ou n'importe quel objet d'un bucket public
create policy storage_objects_select on storage_objects for select
using (
owner_id = auth.uid()
or exists (select 1 from storage_buckets b
where b.name = storage_objects.bucket_name and b.public)
);
-- Écriture : uniquement ses propres objets
create policy storage_objects_insert on storage_objects for insert