Workflows
Parcours dev - mise en place locale
nvm use 22.12.0, puiscd src/Webetnpm install.- Base de donnees : par defaut
Server=localhost\sqlexpress;Database=UmbracoBaseTemplate;User Id=dev;Password=dev. Override viaappsettings.local.json(git-ignore) ou variable d'env.UpgradeUnattended=truecree/migre la base au boot.Variante SQLite, sans SQL Express (verifiee le 2026-08-17) : ecrire
src/Web/appsettings.local.json(git-ignore, charge uniquement en Development parProgram.cs). Umbraco creesrc/Web/umbraco/Data/Umbraco.sqlite.dbau premier boot,InstallUnattendedcree l'utilisateur backoffice sans passer par l'ecran d'installation, et uSync importe le groupeSettingsdans la foulee (doctypes, DataTypes, langues, dictionnaire). Deux contraintes : le mot de passe doit satisfaire la politique deappsettings.json(15 caracteres, majuscule + minuscule + chiffre + non-alphanumerique) et l'e-mail doit se terminer par@spektrummedia.com, sinonGET /lne trouve personne a connecter.json{ "ConnectionStrings": { "umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", "umbracoDbDSN_ProviderName": "Microsoft.Data.Sqlite" }, "Umbraco": { "CMS": { "Unattended": { "InstallUnattended": true, "UpgradeUnattended": true, "UnattendedUserName": "Spektrum Dev", "UnattendedUserEmail": "dev@spektrummedia.com", "UnattendedUserPassword": "<15 caracteres minimum>" } } } }Repartir de zero : arreter le site, supprimer
src/Web/umbraco/Data/*.sqlite.db*, relancer. Les medias seedes vivent danswwwroot/media/(git-ignore) et se re-importent au re-seed.
- (Optionnel) SMTP local :
docker run --rm -it -p 5000:80 -p 2525:25 rnwood/smtp4dev(UI sur http://localhost:5000). - Backend :
dotnet run --project src/Web/Web.csproj. - Frontend en parallele :
npm run dev(build + watch SCSS/JS, live-reload ; proxy/->https://localhost:44360). - Login backoffice rapide en DEBUG :
GET /lconnecte le premier utilisateur@spektrummedia.com.
Parcours dev - tester plusieurs domaines en local (multi-sites)
Une meme instance Umbraco peut heberger plusieurs sites (ex. gilliard.ch + chevaliers.ch, gilliarday.ch, portedenovembre.ch). C'est de la configuration backoffice, aucun code applicatif a modifier : le site courant est resolu par match du host de la requete sur un Domain Umbraco (voir ../modules/extensibility.md, section 404 par site). Un site = un noeud homePage en racine (type AllowAtRoot=True) + un Domain assigne.
- Un noeud
homePagepar site, cote a cote a la racine du contenu. Publier la variantefrde chacun (homePageestVariations=Culture). - Hostnames locaux : utiliser
*.localtest.me(resout automatiquement vers127.0.0.1, aucun fichier hosts a editer), ex.gilliard.localtest.me,chevaliers.localtest.me, etc. - Culture and Hostnames : clic droit sur chaque racine -> Culture and Hostnames -> ajouter le hostname avec le port et la langue French (fr), ex.
https://gilliard.localtest.me:44360. Assigner un domaine a toutes les racines (y compris la principale), sinon le routage devient ambigu. - Lancer sous Kestrel, PAS IIS Express (critique) : le profil IIS Express n'accepte que
localhostet renvoie "HTTP 400 - invalid hostname" pour tout autre host. Utiliser le profilUmbraco.Web.UI(dotnet run --project src/Web/Web.csproj), qui sert le memehttps://localhost:44360via Kestrel et accepte n'importe quel host (AllowedHosts=*par defaut). - HTTPS : le certificat dev ne couvre que
localhost, donc un avertissement de certificat s'affiche sur*.localtest.me-> cliquer "continuer" une fois par host (sans danger en local). Alternative sans avertissement : port http12953. - Assets : on navigue directement sur l'app (pas via le proxy Vite), donc
wwwroot/css|jsdoivent exister -> lancer un build (npm run build:prod) une fois. Le live-reload Vite ne suit pas les hostnames custom.
Le message backoffice "This document is published but its URL cannot be routed" est un artefact d'affichage : l'URL est calculee par rapport au host du backoffice (
localhost), qui ne matche aucun domaine. Le front-end route correctement sur le vrai host.
Parcours dev - modeliser des blocs/doctypes via uSync (regeneration des modeles)
Quand on ajoute ou modifie des content types directement dans les fichiers uSync/v17/ (sans passer par le backoffice), ModelsBuilder (SourceCodeAuto) ne regenere pas les umbraco/Models/*.generated.cs : uSync supprime les notifications de sauvegarde pendant son import au demarrage. Les vues Razor (compilees au build) referencant les nouveaux modeles ne compilent alors pas. Procedure fiable :
- Boot avec compilation Razor desactivee le temps du bootstrap : decommenter le bloc
RazorCompileOnBuild/RazorCompileOnPublish=falsedansWeb.csproj(sinon le build echoue sur les vues referencant des modeles encore inexistants). dotnet run --project src/Web/Web.csproj(profilUmbraco.Web.UI, Kestrel) : uSync importe les nouveaux types.- Regenerer les modeles :
GET http://localhost:12953/generate-models(endpoint DEBUG, voir../modules/extensibility.md). Verifier les nouveaux fichiers dansumbraco/Models/. - Restaurer
Web.csproj(re-commenter le blocRazorCompileOnBuild=false) puisdotnet build: les vues compilent desormais contre les modeles generes (gate reel).
Alternative sans endpoint : ouvrir puis re-sauver chaque content type concerne dans le backoffice (chaque sauvegarde declenche la regeneration).
Parcours dev - demarrer un projet aval depuis le template
upstream = ce repo template, origin = le repo du projet aval.
- Creer le repo GitLab (branche
master, sans.gitignore). - Cloner, creer
developetstaging, les pousser. - Lier et merger le template :bash
git checkout develop git remote add upstream git@gitlab.internal.spektrum-suisse.ch:spektrum/umbraco-base-project.git git fetch upstream git merge upstream/v17 --allow-unrelated-histories # resoudre les conflits (garder la version du template) git commit -m "Merge upstream v17 into develop" git push origin develop - Renommer
UmbracoBaseTemplate.slnen<MonProjet>.sln. - Configurer la base et renseigner
UmbracoApplicationUrl. - Merger
develop->staging->master. Adapter le README aux specificites du projet.
Parcours dev - mise a jour depuis le template
git checkout develop
git fetch upstream
git merge upstream/v17
git push origin developParcours dev - ajouter une fonctionnalite
- Service / composer / content finder / controller : voir
../architecture/patterns.md. - Document type : backoffice + uSync, voir
../modules/content-model.md. - Theme ou module JS : voir
../architecture/frontend-build.md. - Outil marketing : voir
../modules/cookies-marketing.md(consentement obligatoire). - Penser a mettre a jour la doc concernee (protocole dans le CLAUDE.md racine).
Régénérer les modèles ModelsBuilder
ModelsBuilder tourne en SourceCodeAuto : les classes de src/Web/umbraco/Models/*.generated.cs sont réécrites à chaque sauvegarde d'un content type dans le backoffice. C'est le seul déclencheur.
Piège : quand on ajoute un document type en écrivant directement le .config sous uSync/v17/, la régénération n'a pas lieu. uSync supprime les notifications de sauvegarde pendant son import au démarrage, donc rien ne prévient ModelsBuilder. Les modèles restent absents, et une vue Razor qui les référence ne compile pas.
Procédure
dotnet run --project src/Web/Web.csproj. uSync importe les nouveaux types au démarrage.- Backoffice -> Settings -> Document Types -> ouvrir le type concerné -> Save. Refaire pour chaque type ajouté ou modifié. Chaque sauvegarde réécrit les modèles.
- Vérifier les fichiers apparus dans
src/Web/umbraco/Models/. dotnet build: les vues compilent désormais contre les modèles générés.
Si le build de l'étape 1 échoue parce que des vues référencent déjà des modèles inexistants, décommenter le bloc RazorCompileOnBuild / RazorCompileOnPublish = false dans src/Web/Web.csproj (il y est, en commentaire, prêt à servir), faire le cycle, puis le re-commenter. Laisser la compilation Razor désactivée supprimerait le seul garde-fou qui vérifie les vues au build.
Pour un agent
Un agent ne peut pas exécuter cette procédure : elle demande de lancer le site et de passer par le backoffice. Il doit s'arrêter et demander la régénération à l'utilisateur, jamais contourner en écrivant Model.Value<T>("alias"). Voir ../architecture/patterns.md, section "Accéder au contenu".
Contrôle après régénération
Ouvrir le .generated.cs et lire la ligne de déclaration de la classe :
public partial class HomePage : PublishedContentModel, ICookiesSettings, IPageSettingsUne composition manquante dans cette liste ne casse pas le build. Elle fait seulement remonter null au runtime aux helpers qui la cherchent (AncestorOrSelf<ISiteSettings>()), ce qui vide silencieusement un en-tête ou un pied de page. Vérifier la ligne, pas seulement que ça compile.
Parcours dev - release / deploiement
- CI : pipeline sur merge request vers
masteret commits surmaster(build backend + frontend). - Image Docker :
docker build -t columbia-registry.spektrum.media/umb_<site>:<env> -f hosting/Dockerfile .puisdocker push; deploiement viadocker-compose.ymladapte. Voir../architecture/build-deploy.md.
Parcours editeur (backoffice Umbraco)
- Backoffice en
fr-FRpar defaut. Langue de contenu par defaut :fr(en-USest marqueeChange="Delete"dans uSync, en cours de suppression). Le contenu peut etre multilingue si d'autres langues sont ajoutees. - Pages : creer sous l'arbre de contenu (
homePageen racine de site). Les pages portent la compositionpageSettings(SEO, masquage sitemap). - Composer le contenu via les sections/elements de blocs (BlockGrid).
- Reglages transverses :
cookiesSettings(textes du popup cookies),marketingSettings(ID GA4). - Pages techniques :
notFoundPage(404 par site),internalServerErrorPage(500).
Parcours dev - seeder une seconde culture (l'allemand)
Etabli le 2026-08-17 sur Chevaliers et Porte de Novembre. La chaine est la meme que pour le francais : le DOM du live fait foi, on scrape puis on genere.
- Exports WXR : deposer les fichiers du client dans
tools/(git-ignores par**/*.WordPress.*.xml, ce qui garde la PII des commandes WooCommerce hors du depot), puisnode tools/seed-gen/wxr-extract.mjs. Sortie dansdata/sources/<marque>/. - Appariement FR / DE : Polylang groupe un noeud et ses traductions sous un meme
post_translations(trGroup). C'est la SEULE cle fiable : les enfants FR et DE des vins de PDN partagent des slugs identiques et ne different que par leur parent. UntrGroupvide n'apparie rien - deux pages allemandes de PDN etaient dans ce cas, retrouvees en suivant la nav allemande du live. - Scrape allemand :bashLes chemins allemands sont des CONSTANTES MESUREES (
node tools/seed-gen/pdn-bands.mjs --lang de # -> data/pdn-de.json (22 pages) py tools/seed-gen/chevaliers-bands.py --lang de # -> data/bands-de.jsonDE_PATHS,DE_SLUGS), jamais des translitterations :/vins/est/de/weine/,/gammes/est/marken/. ⚠️pdn-bands.mjs --pages x,yREECRIT le fichier avec les seules pages demandees. - Generer :
node pdn-gen.mjsetpy chevaliers-gen.py. Sans les fichiers-de, les deux generateurs emettent exactement le controleur francais d'avant - c'est la porte de non-regression a verifier apres chaque changement (git diffne doit montrer que des ajouts). - Racines :
/seed-rootspose la culturedeet publie sur toute marque qui a un domaine/de. Sans elle, le domaine ne resout rien et/de/renvoie 404. - Dictionnaire : le handler uSync est en
CreateOnly, donc une entree qui existe deja en base n'est jamais mise a jour a l'import. Ajouter une traduction dansuSync/v17/Dictionary/*.confign'a d'effet que sur une base neuve (ou apres suppression de l'entree). En local : supprimerumbraco/Data/*.sqlite.db*et rejouer les seeders. - Rendu : voir
../modules/content-model.md, section « Blocs et cultures » - une valeur de bloc sans culture rend une page vide sans erreur.

