Les événements métier (emails d'invitation, reset password, activation) bloquaient la réponse API en étant traités de manière synchrone. Ce commit route ces événements vers un transport AMQP asynchrone avec un worker dédié, garantissant des réponses API rapides et une gestion robuste des échecs. Le retry utilise une stratégie Fibonacci (1s, 1s, 2s, 3s, 5s, 8s, 13s) qui offre un bon compromis entre réactivité et protection des services externes. Les messages qui épuisent leurs tentatives arrivent dans une dead-letter queue Doctrine avec alerte email à l'admin. La commande console CreateTestActivationTokenCommand détecte désormais les comptes déjà actifs et génère un token de réinitialisation de mot de passe au lieu d'un token d'activation, évitant une erreur bloquante lors de la ré-invitation par un admin.
252 lines
8.3 KiB
YAML
252 lines
8.3 KiB
YAML
services:
|
|
# =============================================================================
|
|
# BACKEND API - PHP 8.5 + FrankenPHP
|
|
# =============================================================================
|
|
php:
|
|
build:
|
|
context: ./backend
|
|
dockerfile: Dockerfile
|
|
target: dev
|
|
container_name: classeo_php
|
|
# FrankenPHP charge les variables d'environnement système AVANT que Symfony
|
|
# ne parse le fichier .env. Sans env_file, les variables du .env ne seraient
|
|
# pas disponibles au démarrage de FrankenPHP.
|
|
# Avantage : une seule source de vérité (.env), pas de duplication.
|
|
# Note : les variables dans 'environment:' ci-dessous écrasent celles du .env
|
|
env_file:
|
|
- ./backend/.env
|
|
environment:
|
|
# Overrides pour Docker : les hostnames des services utilisent les noms
|
|
# des containers (db, redis, rabbitmq...) au lieu de localhost
|
|
# APP_ENV peut être overridé en CI pour désactiver le rate limiting (test)
|
|
APP_ENV: ${APP_ENV:-dev}
|
|
DATABASE_URL: postgresql://classeo:classeo@db:5432/classeo_master?serverVersion=18&charset=utf8
|
|
REDIS_URL: redis://redis:6379
|
|
MESSENGER_TRANSPORT_DSN: amqp://guest:guest@rabbitmq:5672/%2f/messages
|
|
MERCURE_URL: http://mercure/.well-known/mercure
|
|
MEILISEARCH_URL: http://meilisearch:7700
|
|
MAILER_DSN: ${MAILER_DSN:-smtp://mailpit:1025}
|
|
ports:
|
|
- "18000:8000" # Port externe 18000 pour eviter conflit
|
|
volumes:
|
|
- ./backend:/app:cached
|
|
- caddy_data:/data
|
|
- caddy_config:/config
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
rabbitmq:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8000/api/docs"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 30s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# FRONTEND - SvelteKit + Node.js
|
|
# =============================================================================
|
|
frontend:
|
|
build:
|
|
context: ./frontend
|
|
dockerfile: Dockerfile
|
|
target: dev
|
|
container_name: classeo_frontend
|
|
environment:
|
|
# URL de fallback, sera remplacée dynamiquement par le hostname en multi-tenant
|
|
PUBLIC_API_URL: http://localhost:18000/api
|
|
PUBLIC_API_PORT: "18000"
|
|
PUBLIC_BASE_DOMAIN: classeo.local
|
|
PUBLIC_MERCURE_URL: http://localhost:3000/.well-known/mercure
|
|
ports:
|
|
- "5174:5173" # Port externe 5174 pour eviter conflit
|
|
volumes:
|
|
- ./frontend:/app:cached
|
|
- frontend_node_modules:/app/node_modules
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5173/"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 30s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# DATABASE - PostgreSQL 18.1
|
|
# =============================================================================
|
|
db:
|
|
image: postgres:18.1-alpine
|
|
container_name: classeo_db
|
|
environment:
|
|
POSTGRES_DB: classeo_master
|
|
POSTGRES_USER: classeo
|
|
POSTGRES_PASSWORD: classeo
|
|
ports:
|
|
- "5433:5432" # Port externe 5433 pour eviter conflit avec PostgreSQL local
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U classeo -d classeo_master"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# CACHE & SESSIONS - Redis 7.4
|
|
# =============================================================================
|
|
redis:
|
|
image: redis:7.4-alpine
|
|
container_name: classeo_redis
|
|
command: redis-server --appendonly yes
|
|
ports:
|
|
- "6380:6379" # Port externe 6380 pour eviter conflit avec Redis local
|
|
volumes:
|
|
- redis_data:/data
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 5s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# MESSAGE QUEUE - RabbitMQ 4.2
|
|
# =============================================================================
|
|
rabbitmq:
|
|
image: rabbitmq:4.2-management-alpine
|
|
container_name: classeo_rabbitmq
|
|
environment:
|
|
RABBITMQ_DEFAULT_USER: guest
|
|
RABBITMQ_DEFAULT_PASS: guest
|
|
ports:
|
|
- "5672:5672"
|
|
- "15672:15672"
|
|
volumes:
|
|
- rabbitmq_data:/var/lib/rabbitmq
|
|
healthcheck:
|
|
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 30s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# REAL-TIME SSE - Mercure
|
|
# =============================================================================
|
|
mercure:
|
|
image: dunglas/mercure:latest
|
|
container_name: classeo_mercure
|
|
environment:
|
|
MERCURE_PUBLISHER_JWT_KEY: "mercure_publisher_secret_change_me_in_production"
|
|
MERCURE_SUBSCRIBER_JWT_KEY: "mercure_subscriber_secret_change_me_in_production"
|
|
SERVER_NAME: ":80"
|
|
MERCURE_EXTRA_DIRECTIVES: |
|
|
cors_origins http://localhost:5174
|
|
anonymous
|
|
ports:
|
|
- "3000:80"
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost/.well-known/mercure"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# FULL-TEXT SEARCH - Meilisearch 1.12
|
|
# =============================================================================
|
|
meilisearch:
|
|
image: getmeili/meilisearch:v1.12
|
|
container_name: classeo_meilisearch
|
|
environment:
|
|
MEILI_MASTER_KEY: "masterKey"
|
|
MEILI_ENV: "development"
|
|
ports:
|
|
- "7700:7700"
|
|
volumes:
|
|
- meilisearch_data:/meili_data
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:7700/health"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# ASYNC WORKER - Symfony Messenger
|
|
# =============================================================================
|
|
worker:
|
|
build:
|
|
context: ./backend
|
|
dockerfile: Dockerfile
|
|
target: dev
|
|
container_name: classeo_worker
|
|
env_file:
|
|
- ./backend/.env
|
|
environment:
|
|
APP_ENV: ${APP_ENV:-dev}
|
|
DATABASE_URL: postgresql://classeo:classeo@db:5432/classeo_master?serverVersion=18&charset=utf8
|
|
REDIS_URL: redis://redis:6379
|
|
MESSENGER_TRANSPORT_DSN: amqp://guest:guest@rabbitmq:5672/%2f/messages
|
|
MERCURE_URL: http://mercure/.well-known/mercure
|
|
MEILISEARCH_URL: http://meilisearch:7700
|
|
MAILER_DSN: ${MAILER_DSN:-smtp://mailpit:1025}
|
|
command: php bin/console messenger:consume async --time-limit=3600 --memory-limit=128M -vv
|
|
volumes:
|
|
- ./backend:/app:cached
|
|
depends_on:
|
|
rabbitmq:
|
|
condition: service_healthy
|
|
php:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "ps aux | grep 'messenger:consume' | grep -v grep"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 30s
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 256M
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# EMAIL TESTING - Mailpit
|
|
# =============================================================================
|
|
mailpit:
|
|
image: axllent/mailpit:latest
|
|
container_name: classeo_mailpit
|
|
ports:
|
|
- "1025:1025"
|
|
- "8025:8025"
|
|
healthcheck:
|
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8025"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 5s
|
|
restart: unless-stopped
|
|
|
|
# =============================================================================
|
|
# VOLUMES PERSISTANTS
|
|
# =============================================================================
|
|
volumes:
|
|
postgres_data:
|
|
redis_data:
|
|
rabbitmq_data:
|
|
meilisearch_data:
|
|
frontend_node_modules:
|
|
caddy_data:
|
|
caddy_config:
|