Aller au contenu principal

Vue d'ensemble de l'architecture

Le projet est un monorepo Laravel modulaire hébergeant plusieurs applications métier internes sur des sous-domaines distincts.

Principes fondamentaux

PrincipeRègle
Propriété modulaireUne fonctionnalité appartient à un seul module
Contrôleurs mincesValider, autoriser, appeler un service, retourner une réponse
Logique centraliséeLes règles métier vivent dans les Services
Autorisation stricteToute action sensible vérifie les permissions côté serveur
Comportement auditableLes workflows critiques génèrent des logs
Pas de duplicationExtraire la logique partagée en services, repositories ou helpers

Flux d'une requête

1. La route correspond à une action de contrôleur
2. Le middleware authentifie et applique les règles d'accès générales
3. La Form Request valide les entrées
4. La Policy ou le middleware de permission autorise l'action
5. Le contrôleur appelle un service
6. Le service exécute la logique métier (dans try/catch si sensible)
7. Le repository ou le modèle Eloquent persiste les données
8. Un log d'audit enregistre l'opération critique
9. La réponse retourne une vue Blade, une redirection, du JSON ou une ressource

Structure globale

laravel/
├── app/
│ ├── Http/
│ │ └── Middleware/ # KeycloakAuthenticated, ApiKeyAuthenticated
│ ├── Models/ # User, Application, Service, Role, Permission (partagés)
│ ├── Services/
│ └── Providers/

├── Modules/
│ ├── Admin/
│ ├── Actualite/
│ ├── Ai/ # Config providers IA
│ ├── Alert/
│ ├── Analyses/
│ ├── Api/ # Bridge OpenWebUI (Bearer token)
│ ├── ChrConnector/
│ ├── Dashboard/
│ ├── EdiEngine/
│ ├── Elevage/
│ ├── IA/ # Gouvernance Thalia (modèles, quotas, rôles)
│ ├── IdeaBox/
│ ├── Infrastructure/
│ ├── Thalia/ # Runtime IA (audit, permissions, validation)
│ └── ThaliaBridge/ # Connecteurs read-only (BookStack…)

├── resources/views/layouts/ # Layouts Blade partagés
├── bootstrap/app.php # Middleware, scheduler conditionnel, exceptions
├── routes/ # Routes globales (auth callback, etc.)
├── config/
├── database/
├── .ai/ # Docs architecture pour agents IA
└── docs/ # Documentation technique (ce dépôt)

Structure standard d'un module

Modules/<ModuleName>/
├── app/
│ ├── Http/
│ │ ├── Controllers/
│ │ ├── Requests/
│ │ ├── Middleware/
│ │ └── Resources/
│ ├── Models/
│ ├── Policies/
│ ├── Services/
│ ├── Repositories/
│ ├── Events/
│ ├── Listeners/
│ └── Providers/
├── database/
│ ├── migrations/
│ └── seeders/
├── resources/
│ └── views/
├── routes/
│ ├── web.php
│ └── api.php
├── tests/
└── config/

Règles d'isolation des modules

À faire :

  • Garder les contrôleurs, requêtes, politiques, services et vues dans le module
  • Exposer le comportement partagé via un service ou un contrat explicite
  • Garder les helpers partagés génériques et réutilisables

À ne pas faire :

  • Accéder au service privé d'un autre module sans contrat explicite
  • Dupliquer les migrations pour la même table dans plusieurs modules
  • Créer des helpers globaux pour un comportement propre à un seul module

Authentification

Keycloak OIDC uniquement — aucun login local.

  • Package : socialiteproviders/keycloak
  • Middleware : KeycloakAuthenticated
  • Callback : GET /auth/callback
  • Logout : GET /auth/logout
KEYCLOAK_BASE_URL=
KEYCLOAK_REALM=
KEYCLOAK_CLIENT_ID=
KEYCLOAK_CLIENT_SECRET=
KEYCLOAK_REDIRECT_URI=

Scheduler

Tâches conditionnelles enregistrées dans bootstrap/app.php :

->withSchedule(function (Schedule $schedule): void {
$app = Application::where('code', 'my_module')->first();

if ($app && $app->getSetting('my_feature_enabled')) {
$schedule->command('mymodule:my-command')
->everyFiveMinutes()
->withoutOverlapping()
->runInBackground();
}
})

Toujours utiliser withoutOverlapping() + runInBackground() pour les commandes de synchronisation.

Crontab serveur :

* * * * * www-data php /var/www/dashboard/artisan schedule:run >> /dev/null 2>&1