Référence cible CI/CD — heymoov-web¶
Objet du document¶
Ce document décrit l'architecture CI/CD cible retenue pour l'application web HeyMoov, anciennement sports-connect-front.
Il formalise la cible à atteindre après la migration GitHub et après l'abandon de la chaîne historique de build centralisé observée sur sports-connect-front.
Objectifs de cette cible : - rendre la chaîne lisible et traçable - supprimer la dépendance à un serveur de build historique - séparer clairement build et déploiement - fiabiliser la promotion entre environnements - préparer un rollback simple et rapide
Périmètre¶
- application :
heymoov-web - type d'application : front React / Vite servi comme artefacts statiques
- environnements couverts :
dev,staging,prod - gouvernance Git : branches
dev,staging,main - build, stockage d'artefacts, promotion, déploiement, rollback
Le document ne couvre pas : - le déploiement du backend - les secrets backend ou les secrets d'infrastructure non liés au front - la configuration détaillée de chaque serveur web
État de mise en œuvre au 24 avril 2026¶
La cible est désormais partiellement mise en œuvre.
Sont effectivement en place :
- un workflow unique ci.yaml dans le dépôt heymoov-web
- la CI sur Pull Request vers dev, staging et main
- le packaging de release sur merge vers dev
- le packaging de release sur merge vers staging
- le déploiement automatique sur dev
- le job de déploiement automatique sur staging, prêt à s'exécuter sur runner dédié
- la configuration runtime du front générée au déploiement via runtime-config.js
- un environnement GitHub dev
- un runner self-hosted dédié au déploiement dev
- la publication du front sur https://app.dev.heymoov.com
Restent à mettre en place :
- l'environnement GitHub staging, ses variables runtime et le runner heymoov-web-deploy-staging
- la promotion contrôlée de staging vers prod sans rebuild
- les protections et approbations spécifiques aux environnements staging et prod
Décisions retenues¶
1. Plus de serveur de build interne¶
La cible ne conserve pas de serveur de build persistant pour le front.
Le build de heymoov-web doit être produit par GitHub Actions dans un environnement éphémère.
2. Build et CI sur runners GitHub éphémères¶
Les builds et la CI doivent tourner sur des runners GitHub-hosted éphémères.
Conséquences :
- checkout du SHA exact du workflow
- pas de clone local de long terme comme source de vérité
- pas de git pull sur une machine historique
- environnement de build reproductible
3. Runners self-hosted dédiés uniquement au déploiement¶
Des runners self-hosted peuvent rester utiles, mais uniquement pour le déploiement côté infrastructure.
Leur rôle n'est pas de : - cloner le dépôt - installer les dépendances front - rebuild le projet
Leur rôle est de : - récupérer un artefact déjà construit - vérifier cet artefact - l'installer sur le bon environnement - exécuter les vérifications post-déploiement
4. Segmentation des runners de déploiement¶
La cible recommandée est d'avoir au minimum un label de runner par environnement :
- heymoov-web-deploy-dev
- heymoov-web-deploy-staging
- heymoov-web-deploy-prod
Cette séparation permet :
- de segmenter les accès réseau
- de segmenter les secrets
- de limiter l'impact d'une erreur de configuration
- d'éviter qu'un runner dev puisse déployer en prod
Au 24 avril 2026 :
- heymoov-web-deploy-dev est effectivement en place
- le workflow attend un runner heymoov-web-deploy-staging
- heymoov-web-deploy-staging et heymoov-web-deploy-prod restent à créer côté GitHub/infrastructure
5. Gouvernance Git par promotion¶
La gouvernance retenue est :
- dev pilote l'environnement dev
- staging pilote l'environnement staging
- main pilote la gouvernance de prod
La promotion se fait uniquement par Pull Request :
- dev -> staging
- staging -> main
Les branches dev, staging et main doivent être protégées.
6. Pas de push direct sur les branches d'environnement¶
La cible suppose :
- pas de push direct sur dev
- pas de push direct sur staging
- pas de push direct sur main
Le merge via PR est la seule voie normale de progression entre environnements.
7. Déploiement automatique sur dev, puis sur staging¶
Le déploiement automatique après merge est déjà en place sur :
- dev
Le même modèle est retenu comme cible pour :
- staging
8. Déploiement prod protégé par approbation manuelle¶
Le déploiement production reste piloté par la promotion staging -> main, mais la mise en production effective doit être protégée par une approbation manuelle au niveau du workflow ou de l'environnement GitHub prod.
9. Déploiement atomique par release versionnée¶
Le déploiement doit se faire via :
- répertoire de release versionné
- symlink current
- conservation de plusieurs releases
- rollback par repointage du symlink
10. Cible finale : pas de rebuild entre staging et prod¶
La cible finale retenue est :
une release validée en
stagingest promue enprodsans rebuild
Cette propriété ne devient strictement vraie que si la configuration d'environnement du front sort du bundle et devient une configuration runtime.
Principe de proximité des environnements¶
Les environnements n'ont pas besoin d'être strictement identiques sur chaque détail technique.
En particulier :
- dev peut utiliser des services non productifs ou des simulateurs
- exemple acceptable : utilisation de Mailtrap en dev au lieu de l'envoi réel
En revanche, la cible recommande que staging reste aussi proche que possible de prod sur tout ce qui change le comportement réellement livré :
- routage web
- headers et politique de cache
- mode d'authentification
- URLs publiques
- configuration du front
- comportement Nginx
Conclusion :
- dev peut être un environnement d'intégration pratique
- staging doit être l'environnement de validation finale avant prod
Architecture cible — vue d'ensemble¶
Pull Request
-> GitHub Actions CI (runner éphémère)
-> install / lint / tests / build de vérification
Merge sur dev
-> build sur SHA exact
-> artefact versionné
-> publication dans un stockage d'artefacts
-> déploiement automatique sur dev via runner heymoov-web-deploy-dev
PR dev -> staging
-> CI de validation
Merge sur staging
-> build sur SHA exact
-> artefact versionné
-> publication dans un stockage d'artefacts
-> déploiement automatique sur staging via runner heymoov-web-deploy-staging
-> smoke tests
-> validation fonctionnelle
PR staging -> main
-> CI de validation
Merge sur main
-> sélection de la release validée en staging
-> approbation manuelle de l'environnement prod
-> déploiement de cette release via runner heymoov-web-deploy-prod
-> smoke tests
-> production
Composants de la cible¶
1. GitHub¶
GitHub reste le point d'entrée : - gestion du code - Pull Requests - protection des branches - revue de code - exécution des workflows - contrôle des environnements GitHub
2. GitHub Actions éphémère¶
GitHub Actions exécute la CI et les builds dans un environnement propre et jetable.
Caractéristiques attendues :
- checkout du commit exact
- version Node figée
- pnpm install --frozen-lockfile
- aucune dépendance à l'état d'une machine persistante
3. Stockage d'artefacts¶
Un stockage d'artefacts durable et privé doit servir de source de vérité des releases.
Exemples possibles : - bucket privé - dépôt d'artefacts - stockage interne dédié
L'implémentation actuelle sur dev utilise GitHub Artifacts via actions/upload-artifact@v4, avec une rétention de 30 jours.
Cette solution est acceptable pour la mise en service de dev, mais la cible finale doit privilégier un stockage durable et exploitable entre workflows et entre environnements si la promotion staging -> prod doit réutiliser exactement la même release sans rebuild.
Exigences minimales : - artefact versionné - identifiant stable de release - métadonnées de build conservées - checksum conservé - accès contrôlé
4. Runners de déploiement¶
Les runners de déploiement sont self-hosted et rattachés à l'infrastructure.
Leur rôle est limité à : - récupérer l'artefact - le vérifier - l'installer - basculer la release courante - exécuter les vérifications post-déploiement
5. Serveurs web¶
Chaque environnement dispose de son propre serveur web ou de sa propre cible de publication.
Chaque cible :
- récupère sa release
- sert un chemin stable pointant vers current
- garde un historique de releases
6. Nginx¶
Nginx sert toujours le front depuis un chemin stable.
Le mécanisme recommandé est :
- un répertoire releases/
- un symlink current
Mapping branches / environnements¶
Branche dev¶
- cible : environnement
dev - rôle : intégration continue quotidienne
- déploiement : automatique après merge
Branche staging¶
- cible : environnement
staging - rôle : validation finale avant mise en production
- déploiement : automatique après merge
Branche main¶
- cible : environnement
prod - rôle : gouvernance de la production
- déploiement : promotion contrôlée de la release validée en
staging
Pipeline cible détaillé¶
Étape 1 — Pull Request¶
Sur chaque PR vers dev, staging ou main :
- checkout du SHA de la PR
- installation des dépendances
- lint
- tests unitaires si présents
- build de vérification
Objectif : - empêcher l'introduction de régressions avant merge
Étape 2 — Merge sur dev¶
Sur merge vers dev :
- checkout du SHA exact mergé
- build production-ready
- génération d'un artefact versionné
- publication de cet artefact
- déploiement automatique sur dev
dev est l'environnement de validation rapide et d'intégration.
Étape 3 — Promotion dev -> staging¶
La promotion vers staging passe par PR.
Sur merge vers staging :
- checkout du SHA exact mergé sur staging
- build de la release candidate
- publication de l'artefact et de ses métadonnées
- déploiement automatique sur staging
- smoke tests post-déploiement
staging devient la source de vérité fonctionnelle avant prod.
Étape 4 — Promotion staging -> main¶
La promotion vers main passe par PR.
Sur merge vers main :
- le pipeline sélectionne la release validée en staging
- le workflow prod attend l'approbation manuelle de l'environnement prod
- après approbation, le runner heymoov-web-deploy-prod déploie la release validée
Principe retenu :
- on ne doit pas rebuild une nouvelle release pour prod
- on doit promouvoir la release déjà validée
Workflow actuellement retenu et extensions prévues¶
ci.yaml¶
Déclenchement :
- sur toutes les PR vers dev
- sur toutes les PR vers staging
- sur toutes les PR vers main
- sur les push vers dev
- sur les push vers staging
- sur les push vers main
- via workflow_dispatch
Jobs actuellement en place :
- Build sur runner GitHub-hosted ubuntu-latest
- Deploy dev sur runner self-hosted labellisé heymoov-web-deploy-dev
- Deploy staging sur runner self-hosted labellisé heymoov-web-deploy-staging
Responsabilités actuelles du job Build :
- checkout
- pnpm install --frozen-lockfile
- pnpm run setup:runtime-config
- lint
- build de vérification
- packaging de la release uniquement sur push ou workflow_dispatch vers dev ou staging
- upload de l'artefact GitHub
Responsabilités actuelles du job Deploy dev :
- téléchargement de l'artefact précédemment construit
- vérification du checksum
- génération du runtime-config.js
- validation stricte de la configuration runtime
- installation dans une release versionnée
- bascule atomique du symlink current
- smoke check HTTP sur /runtime-config.js puis /
Responsabilités actuelles du job Deploy staging :
- téléchargement de l'artefact précédemment construit
- vérification du checksum
- génération du runtime-config.js
- validation stricte de la configuration runtime
- installation dans une release versionnée
- bascule atomique du symlink current
- smoke check HTTP sur /runtime-config.js puis /
Extensions prévues :
- ajout d'un job Deploy prod
- éventuellement découpage ultérieur en plusieurs workflows si la complexité opérationnelle le justifie
Build cible¶
Conditions de build¶
Le build doit toujours être produit dans un environnement propre avec :
- version Node fixée
- pnpm install --frozen-lockfile
- SHA Git exact
- dépendances déterministes
Contrôles recommandés¶
- lint
- tests unitaires
- build de production
- éventuellement audit dépendances
- éventuellement test minimal end-to-end
Règle importante¶
Les runners de déploiement ne doivent jamais :
- exécuter pnpm install
- exécuter pnpm build
- faire un git pull
Artefacts cibles¶
Nommage actuellement implémenté¶
Le release_id actuellement produit suit le format :
heymoov-web-<short-sha>-<github-run-id>-<github-run-attempt>
Exemple concret :
- heymoov-web-2e5ee379a7b0-24843289444-1
Fichiers publiés pour une release :
- <release_id>.tar.gz
- <release_id>.tar.gz.sha256
- release.json
Métadonnées à conserver¶
Pour chaque release, conserver au minimum :
- release_id
- git_sha
- branche source
- date et heure du build
- numéro de run GitHub Actions
- tentative de run GitHub Actions
- checksum de l'artefact
Source de vérité¶
La source de vérité d'une release n'est pas une branche ou un clone local.
La source de vérité est : - l'artefact publié - accompagné de son manifest de métadonnées
Gestion de la configuration¶
Configuration runtime retenue¶
La configuration runtime du front est désormais le modèle retenu et déjà mis en place sur dev.
Le front charge un fichier runtime-config.js avant le bundle applicatif.
En pratique :
- public/runtime-config.template.js est versionné pour le développement local
- public/runtime-config.js n'est pas versionné
- scripts/render-runtime-config.mjs génère runtime-config.js au déploiement
- scripts/validate-runtime-config.mjs --no-placeholders valide la configuration générée
Variables actuellement injectées au runtime :
- RUNTIME_API_BASE_URL
- RUNTIME_API_PREFIX_AUTH
- RUNTIME_API_PREFIX_PUBLIC
- RUNTIME_API_PREFIX_API
- RUNTIME_MERCURE_URL
- RUNTIME_MERCURE_TOPIC_PREFIX
- RUNTIME_UPLOAD_BASE_URL
- RUNTIME_TURNSTILE_SITE_KEY
- RUNTIME_HUGO_URL
Convention Mercure:
- RUNTIME_MERCURE_URL contient l'origine publique du hub, par exemple https://mercure.staging.heymoov.com
- le chemin technique /.well-known/mercure reste réservé à l'upstream interne Nginx vers le daemon Mercure
- RUNTIME_MERCURE_TOPIC_PREFIX contient le préfixe de topic applicatif sans slash final, par exemple https://app.staging.heymoov.com
Conséquences :
- le code du front n'a plus besoin d'embarquer ces valeurs dans le bundle pour dev
- la promotion d'un même artefact entre environnements redevient techniquement possible
- la chaîne opérationnelle staging -> prod reste toutefois à finaliser
Rappel important¶
Les variables front embarquées dans le bundle ne sont pas des secrets forts.
Les vrais secrets doivent rester : - côté backend - ou côté infrastructure
Déploiement cible¶
Modèle recommandé¶
Le déploiement doit s'appuyer sur des releases versionnées.
Exemple d'arborescence :
/var/www/app.dev.heymoov.com/
├── releases/
│ ├── <release-id>/
│ ├── <release-id>/
│ └── ...
└── current -> /var/www/app.dev.heymoov.com/releases/<release-id>
/var/www/app.staging.heymoov.com/
├── releases/
│ ├── <release-id>/
│ ├── <release-id>/
│ └── ...
└── current -> /var/www/app.staging.heymoov.com/releases/<release-id>
/var/www/app.heymoov.com/
├── releases/
│ ├── <release-id>/
│ ├── <release-id>/
│ └── ...
└── current -> /var/www/app.heymoov.com/releases/<release-id>
Séquence de déploiement recommandée¶
- Télécharger l'artefact versionné
- Vérifier le checksum
- Extraire l'artefact dans un répertoire temporaire
.tmp/<release-id>/ - Générer
runtime-config.jsdans ce répertoire temporaire - Valider la configuration runtime générée
- Déplacer le répertoire temporaire vers
releases/<release-id>/ - Basculer atomiquement
currentvers la nouvelle release - Exécuter les smoke tests
- Conserver les
Ndernières releases - Purger les anciennes releases au-delà du seuil retenu
Implémentation actuelle sur dev :
- racine de déploiement : /var/www/app.dev.heymoov.com
- release courante servie via : /var/www/app.dev.heymoov.com/current
- conservation pilotée par WEB_KEEP_RELEASES, défaut 5
- vérification HTTP post-déploiement sur https://app.dev.heymoov.com/runtime-config.js puis https://app.dev.heymoov.com/
Nginx sur dev¶
Le vhost app.dev.heymoov.com est déjà branché sur la nouvelle arborescence de release.
Points importants de la configuration actuelle :
- racine statique servie : /var/www/app.dev.heymoov.com/current
- runtime-config.js servi avec Cache-Control: no-store, no-cache, must-revalidate
- /v1/ et /uploads/ restent proxifiés côté infrastructure
Pourquoi ce modèle est retenu¶
Il évite : - l'extraction directe dans le dossier servi - les états intermédiaires visibles - les fichiers obsolètes qui survivent entre deux déploiements
Rollback cible¶
Principe¶
Le rollback ne doit jamais nécessiter de rebuild.
Mécanisme recommandé¶
Le rollback consiste à :
- repointer current vers la release précédente
- relancer les vérifications minimales
- conserver la traçabilité de l'opération
Sécurité et exploitation¶
Principes¶
La chaîne doit réduire : - la concentration de privilèges - la dépendance à une machine historique - la dépendance à des secrets longue durée dispersés
Règles retenues¶
- runners GitHub-hosted pour la CI et le build
- runners self-hosted uniquement pour le déploiement
- secrets segmentés par environnement
- environnements GitHub distincts pour
dev,staging,prod - approbation manuelle obligatoire pour
prod - contrôle d'intégrité des artefacts
- journalisation de chaque déploiement
- traçabilité
commit -> artefact -> release -> environnement
Contrôle de concurrence¶
Un seul déploiement doit pouvoir s'exécuter à la fois par environnement.
Le workflow doit imposer une règle de concurrency par environnement pour éviter :
- deux déploiements simultanés sur dev
- deux déploiements simultanés sur staging
- deux déploiements simultanés sur prod
Ce qu'il faut éviter¶
git pullsur une machine persistante comme source de vérité- rebuild côté serveur
- build partagé avec déploiement sur la même machine historique
- déploiement direct dans le web root servi
- production accessible via les secrets d'un runner
dev
Observabilité cible¶
À journaliser¶
Pour chaque build : - SHA - branche - date - résultat - durée - artefact produit
Pour chaque déploiement :
- environnement
- release_id
- SHA déployé
- date
- résultat
- release précédente
- release courante
- déclencheur
- logs de smoke test
À rendre visible¶
Un opérateur doit pouvoir répondre rapidement à ces questions :
- quelle release est en dev ?
- quelle release est en staging ?
- quelle release est en prod ?
- quel SHA correspond à cette release ?
- quand cette release a-t-elle été déployée ?
- quel run GitHub l'a produite ?
- quelle release faut-il réactiver en cas de rollback ?
Synthèse¶
Recommandation principale¶
Pour heymoov-web, la cible retenue est :
GitHub Actions éphémère pour la CI et le build, runners self-hosted dédiés au déploiement, promotion par PR entre
dev,stagingetmain, artefacts versionnés, déploiement atomique et rollback simple
Mise en œuvre déjà opérationnelle¶
Au 24 avril 2026, cette cible est déjà opérationnelle sur dev avec :
- workflow Web CI
- build GitHub-hosted
- déploiement sur runner heymoov-web-deploy-dev
- configuration runtime générée au déploiement
- publication sur app.dev.heymoov.com
Le job Deploy staging est versionné dans le workflow, mais son exécution dépend encore de la création du runner heymoov-web-deploy-staging et des variables de l'environnement GitHub staging.
Runbook opérateur : Déployer la webapp en staging.
En pratique¶
Cela signifie :
- plus de serveur de build historique pour le front
- merge sur dev = build + déploiement dev
- merge sur staging = build + déploiement staging
- merge sur main = promotion de la release staging vers prod, avec approbation manuelle
- pas de build sur les serveurs de déploiement
- cible finale : pas de rebuild entre staging et prod
Conclusion¶
La cible retenue ne consiste pas à renommer la chaîne historique sports-connect-front.
La cible retenue consiste à :
- déplacer le build dans GitHub Actions
- figer les releases par SHA
- réserver les runners self-hosted au seul déploiement
- faire de staging l'étape de validation avant prod
- faire de prod la promotion d'une release validée, et non la reconstruction d'une branche