Logo et cachet d'un établissement — détails techniques
Description et usage : Identité de l'établissement.
Pour l'habillage d'un ENT entier (une région, une collectivité) : Thème d'un ENT.
Le partage des rôles : l'ENT habille, l'établissement signe
Un ENT est déployé pour une région (académie, département, collectivité) et sert des dizaines ou des centaines d'établissements. Les deux niveaux ne portent pas la même chose, et les confondre est la première source d'erreur.
| Thème de l'ENT | Branding de l'établissement | |
|---|---|---|
| Porté par | l'hôte HTTP (table skins:) | le nœud Structure de l'annuaire |
| Contenu | palette complète, feuilles de style, illustrations, gabarits | logo, en-tête, cachet, signature, signataire, 2 couleurs |
| Stocké dans | un artefact tar.gz sur le volume des assets | Neo4j (s.branding*) + documents workspace |
| Modifié par | la CI, puis une installation | un ADML ou un chef d'établissement, en direct |
| Prise d'effet | installation (ou redémarrage pour un nouveau thème) | immédiate |
| Granularité | un domaine | un établissement |
Autrement dit : le branding se superpose au thème, il ne le remplace pas. Chaque champ que l'établissement ne renseigne pas retombe sur le thème. Un établissement sans branding rend donc exactement comme avant que la notion existe — c'est une garantie du mécanisme, pas un effet de bord.
Le modèle ne lie pas une Structure à un thème : la résolution se fait par h ôte. Un
établissement qui doit vraiment avoir un thème distinct a besoin de son propre domaine — voir
Thème d'un ENT § Cas d'un établissement.
Dans la quasi-totalité des demandes réelles, ce n'est pas ce qu'il faut faire : ce que l'on veut,
c'est le logo et le cachet sur les documents, et c'est précisément ce que couvre cette page.
Où vivent ces données
Les propriétés sont posées sur le nœud Structure, préfixées branding. Aucune ne vient de
l'AAF : aucun import ne les écrase.
| Champ d'API | Propriété Neo4j | Nature |
|---|---|---|
primaryColor, accentColor | s.brandingPrimaryColor, s.brandingAccentColor | couleur hexadécimale |
logo, entete, cachet, signature | s.brandingLogo… | identifiant de document workspace |
cachetPourtour, cachetMention | s.brandingCachetPourtour… | texte du cachet composé |
signataireCivilite, signataireNom, signatairePrenom, signataireFonction, signataireLibelle | s.brandingSignataire* | identité du signataire |
Elles sont déposées dans le workspace (POST /workspace/document?application=media-library) et
l'annuaire ne retient que l'identifiant du document ; l'affichage passe par
/workspace/document/<id>. Une image inline en base aurait alourdi chaque lecture de structure et
privé ces fichiers de la gestion de quota et d'antivirus du workspace.
API
GET /directory/structure/:id/branding # AUTHENTICATED
PUT /directory/structure/:id/branding # AdminStructureFilter — admin de CETTE structure
Le PUT n'écrit que les champs présents dans le corps : l'écran « thème » et l'écran « identité
documentaire » peuvent enregistrer chacun sa part sans effacer celle de l'autre. Une clé présente à
null efface — c'est le seul moyen de retirer un logo.
Le GET renvoie aussi name, type et city de la structure : ce sont les valeurs par défaut du
cachet, que l'appelant n'a donc pas à aller chercher ailleurs.
Comment le branding atteint les documents
StructureBrandingService est le point unique de résolution. Deux entrées :
getForStructure(structureId)— pour tout ce qui a un établissement en contexte (publipostage) ;getForUser(userId)— pour le portail, où seul l'utilisateur est connu.
Les deux sont aussi exposées sur l'event bus entcore.directory, actions get-structure-branding
et get-user-branding, pour les modules qui ne partagent pas le verticle de l'annuaire.
Il n'existe pas d'« établissement principal » dans le modèle. getForUser choisit donc
explicitement : la première structure qui définit effectivement un branding, puis par ordre
alphabétique. Le tri par nom n'est pas cosmétique — sans lui, un enseignant partagé entre deux
collèges pourrait recevoir un en-tête différent d'une génération à l'autre.
Portail et applications
GET /theme/branding.css renvoie une feuille de style minuscule, propre à l'utilisateur connecté :
:root{
--custom-primary:#8E136D; /* thème legacy (AngularJS) */
--openent-primary:#8E136D; /* bootstrap React */
--custom-accent:#FFB300;
--openent-secondary:#FFB300;
--structure-logo:url("/workspace/document/abc123");
}
Le SCSS expose déjà --custom-primary / --custom-accent et le bootstrap React lit
--openent-* : les surcharger suffit. Aucun artefact par établissement, aucune recompilation —
ce qui est ce qui rend la chose tenable à l'échelle de centaines d'établissements.
GET /themeLa réponse de /theme est mémorisée dans un attribut de session. Un branding modifié
n'atteindrait donc jamais les sessions déjà ouvertes — exactement le piège rencontré avec la CSP,
qui imposait une reconnexion. Une feuille de style est une ressource HTTP ordinaire, avec ses
propres en-têtes de cache, que le navigateur revalide.
Publipostage
Les gabarits massmail.pdf.xhtml, massmail_simple.pdf.xhtml et massmail_new.pdf.xhtml
préfèrent le logo de l'établissement quand il existe :
{{#branding.logoUrl}}<img id="logo" src="{{branding.logoUrl}}"></img>{{/branding.logoUrl}}
{{^branding.logoUrl}}<img id="logo" src="logo-text.png"></img>{{/branding.logoUrl}}
Les identifiants de documents sont résolus en URL absolues avant d'atteindre le gabarit : le générateur de PDF est un service distinct, qui ne saurait pas résoudre un chemin relatif.
Documents réglementaires
WorkflowHub lit les mêmes propriétés pour les certificats de scolarité et les attestations. Quand
aucune image de cachet n'a été déposée, il en compose un en SVG (Cachet.svg) à partir du nom
de l'établissement, de sa ville et de la qualité du chef d'établissement — cette dernière étant
déduite de s.type et de u.title, ce qui évite un « M. le Proviseur » au bas du certificat d'une
école primaire.
Mettre en service un établissement
- Vérifier que la structure existe et que l'opérateur en est administrateur
(
AdminStructureFilter: un ADML d'un autre établissement sera refusé). - Déposer les images depuis Administration → Configuration → Identité de l'établissement : logo, en-tête (ou papier à en-tête déjà composé), cachet (ou laisser l'ENT le composer), signature (image ou tracé à l'écran).
- Renseigner le signataire : civilité, nom, prénom, fonction. La fonction sert au libellé « Je soussignée Mme X, Proviseure de l'établissement… ».
- Facultatif — les couleurs. À ne renseigner que si l'établissement a une charte propre : sans elles, il hérite de celle de l'ENT, ce qui est le comportement attendu dans la plupart des cas.
- Vérifier sur un document réel, pas sur l'aperçu : produire un courrier d'identifiants et un certificat de scolarité (voir § Vérifier).
Aucun déploiement, aucun redémarrage, aucune intervention sur le cluster : ce sont des données.
Limites à connaître
- Seules les couleurs de marque suivent. Les teintes dérivées (
darken,lightenappliqués à$primary-base) sont calculées à la compilation du SCSS et restent celles du thème. Une charte d'établissement très éloignée de celle de l'ENT donnera donc un rendu hybride sur les composants qui utilisent ces variations. - Un seul branding à la fois par utilisateur. Voir l'encadré sur les comptes multi-structures.
- Le branding ne change pas les gabarits, seulement les images et les couleurs qu'ils utilisent. Un établissement qui veut un texte différent sur son certificat passe par le modèle éditable du document, pas par ici.
- Rien n'est propagé aux sous-structures. Une académie qui renseigne un branding ne l'impose pas
à ses établissements : la résolution part de la structure de l'utilisateur et ne remonte pas la
hiérarchie
HAS_ATTACHMENT.
Vérifier
# Ce que porte la structure
curl -s -b "$COOKIE" https://<hote>/directory/structure/<structureId>/branding | jq
# Ce que le portail sert à un utilisateur de cet établissement
curl -s -b "$COOKIE" https://<hote>/theme/branding.css
# L'image est-elle réellement servie ? (GET, jamais HEAD : les assets répondent 404 en HEAD)
curl -s -o /dev/null -w '%{http_code}\n' https://<hote>/workspace/document/<idDuLogo>
Puis, sur des documents réels : un courrier d'identifiants (Annuaire → publipostage) doit porter le logo de l'établissement, et un certificat de scolarité son en-tête, son cachet et sa signature.
Diagnostic
| Symptôme | Cause probable | Vérification |
|---|---|---|
| Le logo du thème apparaît à la place de celui de l'établissement | Le champ est vide, ou l'utilisateur est résolu sur une autre de ses structures | GET /structure/<id>/branding ; contrôler les structures de l'utilisateur |
| Le logo n'apparaît nulle part, ni thème ni établissement | Document workspace supprimé — l'identifiant reste en base | GET /workspace/document/<id> → 404 |
| Les couleurs ne changent pas dans les applications React | /theme/branding.css n'est pas chargée par le module | Inspecter les feuilles de style de la page |
| Le cachet est vide sur un certificat | Ni image déposée, ni cachetPourtour/cachetMention renseignés | Écran Identité de l'établissement ; l'ENT compose sinon un cachet par défaut |
| Un ADML ne peut pas enregistrer | Il n'est pas administrateur de cette structure | AdminStructureFilter — vérifier son périmètre |