From 56b26db0c1387d83f2a5bd67699047d4c1a19d25 Mon Sep 17 00:00:00 2001 From: Imugiii Date: Wed, 17 Jun 2026 12:41:36 +0000 Subject: [PATCH] chore: remplace le Makefile par un service compose wakdo-migrate (migrate + seed idempotents) Le Makefile portait surtout des cibles mortes/trompeuses (test/test-unit/ test-integration/lint annoncaient "pas implemente" alors que les tests tournent ; install-hooks pointait sur des fichiers absents) ; sa seule cible porteuse, `init`, existait parce que `docker compose up` seul n'applique pas les migrations. En deplacant migrate + seed DANS la stack, `docker compose up` devient l'unique commande qui amene une stack complete et loginnable -> Cr 7.c.4 satisfait sans dependance a l'outil `make`. - db/migrate-container.sh : runner in-container (connexion par le reseau compose), applique db/migrations/*.sql (suivi schema_migrations) puis db/seeds/*.sql (suivi seeds_applied), idempotent. - Service one-shot `wakdo-migrate` (depends_on db healthy) ; wakdo-app/web attendent sa completion (service_completed_successfully). - Makefile supprime ; db/migrate.sh (hote) conserve pour l'usage manuel / --status. - Docs realignees : README, .env.example, db/README, docker-compose, PROJECT_CONTEXT (`make *` -> `docker compose *`, Cr 7.b porte par les scripts Bash). Correction au passage : la CI/CD est Forgejo Actions (pas GitHub Actions), protections cote Forgejo. - Journal : docs/journal/2026-06-17--makefile-to-compose-migrate.md (rationale + verif sur base ephemere : 2 migrations + 2 seeds, idempotent ; note de deploiement pour les bases deja seedees). Verifie : docker compose config valide ; runner teste sur MariaDB ephemere (5 roles, 23 permissions, admin present) ; re-run = 0 nouveau. Aucun code PHP/JS touche. --- .env.example | 7 +- Makefile | 233 ------------------ README.md | 32 +-- db/README.md | 2 +- db/migrate-container.sh | 66 +++++ db/migrate.sh | 6 +- db/seed.sh | 2 +- docker-compose.yml | 50 +++- docs/PROJECT_CONTEXT.md | 26 +- ...2026-06-17--makefile-to-compose-migrate.md | 88 +++++++ 10 files changed, 236 insertions(+), 276 deletions(-) delete mode 100644 Makefile create mode 100644 db/migrate-container.sh create mode 100644 docs/journal/2026-06-17--makefile-to-compose-migrate.md diff --git a/.env.example b/.env.example index 9db4c00..32e902b 100644 --- a/.env.example +++ b/.env.example @@ -157,9 +157,8 @@ TRAEFIK_DOMAIN_ADMIN=admin.example.com # traefik - setups simples # proxy - autre convention frequente # -# Le reseau doit exister AVANT 'make init' (cree par votre stack de -# reverse proxy, ou manuellement : docker network create ). -# La cible 'make init' echoue proprement avec un message d'aide si le -# reseau est introuvable. +# Le reseau doit exister AVANT 'docker compose up' (cree par votre stack de +# reverse proxy, ou manuellement : docker network create ). Sinon +# 'docker compose up' echoue avec une erreur sur le reseau externe introuvable. REVERSE_PROXY_NETWORK=traefik_proxy diff --git a/Makefile b/Makefile deleted file mode 100644 index d7734cb..0000000 --- a/Makefile +++ /dev/null @@ -1,233 +0,0 @@ -# -# Wakdo - Makefile d'orchestration locale -# -# Conventions : -# - Une cible = une action unitaire. Les cibles composites sont commentees. -# - Chaque cible est documentee par un `## description` pour auto-help. -# - Echec sur erreur (set -e implicite via bash recipes + pipefail). -# -# Documentation : -# make help -# - -SHELL := /usr/bin/env bash -.SHELLFLAGS := -eu -o pipefail -c - -# === Configuration === - -# Chargement du .env s'il existe (variables Make + export pour docker compose) -ifneq (,$(wildcard .env)) -include .env -export -endif - -# Prefixe du projet compose (utilise pour nommer les containers) -PROJECT := wakdo - -# Nom du fichier compose (override possible : make up COMPOSE_FILE=docker-compose.prod.yml) -COMPOSE_FILE := docker-compose.yml -COMPOSE := docker compose -f $(COMPOSE_FILE) -p $(PROJECT) - -# Services docker-compose -SERVICE_WEB := wakdo-web -SERVICE_APP := wakdo-app -SERVICE_DB := wakdo-db -SERVICE_CRON := wakdo-cron - -# === Meta === - -.DEFAULT_GOAL := help -.PHONY: help -help: ## Liste toutes les cibles disponibles avec leur description - @echo "Wakdo - cibles Make disponibles :" - @echo "" - @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[1m%-22s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort - @echo "" - -# === Orchestration principale === - -.PHONY: init -init: ## Build et demarre toute la stack en une commande (Cr RNCP 7.c.4) - @test -f .env || { echo "ERREUR: .env manquant. Executer : cp .env.example .env"; exit 1; } - @$(MAKE) --no-print-directory check-env - @echo "[init] Verification du reseau docker '$(REVERSE_PROXY_NETWORK)'..." - @docker network inspect $(REVERSE_PROXY_NETWORK) >/dev/null 2>&1 || { \ - echo "ERREUR: reseau docker '$(REVERSE_PROXY_NETWORK)' introuvable."; \ - echo " - Si un Traefik est installe sur l'hote, verifier le nom de son reseau ;"; \ - echo " - Adapter REVERSE_PROXY_NETWORK dans .env en consequence ;"; \ - echo " - Sinon creer le reseau manuellement :"; \ - echo " docker network create $(REVERSE_PROXY_NETWORK)"; \ - exit 1; } - @echo "[init] Build des images..." - @$(COMPOSE) build - @echo "[init] Demarrage des services..." - @$(COMPOSE) up -d - @echo "[init] Attente de la base de donnees..." - @$(MAKE) --no-print-directory wait-db - @echo "[init] Execution des migrations..." - @$(MAKE) --no-print-directory migrate - @echo "[init] Stack operationnelle." - @$(COMPOSE) ps - -.PHONY: up -up: ## Demarre les services sans rebuild - @$(COMPOSE) up -d - -.PHONY: down -down: ## Arrete et supprime les containers (volumes preserves) - @$(COMPOSE) down - -.PHONY: stop -stop: ## Arrete les services sans les supprimer - @$(COMPOSE) stop - -.PHONY: restart -restart: ## Redemarre tous les services - @$(COMPOSE) restart - -.PHONY: build -build: ## Build les images (utilise le cache) - @$(COMPOSE) build - -.PHONY: rebuild -rebuild: ## Rebuild complet sans cache puis restart - @$(COMPOSE) build --no-cache - @$(COMPOSE) up -d - -# === Observabilite === - -.PHONY: ps -ps: ## Affiche le statut des services - @$(COMPOSE) ps - -.PHONY: logs -logs: ## Suit les logs de tous les services (Ctrl+C pour sortir) - @$(COMPOSE) logs -f --tail=100 - -.PHONY: logs-app -logs-app: ## Suit les logs du service applicatif PHP-FPM - @$(COMPOSE) logs -f --tail=100 $(SERVICE_APP) - -.PHONY: logs-web -logs-web: ## Suit les logs du service web Apache - @$(COMPOSE) logs -f --tail=100 $(SERVICE_WEB) - -.PHONY: logs-db -logs-db: ## Suit les logs de la base de donnees - @$(COMPOSE) logs -f --tail=100 $(SERVICE_DB) - -# === Acces shell === - -.PHONY: shell-app -shell-app: ## Ouvre un shell dans le container applicatif - @$(COMPOSE) exec $(SERVICE_APP) sh - -.PHONY: shell-db -shell-db: ## Ouvre le client mariadb dans le container de base de donnees - @$(COMPOSE) exec $(SERVICE_DB) mariadb -u root -p"$${DB_ROOT_PASSWORD}" - -.PHONY: shell-cron -shell-cron: ## Ouvre un shell dans le container cron - @$(COMPOSE) exec $(SERVICE_CRON) sh - -# === Verification env === - -.PHONY: check-env -check-env: ## Verifie que les variables critiques Wakdo sont definies dans .env - @missing=""; \ - for var in DB_PASSWORD DB_ROOT_PASSWORD REVERSE_PROXY_NETWORK TRAEFIK_DOMAIN_KIOSK TRAEFIK_DOMAIN_ADMIN APP_URL_KIOSK APP_URL_ADMIN CORS_ALLOWED_ORIGIN; do \ - if [ -z "$${!var:-}" ]; then missing="$$missing $$var"; fi; \ - done; \ - if [ -n "$$missing" ]; then \ - echo "ERREUR: variables manquantes dans .env :$$missing"; \ - echo "Conseil : si vous aviez un .env pre-existant (tooling externe),"; \ - echo " merger les variables manquantes depuis .env.example au lieu"; \ - echo " d'ecraser le fichier."; \ - exit 1; \ - fi - -# === Base de donnees === - -.PHONY: wait-db -wait-db: ## Attend que la base de donnees accepte les connexions (timeout 60s) - @echo "[wait-db] En attente de MariaDB..." - @timeout 60 bash -c 'until $(COMPOSE) exec -T $(SERVICE_DB) healthcheck.sh --connect --innodb_initialized >/dev/null 2>&1; do sleep 2; done' \ - || { echo "ERREUR: MariaDB ne repond pas apres 60s"; $(COMPOSE) logs --tail=50 $(SERVICE_DB); exit 1; } - @echo "[wait-db] OK" - -.PHONY: migrate -migrate: ## Applique les migrations SQL en attente (db/migrations/) - @bash db/migrate.sh - -.PHONY: seed -seed: ## Charge les donnees de demo (db/seeds/) - @bash db/seed.sh - -.PHONY: backup -backup: ## Declenche un dump SQL horodate immediat (via le container cron) - @mkdir -p ./var/backups - @echo "[backup] Execution manuelle de /scripts/backup-db.sh dans wakdo-cron..." - @$(COMPOSE) exec -T $(SERVICE_CRON) /scripts/backup-db.sh - @echo "[backup] Dernier dump :" - @ls -lh ./var/backups/ | tail -n 1 - -.PHONY: backup-ls -backup-ls: ## Liste les dumps SQL presents dans ./var/backups/ - @ls -lh ./var/backups/ 2>/dev/null || echo "[backup-ls] Pas de backups (./var/backups/ vide ou inexistant)." - -# === Tests === - -.PHONY: test -test: ## Lance la suite complete de tests PHPUnit [a venir] - @echo "[test] Pas encore implemente. PHPUnit via .phar sera configure en P2." - -.PHONY: test-unit -test-unit: ## Lance uniquement les tests unitaires [a venir] - @echo "[test-unit] Pas encore implemente." - -.PHONY: test-integration -test-integration: ## Lance uniquement les tests d'integration [a venir] - @echo "[test-integration] Pas encore implemente." - -# === Qualite code === - -.PHONY: lint -lint: ## Lance php -l sur tous les fichiers src/ [a venir] - @echo "[lint] Pas encore implemente. PHP syntax check via php -l + outil de style en P2." - -# === Nettoyage === - -.PHONY: clean -clean: ## Stop + suppression containers + volumes (DESTRUCTIF, demande confirmation) - @read -p "Supprimer containers ET volumes (les donnees seront perdues) ? [y/N] " ans; \ - if [ "$$ans" = "y" ] || [ "$$ans" = "Y" ]; then \ - $(COMPOSE) down -v; \ - echo "[clean] Stack et volumes supprimes."; \ - else \ - echo "[clean] Annule."; \ - fi - -.PHONY: clean-force -clean-force: ## Version non interactive de clean (pour CI uniquement) - @$(COMPOSE) down -v - -# === Documentation === - -.PHONY: docs-render -docs-render: ## Regenere les diagrammes Mermaid (docs/**/_diagrams/*.mmd -> *.svg) - @echo "[docs-render] Recherche des sources Mermaid sous docs/..." - @count=0; \ - for src in $$(find docs -name '*.mmd' -path '*/_diagrams/*'); do \ - out="$${src%.mmd}.svg"; \ - echo " $$src -> $$out"; \ - npx -y -p @mermaid-js/mermaid-cli mmdc -i "$$src" -o "$$out" >/dev/null 2>&1 \ - || { echo "[docs-render] ECHEC sur $$src"; exit 1; }; \ - count=$$((count + 1)); \ - done; \ - echo "[docs-render] $$count diagramme(s) genere(s)." - -# === Hooks Git === - -.PHONY: install-hooks -install-hooks: ## Installe les hooks git depuis .githooks/ [a venir] - @echo "[install-hooks] Pas encore implemente. Voir scripts/install-hooks.sh a venir." diff --git a/README.md b/README.md index 3b520cd..da14429 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,9 @@ Realisation avec l'assistance d'outils d'IA generative (Claude Code, BYAN), conf | Tests | PHPUnit | 11.x (`.phar` autonome, sans Composer) | | Front | HTML5 + CSS3 + JS ES6+ vanilla | — | | Conteneurisation | Docker + docker compose v2 | — | -| Orchestration locale | Makefile | — | -| CI/CD | GitHub Actions | — | -| Versioning | Git + GitHub | Conventional Commits | +| Orchestration locale | docker compose v2 (service one-shot `wakdo-migrate`) | — | +| CI/CD | Forgejo Actions | — | +| Versioning | Git + Forgejo (`git.acadenice.com`, miroir GitHub) | Conventional Commits | Detail et justifications : `docs/PROJECT_CONTEXT.md` section 6. @@ -106,19 +106,22 @@ git clone git@github.com:AcadeNice/wakdo_corentin.git cd wakdo_corentin cp .env.example .env # Editer .env : DB_PASSWORD, DB_ROOT_PASSWORD, APP_URL_*, TRAEFIK_DOMAIN_* -make init +docker compose up -d ``` > **Attention au `.env` pre-existant.** Si un fichier `.env` existe deja a la racine (tooling externe, autre plateforme installee dans le meme repertoire), **ne pas faire** `cp .env.example .env` — cela ecraserait les variables existantes. Faire un **merge manuel** a la place : ajouter les variables manquantes du template dans le `.env` actuel. Les prefixes de variables de ce projet (`APP_`, `DB_`, `SESSION_`, `CORS_`, `UPLOAD_`, `CRON_`, `TRAEFIK_`, `REVERSE_PROXY_`) sont disjoints de ceux utilises par des outils tiers courants, donc la cohabitation est safe. -Critere RNCP Cr 7.c.4 couvert : une seule commande (`make init`) orchestre build, demarrage, attente BDD, migrations et seed. +Critere RNCP Cr 7.c.4 couvert : une seule commande (`docker compose up -d`) lance la +stack complete. Le service one-shot `wakdo-migrate` applique le schema (migrations) +puis les donnees de reference (seed) avant que l'app ne serve ; `wakdo-app`/`wakdo-web` +attendent sa completion (`depends_on: service_completed_successfully`). Migrations et +seed sont idempotents (tables de suivi `schema_migrations` / `seeds_applied`). +Detail : `docs/journal/2026-06-17--makefile-to-compose-migrate.md`. -Services accessibles apres `make init` : +Services accessibles apres `docker compose up -d` : - Borne : la valeur de `TRAEFIK_DOMAIN_KIOSK` dans `.env` - Admin + API : la valeur de `TRAEFIK_DOMAIN_ADMIN` dans `.env` -Liste complete des cibles : `make help`. - ### Installation Docker sur un hote neuf (Debian / Ubuntu) Procedure officielle detaillee : `https://docs.docker.com/engine/install/` (selectionner la distribution). Resume pour Debian stable : @@ -153,13 +156,13 @@ docker network create mon_reseau_proxy # REVERSE_PROXY_NETWORK=mon_reseau_proxy ``` -Avant le premier `make init`, s'assurer que le reseau existe. Verification rapide : +Avant le premier `docker compose up`, s'assurer que le reseau existe. Verification rapide : ```bash docker network inspect "$(grep ^REVERSE_PROXY_NETWORK .env | cut -d= -f2)" ``` -Si la commande retourne une erreur, soit adapter `REVERSE_PROXY_NETWORK` au nom du reseau utilise par votre proxy, soit creer le reseau manuellement. La cible `make init` echoue proprement avec un message d'aide si le reseau est introuvable. +Si la commande retourne une erreur, soit adapter `REVERSE_PROXY_NETWORK` au nom du reseau utilise par votre proxy, soit creer le reseau manuellement (le reseau externe doit exister avant `docker compose up`). *Section mise a jour au fil de l'implementation (migrations reelles, seed, CI/CD deploiement).* @@ -170,8 +173,8 @@ Si la commande retourne une erreur, soit adapter `REVERSE_PROXY_NETWORK` au nom ``` . |-- .claude/ # Methodologie BYAN (visible jury : CLAUDE.md + rules/) -|-- .github/ -| `-- workflows/ # CI/CD GitHub Actions [a venir] +|-- .forgejo/ +| `-- workflows/ # CI Forgejo Actions (ci.yml : secret-scan, php-lint, static-tests, js-tests, auto-merge) |-- .githooks/ # pre-commit + commit-msg [a venir] |-- docker/ # Dockerfiles customs par service | |-- apache/ @@ -199,7 +202,6 @@ Si la commande retourne une erreur, soit adapter `REVERSE_PROXY_NETWORK` au nom |-- .env.example |-- .dockerignore |-- .gitignore -|-- Makefile |-- docker-compose.yml `-- README.md ``` @@ -212,7 +214,7 @@ Si la commande retourne une erreur, soit adapter `REVERSE_PROXY_NETWORK` au nom - **Commits** : Conventional Commits en anglais (`feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `ci`, `db`, `perf`, `style`). Format : `type(scope): description`. Voir `docs/PROJECT_CONTEXT.md` section 9. - **Branches** : `feat/*`, `fix/*`, `refactor/*`, `docs/*`, `ci/*`, `db/*`, `chore/*`, `test/*` depuis `dev`. Merge vers `dev` par PR squashee. Periodiquement `dev` -> `main` par PR avec tag semver. -- `main` et `dev` sont proteges cote GitHub (PR requise, force push bloque, resolution des conversations requise). +- `main` et `dev` sont proteges cote Forgejo (PR requise, force push bloque, checks requis : secret-scan / php-lint / static-tests). - Pas d'emoji dans le code, les commits ou les specs techniques (Mantra IA-23). *Sections detaillees (setup env de dev, lint, tests) : a completer au fil de l'implementation.* @@ -227,7 +229,7 @@ Si la commande retourne une erreur, soit adapter `REVERSE_PROXY_NETWORK` au nom ## Deploiement -*Section a completer. Strategie cible : CI GitHub Actions sur PR vers `dev` (lint + PHPUnit), CD automatique sur merge vers `main` via SSH + `make rebuild`, voir `docs/PROJECT_CONTEXT.md` section 7 Bloc 5.* +*Strategie : CI Forgejo Actions sur PR vers `dev`/`main` (secret-scan gitleaks, php-lint, static-tests PHPStan+PHPUnit, js-tests) avec auto-merge sur label + CI verte. CD : declenchement humain, redeploiement par `docker compose pull && docker compose up -d`. Voir `docs/PROJECT_CONTEXT.md` section 7 Bloc 5.* --- diff --git a/db/README.md b/db/README.md index 67384bd..843915e 100644 --- a/db/README.md +++ b/db/README.md @@ -22,7 +22,7 @@ bash db/migrate.sh --status # liste l'etat sans rien appliquer Le runner cible le conteneur `wakdo-db` et lit les identifiants dans `.env` (`DB_NAME`, `DB_ROOT_PASSWORD`). Il maintient une table `schema_migrations` (une ligne par fichier applique) : relancer ne rejoue que les nouvelles -migrations. La cible `make migrate` est destinee a appeler ce script. +migrations. La cible `bash db/migrate.sh` est destinee a appeler ce script. ## Conventions diff --git a/db/migrate-container.sh b/db/migrate-container.sh new file mode 100644 index 0000000..a80952b --- /dev/null +++ b/db/migrate-container.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# +# Wakdo - runner migrations + seed IN-CONTAINER (service compose one-shot wakdo-migrate). +# +# Applique, dans l'ordre lexicographique et de maniere IDEMPOTENTE : +# 1. db/migrations/*.sql (suivi : table schema_migrations) +# 2. db/seeds/*.sql (suivi : table seeds_applied) +# Relancer ne rejoue que les fichiers en attente (tracking par nom de fichier). +# +# Contrairement a db/migrate.sh (hote, via `docker exec`), ce runner tourne DANS +# un conteneur et se connecte a la base PAR LE RESEAU compose (DB_HOST). Il est +# lance par le service `wakdo-migrate` apres que `wakdo-db` soit healthy ; les +# services applicatifs (app/web) attendent sa COMPLETION (service_completed_successfully). +# +# But : `docker compose up` amene une stack COMPLETE et utilisable (schema + donnees +# de reference, dont l'admin bootstrap) en une seule commande, sans dependance a +# l'hote (Cr 7.c.4) -> remplace `make init`. +# +# Variables injectees par docker-compose : DB_HOST, DB_PORT, DB_NAME, DB_ROOT_PASSWORD. +# Root requis : migrations = DDL, seeds = INSERT de reference. +# +set -euo pipefail + +: "${DB_HOST:?DB_HOST manquant}" +: "${DB_NAME:?DB_NAME manquant}" +: "${DB_ROOT_PASSWORD:?DB_ROOT_PASSWORD manquant}" +PORT="${DB_PORT:-3306}" + +db() { mariadb -h "$DB_HOST" -P "$PORT" -uroot -p"$DB_ROOT_PASSWORD" "$@"; } + +# Applique les *.sql d'un dossier non encore enregistres dans sa table de suivi. +apply_tracked() { + local dir="$1" table="$2" + local f base n applied=0 + + db "$DB_NAME" -e "CREATE TABLE IF NOT EXISTS ${table} ( + filename VARCHAR(255) NOT NULL PRIMARY KEY, + applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;" + + shopt -s nullglob + local files=("$dir"/*.sql) + if [ ${#files[@]} -eq 0 ]; then + echo "[${table}] aucun fichier dans ${dir}" + return 0 + fi + + for f in "${files[@]}"; do + base="$(basename "$f")" + n="$(db "$DB_NAME" -N -s -e "SELECT COUNT(*) FROM ${table} WHERE filename='${base}';")" + if [ "$n" = "0" ]; then + echo "[${table}] application de ${base} ..." + db "$DB_NAME" < "$f" + db "$DB_NAME" -e "INSERT INTO ${table} (filename) VALUES ('${base}');" + applied=$((applied + 1)) + else + echo "[${table}] ${base} deja applique, ignore" + fi + done + echo "[${table}] termine (${applied} nouveau(x))." +} + +echo "[migrate] cible ${DB_HOST}:${PORT}/${DB_NAME}" +apply_tracked /db/migrations schema_migrations +apply_tracked /db/seeds seeds_applied +echo "[migrate] stack a jour (schema + donnees de reference)." diff --git a/db/migrate.sh b/db/migrate.sh index b05f65b..5edd909 100755 --- a/db/migrate.sh +++ b/db/migrate.sh @@ -7,7 +7,9 @@ # deja appliques, donc relancer ne rejoue que les nouvelles migrations. # # Cible : le service docker-compose `wakdo-db` (MariaDB). Lance depuis l'hote -# (c'est ce que `make migrate` appellera). Identifiants lus dans .env. +# (usage manuel / `--status`, identifiants lus dans .env). Au boot de la stack, +# c'est le service `wakdo-migrate` (db/migrate-container.sh, via le reseau) qui +# applique migrations + seed automatiquement. # # Usage : # bash db/migrate.sh # applique les migrations en attente @@ -30,7 +32,7 @@ DB_ROOT_PASSWORD="$(grep -E '^DB_ROOT_PASSWORD=' "$ENV_FILE" | cut -d= -f2-)" db() { docker exec -i "$CONTAINER" mariadb -uroot -p"$DB_ROOT_PASSWORD" "$@"; } # Le conteneur doit etre en marche. -docker exec "$CONTAINER" true 2>/dev/null || { echo "ERREUR : conteneur $CONTAINER non demarre (make up)" >&2; exit 1; } +docker exec "$CONTAINER" true 2>/dev/null || { echo "ERREUR : conteneur $CONTAINER non demarre (docker compose up -d)" >&2; exit 1; } # Journal des migrations appliquees. db "$DB_NAME" -e "CREATE TABLE IF NOT EXISTS schema_migrations ( diff --git a/db/seed.sh b/db/seed.sh index 9b0f398..864ac8f 100755 --- a/db/seed.sh +++ b/db/seed.sh @@ -27,7 +27,7 @@ DB_ROOT_PASSWORD="$(grep -E '^DB_ROOT_PASSWORD=' "$ENV_FILE" | cut -d= -f2-)" db() { docker exec -i "$CONTAINER" mariadb -uroot -p"$DB_ROOT_PASSWORD" "$@"; } -docker exec "$CONTAINER" true 2>/dev/null || { echo "ERREUR : conteneur $CONTAINER non demarre (make up)" >&2; exit 1; } +docker exec "$CONTAINER" true 2>/dev/null || { echo "ERREUR : conteneur $CONTAINER non demarre (docker compose up -d)" >&2; exit 1; } if [ ! -d "$SEEDS_DIR" ]; then echo "[seed] aucun repertoire db/seeds/ - rien a charger" diff --git a/docker-compose.yml b/docker-compose.yml index 92489f2..a9e8ed7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,11 +18,11 @@ # wakdo_uploads : named volume pour les uploads produits back-office # ./var/backups : bind-mount lecture-ecriture pour les dumps SQL # -# Variables d'env consommees depuis .env (chargees par make via `include .env` -# et transmises ici par docker compose qui fait l'expansion automatique). +# Variables d'env consommees depuis .env : docker compose lit automatiquement le +# fichier .env a la racine et fait l'expansion des ${...} ci-dessous. # -# Persistance : un `make down` preserve les named volumes. Seul `make clean` -# (interactif) ou `docker compose down -v` supprime les donnees. +# Persistance : `docker compose down` preserve les named volumes ; seul +# `docker compose down -v` supprime les donnees. # name: wakdo @@ -62,8 +62,7 @@ volumes: wakdo_db_data: # Named volume MariaDB. Permissions gerees par Docker (UID mysql=999 # dans le conteneur), zero souci cote hote. Survit a `docker compose down`. - # Pour remise a zero : `make clean` (interactif, confirme) ou - # `docker compose down -v` (destructif direct). + # Pour remise a zero : `docker compose down -v` (destructif : supprime les volumes). wakdo_uploads: # Images produits uploadees par les equipiers depuis le back-office. @@ -113,6 +112,38 @@ services: retries: 6 start_period: 30s + # ======================================================================= + # wakdo-migrate : service ONE-SHOT (migrations + seed idempotents) + # ======================================================================= + # Tourne une fois apres que wakdo-db soit healthy, applique le schema puis les + # donnees de reference (idempotent via schema_migrations / seeds_applied), et + # sort. app/web attendent sa COMPLETION : `docker compose up` rend ainsi la stack + # complete + utilisable en UNE commande, sans dependance a l'hote (Cr 7.c.4). + wakdo-migrate: + image: mariadb:11.4 + container_name: wakdo-migrate + restart: "no" + + environment: + DB_HOST: ${DB_HOST} + DB_PORT: ${DB_PORT} + DB_NAME: ${DB_NAME} + # Root : migrations = DDL, seeds = INSERT de reference. + DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} + + volumes: + # migrations + seeds + le runner, en lecture seule. + - ./db:/db:ro + + networks: + - wakdo_internal + + depends_on: + wakdo-db: + condition: service_healthy + + entrypoint: ["bash", "/db/migrate-container.sh"] + # ======================================================================= # wakdo-app : PHP-FPM 8.3 (execute le code back-office + API) # ======================================================================= @@ -171,13 +202,16 @@ services: # Named volume pour les uploads, plus specifique que le bind-mount # parent : les uploads ne vont pas dans ./src, ils restent dans le - # volume Docker et survivent aux `make down`. + # volume Docker et survivent aux `docker compose down`. - wakdo_uploads:/var/www/html/public/uploads networks: - wakdo_internal depends_on: + # Le schema + les donnees de reference sont en place AVANT que l'app serve. + wakdo-migrate: + condition: service_completed_successfully wakdo-db: condition: service_healthy @@ -210,6 +244,8 @@ services: - reverse_proxy depends_on: + wakdo-migrate: + condition: service_completed_successfully wakdo-app: condition: service_started wakdo-db: diff --git a/docs/PROJECT_CONTEXT.md b/docs/PROJECT_CONTEXT.md index 3429b94..73f16db 100644 --- a/docs/PROJECT_CONTEXT.md +++ b/docs/PROJECT_CONTEXT.md @@ -113,13 +113,13 @@ Client Borne (Bloc 1) API (Bloc 2) BDD **Un seul codebase, deux FQDN d'exposition publique.** Le front Bloc 1 et le back Bloc 2 coexistent dans la meme arborescence. Une bascule mode JSON-seuls (Bloc 1 isole) vs mode API-connecte doit rester possible via configuration. -**Pourquoi pas strategie A (deux rendus isoles)** : le Bloc 5 DevOps impose une conteneurisation **unique** qui lance la stack complete avec `make init` en une commande (Cr 7.c.4). Deux codebases isolees seraient incoherentes avec cette exigence. +**Pourquoi pas strategie A (deux rendus isoles)** : le Bloc 5 DevOps impose une conteneurisation **unique** qui lance la stack complete avec `docker compose up` en une commande (Cr 7.c.4). Deux codebases isolees seraient incoherentes avec cette exigence. ### Compatibilite evaluation par bloc - **Jury Bloc 1** : voit le front seul ; le front peut tomber en fallback sur JSON statiques fournis (`src/public/borne/data/*.json`) si l'API est indisponible. - **Jury Bloc 2** : voit le back-office + teste l'API via curl/Postman de maniere autonome, sans dependre du front. -- **Jury Bloc 5** : lance `make init` ou `docker compose up`, verifie la CI/CD, les crons, l'archi, les scripts. +- **Jury Bloc 5** : lance `docker compose up` ou `docker compose up`, verifie la CI/CD, les crons, l'archi, les scripts. --- @@ -193,7 +193,7 @@ Reseaux : | Reverse proxy | Traefik (deja en place) | existant | `admin_proxy` network | | TLS | Let's Encrypt via Traefik | auto | `acme.json` existant | | Conteneurisation | Docker + docker compose | v2 | Cr 7.c | -| Orchestration locale | Makefile | — | Cr 7.b (script) + Cr 7.c.4 (une commande) | +| Orchestration locale | docker compose (service wakdo-migrate) | — | Cr 7.b (script) + Cr 7.c.4 (une commande) | | CI/CD | Forgejo Actions (act_runner auto-heberge) | — | Cr 7.d | | Versioning | Git + Forgejo auto-heberge (push-mirror GitHub) | — | Cr 4.f (collaboration) | | Hooks Git | pre-commit + commit-msg | versionnes dans `.githooks/` | Conventional Commits | @@ -263,14 +263,14 @@ Reseaux : **IN scope :** - Dockerfile custom PHP-FPM avec extensions - `docker-compose.yml` orchestrant les 4 services (web, app, db, cron) -- `Makefile` avec cible `make init` qui lance tout en une commande (Cr 7.c.4) +- `docker compose up` lance toute la stack (service one-shot `wakdo-migrate` : migrations + seed idempotents) en une commande (Cr 7.c.4) - Scripts Bash d'automatisation (backup, deploy, migrate) - **Cron tab** avec au moins 3 jobs planifies dans la fenetre de maintenance (01h30-09h30) : - `0 3 * * *` — backup BDD quotidien a 03h00 (entre fin service 01h et ouverture 10h) - `*/15 * * * *` — purge sessions expirees toutes les 15 min (leger, peut tourner en service) - `30 4 * * *` — agregation stats commandes a 04h30 sur le **jour de service** ecoule (10h J-1 → 01h J) - **CI Forgejo Actions** (act_runner auto-heberge) : lint PHP + PHPStan + PHPUnit + secret-scan (gitleaks) sur PR -> dev -- **CD Forgejo Actions** : deploy auto sur merge main (SSH + pull + `make rebuild`) +- **CD Forgejo Actions** : deploy auto sur merge main (SSH + `docker compose pull && docker compose up -d`) - `.env.example` documente (parametres securite : argon2id, lockout, seuils throttle, retention RGPD), secrets hors du repo - `php.ini` durci (expose_php off, session cookies httponly/secure/samesite, upload limite) - Healthcheck Traefik + readiness probes @@ -328,13 +328,13 @@ Reseaux : | Critere | Libelle court | Feature Wakdo couvrant | |---|---|---| | Cr 7.a.1-3 | Analyse infra + securite | Audit code + proposition automatisation documentee | -| Cr 7.b.1 | Langage de script | Bash (deploy, backup) + Makefile | -| Cr 7.b.2 | Automatisation fiabilisee | Makefile avec exit codes, retries, logs | +| Cr 7.b.1 | Langage de script | Bash (db/*.sh migrate/seed, scripts/forgejo-*.sh, entrypoints, backup) | +| Cr 7.b.2 | Automatisation fiabilisee | Scripts Bash (set -euo pipefail, exit codes, logs) + service compose wakdo-migrate idempotent | | Cr 7.b.3 | **Cron tab** | `wakdo-cron` service avec crontab : backup BDD, purge sessions, stats | | Cr 7.c.1 | VM operationnelle | Serveur existant Acadenice | | Cr 7.c.2 | OS conteneur installe | Docker Engine | | Cr 7.c.3 | App conteneurisee complete | 4 services (web, app, db, cron) | -| Cr 7.c.4 | **Une ligne de commande** | `make init` lance toute la stack + migrate + seed | +| Cr 7.c.4 | **Une ligne de commande** | `docker compose up` lance toute la stack + migrate + seed | | Cr 7.d.1 | Architecture serveur | Traefik reverse + reseaux segmentes documentes | | Cr 7.d.2 | Tests avant deploy | CI PHPUnit + PHPStan + secret-scan sur PR (Forgejo Actions) | | Cr 7.d.3 | Integration/deploiement continus | Forgejo Actions deploy automatique sur merge main | @@ -439,7 +439,7 @@ Les branches `main` et `dev` sont **protegees** cote Forgejo (push direct interd | 8 | 2 FQDN | Separation claire borne publique / admin+API interne, defensible jury | | 9 | API sous `/api` sur le FQDN admin | Simplicite d'exploitation, CORS explicite gere | | 10 | Service cron dedie | Cr 7.b.3 explicite + realiste prod | -| 11 | Makefile avec `make init` | Cr 7.c.4 + demonstration DevOps | +| 11 | Orchestration `docker compose up` (service wakdo-migrate) | Cr 7.c.4 + demonstration DevOps | | 12 | Conventional Commits + hooks | Cr 4.f.x + discipline de versioning | | 13 | Branches feat/* -> dev -> main | Pipeline propre pour jury, PR tracee (Forgejo, mirror GitHub) | | 14 | CI/CD Forgejo Actions (act_runner auto-heberge) | Cr 7.d explicite ; forge + CI maitrisees de bout en bout (argument Bloc 5) | @@ -490,7 +490,7 @@ Buffer : ~8 h pour imprevus. Cible effective : ~264 h sur 20 semaines = **~13 h/ **Bloc 5 :** - `docker-compose.yml` commente - Dockerfiles customs commentes -- `Makefile` avec `make help` +- Orchestration via `docker compose` (service one-shot `wakdo-migrate` : migrate + seed) - `.forgejo/workflows/` avec CI (PHPUnit + PHPStan + secret-scan) + CD - Crontab documente - Script de backup/restore teste @@ -500,7 +500,7 @@ Buffer : ~8 h pour imprevus. Cible effective : ~264 h sur 20 semaines = **~13 h/ - **README.md** synthetique (quick start + liens docs) - **Presentation** (slides ou live) argumentant les choix -- **Demo** live : borne + back-office + API (Postman/curl) + `make init` +- **Demo** live : borne + back-office + API (Postman/curl) + `docker compose up` - **Capacite modification en direct** (Cr 4.a.1) : code structure pour permettre modifs sans casser --- @@ -511,7 +511,7 @@ Buffer : ~8 h pour imprevus. Cible effective : ~264 h sur 20 semaines = **~13 h/ |---|---|---|---| | Sous-estimation temps front (accessibilite RGAA stricte) | Haute | Moyen | 60 h budgetees + tests W3C/axe-core pendant le dev, pas a la fin | | Complexite MCT (statuts commande) mal modelisee | Moyenne | Fort | Valider MCT avec un pair ou prof avant d'implementer Bloc 2 | -| Dockerfile PHP extensions manquantes decouvert tard | Moyenne | Faible | Tester `make up` + un vrai appel BDD des P0 | +| Dockerfile PHP extensions manquantes decouvert tard | Moyenne | Faible | Tester `docker compose up -d` + un vrai appel BDD des P0 | | Conflit reseau Docker `wakdo_internal` existant | Faible | Faible | Verifie au setup, fallback nom `wakdo_backend` | | CORS mal configure bloque la borne | Moyenne | Moyen | Test immediat apres setup 2 FQDN | | Performance borne sur ecran tactile reel | Faible | Fort | Optimiser images + lazy loading + tests sur device tactile si possible | @@ -614,7 +614,7 @@ L'auteur peut recourir ponctuellement a d'autres outils IA (completion IDE, assi - **Choix du scope fonctionnel** : defini par l'auteur a partir du brief RNCP. L'IA n'ajoute ni ne retire de fonctionnalite sans instruction explicite. - **Modelisation Merise** (MCD, MCT, MLD) : formalisation produite par l'IA a partir du dictionnaire de donnees et des user stories ; arbitrage, validation et corrections par l'auteur. Chaque cardinalite, chaque relation et chaque transition de statut est validee par l'auteur avant integration. Le livrable final reflete ses decisions. - **Validation des livrables** : reservee au jury. L'IA n'emet pas de jugement final sur la conformite RNCP. -- **Deploiements** : declenchement humain uniquement, y compris sur `make init` local. Aucune action sur environnement serveur sans instruction explicite. +- **Deploiements** : declenchement humain uniquement, y compris sur `docker compose up` local. Aucune action sur environnement serveur sans instruction explicite. - **Commit en son nom** : aucun trailer `Co-Authored-By: Claude...` n'est appose sur les commits. Voir section 17.7. - **Decisions de securite critiques** : tous les choix de type hash mdp, CORS, RBAC, politique sessions sont valides par l'auteur meme si l'IA en propose la mise en oeuvre. diff --git a/docs/journal/2026-06-17--makefile-to-compose-migrate.md b/docs/journal/2026-06-17--makefile-to-compose-migrate.md new file mode 100644 index 0000000..41717a9 --- /dev/null +++ b/docs/journal/2026-06-17--makefile-to-compose-migrate.md @@ -0,0 +1,88 @@ +# 2026-06-17 — Du Makefile a `docker compose up` (service wakdo-migrate) + +**Auteur : BYAN.** Remplacement de l'orchestration locale par Makefile par un service +compose one-shot. Objectif : que `docker compose up` amene a lui seul une stack +complete et utilisable, et retirer un Makefile devenu en partie trompeur. + +## Pourquoi ce changement + +### Le declencheur : le Makefile mentait en partie +Un audit du Makefile (24 cibles) a montre trois categories : +- **Cibles mortes / trompeuses** : `test`, `test-unit`, `test-integration`, `lint` + affichaient *« Pas encore implemente … en P2 »* alors que les tests EXISTENT et + tournent (PHPUnit via `.phar`, 263 tests unit + 301/916 en integration ; PHPStan + L6 ; tests JS node:test+jsdom). `install-hooks` referencait un `.githooks/` et un + `scripts/install-hooks.sh` absents. Une cible qui annonce un faux est pire qu'une + cible absente. +- **Wrappers fins** : `up/down/logs/shell/...` = une ligne au-dessus de + `docker compose`, valeur surtout de decouvrabilite (`make help`). +- **Une seule cible reellement porteuse** : `init` (build -> up -> wait-db -> + migrate), citee comme la preuve du critere RNCP **Cr 7.c.4** (*« lancer la stack + complete avec une seule ligne de commande »*). + +### Le point cle : Cr 7.c.4 parle d'un RESULTAT, pas de `make` +Le critere exige *une commande -> stack complete*. Il ne mentionne pas `make` ; +`make init` n'etait qu'un choix d'implementation. Or `docker compose up` seul ne +suffisait pas : il demarre les conteneurs mais **n'applique pas les migrations** +(base vide -> stack non « complete »). C'etait l'unique raison d'etre de `make init`. + +En deplacant migration + seed DANS la stack (un service one-shot qui tourne au +boot), c'est `docker compose up` LUI-MEME qui amene la stack complete. Avantages : +- **Commande universelle** : `docker compose up`, sans dependance a l'outil `make` + sur l'hote (un correcteur n'a pas a installer/connaitre `make`). +- **Comportement = documentation** : l'ancien `make init` ne faisait meme PAS le + seed (il s'arretait a `migrate`), alors que le README annoncait « migrate + seed ». + Le nouveau chemin seed pour de vrai, donc la stack est *loginnable* (admin present) + en une commande. +- **Plus idiomatique** : faire porter l'init par la couche d'orchestration (compose) + plutot que par un outil hote externe. + +## Ce qui a ete fait + +- **`db/migrate-container.sh`** : runner in-container. Applique `db/migrations/*.sql` + (suivi `schema_migrations`) PUIS `db/seeds/*.sql` (suivi `seeds_applied`), de + maniere idempotente, en se connectant a la base par le reseau compose (DB_HOST). + Distinct de `db/migrate.sh` (hote, via `docker exec`), conserve pour l'usage manuel + (`--status`) et la CI. +- **Service `wakdo-migrate`** (image mariadb, `restart: "no"`) : `depends_on` + `wakdo-db: service_healthy`, lance le runner puis sort. `wakdo-app` et `wakdo-web` + gagnent `depends_on wakdo-migrate: service_completed_successfully` -> ils ne servent + qu'une fois le schema + le seed en place. +- **Makefile supprime.** Les commandes equivalentes en clair : + `docker compose up -d` (= ex-`make init`/`up`), `docker compose down` (`make down`), + `docker compose down -v` (`make clean`), `docker compose build --no-cache && up -d` + (`make rebuild`), `docker compose logs -f` (`make logs`), + `docker compose exec wakdo-db mariadb -uroot -p"$DB_ROOT_PASSWORD"` (`make shell-db`). + Tests : `docker run --rm -v "$PWD":/app -w /app wakdo-wakdo-app php phpunit.phar -c phpunit.xml` + (cf. README / SESSION_RESUME). + +## Verification + +Base MariaDB ephemere et vierge (pour ne pas toucher la dev) : +- Run #1 : 2 migrations + 2 seeds appliques. +- Run #2 : 0 nouveau (idempotent, tout ignore). +- Donnees : 5 roles, 23 permissions, admin `admin@wakdo.local` present ; + `schema_migrations`=2, `seeds_applied`=2. + +`docker compose -p wakdo config` valide. La CI n'utilise pas `make` (0 appel) : +elle garde sa propre boucle migrate -> non impactee. + +## Mapping Cr 7.c.4 (apres ce changement) +*« Le fichier de configuration permet de lancer la stack applicative complete avec +une seule ligne de commande »* -> **`docker compose up`** : `docker-compose.yml` +decrit la stack, le service `wakdo-migrate` applique schema + donnees, app/web +attendent sa completion. Une commande, aucune dependance hote. + +## Note de deploiement (environnements deja seedes) +Sur une base existante deja migree ET seedee AVANT l'introduction du suivi +(`seeds_applied` absente), le premier `docker compose up` avec le nouveau service +tenterait de rejouer les seeds (INSERT non idempotents) -> conflits d'unicite. Pour +ces environnements : back-fill une fois la table de suivi +(`CREATE TABLE seeds_applied(...)` + INSERT des noms de fichiers seed deja appliques, +idem `schema_migrations` si besoin) AVANT le premier up. Les deploiements sur volume +VIERGE ne sont pas concernes (le service applique tout proprement, comme verifie). + +## Compromis assumes +- migrations + seeds evalues a CHAQUE `up` : cout negligeable (le suivi rend les + re-runs sans effet). +- `wakdo-migrate` se connecte en root (DDL + INSERT de reference), comme `migrate.sh`. -- 2.45.3