Environnements & versionnement
Pour ne jamais confondre les déploiements (staging, production, build local), le frontend affiche en permanence quel environnement il est et quelle version il exécute. Ces signaux sont figés dans l'artefact de build : un conteneur ne peut afficher que ce pour quoi il a été construit.
Les deux variables
Deux variables VITE_ pilotent tout :
| Variable | Valeurs | Réglée où |
|---|---|---|
VITE_APP_ENV | development | staging | production | Par mode dans les fichiers .env.* |
VITE_APP_VERSION | chaîne libre (tag, branche-sha, dev) | CI (variable shell), repli dev dans .env |
Source unique de lecture : src/lib/env.ts expose APP_ENV, APP_VERSION et isProduction. C'est le seul module qui lit import.meta.env pour ces valeurs ; les composants en dépendent et les tests le moquent (vi.mock("@/lib/env")). Le typage vit dans src/vite-env.d.ts.
APP_ENV retombe sur le MODE Vite si VITE_APP_ENV est absent (dev = development, vite build = production, vite build --mode staging = staging).
Le module lit aussi VITE_PEXELS_API_KEY (clé de la recherche d'images Pexels du formulaire d'étape) et expose PEXELS_API_KEY + isPexelsEnabled : clé vide/absente = bouton « Trouver une image » masqué. La valeur est versionnée dans .env — l'appel part du navigateur, la clé est donc de toute façon embarquée dans le bundle client.
Il lit enfin VITE_SUPPORT_EMAIL et expose SUPPORT_EMAIL : l'alias e-mail du support, cible du lien mailto de la page publique « code indisponible » (/codes/unavailable, voir Routage). Vide/absente = placeholder support@example.com — à surcharger par environnement dans les fichiers .env.* (voir .env.example) avec la vraie boîte de support.
Signaux visibles
- Titre et favicon de l'onglet (
index.html) : suffixe(staging)en staging,(dev)en local, rien en production ; le favicon SVG suit (favicon-sta.svg/favicon-dev.svg,favicon.svgen production — le replifavicon.icoreste celui de prod). Réécrits au build et en dev par le pluginhtml-env(transformIndexHtml) dansvite.config.ts— visibles dès l'onglet, avant l'exécution du JS. - Bandeau global :
AppEnvBanner.vue, monté tout en haut dansApp.vue, donc présent sur toutes les vues. Ambre en staging, bleu en dev, rien en production. - Version :
AppVersion.vueafficheAPP_VERSION, en bas de la page de connexion et dans le bas des barres latérales. En bas de barre latérale,AppSidebarFooter.vuen'affiche par défaut que le libellé de rôle / portail (clé i18n existante) ; un easter-egg révèle (et fige) les versions au cinquième clic sur ce libellé, sur deux lignes :FRONT : <APP_VERSION>etBACK : <version backend>. La version backend provient deGET /api/version(voir Couche API), demandée paresseusement à la révélation seulement.
Libellés du bandeau : clés env.staging / env.development dans les catalogues i18n (voir Internationalisation).
Builds
npm run dev→ modedevelopment(.env.development).npm run build→ modeproduction(.env.production).npm run build:staging→vite build --mode staging(.env.staging).
Le staging est servi même origine que l'API derrière le reverse proxy, donc VITE_API_BASE_URL=/api reste relatif (cookies Sanctum same-origin), comme en dev.
Injection de la version en CI
La version n'est pas dans un fichier : la CI l'injecte comme variable shell avant le build (Vite expose les variables VITE_-préfixées de l'environnement, et elles priment sur les fichiers .env).
L'image n'est construite que sur le pipeline de tag (le tag est poussé par le composant release-tag). Le composant release-detect y émet en dotenv $VERSION (= le tag X.Y.Z ou X.Y.Z-staging.N) et $CHANNEL (staging | production). Le job publish-docker les consomme via needs: [{ job: release-detect, artifacts: true }] :
$VERSION→--build-arg VITE_APP_VERSION(version figée dans l'image) ;$CHANNEL→--build-arg BUILD_MODE(mode Vite : ses valeursstaging/productionsont déjà les noms de mode) et le tag flottant poussé (latest-stagingen staging,latesten production, namespaces disjoints).
$CHANNEL n'étant pas connu à l'évaluation des rules: GitLab, le job est gaté sur le format du tag (même regex que release-detect) et lit $CHANNEL à l'exécution.
Voir le job publish-docker dans .gitlab-ci.yml.
Service : conteneur frontend dédié
Le build statique est servi par un conteneur nginx dédié (Dockerfile, nginx.conf), placé derrière le reverse proxy existant. Le reverse proxy route /api vers le conteneur backend et tout le reste vers ce conteneur frontend. Même origine → /api relatif et cookies Sanctum fonctionnent ; déploiements et versionnement indépendants du backend.
nginx.conf assure le repli SPA (try_files … /index.html, nécessaire avec createWebHistory), un cache long sur les assets hashés et aucun cache sur index.html. Le Dockerfile prend BUILD_MODE (staging | production) et VITE_APP_VERSION en arguments de build, figeant l'environnement et la version dans l'image.
Côté backend (autre dépôt) : les domaines
statefulSanctum / CORS / cookie de session doivent inclure l'hôte de staging pour le flux/apisame-origin.

