Médias (images & vidéo)
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/). - Les images piste/article sont compressées à l'upload (
POST/PATCH /statics: orientation EXIF appliquée, grand côté ≤ 1300 px, même format, JPEG/PNG uniquement → 415 sinon). Les fichiers déjà en bucket ont été recompressés par un backfill one-shot. - Les photos de profil sont compressées à l'upload (
POST /statics/profile-picture: même helpercompressImage, grand côté ≤ 256 px, JPEG) ; celles déjà en bucket ont été recompressées par un backfill one-shot. - 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.
Affichage des images (plus de resizer)
- Il n'y a plus de redimensionnement à la volée : le module
ResizerModule(/resizer/*) a été supprimé. Les images sont compressées à l'upload (voir plus haut) puis servies telles quelles par le CDN Minio ; le recadrage se fait en CSS (object-fit: cover). horizontalPosition(0-100, défaut 50 surMedia) pilote l'object-positionhorizontal du carrousel (SPA et SSR) ; il n'existe pas de position verticale persistée, le vertical reste toujours à 50.
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).