Files
Classeo/Makefile
Mathias STRASSER a0e19627a7 feat: Persister les utilisateurs en PostgreSQL avec cache-aside Redis
Les utilisateurs étaient stockés uniquement dans Redis (CacheUserRepository),
ce qui exposait à une perte totale des comptes en cas de restart Redis,
FLUSHDB ou perte du volume Docker. Les tables student_guardians et
teacher_assignments référençaient des user IDs sans FK réelle.

PostgreSQL devient la source de vérité via DoctrineUserRepository (DBAL,
upsert ON CONFLICT). CachedUserRepository décore l'interface existante
avec le pattern cache-aside : lectures Redis d'abord → miss → PostgreSQL
→ populate Redis ; écritures PostgreSQL d'abord → mise à jour Redis.
Si Redis est indisponible, l'application continue via PostgreSQL seul.

Une commande de migration (app:migrate-users-to-postgres) permet de copier
les données Redis existantes vers PostgreSQL de manière idempotente.
2026-02-15 16:45:24 +01:00

300 lines
13 KiB
Makefile

.DEFAULT_GOAL := help
# =============================================================================
# Docker
# =============================================================================
# Fichiers compose - ajouter monitoring si MONITORING=1
COMPOSE_FILES := -f compose.yaml
ifdef MONITORING
COMPOSE_FILES += -f compose.monitoring.yaml
endif
.PHONY: up
up: ## Lancer les services (ajouter MONITORING=1 pour inclure observabilité)
docker compose $(COMPOSE_FILES) up -d
.PHONY: up-full
up-full: ## Lancer TOUS les services (app + monitoring)
docker compose -f compose.yaml -f compose.monitoring.yaml up -d
.PHONY: down
down: ## Arrêter tous les services (app + monitoring)
docker compose -f compose.yaml -f compose.monitoring.yaml down --remove-orphans
.PHONY: restart
restart: ## Redémarrer les services
docker compose $(COMPOSE_FILES) down
docker compose $(COMPOSE_FILES) up -d
.PHONY: rebuild
rebuild: ## Reconstruire et relancer les services (sans cache)
docker compose $(COMPOSE_FILES) down
docker compose $(COMPOSE_FILES) build --no-cache
docker compose $(COMPOSE_FILES) up -d
.PHONY: build
build: ## Reconstruire les images Docker (sans cache)
docker compose $(COMPOSE_FILES) build --no-cache
.PHONY: logs
logs: ## Voir les logs de tous les services (Ctrl+C pour quitter)
docker compose $(COMPOSE_FILES) logs -f
.PHONY: ps
ps: ## Afficher le statut des services
docker compose $(COMPOSE_FILES) ps
.PHONY: clean
clean: ## Supprimer volumes et images locales
docker compose -f compose.yaml -f compose.monitoring.yaml down -v --rmi local
# =============================================================================
# Monitoring
# =============================================================================
.PHONY: monitoring-up
monitoring-up: ## Lancer uniquement les services de monitoring
docker compose -f compose.monitoring.yaml up -d
.PHONY: monitoring-down
monitoring-down: ## Arrêter les services de monitoring
docker compose -f compose.monitoring.yaml down
.PHONY: monitoring-logs
monitoring-logs: ## Voir les logs du monitoring
docker compose -f compose.monitoring.yaml logs -f
.PHONY: grafana
grafana: ## Ouvrir Grafana dans le navigateur (http://localhost:3001)
@echo "Grafana: http://localhost:3001 (admin/admin)"
@command -v xdg-open >/dev/null && xdg-open http://localhost:3001 || echo "Ouvrir manuellement: http://localhost:3001"
.PHONY: prometheus
prometheus: ## Ouvrir Prometheus dans le navigateur (http://localhost:9090)
@echo "Prometheus: http://localhost:9090"
@command -v xdg-open >/dev/null && xdg-open http://localhost:9090 || echo "Ouvrir manuellement: http://localhost:9090"
.PHONY: glitchtip
glitchtip: ## Ouvrir GlitchTip dans le navigateur (http://localhost:8081)
@echo "GlitchTip: http://localhost:8081"
@command -v xdg-open >/dev/null && xdg-open http://localhost:8081 || echo "Ouvrir manuellement: http://localhost:8081"
# =============================================================================
# Shell
# =============================================================================
.PHONY: shell
shell: ## Ouvrir un shell dans le container PHP
docker compose exec php sh
.PHONY: bash
bash: shell ## Alias pour 'make shell'
.PHONY: console
console: ## Exécuter une commande Symfony (ex: make console c='debug:router')
docker compose exec php php bin/console $(c)
.PHONY: shell-frontend
shell-frontend: ## Ouvrir un shell dans le container frontend
docker compose exec frontend sh
# =============================================================================
# Backend - Qualité
# =============================================================================
.PHONY: phpstan
phpstan: ## Analyse statique PHPStan (level 9)
docker compose exec php composer phpstan
.PHONY: arch
arch: ## Tests d'architecture PHPat
docker compose exec php composer arch
.PHONY: cs-fix
cs-fix: ## Corriger le code style PHP (PHP-CS-Fixer)
docker compose exec php composer cs-fix
.PHONY: cs-check
cs-check: ## Vérifier le code style PHP sans corriger
docker compose exec php composer cs-check
.PHONY: setup-test-db
setup-test-db: ## Créer et migrer la base de test PostgreSQL
docker compose exec php php bin/console doctrine:database:create --if-not-exists --env=test -q
docker compose exec php php bin/console doctrine:migrations:migrate --no-interaction --env=test -q
.PHONY: test-php
test-php: setup-test-db ## Lancer les tests PHPUnit
docker compose exec -e APP_ENV=test php composer test
.PHONY: warmup
warmup: ## Préchauffer le cache Symfony
docker compose exec php php bin/console cache:warmup
# =============================================================================
# Frontend - Qualité
# =============================================================================
.PHONY: lint
lint: ## Lancer ESLint sur le frontend
docker compose exec frontend pnpm run lint
.PHONY: check-types
check-types: ## Vérifier les types TypeScript (svelte-check)
docker compose exec frontend pnpm run check
.PHONY: test-js
test-js: ## Lancer les tests Vitest
docker compose exec frontend pnpm run test
.PHONY: e2e
e2e: e2e-ci e2e-ratelimit ## Lancer tous les tests E2E (CI + rate limiting)
.PHONY: e2e-ci
e2e-ci: ## Lancer les tests E2E sans rate limiting (rapide, parallèle)
docker compose exec php php bin/console cache:pool:clear cache.rate_limiter --env=dev
cd frontend && CI=true PLAYWRIGHT_BASE_URL=http://ecole-alpha.classeo.local:5174 npx playwright test
.PHONY: e2e-ratelimit
e2e-ratelimit: ## Lancer les tests de rate limiting (lent, séquentiel)
docker compose exec php php bin/console cache:pool:clear cache.rate_limiter --env=dev
cd frontend && PLAYWRIGHT_BASE_URL=http://ecole-alpha.classeo.local:5174 npx playwright test --workers=1 --grep="Rate Limiting|CAPTCHA"
# =============================================================================
# Tout-en-un
# =============================================================================
.PHONY: test
test: test-php test-js ## Lancer tous les tests (PHPUnit + Vitest)
.PHONY: check
check: phpstan cs-check lint check-types ## Lancer tous les linters et checks
.PHONY: ci
ci: ## Lancer TOUS les tests et checks (comme en CI)
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " Code Style PHP (PHP-CS-Fixer)"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@$(MAKE) cs-check
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " Analyse statique PHP (PHPStan level 9)"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@$(MAKE) phpstan
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " Tests d'architecture (PHPat)"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@$(MAKE) arch
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " Tests PHP (PHPUnit)"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@$(MAKE) test-php
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " Lint Frontend (ESLint)"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@$(MAKE) lint
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " Types Frontend (svelte-check)"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@$(MAKE) check-types
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " Tests Frontend (Vitest)"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@$(MAKE) test-js
@echo ""
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo " ✅ Tous les checks sont passés !"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo ""
@echo " Note: Tests E2E (make e2e) à lancer séparément depuis l'hôte"
# =============================================================================
# Scripts
# =============================================================================
.PHONY: setup-hooks
setup-hooks: ## Installer les git hooks (pre-push: make ci)
@echo "Installation des git hooks..."
@cp scripts/hooks/pre-push .git/hooks/pre-push
@chmod +x .git/hooks/pre-push
@echo "✅ Git hooks installés (pre-push)"
.PHONY: check-bc
check-bc: ## Vérifier l'isolation des Bounded Contexts
./scripts/check-bc-isolation.sh
.PHONY: check-naming
check-naming: ## Vérifier les conventions de nommage
./scripts/check-naming.sh
.PHONY: check-tenants
check-tenants: ## Vérifier que les tenants répondent
./scripts/check-tenants.sh
# =============================================================================
# Setup initial
# =============================================================================
.PHONY: install
install: up jwt-keys setup-hooks migrate warmup ## Installation complète après clone
.PHONY: migrate
migrate: ## Exécuter les migrations Doctrine
docker compose exec php php bin/console doctrine:database:create --if-not-exists
docker compose exec php php bin/console doctrine:migrations:migrate --no-interaction
.PHONY: jwt-keys
jwt-keys: ## Générer les clés JWT (requis après clone)
@echo "Génération des clés JWT..."
@docker compose exec php mkdir -p config/jwt
@docker compose exec php openssl genpkey -out config/jwt/private.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -pass pass:$${JWT_PASSPHRASE:-classeo_jwt_passphrase_change_me}
@docker compose exec php openssl pkey -in config/jwt/private.pem -out config/jwt/public.pem -pubout -passin pass:$${JWT_PASSPHRASE:-classeo_jwt_passphrase_change_me}
@echo "Clés JWT générées dans backend/config/jwt/"
# =============================================================================
# Dev helpers
# =============================================================================
.PHONY: token
token: ## Créer un token d'activation (interactif). Options: email=, role=, tenant=, minor=1
docker compose exec php php bin/console app:dev:create-test-activation-token \
$(if $(email),--email=$(email),) \
$(if $(role),--role=$(role),) \
$(if $(tenant),--tenant=$(tenant),) \
$(if $(minor),--minor,) \
--base-url=http://localhost:5174
.PHONY: token-alpha
token-alpha: ## Créer un token sur ecole-alpha. Options: email=, role=, minor=1
docker compose exec -T php php bin/console app:dev:create-test-activation-token -n \
--tenant=ecole-alpha --base-url=http://ecole-alpha.classeo.local:5174 \
$(if $(email),--email=$(email),--email=alpha@test.com) \
$(if $(role),--role=$(role),) \
$(if $(minor),--minor,)
.PHONY: token-beta
token-beta: ## Créer un token sur ecole-beta. Options: email=, role=, minor=1
docker compose exec -T php php bin/console app:dev:create-test-activation-token -n \
--tenant=ecole-beta --base-url=http://ecole-beta.classeo.local:5174 \
$(if $(email),--email=$(email),--email=beta@test.com) \
$(if $(role),--role=$(role),) \
$(if $(minor),--minor,)
# =============================================================================
# Help
# =============================================================================
.PHONY: help
help: ## Afficher cette aide
@echo ""
@echo " Classeo - Commandes disponibles"
@echo ""
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}'
@echo ""