feat: Infrastructure multi-tenant avec isolation par sous-domaine
Une application SaaS éducative nécessite une séparation stricte des données entre établissements scolaires. L'architecture multi-tenant par sous-domaine (ecole-alpha.classeo.local) permet cette isolation tout en utilisant une base de code unique. Le choix d'une résolution basée sur les sous-domaines plutôt que sur des headers ou tokens facilite le routage au niveau infrastructure (reverse proxy) et offre une UX plus naturelle où chaque école accède à "son" URL dédiée.
This commit is contained in:
126
backend/tests/Architecture/BoundedContextIsolationTest.php
Normal file
126
backend/tests/Architecture/BoundedContextIsolationTest.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Architecture;
|
||||
|
||||
use PHPat\Selector\Selector;
|
||||
use PHPat\Test\Builder\BuildStep;
|
||||
use PHPat\Test\PHPat;
|
||||
|
||||
/**
|
||||
* Tests ensuring Bounded Contexts are properly isolated.
|
||||
*
|
||||
* Bounded Contexts must communicate through events (via Shared),
|
||||
* not through direct dependencies.
|
||||
*/
|
||||
final class BoundedContextIsolationTest
|
||||
{
|
||||
public function test_scolarite_should_not_depend_on_vie_scolaire(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Scolarite'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\VieScolaire'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_scolarite_should_not_depend_on_communication(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Scolarite'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Communication'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_scolarite_should_not_depend_on_administration(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Scolarite'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Administration'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_vie_scolaire_should_not_depend_on_scolarite(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\VieScolaire'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Scolarite'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_vie_scolaire_should_not_depend_on_communication(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\VieScolaire'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Communication'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_vie_scolaire_should_not_depend_on_administration(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\VieScolaire'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Administration'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_communication_should_not_depend_on_scolarite(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Communication'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Scolarite'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_communication_should_not_depend_on_vie_scolaire(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Communication'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\VieScolaire'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_communication_should_not_depend_on_administration(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Communication'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Administration'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_administration_should_not_depend_on_scolarite(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Administration'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Scolarite'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_administration_should_not_depend_on_vie_scolaire(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\VieScolaire'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Administration'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
|
||||
public function test_administration_should_not_depend_on_communication(): BuildStep
|
||||
{
|
||||
return PHPat::rule()
|
||||
->classes(Selector::inNamespace('App\Administration'))
|
||||
->shouldNotDependOn()
|
||||
->classes(Selector::inNamespace('App\Communication'))
|
||||
->because('Bounded Contexts must communicate through events, not direct calls');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user