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
| Principe | Règle |
|---|---|
| Propriété modulaire | Une fonctionnalité appartient à un seul module |
| Contrôleurs minces | Valider, autoriser, appeler un service, retourner une réponse |
| Logique centralisée | Les règles métier vivent dans les Services |
| Autorisation stricte | Toute action sensible vérifie les permissions côté serveur |
| Comportement auditable | Les workflows critiques génèrent des logs |
| Pas de duplication | Extraire 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