L’onglet Fichiers d’un projet est un gestionnaire de fichiers simple au-dessus d’un compartiment privé. C’est l’endroit idéal pour les artefacts qu’un build ne devrait pas contenir : ce qui change à l’exécution, est trop volumineux pour être versionné, ou est produit par l’application elle-même.
Gérer les fichiers
Ouvrez l’onglet Fichiers d’un projet pour téléverser un fichier, le télécharger de nouveau ou le supprimer. La liste affiche la clé, la taille et la date de modification de chaque objet. Chaque téléversement est plafonné selon le forfait, et l’usage total du compartiment compte dans votre quota de stockage — Forfaits et limites donne les chiffres. Lorsque l’usage atteint le plafond, les téléversements s’interrompent jusqu’à ce que vous libériez de l’espace ou passiez à un forfait supérieur, plutôt que d’échouer de façon imprévisible.
Fichiers supprimés et anciennes versions
Supprimer un fichier, ou téléverser par-dessus, ne détruit pas aussitôt les anciens octets. L’onglet Supprimés de la page Fichiers liste les fichiers supprimés et ceux qui ont des versions antérieures, avec la date de leur purge. Restaurer ramène un fichier supprimé (sans espace supplémentaire), Versions permet de restaurer une version antérieure d’un fichier écrasé, et Supprimer définitivement ou Vider les supprimés les retire immédiatement et libère l’espace.
Ils sont conservés 30 jours par défaut. Modifiez la durée par projet dans l’onglet Supprimés (de 1 à 365 jours); elle n’est jamais plus courte que la plus longue fenêtre de sauvegarde ou de récupération à un instant précis des bases du projet, de sorte qu’une base restaurée à n’importe quel moment conservé retrouve ses fichiers. Les versions conservées comptent dans votre stockage, et la jauge les montre dans un segment à part. Cela vaut aussi pour les fichiers que votre propre code écrit avec les identifiants S3. Les restaurations et les purges sont consignées dans le journal d’audit.
Sauvegarder vos fichiers
L’onglet Sauvegardes de la page Fichiers fonctionne comme les sauvegardes de bases de données : activez une planification (fréquence, durée de conservation, nombre) ou appuyez sur Sauvegarder maintenant. Une sauvegarde de fichiers liste chaque fichier du projet avec sa version, sa taille et son sha256, et empêche que ces versions soient purgées tant que la sauvegarde existe. Rien n’est copié : une sauvegarde n’ajoute aucun stockage; les versions qu’elle retient apparaissent dans la jauge dans un segment à part.
Restaurer remet une version sous le nom du fichier; une référence au fichier dans votre base de données (sa clé) continue donc de fonctionner, sans devoir restaurer la base au même moment. Choisissez de remettre ce qui manque ou a changé (rien n’est supprimé; les fichiers créés depuis restent), de restaurer exactement comme à la sauvegarde (les fichiers créés depuis passent dans Supprimés, où on peut les restaurer), ou de tout copier dans un dossier _restored pour examiner d’abord. Comparer avec maintenant montre ce qui manque, a changé et a été ajouté depuis. Les sauvegardes sont vérifiées à intervalles réguliers en relisant un échantillon de fichiers et en contrôlant chacun avec son sha256; Vérifier tous les fichiers les relit tous.
Manifeste des fichiers (.json) télécharge la liste (clé, version, taille, sha256, sans contenu) pour la comparer aux références de fichiers de votre propre base de données. Les fichiers supprimés sont conservés au moins aussi longtemps que votre plus longue sauvegarde de base de données : une base restaurée à n’importe quel moment conservé retrouve ses fichiers. Pour retirer un fichier pour de bon, sauvegardes comprises, utilisez Supprimer définitivement dans Supprimés et choisissez Effacer aussi des sauvegardes; sinon, une version retenue par une sauvegarde est conservée jusqu’à l’expiration de celle-ci. Une sauvegarde est stockée sur le même serveur que les fichiers : elle protège contre les suppressions et les écrasements, pas contre la perte du serveur.
Pour une copie qui survit à la perte de ce serveur, choisissez une destination hors site (l’un de vos seaux compatibles S3, les mêmes que pour les sauvegardes de bases de données) sous Copier hors site vers. Chaque sauvegarde y est aussi copiée sous forme de fichiers ordinaires, non chiffrés, chaque fichier distinct une seule fois selon son sha256, avec un manifeste lisible qui associe chaque nom de fichier à son empreinte : vous pouvez donc lire la copie sans Canner. Seul le contenu que le seau n’a pas encore est téléversé, supprimer une sauvegarde retire son manifeste et tout fichier dont aucune autre sauvegarde n’a besoin, et si un fichier manque un jour ici, une restauration (et une vérification) utilise la copie hors site.
Privé par défaut
Le compartiment est privé — les objets ne sont pas servis sur une URL publique du simple fait qu’ils existent. Les fichiers sont stockés dans un stockage objet compatible S3, de propriété canadienne (MinIO); la résidence des données correspond donc au reste de votre application. Gardez ici tout ce qui est sensible plutôt que dans votre dépôt ou votre sortie de build.
Se connecter depuis votre propre code
Ceci s’adresse au code serveur de votre application exécuté sur Canner. Le point de terminaison du compartiment se trouve sur l’hôte même où s’exécute votre projet; ces identifications fonctionnent donc depuis le code de votre application déployée — pas depuis votre poste, votre intégration continue, ni aucune machine à l’extérieur de Canner. Il n’existe aucun point de terminaison public vers lequel diriger un client S3 externe.
Le code serveur de votre application se connecte directement au compartiment — de vraies informations d’identification compatibles S3, pas seulement le gestionnaire de fichiers du tableau de bord. Ouvrez l’onglet Fichiers et créez une identification sous Accès API. Sa création révèle un bloc de variables d’environnement prêt à coller — point de terminaison, compartiment, région, ID de clé d’accès et clé d’accès secrète — affiché une seule fois. Ajoutez-les aux variables d’environnement de votre projet (elles ne sont pas injectées automatiquement), puis lisez-les comme ci-dessous. Le secret ne peut pas être récupéré à nouveau — si vous le perdez, régénérez l’identification pour en obtenir un nouveau.
Chaque identification est limitée à votre projet uniquement, appliqué par la politique d’accès de MinIO elle-même, pas seulement une convention côté client — elle ne peut pas lister, lire, écrire ou supprimer des objets appartenant à un autre projet, même au sein de votre propre organisation. Les clés d’objet doivent commencer par le slug de votre projet; la politique de l’identification rejette tout ce qui est en dehors de ce préfixe.
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const s3 = new S3Client({
endpoint: process.env.CANNER_STORAGE_ENDPOINT,
region: process.env.CANNER_STORAGE_REGION,
credentials: {
accessKeyId: process.env.CANNER_STORAGE_ACCESS_KEY_ID,
secretAccessKey: process.env.CANNER_STORAGE_SECRET_ACCESS_KEY,
},
forcePathStyle: true, // MinIO uses path-style addressing, not virtual-hosted-style
});
const bucket = process.env.CANNER_STORAGE_BUCKET;
// Keys must start with your project's slug — that's the prefix your
// credential is scoped to. A key outside it is rejected, not just hidden.
const key = `macapsule-production/certificates/${userId}.pdf`;
await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: pdfBuffer,
ContentType: 'application/pdf',
}));
// A short-lived signed URL, if you want the browser to fetch the file
// directly instead of proxying it through your own server.
const url = await getSignedUrl(
s3,
new GetObjectCommand({ Bucket: bucket, Key: key }),
{ expiresIn: 300 }
);Besoin que le navigateur télécharge un fichier directement? Émettez une URL présignée de courte durée (l’appel getSignedUrl ci-dessus) — un lien à durée limitée vers un seul objet privé, sans jamais exposer quoi que ce soit sur une URL publique.
Style de chemin, pas style d’hôte virtuel : activez forcePathStyle: true sur votre client S3, ou l’option équivalente pour le SDK que vous utilisez. La connexion elle-même est en HTTP simple — elle ne quitte jamais l’hôte sur lequel votre application s’exécute, donc il n’y a aucun saut réseau public à sécuriser avec TLS.
Vérifiez que le stockage est joignable avec une liste, pas avec HeadBucket : HeadBucket interroge le seau entier, ce que votre identification n’a volontairement pas le droit de faire (le seau contient aussi les autres projets de votre organisation); il répond donc 403 AccessDenied. Utilisez plutôt ListObjectsV2 avec Prefix: "slug-de-votre-projet/" et MaxKeys: 1 : c’est permis et cela confirme que le point d’accès, le nom du seau et l’identification sont bons. Un 400 sur un appel de seau signifie généralement que le nom du seau a été mal saisi : copiez-le depuis le panneau de l’identification.
Révoquez ou régénérez une identification à tout moment depuis le même panneau — l’ancien secret d’une identification régénérée cesse de fonctionner immédiatement, et une identification révoquée est rejetée dès sa prochaine requête.
Ce qui va ici plutôt que dans le build
- Stockage objet : images téléversées, PDF et CSV générés, sauvegardes, tout ce qui est créé ou modifié après le déploiement.
- Votre build : les ressources statiques qui font partie de l’application (logos, JS/CSS empaquetés) — livrez-les dans le déploiement, pas dans le compartiment.
- Données structurées : utilisez une base Postgres pour les enregistrements que vous interrogez, pas des fichiers dans un compartiment.