# Runbook — Portail Laravel ## Où sont les choses | Élément | Emplacement | |---|---| | Code de l'application | `/var/www/portail` (propriétaire `adam`, sauf `storage/` et `bootstrap/cache/` → `www-data`) | | Secrets Laravel (`.env`) | `/var/www/portail/.env`, `640 adam:www-data`, généré une seule fois, jamais dans Git | | Secrets MariaDB/Redis de l'app | `/etc/portail/.env`, `600 root:root`, générés une seule fois | | Config Docker Compose (MariaDB + Redis app) | `/etc/portail/docker-compose.yml` | | Vhost Nginx | `/etc/nginx/sites-available/portail.conf` | | PHP | 8.3 (dépôt Sury), FPM sur `/run/php/php8.3-fpm.sock` | Déployé par `ansible/portail.yml` (rôle `portail`) : ``` cd ansible && script -q /dev/null ansible-playbook portail.yml -i inventory.ini ``` ## Architecture de l'app - Laravel 13, Blade + Vite (Tailwind v4 via le plugin Vite officiel). - Deux comptes distincts, deux guards (`config/auth.php`) : - `web` → `User` (profs), email + mot de passe. - `eleve` → `Eleve` (élèves), identifiant (`prenom.initiale`, suffixe numérique si homonyme) + code secret à 6 caractères (haché). - **Une seule session active par compte** (`App\Models\Concerns\GereSessionUnique` + middleware `session.unique`) : un jeton est stocké en session ET en base à chaque connexion ; s'ils ne correspondent plus, la session est coupée à la requête suivante avec un message. - Vues reprises telles quelles depuis `design/` (voir le journal du 2026-10-07, étape 8, pour les deux écarts assumés : mot de passe ajouté au formulaire d'inscription, sélecteur d'établissement retiré du formulaire de connexion). - Écrans sans maquette, construits sobres avec les jetons visuels existants : `resources/views/mes-classes/*` (gestion des élèves, import CSV, fiches QR) et `resources/views/seances/*` (salle d'attente). ## Base de données et cache de l'app MariaDB et Redis **dédiés à l'app**, en Docker Compose, liés à `127.0.0.1` uniquement (jamais sur `10.10.0.1`, qui est le réseau de Kolla) : - MariaDB : port `3307` (celui de Kolla est sur `10.10.0.1:3306`). - Redis : port `6380`. ``` cd /etc/portail && docker compose ps ``` ## Déployer une mise à jour du code ``` cd ansible && script -q /dev/null ansible-playbook portail.yml -i inventory.ini ``` Le rôle synchronise le code (`rsync`, sans `vendor/`, `node_modules/`, `.env`, ni `storage/`/`bootstrap/cache/` — ce sont de l'état runtime, jamais du code), puis `composer install --no-dev`, `npm ci && npm run build`, `php artisan migrate --force`, et recrée les caches (`config:cache`, `route:cache`, `view:cache`). **Après toute modification de code qui touche les routes ou la config**, les caches doivent être régénérés (le rôle le fait automatiquement). Si on modifie une vue sans repasser par Ansible, penser à `php artisan view:clear` à la main. ## Lancer les tests (en local, avant tout déploiement) ``` cd portail && ./vendor/bin/pest ``` 11 tests : connexion prof, connexion élève, session unique (prof et élève), création de classe + établissement. Base de test : SQLite en mémoire (`phpunit.xml`), aucun rapport avec MariaDB de prod. ## Écarts au design assumés le 2026-10-07 - `auth/inscription.blade.php` : champ mot de passe ajouté (absent de la maquette), confirmé par Adam — sans lui, la connexion prof décrite dans le prompt de déploiement n'aurait pas pu fonctionner sans serveur mail. - `auth/connexion.blade.php` : le sélecteur d'établissement du formulaire enseignant a été retiré (un prof qui se connecte a déjà un établissement en base ; ce sélecteur n'avait de sens que pour l'inscription). - `paillasse-contenus/README.md` corrigé : `tree` n'est pas préinstallé dans l'image (le lab 02 demande à l'élève de l'installer lui-même). - Gestion des élèves (ajout, import CSV, fiches QR) et salle d'attente : aucune maquette fournie, design minimal sobre construit avec les jetons visuels existants (confirmé par Adam). ## Piège vécu le 2026-10-07 Un handler Ansible qui notifie un autre handler (`recharger nginx` → `redémarrer nginx`) ne s'est **pas** propagé avant la fin du play : Nginx a continué de servir sa page par défaut malgré un déploiement « réussi ». Corrigé en fusionnant les deux handlers en un seul (`nginx -t && systemctl reload nginx`). Si un jour un changement Nginx semble sans effet, vérifier d'abord `sudo nginx -T` sur le serveur, puis forcer `sudo systemctl reload nginx` à la main. ## Vérifié le 2026-10-07 - `curl http://163.172.4.195/connexion` : les deux formulaires s'affichent. - Un élève fictif (`lea.m` / code à 6 caractères) s'est connecté et a vu son tableau de bord (« Salut Léa », nom de sa classe) — données de test supprimées juste après (accord d'Adam). - `nft list tables` après déploiement : toujours seulement `inet filter` et `ip nat` (+ `f2b-table` de fail2ban) — Nginx n'a rien ajouté au pare-feu.