
# Presets et mise en cache

Deux préoccupations situées derrière les paramètres de [redimensionnement](/fr/docs/image-transforms) et de [format](/fr/docs/image-formats) : donner un nom à une combinaison récurrente, et faire que la deuxième requête ne coûte rien.

## Presets nommés

Un preset regroupe `width`, `height`, `fit`, `crop`, `quality` et `format` sous un seul nom. C'est une configuration d'opérateur — un objet JSON dans une variable d'environnement, pas dans le schéma — car la bonne taille de vignette est une propriété du déploiement, pas du domaine métier.

```bash
STORAGE_TRANSFORM_PRESETS='{
  "thumbnail": { "width": 150, "height": 150, "fit": "cover" },
  "preview":   { "width": 600, "quality": 80 },
  "avatar":    { "width": 64, "height": 64, "fit": "cover", "crop": "attention" }
}'
```

```http
GET /api/buckets/photos/files/{key}?preset=avatar
GET /api/buckets/photos/files/{key}?preset=thumbnail&quality=95
```

| Situation                              | Résultat                                        |
| -------------------------------------- | ----------------------------------------------- |
| Preset connu                           | Ses champs deviennent la transformation.        |
| Paramètre explicite à côté d'un preset | La valeur explicite l'emporte, champ par champ. |
| Nom de preset inconnu                  | `400`                                           |
| `?preset=` sans aucun preset configuré | `400`, avec un message le disant.               |

Les surcharges sont par champ, pas globales : `?preset=thumbnail&quality=95` conserve le 150×150 `cover` du preset et ne change que la qualité.

Les noms de presets doivent être alphanumériques avec des traits d'union simples (`thumbnail`, `hero-banner`), ce qui les garde sûrs dans une URL. Un JSON malformé, une valeur non-objet ou un nom illégal **font échouer le serveur au démarrage** plutôt qu'à la première requête — une faute de frappe dans cette variable se découvre au déploiement, pas par un utilisateur.

## Mise en cache

Une transformation s'exécute une fois par combinaison distincte. Le résultat est conservé dans un cache LRU local au processus, indexé conjointement sur la clé de stockage, les paramètres de transformation et le format négocié.

| Mécanisme       | Comportement                                                                     |
| --------------- | -------------------------------------------------------------------------------- |
| `Cache-Control` | `public, max-age=31536000, immutable` — un an, jamais revalidé.                  |
| `ETag`          | Dérivé du fichier source et des paramètres de transformation.                    |
| `If-None-Match` | Une correspondance renvoie `304 Not Modified`.                                   |
| Cache serveur   | LRU en mémoire, évinçant les entrées les moins récemment utilisées à saturation. |
| Invalidation    | Supprimer un fichier évince toutes les transformations dérivées de sa clé.       |

| Variable                           | Défaut | Signification                    |
| ---------------------------------- | ------ | -------------------------------- |
| `STORAGE_TRANSFORM_CACHE_MAX_SIZE` | `256`  | Plafond du cache, en mégaoctets. |

Une entrée plus lourde que le plafond entier est servie mais jamais conservée — elle évincerait tout le reste pour tenir.

:::callout
**Le cache vit dans le processus, pas sur disque.** Il est vide après chaque redémarrage et n'est pas partagé entre instances : un déploiement multiprocessus détient donc une copie par processus, chacune se réchauffant indépendamment. Ce n'est pas un problème, car le `Cache-Control` exposé aux CDN vaut un an : le navigateur et tout cache de périphérie absorbent le trafic répété, et ce cache-ci n'a qu'à absorber la première requête par processus.
:::

L'en-tête `immutable` d'un an est sûr précisément parce que les clés sont adressées par contenu — une clé stockée vaut `<uuid>-<nom-de-fichier>`, donc un fichier remplacé est une nouvelle clé et une nouvelle URL. Rien n'est jamais servi de façon périmée sous une URL dont le contenu aurait changé, car cette situation ne peut pas se produire.

## Les originaux ne sont jamais touchés

| Garantie               | Comportement                                                             |
| ---------------------- | ------------------------------------------------------------------------ |
| Octets sources         | Identiques bit à bit après un nombre quelconque de transformations.      |
| Requête sans paramètre | L'original, sous réserve de la seule négociation `Accept`.               |
| `?format=origin`       | Les octets originaux tels quels, négociation court-circuitée.            |
| Vidage du cache        | N'écarte que les variantes dérivées ; les originaux restent disponibles. |
| Fichiers non-image     | Les paramètres de transformation répondent `400` — rien n'est tenté.     |

Les transformations sont dérivées, jetables et reproductibles : le cache peut être vidé à tout instant, la requête suivante le reconstruit. Les administrateurs peuvent le faire précisément avec `DELETE /api/admin/storage/transform-cache`.

Les types d'image reconnus sont ceux que Sovrium peut déduire de l'extension de la clé : PNG, JPEG, GIF, WebP, AVIF, SVG et ICO. Le SVG est transmis tel quel plutôt que rasterisé, et il est toujours servi en pièce jointe — voir [Sécurité des téléversements](/fr/docs/file-security).

## Pages associées

- [Redimensionnement et recadrage](/fr/docs/image-transforms) — les paramètres qu'un preset regroupe.
- [Format et qualité](/fr/docs/image-formats) — négociation de format et compression.
- [Opérations sur les fichiers](/fr/docs/file-operations) — le point de terminaison qui sert les résultats en cache.
- [Cycle de vie et quotas](/fr/docs/file-lifecycle) — les originaux dont une transformation part.
- [Variables d'environnement : services](/fr/docs/env-vars-services) — la configuration des presets et du cache.
