Aller au contenu

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 staging est promue en prod sans 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

  1. Télécharger l'artefact versionné
  2. Vérifier le checksum
  3. Extraire l'artefact dans un répertoire temporaire .tmp/<release-id>/
  4. Générer runtime-config.js dans ce répertoire temporaire
  5. Valider la configuration runtime générée
  6. Déplacer le répertoire temporaire vers releases/<release-id>/
  7. Basculer atomiquement current vers la nouvelle release
  8. Exécuter les smoke tests
  9. Conserver les N dernières releases
  10. 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 pull sur 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, staging et main, 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