Skip to main content

Logo et cachet d'un établissement — détails techniques

Fiche fonctionnelle

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'ENTBranding de l'établissement
Porté parl'hôte HTTP (table skins:)le nœud Structure de l'annuaire
Contenupalette complète, feuilles de style, illustrations, gabaritslogo, en-tête, cachet, signature, signataire, 2 couleurs
Stocké dansun artefact tar.gz sur le volume des assetsNeo4j (s.branding*) + documents workspace
Modifié parla CI, puis une installationun ADML ou un chef d'établissement, en direct
Prise d'effetinstallation (ou redémarrage pour un nouveau thème)immédiate
Granularitéun domaineun é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.

Un établissement ne peut pas avoir « son thème » par ce biais

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'APIPropriété Neo4jNature
primaryColor, accentColors.brandingPrimaryColor, s.brandingAccentColorcouleur hexadécimale
logo, entete, cachet, signatures.brandingLogoidentifiant de document workspace
cachetPourtour, cachetMentions.brandingCachetPourtourtexte du cachet composé
signataireCivilite, signataireNom, signatairePrenom, signataireFonction, signataireLibelles.brandingSignataire*identité du signataire
Les images ne sont pas stockées en base

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.

Un utilisateur peut appartenir à plusieurs établissements

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.

Pourquoi une feuille de style et non un champ de GET /theme

La 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

  1. Vérifier que la structure existe et que l'opérateur en est administrateur (AdminStructureFilter : un ADML d'un autre établissement sera refusé).
  2. 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).
  3. Renseigner le signataire : civilité, nom, prénom, fonction. La fonction sert au libellé « Je soussignée Mme X, Proviseure de l'établissement… ».
  4. 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.
  5. 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, lighten appliqué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ômeCause probableVérification
Le logo du thème apparaît à la place de celui de l'établissementLe champ est vide, ou l'utilisateur est résolu sur une autre de ses structuresGET /structure/<id>/branding ; contrôler les structures de l'utilisateur
Le logo n'apparaît nulle part, ni thème ni établissementDocument workspace supprimé — l'identifiant reste en baseGET /workspace/document/<id> → 404
Les couleurs ne changent pas dans les applications React/theme/branding.css n'est pas chargée par le moduleInspecter les feuilles de style de la page
Le cachet est vide sur un certificatNi 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 enregistrerIl n'est pas administrateur de cette structureAdminStructureFilter — vérifier son périmètre