Skip to content

Regles de gestion & contraintes

Nature du repo

  • C'est un gabarit, pas un site fini. Les exemples (exampleSection, exampleElement, themes cave/piscines, module JS exampleSection) sont des demonstrations a adapter ou retirer dans un projet aval.
  • Projets Application/Domain/Persistence : a creer au besoin, absents du template.
  • En cas de conflit lors d'un merge depuis upstream, convention : garder la version du template.

SEO & contenu

  • Titres et meta resolus par priorite (PageExtensions) : head title -> meta title -> nom de page ; og title/description retombent sur les meta.
  • Le _MasterLayout emet : canonical, robots noindex si la page est masquee du sitemap (HideFromSitemap), hreflang en variantes *-CH, et x-default vers le canonical.
  • Sitemap (/sitemap) : XML unique multilingue, force https, n'inclut qu'un noeud qui a un url segment, un template et n'est pas masque du sitemap.
  • robots.txt : en production, ne sert que la ligne sitemap: ; hors production, disallow: / (blocage total de l'indexation).

Cookies & marketing

  • Aucun outil collectant des donnees ne doit se charger avant consentement. Google Consent Mode v2 : analytics_storage='denied' par defaut ; le consentement met a jour via gtag('consent','update',...).
  • Le popup de consentement (vanilla-cookieconsent) ne s'affiche que si CookieConsent:Enabled=true. Mettre a false quand un CMP tiers (OneTrust, Didomi...) est integre.
  • GA4 ne s'injecte que si GoogleAnalytics4Id est renseigne sur le marketingSettings ; anonymize_ip actif.

Skins APOL / PEL

  • Un seul depot, deux deploiements : les DataTypes uSync contiennent les choix des deux marques ; c'est Site:Theme qui decide, au demarrage, de ce que voit l'editeur. Ne jamais dupliquer un DataType ni un fichier uSync par skin — la divergence rendrait chaque merge upstream conflictuel.
  • Options propres a un skin : leur alias (bloc) ou leur valeur (couleur, motif de fond...) doit etre ajoute au jeu correspondant dans BlockGridSkinFilterHandler / DataTypeSkinFilterHandler, sinon elles sont proposees aux deux skins. Les entrees absentes des deux jeux sont considerees communes (blocs partages, neutres blanc/gris/noir). Filtrer une nouvelle liste de choix = une ligne dans la table Filters de DataTypeSkinFilterHandler.
  • Export uSync depuis une instance demarree : les handlers ont deja ampute les DataTypes en base, l'export reecrit donc une config incomplete. Verifier ApprovedColor.config et le BlockGrid avant de committer un export.

Securite

  • DevLoginController (/l, auto-login backoffice) : double garde obligatoire #if DEBUG + check runtime IsDevelopment(). Ne jamais retirer.
  • Politique de mot de passe backoffice (appsettings.json) : 15 caracteres min, majuscule + minuscule + chiffre + non-alphanumerique. AllowConcurrentLogins=false.
  • 2FA backoffice via Google Authenticator (UmbracoUserAppAuthenticator).
  • Secrets (chaine de connexion prod, SentryUrl, cles) : jamais committes ; via appsettings.local.json (git-ignore) ou variables d'env.
  • UmbracoApplicationUrl obligatoire derriere un reverse proxy (breaking change 17.4) sinon spoofing possible sur les emails de reset/invitation.

Intranet & Active Directory (PEL)

  • Accès à l'intranet : réservé aux comptes AD appartenant à au moins un groupe du mapping Ldap:GroupMappings (groupe AD → groupe membre Umbraco). Confirmé avec le SSI de Pully (15.07.2026) : même mode de fonctionnement que Felix, annuaire joignable en LDAPS (chiffré).
  • Mot de passe : validé uniquement par l'AD (bind LDAPS) ; jamais stocké, jamais loggué. Anti-brute-force = politique de verrouillage de l'AD ; anti-énumération = message d'échec générique + délai additionnel fixe (400 ms) sur les échecs côté site.
  • Date de naissance : n'existe pas dans l'AD de Pully ni dans Entra ID (aucun attribut standard) → birthDate est une saisie manuelle backoffice, comme photo et showInDirectory. Confirmé côté Pully (15.07.2026), à confirmer côté APOL. La sync AD ne doit jamais écraser ces trois champs. APOL aurait voulu une reprise automatique depuis l'AD, mais l'AD de Pully disparaît sous ~3 mois et l'attribut anniversaire Entra/Graph (birthday) est généralement vide côté M365 → saisie manuelle en MVP sur les deux skins, avec showBirthday pour l'opt-out (voir ci-dessous).
  • Contacts externes vs personnel : un contact hors personnel (commune, partenaire, service) doit toujours être saisi comme contenu (externalContact), jamais comme intranetMember. La sync AD désactive (IsApproved=false) tout membre absent de l'annuaire AD ; un contact externe créé comme membre disparaîtrait donc à la synchronisation suivante. Umbraco impose en plus un e-mail et un username uniques par membre, contrainte que beaucoup de contacts externes ne remplissent pas.
  • showBirthday distinct de showInDirectory : un collaborateur peut vouloir figurer à l'annuaire sans exposer sa date de naissance. Même sémantique que showInDirectory : visible sauf false explicite, donc les membres existants sans valeur restent visibles par défaut. Comme birthDate, photo et showInDirectory, cette propriété n'est jamais écrite par la synchronisation AD.
  • Départ d'un collaborateur : la sync passe le membre en IsApproved=false (plus de login, exclu de l'annuaire/anniversaires) ; jamais de suppression automatique (les données manuelles seraient perdues). Suppression manuelle possible au backoffice.
  • Garde-fou anti-vidage : si l'AD est injoignable ou renvoie 0 utilisateur, la sync ne modifie rien — un raté réseau ne doit jamais vider l'annuaire.
  • SSO transparent (Windows Auth) : l'hébergement sera Windows IIS chez Pully (confirmé 15.07.2026) → SSO Windows Authentication implémenté (WindowsSsoMiddleware, activé par Intranet:WindowsSso=true) : identité Windows IIS → fiche LDAP → provisioning → connexion membre, sans saisie de mot de passe. Le login formulaire /login reste le repli (postes hors domaine, IIS anonymous actif, annuaire indisponible). Modalités de déploiement IIS à préciser (compte-rendu Xavier attendu) — le pipeline Docker du template ne s'applique pas à ce projet.
  • Page « Mon profil » : un collaborateur ne peut modifier que sa photo et sa date de naissance — exactement les champs que la sync AD n'écrit jamais (avec showInDirectory/showBirthday). Tout le reste (prénom, nom, e-mail, fonction, numéros) vient de l'AD et reste en lecture seule, sinon une saisie manuelle serait écrasée à la synchronisation suivante et donnerait l'impression d'un bug. L'écriture porte toujours sur le membre connecté : le formulaire ne transporte aucun identifiant, la clé est lue dans la session, donc une personne ne peut pas modifier la fiche d'une autre en altérant le POST. Felix n'avait pas cette page en service (les vues du kit Nanoxi existent mais l'entrée de menu desktop est commentée et aucune PageLogin n'est publiée) : c'est un ajout, hors devis. Les opt-out showInDirectory/showBirthday restent pour l'instant réservés au backoffice — à arbitrer avec le client.
  • Âge affiché aux anniversaires : le bloc Anniversaires indique l'âge atteint, comme le widget felix. L'âge n'est affiché que s'il tombe entre 15 et 100 ans : birthDate est une saisie manuelle, et une date choisie sans toucher à l'année prend l'année courante — ce qui afficherait « 0 ans » à un collègue. Hors de cette plage, aucun âge n'est affiché plutôt qu'un âge faux (DirectoryRules.AgeOn). À noter : afficher l'âge expose l'année de naissance, que le seul jour/mois ne révélait pas ; showBirthday reste l'unique opt-out (tout ou rien), comme sur felix.
  • Actualités lues / non lues : repris de felix (Nanoxi.Customization/Felix, en service depuis 2019), avec la même mécanique — les ids des articles ouverts sont stockés en CSV sur le membre (memberReadArticles), et un titre non lu ressort en rouge tandis qu'un titre lu passe en couleur de texte. Pas de badge : sur une liste longue, la couleur seule se lit plus vite. Ouvrir l'article suffit à le marquer lu (ArticlePage.cshtml), il n'existe pas de « marquer comme lu » manuel. Trois écarts assumés avec l'original : lecture null-safe (felix plantait sur un membre n'ayant jamais ouvert d'article), déduplication, et liste bornée à 2000 ids. Sans membre connecté, aucune distinction n'est affichée — surtout pas « tout non lu ». Les états de lecture felix ne sont pas migrés : au basculement, tout repart non lu (décision 22.07.2026). Fonctionnalité hors devis.
  • Risque accepté (décision Clément, 15.07.2026) : avec RequireLogin=true, /media (dont les PDF migrés de Felix) et /sitemap restent accessibles sans login (allowlist du MemberGate + bypass des fichiers à extension). Accepté car l'intranet sera hébergé à l'interne chez Pully, sur un réseau protégé non exposé au public. À réévaluer si l'hébergement ou l'exposition réseau change.

Auth & infra APOL (M365/Entra ID)

  • Authentification : SSO membre via Microsoft Entra ID (M365 APOL), pas d'AD LDAPS comme PEL. Auto-link JIT au premier login (membre intranetMember créé à la volée) ; tout le tenant APOL est autorisé, pas de filtrage par groupe (contrairement au Ldap:GroupMappings de Pully) — voir modules/extensibility.md.
  • Hébergement : chez APOL, via leur prestataire infogérant ANSAM (pas Pully/Windows IIS comme PEL). Modalités de déploiement précises à confirmer avec ANSAM.
  • Rôles/admin backoffice : hors périmètre du devis actuel — pas de gestion fine des rôles éditeurs côté APOL dans le MVP.
  • 2FA membre : bypass assumé. Le callback EntraAuthController.Callback appelle ExternalLoginSignInAsync(..., bypassTwoFactor: true) : Entra impose déjà le MFA en amont (au niveau du tenant M365), et il n'existe aucune UI de 2FA côté membre dans ce codebase (la 2FA existante, UmbracoUserAppAuthenticator, est backoffice uniquement). Une future fonctionnalité de 2FA membre devra composer avec ce bypass déjà en place — ne pas supposer qu'ExternalLoginSignInAsync respecte un 2FA membre qui n'existe pas encore.

Base de donnees & deploiement

  • UpgradeUnattended=true : migrations jouees au boot.
  • Cache statique : /css et /js (fingerprintes) en immutable 1 an ; autres assets 7 jours.
  • Rewrites IIS et Sentry actifs uniquement en Staging/Production.
  • Image Docker buildee depuis la racine du repo (pas depuis hosting/).

Fichiers generes / a ne pas editer

  • src/Web/umbraco/Models/*.generated.cs (ModelsBuilder), src/Web/wwwroot/css|js (Vite).
  • gulpfile.js : legacy, conserve mais inutilise (pipeline = Vite).

Contributors

No contributors

Changelog

No recent changes