ajoute le portail Laravel : connexion prof/élève, session unique, gestion de classe, salle d'attente
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
aa31b6112f
commit
30e14b1c54
191 changed files with 25324 additions and 0 deletions
|
|
@ -272,3 +272,45 @@ La bonne nouvelle de cette étape, c'est que Kolla avait déjà fait le plus gro
|
|||
**Suite**
|
||||
|
||||
Étape 8 : portail Laravel (Blade, Vite, MariaDB/Redis pour l'app, modèles, connexion prof/élève, salle d'attente). Le dossier `design/` doit exister : à vérifier avant de commencer.
|
||||
|
||||
## 2026-10-07 — Étape 8 : portail Laravel
|
||||
|
||||
**Fait**
|
||||
|
||||
- Projet Laravel 13 créé dans `portail/` (développé en local sur le Mac : PHP 8.4/Composer/Node 22 y étaient déjà installés), plateforme Composer forcée à PHP 8.3 pour que les dépendances restent installables sur le serveur (PHP 8.3, via Sury). Pest 4 (Pest 5 exige PHP 8.4). `concurrently` retiré du starter (2 vulnérabilités critiques via `shell-quote`, et en réalité inutilisé : `php artisan dev` de Laravel 13 gère déjà le lancement parallèle nativement).
|
||||
- Vues, routes, JS, CSS, images de `design/` repris tels quels dans `portail/resources` et `portail/public`. Toutes les pages vitrine (une cinquantaine) fonctionnent sans rien construire de plus.
|
||||
- Modèles + migrations : `Etablissement`, `User` (+ `etablissement_id`, `jeton_session_actif`), `Classe` (code unique auto-généré), `Eleve` (identifiant unique, `code_secret` haché, `jeton_qr` à usage unique, `jeton_session_actif`), `Lab`, `Seance`, `LabSession`.
|
||||
- Deux guards d'authentification (`config/auth.php`) : `web` (profs, email/mot de passe) et `eleve` (identifiant/code secret, sans e-mail — minimisation des données mineurs). `App\Models\Eleve` authentifiable via le trait `Illuminate\Auth\Authenticatable` et `getAuthPasswordName()`.
|
||||
- **Session unique par compte** : trait `GereSessionUnique` (un jeton en base, recréé à chaque connexion) + middleware `VerifieSessionUnique` (`session.unique:web`/`session.unique:eleve`), qui déconnecte et prévient si le jeton de la session en cours ne correspond plus à celui, plus récent, enregistré en base.
|
||||
- Connexion (`/connexion`, un seul écran, deux formulaires), inscription (`/inscription` : crée établissement + prof + première classe en une transaction), gestion de classe (`/mes-classes/...` : ajout rapide, import CSV, génération identifiant + code à 6 caractères + QR à usage unique via `bacon/bacon-qr-code` en SVG, fiches imprimables), salle d'attente de séance (`/seances/...`, rafraîchissement automatique, le prof admet).
|
||||
- Service `GenerateurCompteEleve` : identifiant `prenom.initiale` (suffixe numérique si homonyme), code secret à 6 caractères sans caractères ambigus (`0/O`, `1/I/L`).
|
||||
- 11 tests Pest (connexion prof, connexion élève, session unique × 2, création de classe × 3) : tous passent, base SQLite en mémoire.
|
||||
- Déploiement : rôle Ansible `portail` (PHP 8.3 via Sury, Nginx, Composer avec vérification de signature officielle, Node 22 LTS via NodeSource, MariaDB+Redis de l'app en Docker Compose sur `127.0.0.1:3307`/`127.0.0.1:6380` — jamais sur `10.10.0.1`, réservé à Kolla), synchronisation du code par `rsync`, `.env` de production généré une seule fois (secrets jamais dans Git).
|
||||
|
||||
**Deux décisions de design tranchées par Adam**
|
||||
|
||||
1. Champ mot de passe ajouté au formulaire d'inscription (absent de la maquette) : sans lui, la connexion prof décrite dans le prompt n'aurait pas pu fonctionner sans serveur mail.
|
||||
2. Écrans sans maquette (gestion des élèves, salle d'attente) : design minimal sobre, mêmes jetons visuels que le reste du site, pas de recherche d'effet « wow ».
|
||||
|
||||
**Problèmes rencontrés et solution**
|
||||
|
||||
1. `@auth` (sans argument) dans le layout partagé retournait `true` pour un **élève** connecté, affichant le menu du prof. Cause : le middleware `auth:eleve` appelle `Auth::shouldUse('eleve')`, ce qui change le *guard par défaut* pour le reste de la requête — `@auth` nu teste alors ce guard-là, pas forcément `web`. Corrigé en précisant partout `@auth('web')` / `auth('eleve')`.
|
||||
2. Déploiement : j'ai modifié `kolla/globals.yml` et le script de sauvegarde dans le dépôt sans les repousser sur le serveur avant de relancer les outils correspondants (déjà rencontré à l'étape 7 — même piège, maintenant documenté deux fois).
|
||||
3. `php artisan key:generate` échouait : lancé avant `composer install`, donc avant que `vendor/autoload.php` existe. Réordonné : code → composer install → clé/`.env` → npm → migrations.
|
||||
4. `php artisan view:cache` échouait (« View path not found ») : `storage/framework/views` avait été exclu du `rsync` mais n'était créé par rien d'autre. Plus largement, **`storage/` et `bootstrap/cache/` ne doivent jamais être synchronisés depuis le poste de dev** (ce sont de l'état et du cache runtime, pas du code — un `rsync --delete` y effacerait un jour les travaux déposés par les élèves dans `storage/app/`). Corrigé : leur structure est créée une fois sur le serveur, propriété `www-data` dès le départ, et ils sont exclus en bloc du `rsync` (pas juste leurs sous-dossiers).
|
||||
5. **Un handler Ansible qui notifie un autre handler ne s'est pas propagé avant la fin du play** : Nginx a continué de servir sa page par défaut malgré un déploiement sans erreur apparente. Corrigé en fusionnant les deux handlers (`nginx -t` puis `systemctl reload nginx`) en un seul. Détecté uniquement parce que le critère de fin a été vérifié sur le serveur réel, pas seulement sur le code local.
|
||||
6. Vérification Playwright visuelle (demandée par le prompt) non faite : l'extension Chrome n'était pas connectée dans cette session. Vérification faite autrement : les mêmes fichiers Blade que `design/` sont repris sans changement de structure, et le flux complet a été vérifié par capture HTML (`curl`) côté connexion, tableau de bord et gestion de classe.
|
||||
|
||||
**Critère vérifié (sur le serveur réel, pas seulement en local)**
|
||||
|
||||
- 11/11 tests Pest passent (en local, avant déploiement).
|
||||
- Un élève fictif (`lea.m`) s'est connecté sur `http://163.172.4.195/connexion` et a vu son tableau de bord (« Salut Léa », nom de sa classe) — données de test supprimées après coup (accord d'Adam).
|
||||
- `nft list tables` après déploiement : toujours seulement `inet filter` + `ip nat` (+ `f2b-table`) — Nginx/PHP-FPM n'ont rien ajouté au pare-feu.
|
||||
|
||||
**Comprendre**
|
||||
|
||||
Cette étape a un piège intéressant pour la suite : Laravel a deux systèmes de comptes (profs et élèves), et un mécanisme Laravel conçu pour un seul système (« quel est l'utilisateur connecté ? ») suppose souvent qu'il n'y en a qu'un — le bug du menu qui affichait « Mes classes » à un élève connecté vient exactement de là. Chaque fois qu'on ajoutera un rôle (établissement, formateur, opérateur), il faudra se souvenir d'être explicite sur le guard, partout. L'autre leçon, plus générale : un déploiement qui se termine « sans erreur » ne veut pas dire que le résultat est correct — c'est en testant le vrai critère de fin sur le serveur réel (pas juste en relisant les logs Ansible) qu'on a trouvé le bug du handler Nginx.
|
||||
|
||||
**Suite**
|
||||
|
||||
Étape 9 : proxy console Go et xterm.js (jeton Redis à usage unique, relais WebSocket vers `nova-serialproxy`, lecture seule pour le prof).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue