# 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 student guardians cache pool (no TTL - persistent data) Psr\Cache\CacheItemPoolInterface $studentGuardiansCache: '@student_guardians.cache' # Bind paginated queries cache pool (1h TTL, tag-aware) Symfony\Contracts\Cache\TagAwareCacheInterface $paginatedQueriesCache: '@paginated_queries.cache' # Bind named message buses Symfony\Component\Messenger\MessageBusInterface $eventBus: '@event.bus' Symfony\Component\Messenger\MessageBusInterface $commandBus: '@command.bus' Symfony\Component\Messenger\MessageBusInterface $queryBus: '@query.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%' App\Shared\Infrastructure\Persistence\Doctrine\TenantAwareConnection: alias: doctrine.dbal.default_connection App\Shared\Infrastructure\Tenant\TenantDatabaseSwitcher: alias: doctrine.dbal.default_connection # 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\Infrastructure\Persistence\Cache\CachedUserRepository: arguments: $inner: '@App\Administration\Infrastructure\Persistence\Doctrine\DoctrineUserRepository' App\Administration\Domain\Repository\UserRepository: alias: App\Administration\Infrastructure\Persistence\Cache\CachedUserRepository App\Administration\Infrastructure\Console\MigrateUsersToPostgresCommand: arguments: $source: '@App\Administration\Infrastructure\Persistence\Cache\CacheUserRepository' $target: '@App\Administration\Infrastructure\Persistence\Doctrine\DoctrineUserRepository' 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%' App\Shared\Infrastructure\Tenant\TenantUrlBuilder: arguments: $appUrl: '%app.url%' $baseDomain: '%tenant.base_domain%' # Audit Logger Service (writes to append-only audit_log table) App\Shared\Application\Port\AuditLogger: alias: App\Shared\Infrastructure\Audit\AuditLogger App\Shared\Infrastructure\Audit\AuditLogger: arguments: $connection: '@doctrine.dbal.master_connection' $appSecret: '%env(APP_SECRET)%' App\Shared\Infrastructure\Audit\AuditLogRepository: arguments: $connection: '@doctrine.dbal.master_connection' App\Shared\Infrastructure\Console\ArchiveAuditLogsCommand: arguments: $connection: '@doctrine.dbal.master_connection' App\Shared\Infrastructure\Console\ReviewFailedMessagesCommand: arguments: $connection: '@doctrine.dbal.master_connection' # Audit log handlers (use AuditLogger to write to database) App\Shared\Infrastructure\Audit\Handler\AuditAuthenticationHandler: arguments: $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' App\SuperAdmin\Infrastructure\Persistence\Doctrine\DoctrineSuperAdminRepository: arguments: $connection: '@doctrine.dbal.master_connection' App\SuperAdmin\Infrastructure\Persistence\Doctrine\DoctrineEstablishmentRepository: arguments: $connection: '@doctrine.dbal.master_connection' App\SuperAdmin\Application\Query\GetEstablishmentsMetrics\GetEstablishmentsMetricsHandler: arguments: $connection: '@doctrine.dbal.master_connection' # 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 # Class Repository (Story 2.1 - Gestion des classes) App\Administration\Domain\Repository\ClassRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineClassRepository # Subject Repository (Story 2.2 - Gestion des matières) App\Administration\Domain\Repository\SubjectRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineSubjectRepository # Period Configuration Repository (Story 2.3 - Gestion des périodes) App\Administration\Domain\Repository\PeriodConfigurationRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrinePeriodConfigurationRepository # Grading Configuration Repository (Story 2.4 - Mode de notation) App\Administration\Domain\Repository\GradingConfigurationRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineGradingConfigurationRepository # Class Assignment (Story 3.0 - Affectation élèves aux classes) App\Administration\Domain\Repository\ClassAssignmentRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineClassAssignmentRepository # Teacher Assignment (Story 2.8 - Affectation enseignants) App\Administration\Domain\Repository\TeacherAssignmentRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineTeacherAssignmentRepository App\Administration\Application\Port\TeacherAssignmentChecker: alias: App\Administration\Infrastructure\Service\RepositoryTeacherAssignmentChecker # Teacher Replacement Repository (Story 2.9 - Remplaçants temporaires) App\Scolarite\Domain\Repository\TeacherReplacementRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineTeacherReplacementRepository # Homework (Story 5.1 - Création de devoirs) App\Scolarite\Domain\Repository\HomeworkRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineHomeworkRepository App\Scolarite\Domain\Repository\HomeworkRuleExceptionRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineHomeworkRuleExceptionRepository App\Scolarite\Domain\Repository\HomeworkAttachmentRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineHomeworkAttachmentRepository # Homework Submissions (Story 5.10 - Rendu de devoir par l'élève) App\Scolarite\Domain\Repository\HomeworkSubmissionRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineHomeworkSubmissionRepository App\Scolarite\Domain\Repository\SubmissionAttachmentRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineSubmissionAttachmentRepository App\Scolarite\Application\Port\ClassStudentsReader: alias: App\Scolarite\Infrastructure\Service\DoctrineClassStudentsReader App\Scolarite\Domain\Service\DueDateValidator: autowire: true App\Scolarite\Domain\Service\HomeworkDuplicator: autowire: true App\Scolarite\Application\Port\HtmlSanitizer: alias: App\Scolarite\Infrastructure\Service\HomeworkHtmlSanitizer App\Scolarite\Infrastructure\Service\HomeworkHtmlSanitizer: arguments: $homeworkSanitizer: '@html_sanitizer.sanitizer.homework_sanitizer' App\Scolarite\Application\Port\FileStorage: alias: App\Scolarite\Infrastructure\Storage\LocalFileStorage App\Scolarite\Infrastructure\Storage\LocalFileStorage: arguments: $storagePath: '%kernel.project_dir%/var/storage' # Schedule (Story 4.1 - Emploi du temps) App\Scolarite\Domain\Repository\ScheduleSlotRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineScheduleSlotRepository App\Scolarite\Domain\Repository\ScheduleExceptionRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineScheduleExceptionRepository App\Scolarite\Domain\Service\ScheduleConflictDetector: autowire: true App\Scolarite\Application\Port\EnseignantAffectationChecker: alias: App\Scolarite\Infrastructure\Service\CurrentYearEnseignantAffectationChecker App\Scolarite\Domain\Repository\EvaluationRepository: alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineEvaluationRepository App\Scolarite\Application\Port\EvaluationGradesChecker: alias: App\Scolarite\Infrastructure\Service\NoGradesEvaluationGradesChecker # Super Admin Repositories (Story 2.10 - Multi-établissements) App\SuperAdmin\Domain\Repository\SuperAdminRepository: alias: App\SuperAdmin\Infrastructure\Persistence\Doctrine\DoctrineSuperAdminRepository App\SuperAdmin\Domain\Repository\EstablishmentRepository: alias: App\SuperAdmin\Infrastructure\Persistence\Doctrine\DoctrineEstablishmentRepository # School Calendar Repository (Story 2.11 - Calendrier scolaire) App\Administration\Domain\Model\SchoolCalendar\SchoolCalendarRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineSchoolCalendarRepository App\Administration\Application\Port\OfficialCalendarProvider: alias: App\Administration\Infrastructure\Service\JsonOfficialCalendarProvider App\Administration\Infrastructure\Service\JsonOfficialCalendarProvider: arguments: $dataDirectory: '%kernel.project_dir%/var/data/calendar' # School Branding (Story 2.13 - Personnalisation visuelle) App\Administration\Domain\Model\SchoolBranding\ContrastValidator: autowire: true App\Administration\Domain\Repository\SchoolBrandingRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineSchoolBrandingRepository # Homework Rules Repository App\Administration\Domain\Repository\HomeworkRulesRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineHomeworkRulesRepository App\Administration\Domain\Repository\HomeworkRulesHistoryRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineHomeworkRulesHistoryRepository App\Administration\Application\Port\LogoStorage: alias: App\Administration\Infrastructure\Storage\LocalLogoStorage App\Administration\Infrastructure\Storage\LocalLogoStorage: arguments: $uploadDir: '%kernel.project_dir%/public/uploads' $publicPath: '/uploads' App\Administration\Application\Port\ImageProcessor: alias: App\Administration\Infrastructure\Storage\ImagickImageProcessor # Import Batch Repository (Story 3.1 - Import élèves via CSV) App\Administration\Domain\Repository\ImportBatchRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineImportBatchRepository # Saved Column Mapping Repository (Story 3.1 - T3.3 Réutilisation des mappings) App\Administration\Domain\Repository\SavedColumnMappingRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineSavedColumnMappingRepository # Teacher Import Batch Repository (Story 3.2 - Import enseignants via CSV) App\Administration\Domain\Repository\TeacherImportBatchRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineTeacherImportBatchRepository # Saved Teacher Column Mapping Repository (Story 3.2 - Réutilisation des mappings enseignants) App\Administration\Domain\Repository\SavedTeacherColumnMappingRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineSavedTeacherColumnMappingRepository # Parent Invitation Repository (Story 3.3 - Invitation parents) App\Administration\Domain\Repository\ParentInvitationRepository: alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineParentInvitationRepository # Student Guardian Repository (Story 2.7 - Liaison parents-enfants) App\Administration\Infrastructure\Persistence\Cache\CacheStudentGuardianRepository: arguments: $inner: '@App\Administration\Infrastructure\Persistence\Doctrine\DoctrineStudentGuardianRepository' App\Administration\Domain\Repository\StudentGuardianRepository: alias: App\Administration\Infrastructure\Persistence\Cache\CacheStudentGuardianRepository # Paginated Read Model Ports App\Administration\Application\Port\PaginatedUsersReader: alias: App\Administration\Infrastructure\ReadModel\DbalPaginatedUsersReader App\Administration\Application\Port\PaginatedClassesReader: alias: App\Administration\Infrastructure\ReadModel\DbalPaginatedClassesReader App\Administration\Application\Port\PaginatedSubjectsReader: alias: App\Administration\Infrastructure\ReadModel\DbalPaginatedSubjectsReader App\Administration\Application\Port\PaginatedAssignmentsReader: alias: App\Administration\Infrastructure\ReadModel\DbalPaginatedAssignmentsReader App\Administration\Application\Port\PaginatedParentInvitationsReader: alias: App\Administration\Infrastructure\ReadModel\DbalPaginatedParentInvitationsReader App\Administration\Application\Port\PaginatedStudentImageRightsReader: alias: App\Administration\Infrastructure\ReadModel\DbalPaginatedStudentImageRightsReader # GradeExistenceChecker (stub until Notes module exists) App\Administration\Application\Port\GradeExistenceChecker: alias: App\Administration\Infrastructure\Service\NoOpGradeExistenceChecker # ActiveRoleStore (session-scoped cache for active role switching) App\Administration\Application\Port\ActiveRoleStore: alias: App\Administration\Infrastructure\Service\CacheActiveRoleStore # 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' # Parent Activation Processor with rate limiter App\Administration\Infrastructure\Api\Processor\ActivateParentInvitationProcessor: arguments: $parentActivationByIpLimiter: '@limiter.parent_activation_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 # ============================================================================= # Monitoring & Observability (Story 1.8) # ============================================================================= # Prometheus CollectorRegistry - uses Redis for persistence between requests Prometheus\Storage\Redis: factory: ['App\Shared\Infrastructure\Monitoring\PrometheusStorageFactory', 'createRedisStorage'] arguments: $redisUrl: '%env(REDIS_URL)%' Prometheus\CollectorRegistry: arguments: $storageAdapter: '@Prometheus\Storage\Redis' # Sentry/GlitchTip PII scrubber callback App\Shared\Infrastructure\Monitoring\SentryBeforeSendCallback: ~ # Infrastructure Health Checker - shared service for health checks (DRY) App\Shared\Infrastructure\Monitoring\InfrastructureHealthChecker: arguments: $connection: '@doctrine.dbal.master_connection' $redisUrl: '%env(REDIS_URL)%' # Interface alias for InfrastructureHealthChecker (allows testing with stubs) App\Shared\Infrastructure\Monitoring\InfrastructureHealthCheckerInterface: alias: App\Shared\Infrastructure\Monitoring\InfrastructureHealthChecker # Health Check Controller - uses shared InfrastructureHealthChecker App\Shared\Infrastructure\Monitoring\HealthCheckController: ~ # Metrics Controller - restricted to internal networks in production App\Shared\Infrastructure\Monitoring\MetricsController: arguments: $appEnv: '%kernel.environment%' # Health Metrics Collector - exposes health_check_status gauge App\Shared\Infrastructure\Monitoring\HealthMetricsCollector: ~ # Interface alias for HealthMetricsCollector (allows testing with stubs) App\Shared\Infrastructure\Monitoring\HealthMetricsCollectorInterface: alias: App\Shared\Infrastructure\Monitoring\HealthMetricsCollector # Sentry context enricher - adds tenant/user/correlation_id to error reports # Explicitly registered to ensure HubInterface dependency is resolved App\Shared\Infrastructure\Monitoring\SentryContextEnricher: arguments: $sentryHub: '@Sentry\State\HubInterface' # Monolog processors for structured logging App\Shared\Infrastructure\Monitoring\CorrelationIdLogProcessor: tags: - { name: monolog.processor } App\Shared\Infrastructure\Monitoring\PiiScrubberLogProcessor: tags: - { name: monolog.processor } # ============================================================================= # Messenger & Async (Story 2.5b) # ============================================================================= # Fibonacci retry strategy for async transport App\Shared\Infrastructure\Messenger\FibonacciRetryStrategy: ~ # Dead-letter alert: sends admin email when message exhausts all retries App\Shared\Infrastructure\Messenger\DeadLetterAlertHandler: arguments: $adminEmail: '%env(ADMIN_ALERT_EMAIL)%' tags: - { name: kernel.event_listener, event: Symfony\Component\Messenger\Event\WorkerMessageFailedEvent } # Messenger metrics middleware (handled/failed counters) App\Shared\Infrastructure\Messenger\MessengerMetricsMiddleware: ~ # Messenger queue metrics collector (messages waiting gauge) App\Shared\Infrastructure\Monitoring\MessengerMetricsCollector: ~ # ============================================================================= # 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