# Story 4.8: Page Contact - Formulaire et célébration
Status: ready-for-dev
## Story
As a visiteur ayant trouvé le développeur,
I want le contacter facilement avec une célébration,
so that l'envoi du message est une conclusion satisfaisante.
## Acceptance Criteria
1. **Given** le visiteur est sur la page Contact après la révélation **When** la page s'affiche **Then** un message de félicitations avec stats du parcours est visible (zones visitées, easter eggs trouvés, temps passé)
2. **And** un formulaire de contact s'affiche : nom (requis), email (requis), message (requis)
3. **And** la validation temps réel est effectuée côté frontend (champs requis, format email)
4. **And** les erreurs sont communiquées par le narrateur (pas de messages d'erreur classiques)
5. **And** un champ honeypot invisible est présent (anti-spam)
6. **And** reCAPTCHA v3 est intégré de manière invisible
7. **And** le bouton d'envoi utilise la couleur accent (`sky-accent`)
8. **Given** le formulaire est soumis **When** les données sont envoyées à l'API **Then** la validation backend Laravel (Form Request) vérifie les données
9. **And** le rate limiting (5 req/min par IP) est appliqué
10. **And** l'email est envoyé via Laravel Mail
11. **And** une animation de célébration s'affiche (confettis ou similaire)
12. **And** le narrateur confirme l'envoi avec un message personnalisé
13. **And** en cas d'erreur, le narrateur explique le problème avec bienveillance
## Tasks / Subtasks
- [ ] **Task 1: Créer la page contact** (AC: #1, #2)
- [ ] Créer `frontend/app/pages/contact.vue`
- [ ] Afficher les stats du parcours (zones, easter eggs, temps)
- [ ] Formulaire avec nom, email, message
- [ ] **Task 2: Implémenter la validation frontend** (AC: #3, #4)
- [ ] Validation en temps réel avec Vuelidate ou Vee-Validate
- [ ] Format email valide
- [ ] Champs requis
- [ ] Erreurs via le narrateur (pas de messages classiques)
- [ ] **Task 3: Ajouter les protections anti-spam** (AC: #5, #6)
- [ ] Champ honeypot invisible
- [ ] Intégrer reCAPTCHA v3 (invisible)
- [ ] Obtenir token reCAPTCHA avant envoi
- [ ] **Task 4: Créer l'API de contact** (AC: #8, #9, #10)
- [ ] Créer `app/Http/Controllers/Api/ContactController.php`
- [ ] Form Request pour validation backend
- [ ] Rate limiting : 5 requêtes/min par IP
- [ ] Envoi email via Laravel Mail
- [ ] Vérification reCAPTCHA côté serveur
- [ ] **Task 5: Créer le template d'email**
- [ ] Template Blade pour l'email de contact
- [ ] Inclure : nom, email, message
- [ ] Design sobre et professionnel
- [ ] **Task 6: Animation de succès** (AC: #11, #12)
- [ ] Confettis après envoi réussi
- [ ] Message du narrateur confirmant l'envoi
- [ ] Transition vers le challenge post-formulaire
- [ ] **Task 7: Gestion des erreurs** (AC: #13)
- [ ] Erreur réseau : narrateur explique
- [ ] Rate limit : narrateur demande de patienter
- [ ] reCAPTCHA : narrateur suggère de réessayer
- [ ] **Task 8: Tests et validation**
- [ ] Tester la validation frontend
- [ ] Tester l'envoi complet (API + email)
- [ ] Vérifier le rate limiting
- [ ] Tester le honeypot
- [ ] Valider reCAPTCHA
## Dev Notes
### Page contact.vue
```vue
{{ stats.zonesVisited }}/{{ stats.zonesTotal }}
{{ t('contact.zones') }}
{{ stats.easterEggsFound }}/{{ stats.easterEggsTotal }}
{{ t('contact.easterEggs') }}
{{ stats.challengeCompleted ? '✓' : '—' }}
{{ t('contact.challenge') }} 🏆 {{ t('contact.explorer') }}
{{ t('contact.subtitle') }}
{{ t('contact.successMessage') }}
{{ t('contact.redirecting') }}
{{ t('contact.yourJourney') }}
{{ t('contact.title') }}
{{ t('contact.successTitle') }}
De : {{ $name }}
Email : {{ $email }}
{!! nl2br(e($message)) !!}
Ce message a été envoyé depuis le portfolio Skycel.
``` ### Clés i18n **fr.json :** ```json { "contact": { "yourJourney": "Ton parcours", "zones": "Zones explorées", "easterEggs": "Easter eggs", "challenge": "Challenge", "explorer": "Explorateur", "title": "Contacte-moi", "subtitle": "Tu m'as trouvé ! Maintenant, écris-moi. Je lis chaque message.", "name": "Ton nom", "namePlaceholder": "Comment dois-je t'appeler ?", "email": "Ton email", "emailPlaceholder": "Pour que je puisse te répondre", "message": "Ton message", "messagePlaceholder": "Dis-moi tout...", "send": "Envoyer le message", "sending": "Envoi en cours...", "recaptchaNote": "Ce site est protégé par reCAPTCHA.", "successTitle": "Message envoyé !", "successMessage": "Je l'ai bien reçu et je te réponds dès que possible. En attendant, un petit défi bonus ?", "redirecting": "Redirection vers le challenge bonus..." } } ``` **en.json :** ```json { "contact": { "yourJourney": "Your journey", "zones": "Zones explored", "easterEggs": "Easter eggs", "challenge": "Challenge", "explorer": "Explorer", "title": "Contact me", "subtitle": "You found me! Now, write to me. I read every message.", "name": "Your name", "namePlaceholder": "What should I call you?", "email": "Your email", "emailPlaceholder": "So I can reply to you", "message": "Your message", "messagePlaceholder": "Tell me everything...", "send": "Send message", "sending": "Sending...", "recaptchaNote": "This site is protected by reCAPTCHA.", "successTitle": "Message sent!", "successMessage": "I received it and will reply as soon as possible. In the meantime, a bonus challenge?", "redirecting": "Redirecting to bonus challenge..." } } ``` ### Dépendances **Cette story nécessite :** - Story 3.5 : Store de progression (stats) - Story 3.3 : useNarrator (messages d'erreur) - Story 4.7 : Révélation (page précédente) **Cette story prépare pour :** - Story 4.9 : Challenge post-formulaire ### Project Structure Notes **Fichiers à créer :** ``` frontend/app/pages/ └── contact.vue # CRÉER api/ ├── app/Http/Controllers/Api/ │ └── ContactController.php # CRÉER ├── app/Http/Requests/ │ └── ContactRequest.php # CRÉER ├── app/Mail/ │ └── ContactMail.php # CRÉER └── resources/views/emails/ └── contact.blade.php # CRÉER ``` **Fichiers à modifier :** ``` api/routes/api.php # AJOUTER route contact api/config/services.php # AJOUTER recaptcha config frontend/nuxt.config.ts # AJOUTER reCAPTCHA frontend/i18n/fr.json # AJOUTER contact.* frontend/i18n/en.json # AJOUTER contact.* ``` ### References - [Source: docs/planning-artifacts/epics.md#Story-4.8] - [Source: docs/planning-artifacts/ux-design-specification.md#Contact-Form] - [Source: docs/planning-artifacts/architecture.md#Security] ### Technical Requirements | Requirement | Value | Source | |-------------|-------|--------| | Validation | Frontend + Backend | Epics | | Anti-spam | Honeypot + reCAPTCHA v3 | Epics | | Rate limiting | 5 req/min/IP | Epics | | Envoi email | Laravel Mail | Architecture | ## Dev Agent Record ### Agent Model Used {{agent_model_name_version}} ### Debug Log References ### Completion Notes List ### Change Log | Date | Change | Author | |------|--------|--------| | 2026-02-04 | Story créée avec contexte complet | SM Agent | ### File List