# Déploiement Ustagammon est un site statique (PWA, ADR 0009) : des fichiers HTML, JavaScript, le moteur en WebAssembly et ses données. L'application est à la racine ; les pages de test du moteur de l'étape 0b restent publiées sous `/moteur/` (test du moteur) et `/moteur/bench.html` (mesure). Il est publié sur CapRover, machine `sans-pub` (https://captain.cloud.sans.pub), app `ustagammon`, sur https://ustagammon.sans.pub. **Le site est construit et testé sur le PC, pas sur le serveur.** La construction est lourde (Emscripten, génération des données du moteur) et déjà outillée en local. `make deploy-prod` envoie à CapRover une archive qui contient le site prêt, un `Dockerfile` et un `Caddyfile` (`deploy/`). Le serveur ne fait que copier les fichiers dans une image Caddy (`caddy:2.8.4-alpine`), qui les sert en HTTP derrière le HTTPS de CapRover. ## Prérequis - La chaîne d'outils du projet : `make setup`. - **CLI CapRover**, installée avec Node par `fnm` (le script la trouve seul) : ```bash eval "$(fnm env)"; fnm use lts-latest ``` - **Session CapRover valide.** Le jeton expire ; pour vérifier : ```bash caprover api -n sans-pub -t /user/system/info -m GET -d '{}' -o false ``` En cas de `not valid anymore` : `caprover login` dans un vrai terminal. - **L'app `ustagammon` existe dans CapRover** (créée le 2026-11-02) : sans volume (rien n'est stocké côté serveur), port du conteneur 80, domaine `ustagammon.sans.pub` avec HTTPS forcé. ## Publier Depuis `main`, à jour avec `origin/main` (après fusion de la MR) : ``` make deploy-prod ``` Le script refuse de publier si l'arbre n'est pas propre, si l'on n'est pas sur `main`, si `main` diffère d'`origin/main`, ou si la session CapRover a expiré. Il lance `make lint` et `make test`, assemble le site (`make package`), puis `caprover deploy -t build/ustagammon.tar`. Pour une autre machine ou une autre app : `CAPROVER_MACHINE=… CAPROVER_APP=… make deploy-prod`. ## Ce qui est publié - `make site` assemble `build/site/` (9 Mo) : - le contenu de `web/` à la racine : la page de l'application (`index.html`, `app.css`), le manifeste (`manifest.webmanifest`), les icônes (`icons/`), le service worker (`sw.js`), le Web Worker du moteur (`engine-worker.mjs`, `engine-wasm.mjs`) et les pages de test sous `moteur/` ; - l'application TypeScript compilée (`build/web/src/`) sous `app/` ; - le moteur (`engine.mjs`, `engine.wasm`, `engine.data`, `positions.json`) sous `wasm/` ; - des copies de `docs/glossaire/` et `docs/scenarios/` sous `docs/`, lues par l'aide de l'application (ADR 0008) ; - `version.json` avec le commit publié ; - enfin, `scripts/service-worker.sh` écrit en tête de `sw.js` la liste de tous ces fichiers et une empreinte de leur contenu. - `make package` ajoute `deploy/` et produit `build/ustagammon.tar` (environ 9 Mo, 7,3 Mo transférés grâce à la compression). - `tests/test_site.sh` (dans `make test`) construit l'image de production en local, la lance et vérifie ce que reçoit un navigateur : application, pages de test, aide, manifeste et icônes, liste du service worker, types MIME (`application/wasm` pour le moteur), compression gzip des données, en-têtes dont la politique de sécurité, et commit de `version.json`. - `make test-browser` (hors de `make test`, plusieurs minutes) joue une partie complète par l'interface dans Chromium et Firefox sans écran, sur la même image, puis vérifie la reprise, l'aide et le hors ligne. **Hors ligne et mises à jour.** Le service worker met tous les fichiers du site en cache à la première visite (environ 9 Mo), puis sert tout depuis ce cache, avec ou sans réseau. À chaque publication, l'empreinte écrite dans `sw.js` change dès qu'un fichier a changé : le navigateur, qui revérifie `sw.js` à chaque ouverture, installe la nouvelle version (tout le site est retéléchargé), qui prend la main et efface l'ancien cache. La page déjà ouverte continue sur l'ancienne version ; le lancement suivant utilise la nouvelle. Une publication sans changement de fichier garde le même `sw.js` : rien n'est retéléchargé. Le service worker exige https (ou `localhost`) : avec `make deploy`, en http sur le réseau local, l'application fonctionne, mais pas hors ligne. Réglages du serveur (`deploy/Caddyfile`) : compression zstd ou gzip, y compris pour les données du moteur ; `Cache-Control: no-cache` (les noms de fichiers ne changent pas d'une version à l'autre, le navigateur revalide chaque fichier) ; `X-Content-Type-Options: nosniff` ; `Referrer-Policy: no-referrer` ; et une politique de sécurité du contenu (`Content-Security-Policy`) : tout vient du site lui-même, aucun script ni style en ligne, aucun `eval`, seule la compilation du WebAssembly est permise (`'wasm-unsafe-eval'`). Elle est vérifiée par `tests/test_site.sh` (en-tête présent) et par `make test-browser` (aucune violation signalée par Chromium ni Firefox pendant une partie). ## Vérifier ```bash curl -s https://ustagammon.sans.pub/version.json # commit publié curl -sI https://ustagammon.sans.pub/wasm/engine.wasm # application/wasm curl -sI https://ustagammon.sans.pub/ | grep -i content-security # CSP curl -s https://ustagammon.sans.pub/sw.js | head -2 # version du cache ssh sans.pub 'sudo docker service ps srv-captain--ustagammon --format "{{.Image}} {{.CurrentState}}" | head -2' ``` Puis ouvrir le site sur le téléphone : le plateau s'affiche et une consigne remplace « Chargement du moteur… ». La page de test du moteur (https://ustagammon.sans.pub/moteur/) doit afficher « Moteur prêt ». ## Retour arrière Dans CapRover, onglet *Deployment* de l'app `ustagammon` : redéployer une image précédente (`img-captain-ustagammon:N`). Rien n'est stocké côté serveur : aucun risque pour des données. ## Incidents connus Voir `la-main-libre` (`docs/technique/deploiement.md`) pour le registre Docker de CapRover dont le certificat expire : le build réussit, l'envoi échoue, la production n'est pas touchée ; redémarrer `captain-registry` puis relancer.