Skip to main content

Thème d'un ENT — détails techniques

Fiche fonctionnelle

Description et usage de l'éditeur de thème : Configuration ENT › Personnalisation.

Pour le logo et le cachet d'un établissement — qui ne passent pas par un thème : Logo et cachet d'un établissement.

Quelle configuration modifier ?

Selon que la demande concerne l’apparence de l’ENT ou l’identité d’un établissement, les réglages et les étapes diffèrent. Le tableau suivant indique la méthode à suivre pour chaque cas.

BesoinLevierRedémarrage
Changer les couleurs ou le logo d'un ENT existantÉditeur de thème du dashboardnon/admin/configuration/ent
Ouvrir un nouvel ENT (région, collectivité, département)Nouveau skin + nouvel hôteouicette page
Donner à un établissement son logo, son cachet, ses couleursBranding par structurenondoc dédiée
Donner à un établissement un thème entièrement distinctHôte dédié + nouveau skinouicette page, §« Cas d'un établissement »
Il n'existe pas de « thème par établissement »

Le modèle ne lie pas une Structure à un thème. Tenant n'en porte pas non plus. Le thème se résout par hôte HTTP ; le branding se résout par structure. Un établissement qui doit avoir un thème à lui a donc besoin de son propre nom de domaine — il n'y a pas d'autre levier, et chercher un champ « thème » sur l'établissement est une impasse.

Comment un thème est choisi à l'exécution

PortalController#getSkinFromConditions (libs/portal-mui/backend) applique, dans l'ordre :

Deux conséquences pratiques :

  • La table skins: est la seule chose qui rattache un ENT à son habillage. Elle est lue une fois, à l'initialisation du verticle du portail (initAsync), et recopiée dans hostSkin. Ajouter une entrée impose donc un redémarrage — c'est la raison pour laquelle un nouveau thème ne peut pas se déployer à chaud, alors que la mise à jour d'un thème existant le peut.
  • La préférence utilisateur l'emporte sur l'hôte. Un compte qui a un uac.theme hérité d'un autre déploiement verra le mauvais thème, même sur le bon domaine. Le dashboard expose un diagnostic et une réinitialisation par établissement (Configuration ENT › Thème par établissement), dont l'effet n'est visible qu'à la reconnexion.

Anatomie d'un thème

Un thème vit dans le dépôt open-ent/theme-open-ent, sous overrides/<skin>/ :

overrides/<skin>/
├── css/_overridable-variables.scss # $primary, $accent, $hover — la charte
├── img/ # logo.png, logo-text.png, illustrations…
├── i18n/<App>/<langue>.json # libellés propres au déploiement
└── template/directory/ # gabarits de publipostage (massmail)

Le SCSS commun (scss/, skins/) est partagé ; build.sh -o=<skin> écrase les fichiers communs par ceux de l'override, puis compile chaque skin (default, dyslexic) en dist/skins/<skin>/theme.css.

Le résultat n'est plus embarqué dans l'image assets : il est publié en artefact, un tar.gz par skin, que l'ENT télécharge lui-même.

Pourquoi l'ENT tire au lieu que la CI pousse

La chaîne précédente reconstruisait une image de 195 Mo pour un changement de couleur, puis faisait kubectl set image avec un KUBE_CONFIG stocké chez GitHub : un workflow déclenchable par un ADML détenait un accès en écriture à la production. Désormais la CI ne publie qu'une Release sur son propre dépôt, et aucun identifiant de cluster ne sort du cluster.

Créer le thème d'un nouvel ENT

Les étapes 1 à 4 se font sans toucher à la production ; les étapes 5 à 8 sont la mise en service.

1. Créer l'override

Dans open-ent/theme-open-ent, partir de l'override le plus proche plutôt que de default — les chartes existantes documentent ce qui se surcharge réellement :

cp -r overrides/eclat-bfc overrides/<nouveau-skin>
$EDITOR overrides/<nouveau-skin>/css/_overridable-variables.scss # $primary, $accent, $hover

Remplacer les images de img/ : au minimum logo.png (marque carrée, icône d'application) et logo-text.png (logotype horizontal, utilisé en tête des courriers d'identifiants).

Ne pas committer de sources de maquettage

logo-text.xcf pèse jusqu'à 4,5 Mo, n'est jamais servi en HTTP et serait téléchargé par chaque cluster à chaque publication. package-theme.sh les exclut de l'artefact (.xcf, .psd, .ai), mais ils alourdissent quand même le dépôt.

2. Déclarer le thème dans theme-conf.js

open-ent-mods/starter/assets/theme-conf.js, servi en /assets/theme-conf.js, est ce que lisent les ThemeProvider React :

{
parent: "theme-open-ent",
child: "<nouveau-skin>",
group: "<nouveau-skin>",
skins: ["default", "dyslexic"],
help: "/help-2d", // ou /help-1d pour un ENT premier degré
bootstrapVersion: "ode-bootstrap-neo", // ou ode-bootstrap-1d
}

Le dernier segment de bootstrapVersion devient l'attribut data-product de la balise <html>, qui pilote la majeure partie du style des modules React.

data-product="1d" est récent

Beaucoup de règles n'existaient que pour neo/one et doivent être étendues explicitement à 1d. C'est la cause de la plupart des écarts visuels sur un thème premier degré — voir README-THEME.md du dépôt open-ent-mods.

3. Construire et inspecter en local

cd open-ent-mods
./scripts/build-theme.sh <nouveau-skin> # → starter/assets/themes/<nouveau-skin>/
./scripts/build-theme.sh <nouveau-skin> --package # → artifacts/theme-<skin>-<version>.tar.gz

--package appelle exactement le script qu'utilise la CI : ce qui sort de là est bit pour bit ce que publierait le workflow pour la même source et la même version.

4. Publier l'artefact

Pousser l'override sur la branche par défaut de theme-open-ent (ou passer par l'éditeur de thème, qui ouvre une PR). Le workflow theme-release.yml construit le thème et publie le tag theme-<skin>-<version> avec deux fichiers : l'archive et sa somme .sha256.

Une release sans les deux fichiers est ignorée par l'ENT : sans le .sha256, impossible de vérifier ce qu'on s'apprête à servir.

5. Déclarer l'hôte → thème

Dans open-ent-mods/starter/ent-core.yaml, la table skins: apparaît à trois endroits : sharedConf, le module infra, et le module portal-mui. Les trois doivent être alignées.

skins:
<nouvel-hote>.ent-scolaire.fr: <nouveau-skin>
<nouvel-hote>.ent-scolaire.fr:443: <nouveau-skin>
L'entrée avec :443 n'est pas décorative

Les clés de skins: alimentent aussi la liste des hôtes de confiance de Renders.getHost(). Un hôte absent de cette liste retombe sur le premier de la table, ce qui casse silencieusement les URL générées (retours d'authentification, liens des courriels, WOPI).

6. Router l'hôte

Ajouter l'hôte dans helm/openent-monolithe/values.yaml, section ingress.hosts :

ingress:
hosts:
- host: <nouvel-hote>.ent-scolaire.fr

Le DNS doit pointer vers le cluster, et le certificat Traefik couvrir le sous-domaine (le résolveur ACME du cluster gère *.ent-scolaire.fr).

Le joker WordPress capte les sous-domaines non prioritaires

Sur k3sprd, l'ingress WordPress déclare *.ent-scolaire.fr et renvoie un 302 vers wp-signup.php, qui atterrit sur l'ENT en 404 — un 404 trompeur, alors que DNS, certificat et routage sont corrects. Vérifier en une commande :

curl -s -o /dev/null -D - https://<nouvel-hote>.ent-scolaire.fr/ | grep -iE '^HTTP|^location'

Si la location pointe vers wp-signup.php, c'est cela et rien d'autre : poser traefik.ingress.kubernetes.io/router.priority sur l'Ingress de l'ENT.

7. Épingler la version du thème

themes:
pinned:
- { skin: <nouveau-skin>, version: "<version publiée>" }

C'est ce pin que l'init container sync-themes réinstalle à chaque démarrage : c'est lui qui rend la production reproductible, pas ce qui se trouve sur le volume.

Le chart refuse de se rendre si themes.pinned est vide

L'image assets n'embarque plus les skins. Un helm upgrade avec un pinned vide donnerait un ENT sans aucun thème — toutes les feuilles de style en 404. Le garde-fou templates/_theme-preflight.tpl bloque le rendu avec la marche à suivre. Repli tant qu'aucune release n'existe : --set themes.enabled=false.

8. Déployer

export KUBECONFIG=~/.kube/config-k3sprd
helm upgrade ent ./helm/openent-monolithe -n ent \
--set-file entCoreConfig=starter/ent-core.yaml

Le redémarrage est nécessaire ici : la table skins: est figée à l'initialisation du verticle.

Mettre à jour un thème existant

C'est le cas courant, et il ne demande aucun redémarrage :

  1. Publier depuis l'éditeur de thème (Configuration ENT › Personnalisation › Publier) — ou pousser sur overrides/<skin>/, ce qui déclenche la même release.
  2. L'installer depuis l'onglet Versions du thème du dashboard. L'ENT télécharge l'archive, vérifie sa somme de contrôle, l'extrait dans themes/.store/<skin>/<version>/ et permute le lien themes/<skin> de façon atomique.
  3. Reporter la version dans themes.pinned (le dashboard signale la dérive) pour qu'un pod recréé la réinstalle.

Les versions précédentes restent sur le volume (themes.keepVersions, 3 par défaut) : revenir en arrière est immédiat, c'est une permutation de lien sans téléchargement.

Cas d'un établissement qui doit avoir son propre thème

Il n'y a pas de raccourci : c'est un ENT de plus, avec son hôte. La procédure est celle ci-dessus, l'hôte étant dédié à cet établissement (<etablissement>.ent-scolaire.fr). Cela entraine :

  • un hôte de plus à router, à certifier et à surveiller ;
  • les utilisateurs de cet établissement doivent entrer par ce domaine — un lien profond vers le domaine de la région leur servira le thème de la région ;
  • un compte rattaché à plusieurs établissements n'aura qu'un seul thème à la fois, celui du domaine par lequel il est entré.

Dans la grande majorité des cas, ce n'est pas ce qu'il faut faire : un établissement qui veut « son identité » veut son logo, son cachet et ses couleurs sur ses documents — ce que couvre le branding par structure, sans hôte, sans artefact et sans redémarrage.

Vérifier

Toujours en GET : les assets de l'ENT répondent 404 en HEAD, ce qui donne un faux diagnostic.

# Le thème est bien associé à l'hôte
curl -s https://<hote>/skin

# La feuille de style du thème est servie, et à jour (200, pas 304)
curl -s -o /dev/null -D - "https://<hote>/assets/themes/<skin>/skins/default/theme.css" \
| grep -iE '^HTTP|^last-modified|^cache-control'

# Ce que le cluster sert réellement, et depuis quelle version
kubectl -n ent exec deploy/ent-openent-monolithe -c launcher -- \
sh -c 'cat /srv/launcher/assets/themes/.installed.json; ls -l /srv/launcher/assets/themes/<skin>'