Stockage et traitement des images et vidéos. Schéma des tables medias / media-images / media-videos : voir entities/medias.md.
Qui stocke quoi
- Images → Minio (module
statics), un seul bucket. Deux flux distincts y écrivent : les médias piste/article (media-images, viaPOST /statics) et les photos de profil (flux séparépostProfilePictureToMinio, dossierprofile-pictures/). - Vidéo → Mux entièrement. Les octets vidéo ne transitent jamais par Minio.
- Pas de Minio ni de Mux en local :
docker-compose.ymlne lance aucun conteneur Minio, le dev pointe vers une instance distante via les variables d'env. Les credentials Mux ne sont même pas déclarées dansdocker-compose.ymlet ne sont pas validées au démarrage (lues directement dansprocess.env, pas viaConfigService/Joi) — une vidéo en local dépend donc de vraies credentials Mux présentes dans l'environnement ; sans elles, l'appel échoue au moment de l'upload, pas au démarrage.
Redimensionnement (resizer)
- À la demande, pas à l'upload :
GET /resizer/:width/:height[/crop/:horizontal-:vertical]/:pathtélécharge l'original depuis Minio et le redimensionne/recadre avecsharp. Sert du WebP si le client l'accepte viaAccept. - Le résultat est mis en cache sur le disque local du conteneur (
cache/resized-images/), pas dans Minio. Le cache est donc propre à chaque instance et n'est jamais invalidé quand l'original est remplacé au même chemin (PATCH /statics/:id) — une image obsolète continue d'être servie jusqu'à un appel manuel àGET /resizer/cache/clearou un redémarrage du conteneur. horizontalPosition(0-100, défaut 50 surMedia) ne pilote que le recadrage horizontal ; il n'existe pas de position verticale persistée, le vertical reste toujours à 50.- Toute erreur (image absente, Minio injoignable,
sharpqui échoue) ressort comme la même 404 génériqueImage not found or processing failed— impossible de distinguer la cause sans regarder les logs serveur.
Vidéo (Mux)
- Upload direct navigateur → Mux (librairie
upchunk), l'API ne voit jamais les octets. Elle se contente de créer l'URL d'upload (muxUploadUrl) et d'attendre. - Pas de webhook Mux : un cron (
monitorMuxAssets, toutes les 2 secondes, voir cron-tasks.md) interroge l'état de l'asset et met à jour le statut (ready/errored) ainsi quemuxPlaybackId. - Un statut Mux non reconnu par le code laisse la vidéo bloquée en
preparingindéfiniment, sans alerte — d'où le bouton admin "vérifier sur Mux" (check-mux), qui interroge directement la miniature Mux pour confirmer qu'une vidéo est vraiment jouable quand le statut local semble en décalage. - L'upload direct dépend de
FRONTEND_URL(envoyée à Mux commecors_origin) — une valeur incorrecte casse l'upload avec une erreur CORS qui n'a rien à voir avec Minio ni l'API.
Pièges
proccessing(faute d'orthographe) est la vraie valeur stockée en base, pas juste un nom d'identifiant : c'est le défaut de la colonnemedias.status, dupliqué tel quel dans plusieurs fichiers front qui comparent à cette chaîne. Corriger la faute demande une vraie migration d'enum Postgres (renommer la valeur + mettre à jour le défaut) et une mise à jour synchronisée de tous les endroits qui comparent à'proccessing', pas un simple renommage d'identifiant.- Supprimer un média (flux normal piste/article) ne supprime pas le fichier Minio. Seul un soft-delete de la ligne
media-imagesest effectué. Le fichier reste orphelin dans le bucket indéfiniment. Seule la suppression viaDELETE /statics/:id, ou la suppression d'une photo de profil, retire réellement l'objet Minio. media.urlest vide pour les images ajoutées via le flux standard piste/article — l'URL réelle est reconstruite côté front à partir deimage.folder/image.name, pas demedia.url. Ce champ n'est effectivement renseigné que pour les photos de profil (URL publique complète) et les vidéos prêtes (URL de stream Mux).