feat: Provisionner automatiquement un nouvel établissement
Lorsqu'un super-admin crée un établissement via l'interface, le système doit automatiquement créer la base tenant, exécuter les migrations, créer le premier utilisateur admin et envoyer l'invitation — le tout de manière asynchrone pour ne pas bloquer la réponse HTTP. Ce mécanisme rend chaque établissement opérationnel dès sa création sans intervention manuelle sur l'infrastructure.
This commit is contained in:
@@ -64,3 +64,5 @@ framework:
|
||||
# Import élèves/enseignants → async (batch processing, peut être long)
|
||||
App\Administration\Application\Command\ImportStudents\ImportStudentsCommand: async
|
||||
App\Administration\Application\Command\ImportTeachers\ImportTeachersCommand: async
|
||||
# Provisioning établissement → async (création BDD, migrations, premier admin)
|
||||
App\SuperAdmin\Application\Command\ProvisionEstablishment\ProvisionEstablishmentCommand: async
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
# Configuration des tenants en production
|
||||
# Tenants en production : résolution dynamique depuis la base establishments
|
||||
#
|
||||
# En production, les tenants peuvent être configurés de deux façons :
|
||||
# 1. Via la variable d'environnement TENANT_CONFIGS (JSON)
|
||||
# 2. Via une implémentation DatabaseTenantRegistry (à implémenter)
|
||||
#
|
||||
# Pour l'instant, on utilise InMemoryTenantRegistry avec configuration env.
|
||||
# Si aucun tenant n'est configuré, toutes les requêtes retourneront 404.
|
||||
|
||||
parameters:
|
||||
# Format JSON attendu: [{"tenantId":"uuid","subdomain":"ecole","databaseUrl":"postgres://..."}]
|
||||
tenant.prod_configs_json: '%env(default::TENANT_CONFIGS)%'
|
||||
# Le DoctrineTenantRegistry interroge la table establishments sur la base master.
|
||||
# Les nouveaux établissements sont immédiatement accessibles via leur sous-domaine
|
||||
# sans redémarrage de l'application.
|
||||
|
||||
services:
|
||||
App\Shared\Infrastructure\Tenant\TenantRegistry:
|
||||
class: App\Shared\Infrastructure\Tenant\InMemoryTenantRegistry
|
||||
factory: ['@App\Shared\Infrastructure\Tenant\TenantRegistryFactory', 'createFromEnv']
|
||||
App\Shared\Infrastructure\Tenant\DoctrineTenantRegistry:
|
||||
arguments:
|
||||
$configsJson: '%tenant.prod_configs_json%'
|
||||
$connection: '@doctrine.dbal.master_connection'
|
||||
$masterDatabaseUrl: '%env(DATABASE_URL)%'
|
||||
|
||||
App\Shared\Infrastructure\Tenant\TenantRegistry:
|
||||
alias: App\Shared\Infrastructure\Tenant\DoctrineTenantRegistry
|
||||
|
||||
@@ -247,12 +247,20 @@ services:
|
||||
$homeworkSanitizer: '@html_sanitizer.sanitizer.homework_sanitizer'
|
||||
|
||||
App\Scolarite\Application\Port\FileStorage:
|
||||
alias: App\Scolarite\Infrastructure\Storage\LocalFileStorage
|
||||
alias: App\Scolarite\Infrastructure\Storage\S3FileStorage
|
||||
|
||||
App\Scolarite\Infrastructure\Storage\LocalFileStorage:
|
||||
arguments:
|
||||
$storagePath: '%kernel.project_dir%/var/storage'
|
||||
|
||||
App\Scolarite\Infrastructure\Storage\S3FileStorage:
|
||||
arguments:
|
||||
$endpoint: '%env(S3_ENDPOINT)%'
|
||||
$bucket: '%env(S3_BUCKET)%'
|
||||
$key: '%env(S3_KEY)%'
|
||||
$secret: '%env(S3_SECRET)%'
|
||||
$region: '%env(S3_REGION)%'
|
||||
|
||||
# Schedule (Story 4.1 - Emploi du temps)
|
||||
App\Scolarite\Domain\Repository\ScheduleSlotRepository:
|
||||
alias: App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineScheduleSlotRepository
|
||||
@@ -298,12 +306,18 @@ services:
|
||||
App\Scolarite\Domain\Service\AverageCalculator:
|
||||
autowire: true
|
||||
|
||||
App\Scolarite\Domain\Service\TeacherStatisticsCalculator:
|
||||
autowire: true
|
||||
|
||||
App\Scolarite\Application\Service\RecalculerMoyennesService:
|
||||
autowire: true
|
||||
|
||||
App\Scolarite\Application\Port\PeriodFinder:
|
||||
alias: App\Scolarite\Infrastructure\Service\DoctrinePeriodFinder
|
||||
|
||||
App\Scolarite\Application\Port\TeacherStatisticsReader:
|
||||
alias: App\Scolarite\Infrastructure\ReadModel\DbalTeacherStatisticsReader
|
||||
|
||||
App\Scolarite\Infrastructure\Persistence\Doctrine\DoctrineEvaluationStatisticsRepository:
|
||||
autowire: true
|
||||
|
||||
@@ -333,6 +347,23 @@ services:
|
||||
App\SuperAdmin\Domain\Repository\EstablishmentRepository:
|
||||
alias: App\SuperAdmin\Infrastructure\Persistence\Doctrine\DoctrineEstablishmentRepository
|
||||
|
||||
# Provisioning (Story 2.17 - Provisioning automatique)
|
||||
App\SuperAdmin\Infrastructure\Provisioning\TenantDatabaseCreator:
|
||||
arguments:
|
||||
$connection: '@doctrine.dbal.master_connection'
|
||||
|
||||
App\SuperAdmin\Infrastructure\Provisioning\TenantMigrator:
|
||||
arguments:
|
||||
$projectDir: '%kernel.project_dir%'
|
||||
$masterDatabaseUrl: '%env(DATABASE_URL)%'
|
||||
|
||||
App\SuperAdmin\Application\Port\TenantProvisioner:
|
||||
alias: App\SuperAdmin\Infrastructure\Provisioning\DatabaseTenantProvisioner
|
||||
|
||||
App\SuperAdmin\Infrastructure\Provisioning\ProvisionEstablishmentHandler:
|
||||
arguments:
|
||||
$masterDatabaseUrl: '%env(DATABASE_URL)%'
|
||||
|
||||
# School Calendar Repository (Story 2.11 - Calendrier scolaire)
|
||||
App\Administration\Domain\Model\SchoolCalendar\SchoolCalendarRepository:
|
||||
alias: App\Administration\Infrastructure\Persistence\Doctrine\DoctrineSchoolCalendarRepository
|
||||
|
||||
Reference in New Issue
Block a user