# This file is the entry point to configure your own services. # Files in the packages/ subdirectory configure your dependencies. # Put parameters here that don't need to change on each machine where the app is deployed # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration parameters: tenant.base_domain: '%env(TENANT_BASE_DOMAIN)%' app.url: '%env(APP_URL)%' services: # default configuration for services in this file _defaults: autowire: true # Automatically injects dependencies in your services. autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. bind: # Bind activation tokens cache pool (7-day TTL) Psr\Cache\CacheItemPoolInterface $activationTokensCache: '@activation_tokens.cache' # Bind users cache pool (no TTL - persistent data) Psr\Cache\CacheItemPoolInterface $usersCache: '@users.cache' # Bind refresh tokens cache pool (7-day TTL) Psr\Cache\CacheItemPoolInterface $refreshTokensCache: '@refresh_tokens.cache' # Bind password reset tokens cache pool (1-hour TTL) Psr\Cache\CacheItemPoolInterface $passwordResetTokensCache: '@password_reset_tokens.cache' # Bind sessions cache pool (7-day TTL) Psr\Cache\CacheItemPoolInterface $sessionsCache: '@sessions.cache' # Bind named message buses Symfony\Component\Messenger\MessageBusInterface $eventBus: '@event.bus' Symfony\Component\Messenger\MessageBusInterface $commandBus: '@command.bus' # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name App\: resource: '../src/' exclude: - '../src/DependencyInjection/' - '../src/Entity/' - '../src/Kernel.php' # Exclude Domain layers - they should be pure PHP with no framework deps - '../src/*/Domain/' # Domain services need to be registered explicitly to avoid framework coupling # Example: App\Administration\Application\Command\: # resource: '../src/Administration/Application/Command/' # Tenant services App\Shared\Infrastructure\Tenant\TenantResolver: arguments: $baseDomain: '%tenant.base_domain%' # TenantRegistry est configuré par environnement : # - dev: config/packages/dev/tenant.yaml (tenants de test) # - prod: à configurer via admin ou env vars App\Shared\Infrastructure\Tenant\Command\CreateTenantDatabaseCommand: arguments: $masterDatabaseUrl: '%env(DATABASE_URL)%' App\Shared\Infrastructure\Tenant\Command\TenantMigrateCommand: arguments: $projectDir: '%kernel.project_dir%' # Administration services # Bind Repository interfaces to their implementations App\Administration\Domain\Repository\ActivationTokenRepository: alias: App\Administration\Infrastructure\Persistence\Redis\RedisActivationTokenRepository App\Administration\Domain\Repository\UserRepository: alias: App\Administration\Infrastructure\Persistence\Cache\CacheUserRepository App\Administration\Application\Port\PasswordHasher: alias: App\Administration\Infrastructure\Security\SymfonyPasswordHasher # Clock interface binding App\Shared\Domain\Clock: alias: App\Shared\Infrastructure\Clock\SystemClock # Domain policies (need explicit registration as Domain is excluded from autowiring) App\Administration\Domain\Policy\ConsentementParentalPolicy: autowire: true # Email handlers App\Administration\Infrastructure\Messaging\SendActivationConfirmationHandler: arguments: $appUrl: '%app.url%' App\Administration\Infrastructure\Messaging\SendPasswordResetEmailHandler: arguments: $appUrl: '%app.url%' App\Administration\Infrastructure\Messaging\SendPasswordResetConfirmationHandler: arguments: $appUrl: '%app.url%' # Audit log handler (uses dedicated audit channel) App\Administration\Infrastructure\Messaging\AuditLoginEventsHandler: arguments: $auditLogger: '@monolog.logger.audit' $appSecret: '%env(APP_SECRET)%' # JWT Authentication App\Administration\Infrastructure\Security\JwtPayloadEnricher: tags: - { name: kernel.event_listener, event: lexik_jwt_authentication.on_jwt_created, method: onJWTCreated } App\Administration\Infrastructure\Security\DatabaseUserProvider: arguments: $userRepository: '@App\Administration\Domain\Repository\UserRepository' # Refresh Token Repository App\Administration\Domain\Repository\RefreshTokenRepository: alias: App\Administration\Infrastructure\Persistence\Redis\RedisRefreshTokenRepository # Password Reset Token Repository App\Administration\Domain\Repository\PasswordResetTokenRepository: alias: App\Administration\Infrastructure\Persistence\Redis\RedisPasswordResetTokenRepository # Session Repository App\Administration\Domain\Repository\SessionRepository: alias: App\Administration\Infrastructure\Persistence\Redis\RedisSessionRepository # GeoLocation Service (null implementation - no geolocation) App\Administration\Application\Port\GeoLocationService: alias: App\Administration\Infrastructure\Service\NullGeoLocationService # Password Reset Processor with rate limiters App\Administration\Infrastructure\Api\Processor\RequestPasswordResetProcessor: arguments: $passwordResetByEmailLimiter: '@limiter.password_reset_by_email' $passwordResetByIpLimiter: '@limiter.password_reset_by_ip' # Login handlers App\Administration\Infrastructure\Security\LoginSuccessHandler: tags: - { name: kernel.event_listener, event: lexik_jwt_authentication.on_authentication_success, method: onAuthenticationSuccess } App\Administration\Infrastructure\Security\LoginFailureHandler: tags: - { name: security.authentication_failure_handler, firewall: api_login } # Rate Limiter (délai Fibonacci + CAPTCHA + blocage IP) App\Shared\Infrastructure\RateLimit\LoginRateLimiter: arguments: $cache: '@cache.rate_limiter' App\Shared\Infrastructure\RateLimit\LoginRateLimiterInterface: alias: App\Shared\Infrastructure\RateLimit\LoginRateLimiter # Rate Limit Listener (vérifie le rate limit AVANT authentification) App\Shared\Infrastructure\RateLimit\LoginRateLimitListener: arguments: $rateLimiterCache: '@cache.rate_limiter' # Turnstile CAPTCHA Validator # failOpen: true en dev (ne pas bloquer si API down), false en prod (sécurité) App\Shared\Infrastructure\Captcha\TurnstileValidator: arguments: $secretKey: '%env(TURNSTILE_SECRET_KEY)%' $failOpen: '%env(bool:default::TURNSTILE_FAIL_OPEN)%' App\Shared\Infrastructure\Captcha\TurnstileValidatorInterface: alias: App\Shared\Infrastructure\Captcha\TurnstileValidator # ============================================================================= # Test environment overrides # ============================================================================= when@test: services: # Use null rate limiter in test environment to avoid IP blocking during E2E tests App\Shared\Infrastructure\RateLimit\LoginRateLimiterInterface: alias: App\Shared\Infrastructure\RateLimit\NullLoginRateLimiter App\Shared\Infrastructure\RateLimit\NullLoginRateLimiter: autowire: true