Médiathèque
Ressources média bornées par organisation, dossiers, quotas, miniatures et génération d'images IA.
Vue D'Ensemble
La médiathèque est le magasin partagé de ressources d'organisation pour les workflows de contenu. Elle est disponible depuis:
/dashboard/content/media, la médiathèque/dashboard/content/media/trash, sa corbeille, pour les gestionnaires des médias
Les ressources média sont bornées par organisation. Elles sont utilisées par l'éditeur de page, Page AI et les workflows de contenu qui ont besoin d'URL durables pour images, vidéos, audio, PDF ou autres fichiers supportés.
Rôle CMS
Les médias sont la couche de ressources du CMS. Elle possède les fichiers binaires, miniatures générées, images générées, URL publiques, l'application des quotas et l'organisation en dossiers. Les données CMS structurées peuvent référencer des URL média, et les pages ou sections peuvent lier des champs média à des ressources sélectionnées, mais la ressource elle-même reste dans la médiathèque.
Utilisez les médias lorsqu'un workflow a besoin d'un fichier stocké. Utilisez les données CMS pour le contenu typé, les sections pour le layout réutilisable et les documents de page pour la composition.
Modèle De Données
Les médias utilisent cinq tables système:
media_foldersmedia_assetsmedia_asset_activitymedia_tagsmedia_asset_tags
Les ressources stockent:
organization_idpropriétairefolder_idoptionnelnom d'affichage et nom d'affichage normalisé
type MIME et kind de ressource
taille en octets
bucket de stockage objet et clé de stockage
URL publique
métadonnées optionnelles de miniature
métadonnées de téléversement ou génération
La propriété des dossiers est bornée à la même organisation que la ressource. Les actions serveur doivent rejeter les mutations de dossiers ou ressources inter-organisations.
Les tags (migration 0093) appartiennent eux aussi à l'organisation :
media_tags porte le nom de chaque tag, unique dans l'organisation sans tenir
compte de la casse, des accents ni des espaces en trop, et sa couleur ;
media_asset_tags porte une ligne par fichier et par tag. Un lien nomme son
organisation et référence le fichier et le tag à travers elle : la base refuse
de donner à un fichier le tag d'une autre organisation, et supprimer un
fichier, un tag ou l'organisation supprime ses liens.
Stockage
Le stockage média utilise un fournisseur compatible S3 comme MinIO, AWS S3 ou R2. Les clés de stockage suivent la convention de chemin d'organisation:
organizations/<organizationId>/media/<asset>
organizations/<organizationId>/media/thumbnails/<assetId>.webp
global/site-variables/<asset>.<content-hash>.<ext>La base stocke publicUrl parce que les pages publiées et le contenu rendu par
le CMS ont besoin d'URL publiques stables. Les URL média existantes ne sont pas
réécrites lorsque STORAGE_PROVIDER change; les opérateurs doivent donc garder
les anciennes URL publiques joignables ou prévoir une migration ultérieure.
Fournisseur de stockage:
STORAGE_PROVIDER=s3
Le stockage compatible S3 requiert:
STORAGE_MEDIA_BUCKETSTORAGE_PUBLIC_BASE_URLS3_ENDPOINTS3_REGIONS3_ACCESS_KEY_IDS3_SECRET_ACCESS_KEYS3_FORCE_PATH_STYLE
La médiathèque écrit dans le bucket média configuré, et les uploads de logo
d'organisation utilisent le bucket organization-logos. Lorsque l'URL publique
de base est l'origine app ou CDN, les deux préfixes de bucket doivent être
routés vers le stockage objet compatible S3 avant le repli vers l'app.
Le script seed téléverse les ressources par défaut de variables globales de
site, comme le logo et l'image sociale, dans le bucket média configuré avant de
publier l'entrée de données globales site-variables/main. Les URL de
ressources personnalisées existantes sont préservées; seuls les anciens défauts
seed ou les anciennes URL de stockage possédées par le seed sont réparés.
Voir Configuration de l'environnement de déploiement pour les étapes de setup fournisseur.
Types De Ressources Supportés
Le kind de ressource est dérivé du type MIME:
imagevideoaudiopdfdocumentarchiveother
Les ressources visuelles peuvent recevoir des miniatures WebP. Les miniatures manquantes sont générées pour les fichiers de la page listée (jamais dans la corbeille) si la ressource est éligible et que le délai de nouvelle tentative le permet.
Permissions
Les opérations média sont bornées par organisation.
Accès typique:
les membres d'organisation peuvent lister/lire les ressources
les managers/admins/propriétaires peuvent téléverser, éditer, déplacer et supprimer des ressources
les superadmins peuvent opérer globalement lorsque l'autorisation sous-jacente le permet
Toutes les actions serveur doivent inclure le périmètre d'organisation active. La visibilité navigation ou UI ne remplace pas l'autorisation serveur.
Chaque action média, dans le tableau de bord comme via le MCP, est autorisée par
can() sur la ressource media dans l'organisation, et par rien d'autre. Les
accès ci-dessus viennent des rôles initiaux liés aux groupes de l'organisation :
Organization Member liste et lit les médias, Organization Manager et
Organization Admin les gèrent. Un rôle de membre Better Auth (owner, admin,
manager ou member) ne donne jamais à lui seul accès aux médias : une personne
n'atteint la bibliothèque que par un groupe dont le rôle porte une politique
media.
Quotas
Les quotas de téléversement viennent des limites runtime du plan de facturation. Les défauts sont définis dans la configuration de facturation et peuvent être surchargés via les données de plan:
| Plan | Taille max de fichier | Stockage max d'organisation |
|---|---|---|
| Free | 25 MB | 1 GB |
| Pro | 100 MB | 10 GB |
| Business | 250 MB | 50 GB |
Les contrôles de quota ont lieu avant la persistance. Les images générées par IA utilisent le même chemin de quota que les uploads manuels, donc la génération IA ne peut pas contourner les limites du plan.
UX Dashboard
La médiathèque est un écran du tableau de bord (dashboard.content.media, voir
Tableau de bord). Son défaut affiche le résumé du stockage (le
stockage du forfait face à ce que l'organisation utilise, corbeille comprise),
puis la médiathèque en table pleine page avec trois modes d'affichage des mêmes
fichiers : Galerie (par défaut), Tableau et Arborescence (voir plus
bas).
Vues système. La table propose trois vues d'emblée, avant les vues que les membres enregistrent : Médiathèque (la Galerie, les plus récents d'abord : la vue de l'écran, au nom de sa table), Arborescence (dossiers et fichiers par nom) et Table (les plus récents d'abord). Elles sont nommées dans la langue du lecteur (Media library, File tree et Table en anglais) et ne peuvent être ni modifiées ni supprimées ; un membre en enregistre une copie pour la changer. Les vues Arborescence et Table viennent avec la source des médias, pas avec le document de l'écran : toute organisation les a, que son écran soit personnalisé ou non.
Dossiers. Les dossiers s'ouvrent, se créent, se renomment, se déplacent et se suppriment dans l'arborescence, et Galerie et Tableau filtrent sur un dossier, racine de la médiathèque comprise.
Tags et facettes. Les fichiers portent des tags du catalogue propre à l'organisation : la colonne Tags, les cartes de la Galerie (version 2 de l'écran), la fiche d'un fichier et le volet de détails de l'arborescence, et le panneau de facettes à côté de chaque vue, avec Tags et Dossiers. Voir Tags.
Recherche. Le serveur cherche dans toute la médiathèque, quel que soit le dossier : nom affiché, nom de fichier d'origine et type MIME. Filtres, tris et pages s'exécutent en base, les tris de texte dans sa collation.
Barre d'outils. Les gestionnaires des médias téléversent des fichiers, importent une image depuis une URL publique, génèrent une image quand la génération d'images est active et ouvrent la corbeille. Des fichiers peuvent aussi être déposés sur l'arborescence.
Modification. Le formulaire de modification change le nom, le dossier et les tags d'un fichier, ou le dossier d'une sélection. Les fichiers peuvent être dupliqués ou mis à la corbeille, et les aperçus et fiches gardent leur rendu adapté au kind.
Corbeille. La corbeille est une page à part,
/dashboard/content/media/trash, ouverte aux gestionnaires des médias (media:manage) : sa vue Corbeille (la Galerie) et une vue système Table, les derniers fichiers supprimés d'abord avec le jour où chacun part définitivement, et la restauration.Vues enregistrées. Les vues de la médiathèque sont enregistrées sous
media-assets-v1:allet celles de la corbeille sousmedia-assets-v1:trash. Les vues enregistrées pour un dossier sont devenues des vues de toute la médiathèque filtrées sur ce dossier, à son nom (migration 0092).
Gardez l'interface dense et opérationnelle. La médiathèque est une bibliothèque de travail, pas une galerie marketing.
Tags
Les tags classent les fichiers au-delà des dossiers : un fichier est dans un seul dossier et porte autant de tags qu'il faut. Chaque organisation a son propre catalogue, pour sa médiathèque seulement, et tout gestionnaire des médias peut l'enrichir.
Taguer. Les gestionnaires des médias (
media:manage) taguent un fichier dans la colonne Tags (double-clic sur la cellule : une liste qui cherche les tags sans tenir compte de la casse ni des accents et crée un tag à partir de la saisie), dans le formulaire de modification, ou toute une sélection avec Ajouter des tags et Retirer des tags dans la barre de sélection. Ajouter et retirer gardent les autres tags de chaque fichier, y compris ceux qu'une autre personne a ajoutés entre-temps. Les membres qui ne font que consulter les médias voient les tags.Facettes. Le panneau de facettes de la médiathèque se trouve à gauche de chaque vue (en feuille sur téléphone ; le bouton de la barre d'outils l'affiche et le masque). Il liste les Tags et les Dossiers avec le nombre de fichiers de chacun, sous la recherche et les autres filtres de la vue. Un clic filtre sur les valeurs choisies : les fichiers qui ont l'un des tags choisis, dans l'un des dossiers choisis ; Aucune valeur liste les fichiers sans tag (pour les dossiers, la racine de la médiathèque). Le choix est un filtre ordinaire : dans l'URL, enregistré avec une vue et listé dans le menu des filtres, où un filtre sur les tags peut aussi exiger tous les tags choisis, ou aucun.
Gérer les tags. Le menu de la colonne Tags › Gérer les tags renomme un tag, lui donne une couleur de la palette (ou aucune : sa couleur automatique), le fusionne dans un autre tag (chaque fichier qui le portait porte l'autre à la place) ou le supprime (chaque fichier le perd), avec pour chaque tag le nombre de fichiers hors corbeille qui le portent. Fusionner et supprimer sont irréversibles. Réservé aux gestionnaires des médias.
Annuler. Une modification des tags de fichiers est inscrite dans l'Activité de chaque fichier, avec les tags avant et après. Son auteur l'annule depuis la fiche du fichier ou avec Ctrl/Cmd+Z, comme une suppression, tant qu'elle est la dernière modification des tags du fichier et que chaque tag qu'elle rétablit existe encore ; la modification d'une sélection s'annule d'un bloc.
Les fichiers ne changent pas. Taguer ne modifie aucun fichier : son
updatedAtreste, et les fichiers d'une ancienne maquette de page, en lecture seule, peuvent être tagués. Un fichier garde ses tags dans la corbeille et les retrouve à la restauration ; la corbeille les affiche en lecture seule.Limites. 500 tags par organisation, 64 caractères par nom, 500 fichiers et 50 tags par modification.
Serveur. Le service des tags des médias (
src/lib/server/services/media/media-tags.ts) vérifiecan()sur les médias dans l'organisation pour chaque lecture et chaque modification :media:listlit le catalogue,media:managele modifie et tague les fichiers. Les modifications du catalogue se suivent une à une par organisation ; une fusion déplace les liens et supprime les tags fusionnés dans une seule transaction. Une modification des tags de fichiers verrouille les fichiers, refuse un tag qui n'existe plus et signale les fichiers hors de la médiathèque ou dans la corbeille. La colonnetagsdesystem:mediafiltre sur l'un, tous ou aucun des tags et sur les fichiers sans tag, et compte chaque fichier une fois sous chacun de ses tags ; les agrégats des sources médias sont lus en direct, jamais mis en cache, si bien que les facettes et les nombres de fichiers par tag suivent chaque modification.MCP.
yayaw_media_tags_listlit le catalogue avec le nombre de fichiers de chaque tag ;yayaw_media_tags_applyajoute, retire ou fixe les tags de fichiers (par identifiant ou par nom,createMissingpour créer les noms, un motif, une simulation par défaut) ;yayaw_media_listetyayaw_media_searchrenvoient les tags de chaque fichier et filtrent surtagIds. Renommer, recolorer, fusionner et supprimer des tags restent dans le tableau de bord. Voir Plan de contrôle.
Intégration Page Builder
L'éditeur de page peut lier des champs média à des ressources existantes de
l'organisation. Les bindings gardent le publicUrl original de la ressource
afin que les pages publiées résolvent le même fichier que celui sélectionné dans
le picker.
Page AI peut générer au plus une image pour un prompt qui demande un média ou
implique fortement un visuel riche de landing page. L'image générée est
persistée par le pipeline médiathèque puis liée à un champ de section générée
compatible comme heroImage.
Les pages publiques globales peuvent utiliser des ressources générées depuis la médiathèque privée de l'organisation active parce que l'URL stockée est publique. Si aucune organisation active ou permission média n'est disponible, la génération d'image est ignorée avec un avertissement et le brouillon de page réussit quand même.
Pipeline De Miniatures
La génération de miniature:
télécharge la ressource visuelle source
convertit en WebP
téléverse dans le bucket
mediasous le chemin de miniaturesstocke l'URL et les métadonnées de stockage de miniature sur
media_assetsenregistre les métadonnées d'échec en cas d'erreur de conversion ou upload
Les échecs de miniature ne doivent pas bloquer le listing ni le rendu de la ressource originale. Le cooldown de retry évite les tentatives coûteuses répétées sur la même source cassée.
Génération D'Images IA
La génération d'images est gardée par:
OPENAI_API_KEYOPENAI_IMAGE_GENERATION_ENABLEDle réglage de site géré
media-image-generation-enabledpermissions et quotas média
Les images générées utilisent le modèle configuré via OPENAI_IMAGE_MODEL et
sont sauvegardées comme ressources média WebP.
Points D'Entrée Serveur
Fichiers clés:
src/lib/server/services/screens/defaults/dashboard-content-media.tsetdashboard-content-media-trash.ts(les écrans par défaut)src/lib/server/services/screens/sources/system/media.tsetsrc/lib/server/services/media/media-catalog-query.ts(la médiathèque et la corbeille comme sources, en SQL)src/blocks/dashboard/screens/sources/media-extensions.tsx(la table des médias, sa barre d'outils, ses écritures et ses fenêtres)src/lib/server/actions/media/media-library-actions.tssrc/lib/server/actions/media/media-screen-actions.tssrc/lib/server/services/media/media-trash.ts(la corbeille, ses lots et la restauration)src/lib/server/services/media/media-tags.tsetsrc/lib/server/actions/media/media-tag-actions.ts(les tags)src/lib/shared/media-tags.ts(noms, couleurs et limites des tags)src/lib/server/services/media/media-permissions.tssrc/lib/server/services/media/media-asset-storage.tssrc/lib/server/services/media/media-asset-thumbnails.tssrc/lib/server/services/media/media-image-asset-generation.tssrc/lib/server/services/media/media-quotas.tssrc/lib/server/services/media/media-folder-move.tssrc/lib/server/services/media/media-folder-create.tssrc/lib/server/services/media/media-folder-store.tssrc/lib/shared/media-folder-rules.tssrc/lib/shared/media-tree-ids.ts
Notes Opérationnelles
Ne stockez pas les binaires média dans Postgres.
N'utilisez pas d'URL privée pour les ressources de pages publiées sauf si le runtime implémente aussi le renouvellement d'URL signées.
Ne comptez pas les miniatures générées dans le quota d'upload utilisateur.
Ne laissez pas une organisation sélectionner, muter ou supprimer le dossier ou la ressource d'une autre organisation.
Gardez les identifiants S3 server-only.
Validation
Checks utiles après des changements média:
bun test src/lib/server/services/media/media-mappers.test.ts
bun test src/lib/server/services/media/media-quotas.test.ts
bun test src/lib/server/services/media/media-asset-storage.test.ts
bun test src/lib/server/services/media/media-asset-thumbnails.test.ts
bun test src/lib/server/services/media/media-folder-move.test.ts src/lib/server/services/media/media-folder-create.test.ts
bun test src/lib/server/services/media/media-permissions.test.ts
.github/scripts/with-throwaway-postgres.sh env MEDIA_FOLDERS_TEST_THROWAWAY=1 bun test src/lib/server/services/media/media-folder-store.postgres.test.ts
.github/scripts/with-throwaway-postgres.sh env MEDIA_TRASH_TEST_THROWAWAY=1 bun test src/lib/server/services/media/media-trash.postgres.test.ts
bun test src/lib/shared/media-tags.test.ts src/lib/server/services/media/media-tags.test.ts
bun test src/lib/server/actions/media/media-tag-actions.test.ts
.github/scripts/with-throwaway-postgres.sh env MEDIA_TAGS_TEST_THROWAWAY=1 bun test src/lib/db/migrations/media-tags.postgres.test.ts src/lib/server/services/media/media-tags.postgres.test.ts
bun test src/lib/server/services/screens/sources/system/media.test.ts src/lib/shared/media-tree-ids.test.ts
bun test src/lib/server/actions/media/media-library-actions.test.ts
bun test src/lib/server/actions/media/media-screen-actions.test.ts
bun test src/blocks/dashboard/screens/sources/media-source-actions.test.ts src/blocks/dashboard/screens/sources/media-source-config.test.ts
bun test src/blocks/dashboard/screens/sources/media-extensions.test.ts
.github/scripts/with-throwaway-postgres.sh env SCREENS_TEST_THROWAWAY=1 bun test src/lib/server/services/screens/sources/system/media.postgres.test.ts
bun run check
bunx tsc --noEmitCorbeille restaurable et activité
Supprimer un média le place dans la Corbeille pendant 30 jours. Le fichier original et sa miniature restent stockés, conservent leurs URL publiques et comptent toujours dans le quota. Les listes actives et les nouvelles recherches de médias CMS excluent la corbeille. Les réservations de dossier et de nom restent en place jusqu’à la restauration ou la purge.
Les gestionnaires peuvent restaurer un fichier ou une sélection depuis la corbeille. Ctrl/Cmd+Z dans le tableau ou la galerie média actif annule la dernière suppression admissible de l’utilisateur courant en utilisant l’historique Activité de la fiche. Une suppression en lot partage un identifiant de transaction ; un raccourci restaure ses membres et, après un échec partiel, seuls les échecs restent à retenter. La restauration conserve l’historique : un événement inverse référence la suppression initiale.
Supprimer une sélection, c’est une seule requête et une seule transaction en base (trashMediaAssetsAction, 500 fichiers au plus ; une sélection plus grande part en plusieurs requêtes sous le même identifiant de transaction). Les fichiers qu’elle ne peut pas déplacer restent dans la médiathèque, et la table dit combien et pourquoi : fichiers qui ne sont plus dans la médiathèque, et fichiers qui appartiennent à une ancienne maquette de page, que la base garde en lecture seule depuis que le runtime exact des pages a pris le relais (les renommer, les déplacer ou les restaurer est refusé de la même façon). Les autres fichiers partent ensemble à la corbeille. Les dossiers gardent leur règle et sont supprimés un par un, seulement vides. Aucune action média ne refait le rendu de la page dans sa réponse : l’écran recharge lui-même ses données, et l’échec d’un rechargement des dossiers ou de l’historique ne remplace jamais la réponse du changement lui-même.
media_assets.deleted_at fixe l’expiration ; purge_started_at empêche la restauration pendant le nettoyage. media_asset_activity conserve l’acteur, les valeurs avant/après et les références d’annulation. Le worker page-AI existant contrôle régulièrement la corbeille et retire le fichier et sa miniature après 30 jours. Un échec du stockage conserve la ligne en base pour une nouvelle tentative. La restauration expire exactement 30 jours après la suppression, même si le worker n’a pas encore retiré le fichier. Appliquez la migration et lancez le worker lors du déploiement.
Le tableau de bord et MCP utilisent le même service avec contrôle des droits. yayaw_media_list liste les médias actifs par défaut et accepte trashed: true. yayaw_media_trash et yayaw_media_restore exigent orgId, un reason non vide, le droit d’écriture et media:manage dans l’organisation ; dryRun: true est la valeur par défaut. Ils prennent un fichier ou un lot :
Un fichier :
assetIdavecexpectedUpdatedAt; la restauration accepte aussirevertEventId. La version et l’organisation sont vérifiées dans une transaction verrouillée, et la réponse est{ assetId, dryRun }.Un lot :
assetIds, de 1 à 500 identifiants distincts. Une liste vide, un identifiant répété, plus de 500 identifiants, ouassetId,expectedUpdatedAtourevertEventIden plus sont refusés avant tout changement. Le lot passe par le service par lot du tableau de bord : une transaction, les lignes verrouillées dans l’ordre des identifiants, un savepoint par fichier, une entrée d’activité par fichier sous l’identifiant de transaction du lot. Une restauration annule le dernier passage de chaque fichier à la corbeille. Un fichier que le lot ne peut pas changer n’arrête jamais les autres.
Un lot répond results, un { assetId, status } par fichier dans l’ordre d’envoi : trashed ou restored (y compris un fichier déjà dans la corbeille, ou déjà sorti), refused avec un code et une raison (reason), ou not_found (hors de la médiathèque de l’organisation). Les codes sont read_only (un fichier d’une ancienne maquette de page), failed (réessayer) et, pour une restauration, not_restorable (ses 30 jours sont passés ou son retrait a commencé) et not_reversible (son passage à la corbeille ne peut plus être annulé). Viennent ensuite counts (requested, trashed ou restored, refused, notFound) et, une fois appliqué, transactionId : dans le tableau de bord, une seule annulation par la même personne restaure ensemble un lot mis à la corbeille. La simulation d’un lot fait les changements dans une transaction qu’elle annule : elle répond exactement ce que ferait l’appel, refus de la base compris.
Dupliquer des médias
Utilisez Dupliquer dans le menu ou Ctrl/Cmd+D sur les médias sélectionnés. Chaque copie reçoit un fichier indépendant et un nom unique dans le même dossier via le mécanisme d’import existant. Les copies comptent dans le quota de stockage. Les droits de lecture et de création sont vérifiés côté serveur, et les éléments de la corbeille ne peuvent pas être dupliqués. Un lot réussi sélectionne les copies et affiche un nombre traduit.
Vue Arborescence
Le tableau média (media-assets-v1) propose la vue
Arborescence de YaYaw Table à côté de Galerie et
Tableau. La galerie reste la vue par défaut ; le choix est enregistré par vue
comme tout mode d’affichage. La corbeille ne garde que Galerie et Tableau, car
un fichier supprimé n’a plus de dossier à parcourir.
Lignes. Galerie et Tableau ne listent que les fichiers. L’arborescence liste dossiers et fichiers ensemble : un dossier devient une ligne
folder:<id>avecnodeKind: "folder", un fichier garde son identifiant avecnodeKind: "file", et tous deux portentparentId(folder:<id>de leur dossier, ou vide à la racine). L’arborescence demande ses lignes àsystem:mediaavec unscope, traité sur le serveur :children(les sous-dossiers d’un dossier, puis une page de ses fichiers),subtree(tous les dossiers et fichiers sous un dossier, les niveaux supérieurs d’abord) ettree-matches(les fichiers que la recherche ou les filtres retiennent et, pour une simple recherche, les dossiers qui portent ce nom, avec leurs dossiers dansancestors).subtreeettree-matchess’arrêtent à 200 lignes, puis indiquenttruncated.Tailles et nombres. La taille d’un dossier est la somme de tous les fichiers qu’il contient, sous-dossiers compris (fichiers actifs seulement) ; chaque réponse fournit les
childCountsetsizesde ses lignes de dossier.Racine. L’arborescence part de la racine de la médiathèque : créer un dossier ou déposer des fichiers à la racine de l’arborescence vise la racine de la médiathèque.
Déplacements. Les fichiers se déplacent avec l’action existante (un nom déjà pris reçoit un suffixe unique). Les dossiers se déplacent avec
moveMediaFolderAction, qui exige le droit médiaupdateet refuse, avec uncodetypé traduit dans l’interface : un déplacement dans le dossier lui-même ou l’un de ses sous-dossiers (cycle), au-delà de deux niveaux de dossiers pour tout le sous-arbre déplacé (depth_limit), à côté d’un dossier du même nom (name_conflict, y compris quand une modification simultanée heurte l’index unique), ou un dossier ou une cible hors de l’organisation active (not_found,target_not_found). Les dossiers de l’organisation sont verrouillés pendant la vérification : deux déplacements simultanés ne peuvent pas former un cycle ni un troisième niveau.Autres actions. Nouveau dossier utilise l’action de création (deux niveaux au plus), qui exige le droit média
createet prend le même verrou qu’un déplacement : le parent, la limite de profondeur et le nom sont vérifiés sur les dossiers verrouillés, si bien qu’un sous-dossier créé pendant le déplacement de son parent ne peut pas se retrouver au troisième niveau. Le renommage utilise l’action de renommage du dossier ou du fichier, et la suppression garde ses règles : les fichiers vont à la corbeille, un dossier n’est supprimé que s’il est vide. Les fichiers déposés depuis le bureau sur un dossier passent par le téléversement habituel, avec les limites de la fenêtre de téléversement (20 fichiers, la taille maximale du forfait) vérifiées d’abord ; droits, types et quotas sont vérifiés de nouveau sur le serveur.Droits. Les membres qui ne gèrent pas les médias parcourent l’arborescence sans déplacer, renommer, créer ni déposer. L’interface ne fait que refléter les règles du serveur ; chaque action serveur les vérifie de nouveau.
MCP.
yayaw_media_listn’a pas encore d’argument de dossier ; exposer les dossiers et leurs déplacements au MCP est une suite prévue. Les tags sont exposés (voir Tags).
Médias privés
Les médias privés sont les fichiers qu'une personne garde pour elle dans une
organisation, comme un avatar ou une icône qu'elle a choisie. Ils ne font
pas partie de la médiathèque ci-dessus : ils n'apparaissent jamais dans le
dashboard, la vue arborescence, la recherche, les outils média MCP ni dans la
liste de quelqu'un d'autre. Seul leur propriétaire les liste, les lit et les
supprime, via /api/account/media, avec le jeton bearer que son application
utilise déjà (jeton d'accès OAuth pour /api/mcp ou session d'appareil) et les
origines CORS des clients publics.
Autorisation :
can()sur la ressourceprivate-mediadans l'organisation, pour un membre de celle-ci. Les rôles Organization Member, Manager et Admin fournis par le seed, ainsi que Super Admin, détiennentprivate-media:manage; Super Admin ne garde de médias privés que dans les organisations dont il est membre. Le service n'atteint ensuite que les lignes de l'appelant, donc un administrateur de l'organisation voit ses propres médias privés, pas ceux de ses membres.Types : PNG, JPEG et WebP sont réencodés avec sharp ; le SVG est contrôlé (pas de DOCTYPE, de script, de contenu étranger ni de référence externe) puis rastérisé en PNG. Seules des images matricielles sont stockées et servies.
Limites : 5 Mio par fichier et 25 Mio par personne et par organisation par défaut (
PRIVATE_MEDIA_MAX_FILE_BYTES,PRIVATE_MEDIA_MAX_USER_BYTES). Les médias privés comptent dans le quota de stockage du forfait de l'organisation, sous le même verrou que les téléversements de la médiathèque.Stockage et diffusion : les objets sont dans un bucket privé (
STORAGE_PRIVATE_MEDIA_BUCKET, ou le bucket de staging). Il n'y a ni URL publique ni URL signée :GET /api/account/media/{id}/contentrenvoie les octets au propriétaire authentifié avecCache-Control: private, no-cache, unETaget une Content-Security-Policy de bac à sable.Nettoyage : quitter une organisation supprime les médias privés du membre dans celle-ci, et supprimer une organisation supprime d'abord les fichiers privés de ses membres ; le worker page AI supprime aussi les téléversements expirés, les comptes supprimés et les anciens membres.
Le contrat des routes pour les applications clientes (requêtes, réponses,
erreurs) est dans docs/private-media.md.