Déploiement (staging)
This content is not available in your language yet.
Ce qu’il faut retenir. L’environnement déployé tient sur une machine Hetzner (arm64, Allemagne). bo deploy up construit le code de votre checkout sur la machine, applique les migrations et redémarre ce qui a changé. La décision est dans l’ADR-0016.
Ce qui tourne
Section intitulée « Ce qui tourne »postgres,api,worker,mcp, etedge(Caddy, qui sert aussi le desk et l’application joueur).- Chaque club a son hôte
<club>.rebond.dev, et tout y passe : l’application joueur à la racine, le desk sous/desk, l’API sur ses chemins (/graphql,/auth/…,/oauth/…,/pay/…,/webhooks/…), le serveur MCP sur/mcp. - Le site public (ce site) sur le domaine lui-même,
https://rebond.dev(site.etwww.y redirigent), servi par Caddy depuis le volumesite:bo deploy upne le touche pas,bo deploy sitele remplace, depuisapps/site/dist(bo site build; captures seulement sibo site shotsa tourné) ou, avec--run latest(ou--run <id>), depuis l’artefact d’un run desite.yml(bo site publish, gardé 14 jours). Non indexé par les moteurs de recherche. Après l’envoi, la commande attend que le site serve bien la nouvelle version. Ses liens canoniques suiventSITE_URLau moment du build : la variable du dépôt poursite.yml(https://rebond.devtant que le domaine n’est pas choisi), et en localSITE_URL=https://rebond.dev pnpm bo site build;bo deploy siterefuse un build dont les liens canoniques ne visent pasrebond.dev. - Le Storybook (système de design, desk, appli joueur, site) sur
https://design.rebond.dev, servi par Caddy depuis le volumedesign:bo deploy designle remplace, depuisdist/design(bo ui storybook --build), à défaut depuis celui du dernierbo ci mainvert, ou, avec--run latest(ou--run <id>), depuis l’artefactdesigndu dernier run réussi deci.ymllancé à la main surmain(gardé 14 jours). Public et non indexé, comme le site ; les captures du site n’y sont pas (des emplacements « Capture à venir » à la place). Le premier envoi demande unbo deploy up(le volume et le bloc Caddy). Après l’envoi, la commande attend quedesign.rebond.dev/version.jsonserve la nouvelle version. - Un certificat
*.rebond.devet un pourrebond.dev(Let’s Encrypt, validés par DNS chez Cloudflare). mailpit: tant queSEND_EMAILS/SEND_SMSsont àfalse, chaque e-mail et SMS arrive dans la boîte de testhttps://mail.rebond.dev, ouverte sans mot de passe : n’importe qui peut y lire les liens de connexion de staging, qui ne garde donc que des données de test. Brevo, pour les vrais envois, se prépare avecbo deploy notify: il crée l’expéditeur deBO_EMAIL_FROMet les webhooks des statuts de remise (e-mail et SMS), et écrit son jeton dans.env.staging.local. Il faut d’abord que le domaine de l’expéditeur soit authentifié dans Brevo (ses enregistrements DNS sur Cloudflare) ;--checkdit ce qui manque sans rien changer. Sur staging, les vrais envois ne durent qu’un moment, pour un essai : avecSEND_EMAILS=true,bo deploy uprefuse tant que Brevo n’est pas prêt, et retire la page « comptes de test » (l’api ne démarre pas avec les deux). Pendant ce temps, les rappels des clubs de démonstration partent aussi, vers des adresses@<slug>.example.testqui n’existent pas. AvecBO_CAPTURE_WEBHOOKS=true, l’api écrit dans ses journaux chaque statut de remise tel que Brevo l’envoie (bo deploy logs api), pour remplacer les exemples des tests (fait pour les e-mails ; ceux des SMS suivent la doc de Brevo jusqu’à une vraie capture, #415). Revenir àSEND_EMAILS=false(etBO_CAPTURE_WEBHOOKS=false) puisbo deploy uprétablit Mailpit et la page.- SMS :
SEND_SMS=truedemande en plusBO_SMS_SENDER(11 lettres ou chiffres au plus, ou un numéro) et des crédits SMS achetés dans Brevo. Les numéros des clubs de démonstration sont dans la plage fictive de l’ARCEP : leurs rappels échouent, mais consomment des crédits. - Sauvegardes : celles de Hetzner chaque jour, plus un
pg_dumpchaque nuit sur la machine, gardé 7 jours.
Les secrets
Section intitulée « Les secrets »Tout est dans .env.staging.local à la racine du checkout principal (les clés attendues sont dans .env.staging.example) (ignoré par git, lié dans chaque worktree) : les jetons Hetzner et Cloudflare, les clés de la sandbox Stripe « Rebond Staging » et ses deux secrets de webhook (écrits par bo deploy webhooks), les clés R2 du bucket média (bo site media, elles ne quittent jamais votre poste), et les secrets que bo deploy init génère (session, mots de passe Postgres). Les autres clés de ce fichier (SEND_EMAILS, PLATFORM_FEE_BP…) partent telles quelles vers les applications.
Les commandes
Section intitulée « Les commandes »pnpm bo deploy init # la machine, son pare-feu, ses sauvegardes, le DNS rebond.dev et *.rebond.dev (idempotent)pnpm bo deploy up # construit, migre, redémarre, vérifie que seul Caddy publie des ports, attend /healthpnpm bo deploy prune # libère le disque : garde l'image en service et la plus récente des autres, vide le cache de build au-delà de 4 Gopnpm bo deploy site # le site public sur rebond.dev, depuis apps/site/distpnpm bo deploy site --run latest # depuis l'artefact du dernier run réussi de site.yml (ou --run <id>), captures comprisespnpm bo deploy design # le Storybook sur design.rebond.dev, depuis dist/design (bo ui storybook --build ; sinon celui du dernier bo ci main vert)pnpm bo deploy design --run latest # depuis l'artefact design du dernier ci.yml lancé à la main (gh workflow run) et réussi sur mainpnpm bo deploy webhooks # les deux webhooks Stripe (plateforme, Connect) sur api.rebond.dev, version d'API figée (idempotent)pnpm bo deploy notify # Brevo pour les vrais envois : l'expéditeur, les webhooks des statuts de remise, e-mail et SMS (idempotent ; --check : sans rien changer)pnpm bo deploy status # les services, la santé de l'API, le disque libre (alerte sous 20 %) ; vérifie que seuls ssh et Caddy (22, 80, 443) sont ouvertspnpm bo deploy logs api --followpnpm bo deploy psql # la base, en propriétairepnpm bo platform clubs --target staging # une commande bo sur la machine, à côté de sa baseChaque bo deploy up construit ses images (application et Caddy) sous le nom du commit : une fois la nouvelle version en ligne et /health vert, il supprime nos autres images, en gardant celles de la version qui tournait avant (pour revenir en arrière) ; le cache de build est ramené à 4 Go. Un up qui échoue après la construction ne supprime rien. up et status signalent un disque libre sous 20 % ; sous ce seuil, up fait d’abord le ménage avant de construire (en gardant la version en service). bo deploy prune le fait sans déployer.
Créer un club sur staging : pnpm bo club create <slug> --owner <e-mail> --legal-name … --siret … --legal-address … --target staging. Le propriétaire reçoit une invitation (dans mail.rebond.dev tant que SEND_EMAILS=false) : le lien ouvre /desk/invitation, où il choisit son mot de passe. Pour inviter le propriétaire d’un club existant : pnpm bo club invite-owner <slug> <e-mail> --target staging (le lien donne un premier mot de passe, il ne remplace jamais un mot de passe existant). Configurer un club sans terrains d’un coup : pnpm bo club setup <slug> --preset bo|padel|tennis|squash|demo --target staging (ou --preset dès club create). Les quatre premiers posent la configuration : horaires, sports, terrains, périodes, tarifs, formules ; le club garde son nom de site et son identité ; ni utilisateurs ni argent ; refusé si le club a déjà des terrains, sports, périodes, tarifs, formules ou options. demo pose la configuration de Bø puis donne vie au club : environ 90 joueurs fictifs en @<slug>.example.test, sans mot de passe, une semaine de réservations passées et à venir, paiements au comptoir, portefeuilles, abonnements, formules vendues, un cours collectif ; il faut un propriétaire. Les joueurs se connectent par lien magique, reçu dans Mailpit. Mot de passe des comptes de test : avec --test-password, club create --owner et club invite-owner donnent au propriétaire le mot de passe BO_TEST_ACCOUNT_PASSWORD de .env.staging.local (8 caractères ou plus), sauf s’il en a déjà un ; son invitation ne s’accepte alors qu’avec ce mot de passe. Réservé aux comptes de test, jamais ailleurs que sur staging ou en local. Avec club invite-owner, --test-password --reset remplace le mot de passe du compte nommé dans la commande, et de lui seul. Sur staging, club create sans --owner donne au club le propriétaire owner.<slug>@rebond.dev, une adresse du domaine de staging : un envoi réel ne lui parvient que si ce domaine a une messagerie (enregistrements MX, boîte « catch-all »). Un compte accueil et un compte coach pour essayer chaque rôle : pnpm bo club test-accounts <slug> --target staging fait de staff.<slug>@rebond.dev un compte accueil et de coach.<slug>@rebond.dev un coach du club, sans invitation, avec le mot de passe de test (il faut BO_TEST_ACCOUNT_PASSWORD ; refusé ailleurs qu’en local ou sur staging ; --reset remplace le mot de passe qu’ils ont déjà ; un responsable du club le reste ; en local : staff@<slug>.test, coach@<slug>.test). Donner à un utilisateur existant les droits de la plateforme (tous les clubs, comme leur responsable) : pnpm bo platform grant-admin <e-mail> --target staging (journalisé). Page « comptes de test » : https://comptes.rebond.dev liste chaque club (desk, appli joueur), son responsable, son accueil, son coach et trois joueurs, avec un lien vers leurs e-mails dans Mailpit ; le bouton « Envoyer le lien » envoie à un joueur son lien de connexion. On s’y connecte avec un compte administrateur de la plateforme : pnpm bo platform grant-admin admin@rebond.dev --test-password --target staging le crée avec BO_TEST_ADMIN_PASSWORD de .env.staging.local, un secret à part, jamais celui des comptes de test donné aux testeurs (refusé pour un compte existant sans mot de passe ; un compte à part : un responsable de club qui devient administrateur voit chaque desk avec ces droits). Chaque lien envoyé est journalisé. Hors staging (BO_ACCOUNTS_HOST vide), pas de page ; l’api refuse de démarrer avec la page si SEND_EMAILS=true. Changer l’adresse de connexion d’un utilisateur, pour tous ses clubs : pnpm bo platform change-email <ancienne> <nouvelle> --target staging (journalisé ; mot de passe, sessions et rôles restent ; la nouvelle adresse reste à vérifier ; les invitations en attente la suivent ; refusé si elle est déjà prise). Paiement par carte d’un club de staging : pnpm bo stripe connect --club <slug> --target staging crée son compte Standard dans la sandbox de staging, pré-rempli des données de test de Stripe ; reste à accepter les conditions sur la page Stripe affichée. --email <adresse> choisit l’adresse du compte (Stripe y envoie sa vérification ; une adresse en .test ne reçoit rien). --replace crée un nouveau compte puis supprime de la sandbox celui resté en attente ; refusé si le compte a déjà été activé. Les données de test (bo e2e setup) refusent toute base qui n’est pas locale : ses mots de passe sont connus. --target staging n’accepte que club, platform, stripe connect et stripe reconcile. La commande tourne sur la machine, dans un conteneur à côté de la base, avec le code du dernier bo deploy up : une commande modifiée localement n’y arrive qu’après un bo deploy up. Ses réglages, eux, sont ceux de votre .env.staging.local au moment de la commande.