# Passation — Festival Yggdrasil (site vitrine + back-office IA)

> Document pour le prochain assistant (Claude Code). Tout le contexte, l'état d'avancement, les décisions et la liste complète des actions à mener.
> Langue du projet : **français**. Préférence forte de Jérémy : **pas de tiret cadratin (—)** dans les contenus publics, phrases naturelles et dynamiques, livrables « prêts à l'emploi ».

---

## 0. Contexte & personne

- **Jérémy Loir** organise le festival **Yggdrasil — Fort Fort Lointain**, édition 2026 « Festum Draconum » (thème **Vikings & Dragons**), les **5 & 6 septembre 2026** à l'**Hippodrome de Parilly, Bron (Lyon)**.
- Deux projets parallèles ont été menés :
  - **Projet A — Site vitrine** (HTML statique, dossier `C:\Users\jerem\OneDrive\Bureau`).
  - **Projet B — Back-office + chatbot IA** (Laravel 12, dossier `C:\laragon\www\fflv2`, ce dépôt).
- Règles de dev imposées : voir `regles_developpement_applications_web_optimise_ia.md` (fourni par Jérémy). MVC strict, RGPD, sécurité, versioning, docs racine, IA embarquée, etc. **À respecter sans dérogation inventée ; signaler toute contradiction.**

---

## 1. Projet A — Site vitrine (HTML)

### État : quasi finalisé, en attente d'assets.
Dossier : `C:\Users\jerem\OneDrive\Bureau`. 14 pages HTML autonomes (CSS inline, Google Fonts Cinzel + Mulish, icônes Material Symbols), responsive (breakpoints 760/920, + 1500/1900 sur l'accueil).

**Pages :** `Site_FFL_2026.html` (accueil, = ancienne v2 devenue officielle), `Le_theme_FFL_2026.html`, `Univers_FFL_2026.html` (6 univers : Drakenfjord, médiéval, steampunk « campement de la Barrière », fantastique, contes de fées, caravansérail), `Invites_FFL_2026.html`, `Createurs_FFL_2026.html` (iframe), `Photographes_FFL_2026.html` (iframe), `Personnages_FFL_2026.html`, `Troupes_FFL_2026.html` (iframe), `Animations_FFL_2026.html`, `Concerts_FFL_2026.html`, `Chasse_aux_cles_FFL_2026.html` (mode d'emploi complet), `Ygg_FFL_2026.html`, `Infos_FAQ_FFL_2026.html`. Sauvegarde de l'ancienne v1 : `Site_FFL_2026_v1_sauvegarde.html`.

### Décisions clés déjà actées (à NE PAS recasser)
- Accueil = **v2** partout (textures fines « grain » papier, mobile centré, footer repliable, vidéo teaser, concerts retravaillés, parallaxe).
- **Concerts** : ordre = bloc Concerts AVANT Drakenfjord. 2 têtes d'affiche **Naheulband + La Rioule** ; petites tuiles **Talers, Avaland, Maître Frelon, La Band'Originale Lyonnaise** (la « fanfare ciné »). Soirée concerts dès 17h, supplément billet.
- **Parallaxe** (background-attachment:fixed) sur blocs Concerts + Drakenfjord, désactivée en mobile.
- **Menu** : dropdown « Découvrir » (desktop + sous-menu repliable mobile), icône `expand_more`.
- **Chasse aux clés** : 4 quêtes × 6 serrures (univers, décors, animations, œufs de dragons) = 4 badges. Clé collector 25 € (réservable en ligne, déclenche bulles/étincelles), Carte rechargeable 5 € (2 €+3 €), Recharge 3 €. Retrait au **Bureau des Aventuriers** ou billetterie. Nombre limité.
- **Ygg** : gagnés en jouant + 1 Ygg offert par créateur dès 15 € d'achat (un seul), échangeables à la sortie.
- Infos pratiques validées (voir §3 ci-dessous) intégrées dans `Infos_FAQ` (10 cartes + 15 FAQ + formulaire contact).
- Lightbox sur l'affiche (clic = agrandit).

### Infos pratiques confirmées par Jérémy
- Horaires : **samedi 10h-19h + soirée concerts**, **dimanche 10h-18h**.
- **Parking gratuit** · Paiement **CB + espèces** · Billets **en ligne + sur place** · **Entrée unique** (pas de réentrée).
- **PMR** : accessible, terrain naturel (herbe/gravier), places limitées.
- **Animaux** : non, sauf chiens d'assistance · **Pique-nique autorisé**.
- **Plein air** : maintenu beau temps comme pluie, prévoir tenue adaptée.
- **Cosplay** : inscription en ligne à l'avance OU sur place.
- **Billets non remboursables** sauf assurance Billetweb souscrite.
- Durée conseillée : une journée entière.
- Billetterie (à confirmer) : `https://www.billetweb.fr/fort-fort-lointain`.
- Contact : formulaire en ligne après la FAQ → à brancher.

### À FAIRE (site vitrine)
1. **Fournir les 27 images + la vidéo** : voir `Bureau/ASSETS_A_FOURNIR_FFL_2026.md` (liste détaillée avec dimensions). Sans elles, des placeholders s'affichent.
2. Intégrer la **grille tarifaire** (image A4 à venir) : prix entrée/pass/enfants + supplément soirée.
3. Renseigner les **3 URLs d'iframe** (Createurs / Photographes / Troupes).
4. Confirmer/мettre l'**URL billetterie** définitive (variable `BILLETTERIE` dans chaque page).
5. **Brancher le formulaire de contact** (Infos_FAQ) sur un vrai backend → idéalement l'API du back-office (voir Projet B) ou Airtable/n8n.
6. **Favicon + logo** (aucun pour l'instant).
7. **Test visuel réel** aux 4 tailles (mobile 375 / tablette 768 / desktop 1440 / large 1920) — non fait par l'assistant précédent (pas de navigateur dispo). Jérémy ne veut **AUCUN bug d'affichage**. Garde-fous anti-débordement déjà ajoutés.
8. Intégrer le **widget de chat** du back-office sur le site (balise `<script>`, voir Projet B).

---

## 2. Projet B — Back-office Laravel + chatbot IA (CE DÉPÔT)

### Stack & décisions
- **Laravel 12** (PHP 8.3 chez Jérémy), MySQL/MariaDB, frontend **Blade + CSS/JS vanilla** (config minimale Laravel : valeurs par défaut + `.env`), icônes **Lucide** (via CDN unpkg).
- IA : **Claude (Anthropic)** dès le départ. Clé dans `.env` (`ANTHROPIC_API_KEY`).
- Périmètre choisi : « tout le référentiel » → mais livré en **v0.1.0 (MVP fonctionnel)** ; le reste est en roadmap (voir §4).
- Dev **en ligne / Laragon uniquement** (pas de PHP dans l'environnement de l'assistant précédent → tout généré à la main).
- **Git** : dépôt déjà initialisé, remote `https://github.com/jeremyloir/fflv2.git`, branche `main`. **Ne pas committer `.env` ni `vendor/`** (déjà dans `.gitignore`). Commit v0.1.0 déjà fait (hash `d207808`).

### Fonctionnel (objectif du chatbot)
Widget public sur le site → API `/api/v1/chat`. Pour chaque question :
1. Recherche dans la **base de connaissances** (scoring mots-clés/question/réponse).
2. Si pas de match franc et IA active → **Claude répond STRICTEMENT à partir de la base** fournie (RAG). Si la base ne contient pas la réponse, Claude renvoie `INCONNU`.
3. Sinon → le bot **demande l'email** (avec consentement RGPD), crée un **Lead**, et envoie un mail à **contact@festivalyggdrasil.com** (`OrgQuestionMail`).
La base de connaissances est **éditable dans le back-office** (CRUD + boutons IA humaniser/grammaire/générer).

### Arborescence livrée (fichiers clés)
- **Models** (`app/Models/`) : User, Role, KnowledgeCategory, KnowledgeArticle, ChatConversation, ChatMessage, Lead, Setting, AuditLog, AiUsageLog. UUID auto sur la plupart, soft delete où pertinent.
- **Migrations** (`database/migrations/`) : users/roles/sessions/cache/jobs + knowledge + chat + leads + settings/audit/ai_usage.
- **Seeders** : RoleSeeder, SuperAdminSeeder (affiche email+mdp), SettingSeeder, **KnowledgeBaseSeeder** (FAQ du festival pré-remplie). `DatabaseSeeder` les appelle.
- **Services** (`app/Services/`) : `ClaudeClient` (HTTP Anthropic), `ChatbotService` (cœur : recherche + RAG + capture lead), `AiTextService` (boutons IA), `AuditLogger`.
- **Controllers** : `Api/ChatController` (public, CORS whitelist + throttle), `Auth/LoginController`, `Admin/*` (Dashboard, KnowledgeArticle, KnowledgeCategory, Lead, Conversation, Setting, User, AuditLog, AiUsage, AiAssist), `LegalController`.
- **Middleware** : `EnsureRole` (alias `role`), `SecurityHeaders`.
- **Mail** : `OrgQuestionMail` + vue `emails/org_question.blade.php`.
- **Vues** (`resources/views/`) : layout `layouts/app` (sidebar + dark mode + Lucide + burger mobile), `auth/login`, `admin/*` (dashboard, knowledge index/form avec boutons IA, categories, leads, conversations, settings, users, audit, ai-usage), `legal/page`.
- **Widget** : `public/widget/chat-widget.js` (bulle flottante autonome, à intégrer via `<script src=... data-api=... data-name="Yggi">`).
- **Console** : `app/Console/Commands/PurgeTrash.php` (`yggdrasil:purge-trash`, planifié dans `routes/console.php`).
- **Tests** : `tests/Feature/ChatbotTest.php` (2 tests : réponse depuis la base / question inconnue → email). `phpunit.xml` configuré en SQLite mémoire, IA off.
- **Config** : `config/services.php` (anthropic, org email, chat allowed origins). Reste = défauts Laravel 12 + `.env`.
- **Docs racine** : README, ARCHITECTURE, CHANGELOG, PERMISSIONS, RGPD, BACKUP, CRON, INTEGRATIONS, API, DEPLOY.

### Conventions / rôles
- Rôles : **super_admin** (1 seul), **admin**, **editor**. Matrice dans `PERMISSIONS.md`.
- UUID v4 exposés (jamais l'auto-increment) — prêt pour le futur Hub central (règles §16).
- Montants en centimes/micros, dates ISO 8601, format d'erreur standard (voir API.md).

### OÙ ON EN EST (reprise immédiate)
Jérémy est en train d'exécuter, dans le terminal Laragon (dossier `fflv2`) :
```
php artisan key:generate
mysql -u root -e "CREATE DATABASE IF NOT EXISTS yggdrasil_bo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
php artisan migrate --seed
```
- `.env` déjà réglé pour Laragon : `DB_USERNAME=root`, `DB_PASSWORD=` (vide), `DB_DATABASE=yggdrasil_bo`.
- `composer install` a réussi (Laravel 12 installé, package discovery OK).
- **Prochaine vérif** : récupérer email+mdp Super Admin affichés par le seeder → tester `http://fflv2.test/login` (ou `php artisan serve`). Puis `php artisan test`.
- **3 fichiers .lock résiduels** (`.git/HEAD.lock`, `.git/index.lock`, `.git/objects/maintenance.lock`) doivent être supprimés (créés par un commit depuis l'environnement sandbox aux permissions limitées). Sous Windows : `del .git\HEAD.lock` etc. (une commande par ligne).

---

## 3. Pièges connus / à surveiller
- **PowerShell ≠ terminal Laragon** : utiliser le terminal Laragon (php/composer/git dans le PATH). Commandes **une par ligne** (le copier-coller multi-lignes fusionne).
- Laravel 11 est **bloqué par les avis de sécurité Composer** → on est passé en **Laravel 12** (fait).
- `Str::limit` dans Blade → utiliser `\Illuminate\Support\Str::limit` (fait).
- Le dossier monté côté sandbox empêchait `rm` dans `.git` → gérer les locks côté Windows.
- Il existe un AUTRE projet `C:\laragon\www\Ffl` (seeders CategorySeeder/ContentSeeder) : **ne pas confondre** avec `fflv2`.

---

## 4. TODO complet — back-office (priorisé)

### P0 — Finir l'amorçage (en cours)
- [ ] Valider `migrate --seed` + connexion `/login` + `php artisan test` (vert).
- [ ] Changer le mot de passe Super Admin par défaut.
- [ ] Renseigner `ANTHROPIC_API_KEY` et tester un échange de chat réel (KB → Claude → fallback email).
- [ ] Configurer SMTP (`MAIL_*`) pour l'envoi des leads à contact@festivalyggdrasil.com (tester un envoi).
- [ ] Supprimer les `.lock` git, puis `git add -A && git commit` + `git push -u origin main`.

### P1 — Conformité aux règles (manquant en v0.1.0)
- [ ] **2FA TOTP** obligatoire Super Admin/Admin (champs `two_factor_*` déjà en base ; ajouter pragmarx/google2fa + flow enable/verify + écran).
- [ ] **install.php / installateur web** guidé + flag `.installed` (règle 3.1) — ou documenter clairement la procédure artisan comme équivalent validé.
- [ ] **Module de migration BDD** côté Super Admin (vérifier/appliquer, backup auto avant) (règle 3.2).
- [ ] **Corbeille / restauration** UI (soft delete déjà en place côté modèles) (règle 5.4).
- [ ] **Export RGPD** d'un lead (JSON) + suppression sur demande (règle 5.1).
- [ ] **Bandeau cookies** conforme CNIL + **contenu réel** des pages légales (mentions, confidentialité, CGU, cookies) — actuellement gabarits vides.
- [ ] **Politique de mot de passe** vérifiée (min 10, maj, chiffre, spécial — déjà via Password::min sur UserController) + verrouillage après 5 échecs (à ajouter).
- [ ] **CSP / HSTS** affinés (SecurityHeaders pose déjà X-Frame, nosniff, Referrer, Permissions, HSTS en prod).

### P2 — Industrialisation
- [ ] **CI/CD GitHub Actions** : Pint (lint), PHPUnit, déploiement staging/prod (règle 3.3).
- [ ] **Tests à 70 %** sur le métier (chatbot, recherche KB, permissions, leads).
- [ ] **API OpenAPI/Swagger** (`/api/docs`) + API keys/scopes (règle 16).
- [ ] **Notifications in-app** (cloche) + préférences utilisateur + templates email éditables (règle 10).
- [ ] **Backups automatiques** BDD+fichiers (spatie/laravel-backup) + test de restauration (règle 11, BACKUP.md).
- [ ] **Monitoring** : Sentry + endpoint `/up` (déjà présent), alertes.
- [ ] **Cron serveur** : `* * * * * php artisan schedule:run` (CRON.md).

### P3 — Écosystème (Hub)
- [ ] Préparer l'intégration **Hub central** (SSO, référentiels partagés, webhooks signés HMAC) — règles §16. UUID déjà en place.
- [ ] Brancher le **formulaire de contact du site vitrine** sur l'API du back-office (créer un endpoint Lead public dédié, réutilisant `captureLead`).
- [ ] **Tableau de bord IA** : quotas par rôle/utilisateur, alertes coûts (table `ai_usage_logs` déjà là).

### P4 — Confort
- [ ] Recherche globale Ctrl+K, pagination 25 cohérente (partiellement là), export CSV des tables.
- [ ] Onboarding 1er login, aide contextuelle (règle 6.3).
- [ ] Améliorer le widget : persistance de conversation (localStorage), accusés de lecture, pièces jointes.

---

## 5. Commandes utiles
```
composer install
php artisan key:generate
php artisan migrate --seed     # crée tables + super admin + FAQ
php artisan test               # tests chatbot
php artisan serve              # http://127.0.0.1:8000  (ou http://fflv2.test via Laragon)
php artisan yggdrasil:purge-trash   # purge RGPD (planifiée 03:30)
```
Widget à coller sur le site vitrine :
```html
<script src="https://backoffice.festivalyggdrasil.com/widget/chat-widget.js"
        data-api="https://backoffice.festivalyggdrasil.com/api/v1/chat"
        data-name="Yggi" defer></script>
```
(et ajouter le domaine du site dans `CHAT_ALLOWED_ORIGINS` du `.env`.)

---

## 6. Idées / pistes évoquées
- Le chatbot « Yggi » comme porte d'entrée unique du visiteur (FAQ vivante alimentée par les vraies questions reçues via les leads).
- Réutiliser les leads pour **enrichir la base de connaissances** (boucle d'amélioration).
- À terme : un **Hub** propriétaire orchestrant toutes les apps du festival (tronc, photographes, etc.) — voir règles §16.
- Brancher la billetterie Billetweb et, plus tard, des webhooks (inscriptions exposants/troupes via Airtable).
