
# Opérations sur les fichiers

Chaque bucket expose une API REST pour le cycle de vie principal des fichiers : téléversement, téléchargement et suppression. Les opérations sont authentifiées par rapport aux [permissions](/fr/docs/buckets-overview#permissions) du bucket, durcies contre la traversée de chemin et le XSS, et intégrées au [modèle de soft-delete](/fr/docs/tables-overview) de Sovrium.

Le paramètre de chemin `{bucket}` référence un nom de bucket déclaré dans votre tableau `buckets[]`. Voir [Présentation des buckets](/fr/docs/buckets-overview).

## Points de terminaison

| Méthode  | Point de terminaison                | Description                                                                                           |
| -------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `POST`   | `/api/buckets/{bucket}/files`       | Téléverse un fichier (données de formulaire multipart). Renvoie `201` avec la clé de fichier générée. |
| `GET`    | `/api/buckets/{bucket}/files/{key}` | Télécharge un fichier par clé. Renvoie le contenu du fichier avec le bon `Content-Type`.              |
| `DELETE` | `/api/buckets/{bucket}/files/{key}` | Supprime un fichier par clé du stockage.                                                              |
| `GET`    | `/api/admin/buckets/quota`          | _(Admin)_ Renvoie l'utilisation actuelle du stockage en octets.                                       |

## Téléversement

Envoyez le fichier sous forme de données de formulaire multipart. Le serveur le valide par rapport aux `maxFileSize` et `allowedMimeTypes` du bucket, génère une clé imprévisible, et le stocke dans le backend configuré.

```bash
curl -X POST https://app.example.com/api/buckets/documents/files \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@report.pdf"
```

```json
{
  "key": "documents/9f3c1e2a-7b44-4d10-9e21-8a6f0c1d2e3b.pdf",
  "filename": "report.pdf",
  "size": 245760,
  "mimeType": "application/pdf"
}
```

| Comportement                                        | Résultat                                                                  |
| --------------------------------------------------- | ------------------------------------------------------------------------- |
| Fichier valide dans les limites                     | `201` avec la clé de fichier générée.                                     |
| Corps de requête vide                               | `400 Bad Request`.                                                        |
| Dépasse la taille max du bucket ou globale          | `413 Payload Too Large` (rejeté tôt, avant la lecture complète du corps). |
| Dépasse le quota `STORAGE_MAX_TOTAL_SIZE`           | `507 Insufficient Storage`.                                               |
| Requête non authentifiée vers un bucket authentifié | `401 Unauthorized`.                                                       |

:::callout
**Les clés sont aléatoires.** Les téléversements reçoivent toujours une clé basée sur UUID, de sorte que les fichiers ne s'écrasent jamais l'un l'autre et que les URL de stockage sont indevinables. Deux téléversements du même nom de fichier produisent deux clés distinctes.
:::

## Téléchargement

```bash
curl https://app.example.com/api/buckets/documents/files/{key} \
  -H "Authorization: Bearer $TOKEN" -O
```

| Comportement                                                          | Résultat                                                   |
| --------------------------------------------------------------------- | ---------------------------------------------------------- |
| Le fichier existe, l'appelant a la permission `download`              | `200` avec le contenu du fichier et le bon `Content-Type`. |
| Clé inexistante                                                       | `404 Not Found`.                                           |
| Fichier privé, pas d'auth et pas d'[URL signée](/fr/docs/signed-urls) | `403 Forbidden`.                                           |

Les réponses incluent un en-tête `Content-Disposition` — les fichiers non image sont servis en `attachment` pour empêcher le navigateur de les afficher en ligne.

## Suppression

```bash
curl -X DELETE https://app.example.com/api/buckets/documents/files/{key} \
  -H "Authorization: Bearer $TOKEN"
```

| Comportement                                           | Résultat                           |
| ------------------------------------------------------ | ---------------------------------- |
| Le fichier existe, l'appelant a la permission `delete` | `200`, fichier retiré du stockage. |
| Clé inexistante                                        | `404 Not Found`.                   |

## Durcissement de sécurité

Les opérations sur les fichiers appliquent automatiquement la [base de sécurité de pré-lancement](/fr/docs/buckets-overview) récurrente pour les téléversements :

| Mesure                            | Comportement                                                                   |
| --------------------------------- | ------------------------------------------------------------------------------ |
| Traversée de chemin               | Les séquences `../` dans les noms de fichiers sont assainies ou rejetées.      |
| Octets nuls                       | Les noms de fichiers contenant des octets nuls sont rejetés.                   |
| Caractères spéciaux / unicode     | Encodés en toute sécurité pour le stockage.                                    |
| Clés aléatoires                   | Les clés basées sur UUID empêchent les URL devinables.                         |
| `X-Content-Type-Options: nosniff` | Envoyé sur chaque fichier servi.                                               |
| `Content-Security-Policy`         | Envoyé sur chaque fichier servi.                                               |
| Types sujets au XSS (HTML, SVG)   | Servis avec un `Content-Type` sûr ou forcés au téléchargement en pièce jointe. |

## Cycle de vie des fichiers

Les pièces jointes suivent le cycle de vie soft-delete-par-défaut de Sovrium. La présence du fichier suit l'enregistrement propriétaire :

| Action sur l'enregistrement                   | Comportement du fichier                                        |
| --------------------------------------------- | -------------------------------------------------------------- |
| Soft-delete de l'enregistrement               | Fichier préservé dans le stockage.                             |
| Restauration de l'enregistrement              | Accès au fichier restauré.                                     |
| Hard-delete (purge)                           | Fichier retiré du stockage.                                    |
| Remplacement de la pièce jointe               | Ancien fichier retiré du stockage.                             |
| Effacement de la pièce jointe (mettre `null`) | Fichier retiré du stockage.                                    |
| Référence partagée                            | Fichier préservé tant qu'un autre enregistrement le référence. |

## Téléversements volumineux et quota

Les téléversements diffusent en flux plutôt que de tamponner en bloc, donc les gros fichiers ne font pas grimper la mémoire. Les limites sont contrôlées par l'opérateur via des variables d'environnement.

| Variable                 | Par défaut           | Objectif                                                                                               |
| ------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------ |
| `STORAGE_MAX_FILE_SIZE`  | `104857600` (100 Mo) | Taille maximale d'un fichier unique en octets. Le `maxFileSize` d'un bucket surcharge ceci par bucket. |
| `STORAGE_MAX_TOTAL_SIZE` | Illimité             | Stockage total maximal par application en octets (sécurité multi-locataire).                           |

```bash
STORAGE_MAX_FILE_SIZE=52428800
STORAGE_MAX_TOTAL_SIZE=10737418240
```

Le point de terminaison de quota admin rapporte l'utilisation :

```bash
curl https://app.example.com/api/admin/buckets/quota \
  -H "Authorization: Bearer $ADMIN_TOKEN"
```

```json
{ "usedBytes": 524288000, "maxBytes": 10737418240 }
```

La suppression de fichiers réduit l'utilisation suivie. Lorsqu'aucun `STORAGE_MAX_TOTAL_SIZE` n'est configuré, les téléversements sont illimités.

## Pages associées

- [Présentation des buckets](/fr/docs/buckets-overview) — déclarer les buckets, les backends et les permissions.
- [URL signées](/fr/docs/signed-urls) — téléchargement limité dans le temps et téléversements directs depuis le navigateur.
- [Transformations d'image](/fr/docs/image-transforms) — redimensionnement et reformatage au téléchargement.
- [Champs de pièce jointe](/fr/docs/attachment-fields) — fichiers attachés aux enregistrements de table.
- [Téléversements de fichiers de formulaire](/fr/docs/form-file-uploads) — accepter des téléversements via des formulaires.
- [Variables d'environnement](/fr/docs/env-vars) — configuration de la taille et du quota.
