diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c9fe9c..1aa0355 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,3 +155,26 @@ jobs: name: playwright-report path: apps/web/playwright-report/ retention-days: 7 + + # Déploiement continu (runbook §4) : Dokploy reconstruit et redéploie le + # compose UNIQUEMENT quand les 5 verrous sont verts sur main. Le webhook + # vit dans le secret DOKPLOY_WEBHOOK_URL (Dokploy → service compose → + # Deployments → Webhook URL) ; tant qu'il n'est pas configuré, le job + # se termine en « skip » sans faire échouer le pipeline. + deploy: + name: deploy (Dokploy — siop2.apps.enset.top) + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: [lint, contract, api, web, e2e] + runs-on: ubuntu-latest + environment: production + steps: + - name: Déclencher le déploiement Dokploy + env: + WEBHOOK_URL: ${{ secrets.DOKPLOY_WEBHOOK_URL }} + run: | + if [ -z "$WEBHOOK_URL" ]; then + echo "::notice::DOKPLOY_WEBHOOK_URL absent — déploiement sauté (configurer le secret pour activer le CD)." + exit 0 + fi + curl -fsS -X POST "$WEBHOOK_URL" + echo "Déploiement déclenché — suivi : Dokploy → Deployments." diff --git a/docs/06-production/runbook-dokploy.md b/docs/06-production/runbook-dokploy.md index c811b0b..ffcd26a 100644 --- a/docs/06-production/runbook-dokploy.md +++ b/docs/06-production/runbook-dokploy.md @@ -1,16 +1,18 @@ # Runbook — déploiement Dokploy > **Rôle de ce document (playbook)** : la procédure REJOUABLE de mise en production -> sur Dokploy (PaaS auto-hébergé du partenaire), écrite en R0.13 et répétée à chaque -> release (principe « déployer tôt »). Statut : **répété en local, en attente des -> accès au serveur du partenaire** pour la première exécution réelle. +> sur Dokploy, écrite en R0.13 et répétée à chaque release (principe « déployer tôt »). +> +> **Instances** : démonstration/cours → `https://siop2.apps.enset.top` (Dokploy ENSET, +> projet créé le 15/07/2026) ; production client SPELEV → en attente des accès au +> serveur du partenaire (même procédure, profil d'environnement « production client »). ## 1. Topologie Un projet Dokploy = un service « Compose » pointant sur ce dépôt, fichier [`infra/docker-compose.dokploy.yml`](../../infra/docker-compose.dokploy.yml) : -``` +```text domaine (Traefik/Dokploy) ──▶ siop2-web :80 (nginx, statique) │ /api/** (préfixe retiré) ▼ @@ -48,27 +50,58 @@ Profils types : - **Instance de démonstration** : `DEMO_MODE=true`, `DEMO_MODE_I_KNOW=true`, `SEED_ON_START=true`. -## 3. Première mise en production (checklist) +## 3. Première mise en production — déploiement manuel depuis GitHub (checklist) -1. Dokploy → **Create Project** `siop2` → **Compose** ; source = dépôt - `siop-spelev/siop2`, branche `main`, fichier `infra/docker-compose.dokploy.yml`. -2. Renseigner les variables d'environnement (§2) dans l'onglet Environment. -3. **Deploy**. Dokploy construit les images (contexte = racine du dépôt, - Dockerfiles `apps/api` et `apps/web`) puis démarre les 5 services ; - l'API attend PostgreSQL/Redis/MinIO sains (healthchecks) et migre la base. -4. Onglet Domains du service `siop2-web` : associer le domaine (port **80**, - HTTPS Let's Encrypt géré par Dokploy). +Dans le service **Compose** du projet Dokploy (déjà créé pour l'instance ENSET) : + +1. **Onglet General — source GitHub** : Provider `GitHub` (application GitHub + Dokploy autorisée sur `siop-spelev/siop2`, dépôt privé), Branch `main`, + **Compose Path** `infra/docker-compose.dokploy.yml`. +2. **Onglet Environment** : coller les variables du §2. Pour l'instance de + démonstration ENSET : + + ```env + POSTGRES_PASSWORD= + MINIO_ROOT_PASSWORD= + JWT_SECRET= + DEMO_MODE=true + DEMO_MODE_I_KNOW=true + SEED_ON_START=true + ``` + +3. **Deploy** (bouton). Dokploy clone le dépôt, construit les images (contexte = + racine, Dockerfiles `apps/api` et `apps/web` — ~5-10 min au premier build) puis + démarre les 5 services ; l'API attend PostgreSQL/Redis/MinIO sains et migre la base. + Suivi : onglet **Deployments** (logs de build) puis **Logs** par service. +4. **Onglet Domains** : Add Domain → Host `siop2.apps.enset.top`, + **Service Name `siop2-web`**, **Container Port `80`**, HTTPS activé + (certificat Let's Encrypt géré par Dokploy/Traefik). 5. Vérifications : - - `https:///api/health` → `{"status":"ok", ...}` (les 3 services `up`) ; - - production client : `https:///api/auth/demo-accounts` → **404** ; - - instance démo : écran de connexion avec les 7 comptes, bascule de rôle < 3 s. -6. Consigner la mise en production dans `docs/journal/journal.md` (date, version, domaine). + - `https://siop2.apps.enset.top/api/health` → `{"status":"ok", ...}` (3 services `up`) ; + - écran de connexion : 7 comptes démo, bascule de rôle < 3 s, bi-thème ; + - production client (quand elle existera) : `/api/auth/demo-accounts` → **404**. +6. Consigner la mise en production dans `docs/journal/journal.md` (date, commit, domaine). -## 4. Releases suivantes +## 4. Releases suivantes — déploiement continu par GitHub Actions -`git push` sur `main` (CI verte exigée) → Dokploy **Deploy** (ou webhook auto-deploy). -Les migrations de la release s'appliquent au démarrage ; en cas d'échec de migration, -le conteneur s'arrête **sans** servir de trafic (l'ancienne version reste visible côté web). +Le job `deploy` de `.github/workflows/ci.yml` appelle le **webhook Dokploy** +à chaque push sur `main`, **uniquement si les 5 jobs (lint, contrat, api, web, e2e) +sont verts** — c'est la CI qui garde la porte, pas l'inverse. Mise en place (une fois) : + +1. Dokploy → service compose → onglet **Deployments** → copier la **Webhook URL**. +2. Dépôt GitHub → Settings → Secrets and variables → Actions → + **New repository secret** : nom `DOKPLOY_WEBHOOK_URL`, valeur = l'URL copiée. + (Ou en CLI : `gh secret set DOKPLOY_WEBHOOK_URL`.) +3. C'est tout : le prochain push vert sur `main` déclenche le build + redéploiement + côté Dokploy. Tant que le secret n'existe pas, le job `deploy` se termine en + « skip » explicite sans faire échouer le pipeline. + +> **Ne pas activer** l'« Auto Deploy » natif de Dokploy (webhook GitHub direct) : +> il déploierait aussi les commits dont la CI est rouge. + +Les migrations de la release s'appliquent au démarrage du conteneur API ; en cas +d'échec de migration, le conteneur s'arrête **sans** servir de trafic (l'ancienne +version reste visible côté web). ## 5. Incidents & retours arrière diff --git a/docs/journal/journal.md b/docs/journal/journal.md index 9b1d513..36b5865 100644 --- a/docs/journal/journal.md +++ b/docs/journal/journal.md @@ -30,6 +30,18 @@ Trace chronologique des sessions (la plus récente en premier). Le **playbook** --- +## 2026-07-15 — Pr. Daaif (+ Claude) — R0.13 (suite) : instance ENSET + déploiement continu + +**Actions** + +- **Instance de démonstration décidée** : `https://siop2.apps.enset.top` (Dokploy ENSET, projet compose créé par le référent) — la production client SPELEV suivra la même procédure avec le profil « production client ». +- Job **`deploy`** ajouté au pipeline : appelle le webhook Dokploy sur push `main` **uniquement si lint + contrat + api + web + e2e sont verts** ; « skip » explicite tant que le secret `DOKPLOY_WEBHOOK_URL` n'est pas configuré. L'« Auto Deploy » natif de Dokploy reste désactivé (il ignorerait la CI). +- Runbook §3 réécrit en checklist concrète (source GitHub, Compose Path, variables du profil démo, domaine → `siop2-web:80`) et §4 en procédure CD (secret webhook). + +**Prochaine étape** : premier déploiement manuel (runbook §3), pose du secret `DOKPLOY_WEBHOOK_URL` (§4), vérification `https://siop2.apps.enset.top/api/health`, puis recette R0 avec le référent sur l'instance en ligne. + +--- + ## 2026-07-15 — Pr. Daaif (+ Claude) — R0.12 (2/2) : ESLint + parcours Playwright — R0.12 CLOS **Actions**