release: dev -> main v0.2.0 #93

Merged
Corentin merged 96 commits from dev into main 2026-06-23 10:09:58 +02:00
10 changed files with 236 additions and 276 deletions
Showing only changes of commit e613adc24a - Show all commits

View file

@ -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 <nom>).
# 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 <nom>). Sinon
# 'docker compose up' echoue avec une erreur sur le reseau externe introuvable.
REVERSE_PROXY_NETWORK=traefik_proxy

233
Makefile
View file

@ -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."

View file

@ -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.*
---

View file

@ -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

66
db/migrate-container.sh Normal file
View file

@ -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)."

View file

@ -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 (

View file

@ -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"

View file

@ -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:

View file

@ -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.

View file

@ -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`.