Skip to content

Build, base de donnees, uSync, deploiement

Build

  • Backend : dotnet build Gilliard.sln (.NET 10). dotnet run --project src/Web/Web.csproj pour lancer en local.
  • Frontend : depuis src/Web, npm ci + npm run build:prod (lint + Vite prod). Voir frontend-build.md.
  • Web.csproj : CopyRazorGenerateFilesToPublishDirectory=true (vues backoffice), rewriteRules.xml copie en sortie/publish (PreserveNewest), ICU app-local (Microsoft.ICU.ICU4C.Runtime).

Le build est la vraie porte : les vues Razor sont compilees au build (RazorCompileOnBuild actif — le bloc qui le desactive doit rester commente). Une vue qui reference un modele inexistant casse le build : c'est voulu. Ne le desactiver que le temps d'un cycle de regeneration ModelsBuilder, puis le re-commenter (voir ../domain/workflows.md).

Tests

dotnet test tests/Web/Tests.Web.csproj — xUnit + Moq, TestBase partagee (tests/Common), un test reproduit le chemin de sa source (src/Web/Extensions/ThemeExtensions.cs -> tests/Web/Extensions/ThemeExtensionsTests.cs).

Piege (corrige le 2026-07-16) : Tests.Web embarquait xunit mais pasxunit.runner.visualstudio -> aucun adaptateur de test. dotnet test affichait « A total of 1 test files matched » et n'executait rien, en sortant 0 (vert). Aucun test n'avait donc jamais tourne. Le runner est desormais reference ; verifier que la sortie annonce un nombre de tests non nul (Passed! - Failed: 0, Passed: N). Tests.Web reference aussi src/Web/Web.csproj (sans quoi il ne peut rien tester du projet).

Base de donnees

  • SQL Server. Chaine par defaut (appsettings.json) : Server=localhost\sqlexpress;Database=UmbracoBaseTemplate;User Id=dev;Password=dev;TrustServerCertificate=true;, provider Microsoft.Data.SqlClient.
  • Override par appsettings.local.json (git-ignore) ou variable d'env.
  • Umbraco:CMS:Unattended:UpgradeUnattended=true : Umbraco applique les migrations au boot (pas de restauration manuelle ni d'etape d'install).
  • En local, SQLite est une alternative valide (provider Microsoft.Data.Sqlite, base sous src/Web/umbraco/Data/, git-ignore) : elle evite d'installer SQL Express et se combine avec InstallUnattended pour un premier boot sans ecran d'installation. Procedure et JSON complet : ../domain/workflows.md, « mise en place locale ». Local uniquement : staging et production restent sur SQL Server.

uSync

  • uSync 17.3.5. Config serialisee sous src/Web/uSync/v17/ (ContentTypes, DataTypes, Dictionary, Languages, MediaTypes, MemberTypes, Templates).
  • Reglages (appsettings.json) : ExportOnSave="Settings", ImportAtStartup="Settings", UIEnabledGroups="Settings". Le handler Dictionnaire est en CreateOnly (les traductions ne sont pas ecrasees a l'import).
  • Workflow : modifier dans le backoffice -> uSync exporte les .config ; au demarrage, uSync importe le groupe Settings.

Docker

hosting/Dockerfile (build multi-stage, build depuis la racine du repo, pas depuis hosting/). Trois stages : frontend (Vite prod) -> build (.NET 10) -> runtime.

dockerfile
# 1. Frontend: Vite prod (ESLint + PurgeCSS + minify)
FROM node:22.12.0-slim AS frontend
WORKDIR /src
COPY ./src/Web/package.json ./src/Web/package-lock.json ./
RUN npm ci
# PurgeCSS scans ./Views/**/*.cshtml: without the Views, CSS used only in a
# view is stripped (silent, prod-only failure)
COPY ./src/Web/vite.config.js ./src/Web/vite.config.helper.js ./src/Web/eslint.config.js ./
COPY ./src/Web/styles/ ./styles/
COPY ./src/Web/scripts/ ./scripts/
COPY ./src/Web/Views/ ./Views/
RUN npm run build:prod

# 2. Backend .NET 10
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ./src/Web/*.csproj ./
RUN dotnet restore
COPY ./src/Web/ ./
COPY --from=frontend /src/wwwroot/css/ ./wwwroot/css/
COPY --from=frontend /src/wwwroot/js/ ./wwwroot/js/
# Per-environment backoffice style: backoffice-env.<ENVIRONMENT>.css -> backoffice-env.css
ARG ENVIRONMENT
RUN if [ -n "$ENVIRONMENT" ] && [ -f "./App_Plugins/CustomEnvironmentBackofficeStyles/backoffice-env.${ENVIRONMENT}.css" ]; then \
      cp "./App_Plugins/CustomEnvironmentBackofficeStyles/backoffice-env.${ENVIRONMENT}.css" \
         "./App_Plugins/CustomEnvironmentBackofficeStyles/backoffice-env.css"; fi
RUN dotnet publish -c Release -o /app/publish --no-restore

# 3. Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
# Source-code version metadata (consumed by the backoffice "Système" dashboard).
ARG GIT_COMMIT_COUNT=""
ARG GIT_COMMIT_SHA=""
ARG GIT_COMMIT_DATE=""
ENV GIT_COMMIT_COUNT=${GIT_COMMIT_COUNT} \
    GIT_COMMIT_SHA=${GIT_COMMIT_SHA} \
    GIT_COMMIT_DATE=${GIT_COMMIT_DATE}
ENTRYPOINT ["dotnet", "Web.dll"]

Le stage frontend est necessaire : le CSS des themes (wwwroot/css/<theme>/main.css) n'est pas versionne (seul placeholder.txt + rte.css le sont). Un .dockerignore a la racine exclut node_modules/obj/bin/secrets du contexte.

Build / push manuels (le CI le fait automatiquement, voir ci-dessous) :

bash
docker build --build-arg ENVIRONMENT=staging -t registry.internal.spektrum-suisse.ch/gilliard-website:staging -f hosting/Dockerfile .
docker push registry.internal.spektrum-suisse.ch/gilliard-website:staging

ENVIRONMENT = staging ou master (choisit le style backoffice, cf. backoffice-env.<env>.css).

Version affichee dans le dashboard "Système" : les ARG/ENV GIT_COMMIT_* du stage runtime alimentent la boite "Version & build" du backoffice (voir modules/backoffice.md). Pour renseigner la version au build, passer les infos git en --build-arg :

bash
docker build \
  --build-arg ENVIRONMENT=staging \
  --build-arg GIT_COMMIT_COUNT="$(git rev-list --count HEAD)" \
  --build-arg GIT_COMMIT_SHA="$(git rev-parse --short HEAD)" \
  --build-arg GIT_COMMIT_DATE="$(git log -1 --format=%cI)" \
  -t registry.internal.spektrum-suisse.ch/gilliard-website:staging -f hosting/Dockerfile .

Sans ces --build-arg, la version tombe sur 1.0.0.dev (l'image runtime aspnet:10.0 ne contient pas git : aucun fallback CLI, la version vient uniquement des env vars). Le CI injecte ces build-args (calcul git dans .build_template).

hosting/docker-compose.yml (exemple a adapter, placeholders <mon-site>/<env>/<mon-port-externe>) : monte appsettings.json (ro), media/, logs/ en volumes, reseau externe app-network, ASPNETCORE_ENVIRONMENT=Staging, ASPNETCORE_URLS=http://*:5000, forwarded headers actives.

CI/CD (GitLab)

.gitlab-ci.yml. Le pipeline applicatif (stage build) construit et pousse l'image Docker via un template partage .build_template (image docker:25 + docker:25-dind, tag runner linux, cache via docker pull --cache-from, calcul des GIT_COMMIT_* passes en --build-arg, GIT_DEPTH: 0 pour un compte de commits exact) :

  • build:staging : sur push de la branche staging -> tags :staging + :<sha>, ENVIRONMENT=staging, ALLOW_SEED=true.
  • build:production : sur push de la branche main -> tags :prod + :<sha>, ENVIRONMENT=master (le style backoffice est nomme backoffice-env.master.css), ALLOW_SEED vide.

Seeders /seed-* en staging (ALLOW_SEED)

Les seeders de contenu (/seed-roots, /seed-home, /seed-pages, /seed-chevaliers, /seed-pdn) et les deux endpoints d'orchestration (/seed-all, /seed-clear) sont gardes #if DEBUG || ALLOW_SEED. Trois verrous, defense en profondeur :

  1. Compilation : AllowSeed=true (passe par le CI en staging) definit le symbole ALLOW_SEED et laisse les seeders dans l'image ; un build Release sans AllowSeed les exclut du compile (Web.csproj), donc l'image de prod ne les contient pas - absents par construction, comme avant.
  2. Runtime : chaque seeder renvoie NotFound() hors Development/Staging (if (!Env.IsDevelopment() && !Env.IsStaging())), donc inertes meme si l'image staging etait deployee en prod par erreur.
  3. Auth : [Authorize(AuthenticationSchemes = Constants.Security.BackOfficeAuthenticationType, Policy = AuthorizationPolicies.BackOfficeAccess)] - il faut etre connecte au backoffice pour les appeler.

Pour peupler un staging : deployer l'image :staging, se connecter au backoffice, appeler /seed-all - qui enchaine /seed-roots puis /seed-home, /seed-pages, /seed-chevaliers, /seed-pdn dans cet ordre et stream son rapport - ou les 5 routes une par une. Pour repartir d'un arbre vide : /seed-all?clear=yes (ou /seed-clear?confirm=yes seul). Le nettoyage supprime les enfants des racines, jamais les racines elles-memes : leurs domaines sont en base uniquement et ne sont poses que par /seed-roots. Detail des parametres : ../modules/extensibility.md. Les medias sont importes dans le volume media du conteneur. Les domaines sont poses par /seed-roots selon l'environnement : https://<marque>.staging.spektrum-suisse.ch en Staging, *.localtest.me sur les deux ports en local (les domaines sont DB-only, pas dans uSync). Les deux controllers generes (DevSeedChevaliersController, DevSeedPdnController) portent ces gardes via leurs generateurs (chevaliers-gen.py, pdn-gen.mjs).

Image : registry.internal.spektrum-suisse.ch/gilliard-website. Pas de job de deploiement dans le repo (le pull sur le serveur est hors CI). Pas de workflow.rules global : chaque job filtre par branche, donc develop et les MR ne declenchent aucun build.

Ce fichier a ete adapte du template upstream (qui ne buildait pas d'image et ciblait master, branche absente ici) : registry propre a Gilliard, branche prod main, stage frontend Vite ajoute au Dockerfile.

Un bloc docs (composant sync-claude-docs) synchronise .claude/docs/** vers le site de doc interne sur main/staging (gate sur changements de .claude/docs/** ou declenchement web manuel).

Sentry

Charge uniquement en Staging/Production et si SentryUrl est defini (appsettings.json, vide par defaut, a injecter sans le committer). Prod : TracesSampleRate=0.1. Staging : ProfilingIntegration a 500 ms et Debug=true.

URL rewrites

src/Web/rewriteRules.xml (format IIS) applique via app.UseRewriter() en Staging/Production uniquement.

Breaking change Umbraco 17.4 - URL applicative

Depuis 17.4, la detection auto de l'URL via le header Host est optionnelle (risque de spoofing sur emails de reset/invitation). Le template fournit une section vide Umbraco:CMS:WebRouting:UmbracoApplicationUrl. Tout projet aval derriere un reverse proxy doit la renseigner (appsettings de prod ou variable d'env Umbraco__CMS__WebRouting__UmbracoApplicationUrl).

Contributors

No contributors

Changelog

No recent changes