Files
skycel ec1ae92799 🎉 Init monorepo Nuxt 4 + Laravel 12 (Story 1.1)
Setup complet de l'infrastructure projet :
- Frontend Nuxt 4 (SSR, TypeScript, i18n, Pinia, TailwindCSS)
- Backend Laravel 12 API-only avec middleware X-API-Key et CORS
- Design tokens (sky-dark, sky-accent, sky-text) et polices (Merriweather, Inter)
- Documentation planning et implementation artifacts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 02:08:56 +01:00

42 KiB

stepsCompleted, status, validatedAt, inputDocuments
stepsCompleted status validatedAt inputDocuments
1
2
3
4
complete 2026-02-03
docs/prd-gamification.md
docs/planning-artifacts/architecture.md
docs/planning-artifacts/ux-design-specification.md
docs/brainstorming-gamification-2026-01-26.md

skycel - Epic Breakdown

Overview

This document provides the complete epic and story breakdown for skycel, decomposing the requirements from the PRD, UX Design if it exists, and Architecture requirements into implementable stories.

Requirements Inventory

Functional Requirements

  • FR1 : Le système offre une double entrée au visiteur : "Partir à l'aventure" (expérience complète) ou "Je n'ai pas le temps" (mode express avec roadmap)
  • FR2 : Les transitions entre pages sont animées de manière seamless via Nuxt transitions, créant une impression de "changement de zone" immersive
  • FR3 : Un narrateur-guide accompagne le visiteur avec des textes contextuels tout au long de l'expérience
  • FR4 : Une carte interactive (Konva.js) permet la navigation non-linéaire et affiche la progression du visiteur
  • FR5 : Un arbre de compétences interactif (vis.js) visualise les skills avec niveaux évoluant selon les projets
  • FR6 : Les compétences sont cliquables et mènent directement aux projets qui les utilisent
  • FR7 : Les témoignages s'affichent sous forme de dialogues PNJ style Zelda avec avatar, bulles, effet typewriter et personnalités variées
  • FR8 : Une barre de progression globale indique l'avancement dans l'exploration du site
  • FR9 : Le système propose 2-3 choix binaires créant 4-8 parcours narratifs différents, tous menant au contact
  • FR10 : Un challenge/puzzle accessible doit être résolu pour accéder au formulaire de contact (avec système d'indices)
  • FR11 : Des easter eggs cachés récompensent l'exploration avec des snippets de code ou anecdotes
  • FR12 : La progression est sauvegardée automatiquement en LocalStorage pour permettre la reprise
  • FR13 : Le site supporte deux langues (FR par défaut + EN) avec détection par URL (/en/...)
  • FR14 : Le formulaire de contact est présenté comme la récompense finale "Tu m'as trouvé !" avec célébration

NonFunctional Requirements

  • NFR1 : Le bundle JS total (Nuxt + Konva + vis.js) ne doit pas dépasser 170kb gzippé, avec lazy-loading des composants lourds
  • NFR2 : Le temps de chargement initial (LCP) doit rester sous 2.5 secondes sur connexion 3G
  • NFR3 : Le site doit être responsive et offrir une expérience adaptée mobile (carte simplifiée en Chemin Libre vertical)
  • NFR4 : Le site doit fonctionner sur les navigateurs modernes (Chrome, Firefox, Safari, Edge — 2 dernières versions)
  • NFR5 : Les URLs doivent être SEO-friendly et le contenu principal accessible aux crawlers (SSR Nuxt 4)
  • NFR6 : Les animations doivent respecter prefers-reduced-motion pour l'accessibilité
  • NFR7 : Le système i18n utilise @nuxtjs/i18n avec fichiers JSON, rendu SSR pour SEO optimal
  • NFR8 : Les images sont optimisées en WebP avec lazy loading

Additional Requirements

Architecture :

  • Starter template : Nuxt 4 (npx nuxi@latest init) + Laravel 12 (composer create-project) — impacte Epic 1 Story 1
  • Structure monorepo frontend/ (Nuxt 4 avec structure app/) + api/ (Laravel 12)
  • Table translations centralisée en MariaDB pour i18n du contenu dynamique (clés i18n dans les tables métier)
  • API REST avec API Key (X-API-Key) + CORS strict (domaine frontend uniquement)
  • Store Pinia useProgressionStore avec persistance LocalStorage via pinia-plugin-persistedstate + compatibilité SSR
  • Architecture composants frontend : ui/ (atomiques réutilisables), feature/ (métier), layout/ (structure page)
  • GSAP pour animations complexes (Swup.js abandonné — redondant avec transitions Nuxt natives)
  • Transitions Nuxt natives (pageTransition + <Transition>) + CSS animations
  • Sécurité contact : reCAPTCHA v3 (invisible) + honeypot + rate limiting Laravel (5 req/min par IP)
  • Bandeau RGPD intégré à l'immersion narrative (dialogue PNJ/narrateur, style "pacte d'aventurier")
  • Déploiement : Nginx → Node.js :3000 (Nuxt SSR) + PHP-FPM :9000 (Laravel API) + MariaDB :3306
  • CI/CD : Script deploy.sh manuel (git pull, build, migrate, restart)
  • Backups BDD : cron quotidien mysqldump + réplication distante rsync/scp, rétention 7 jours
  • Environnements : production (skycel.fr, branche prod) + staging (staging.skycel.fr)
  • Cache : File cache Laravel (driver file, pas de Redis)
  • Double validation : frontend (UX temps réel) + backend (Form Requests Laravel, source de vérité)
  • Format réponse API : Laravel API Resources avec enveloppe { data, meta }
  • Gestion langue API : header Accept-Language → middleware Laravel → jointure table translations

UX :

  • Système de héros : 3 personnages (Recruteur/Client/Dev) impactant vouvoiement, ton narrateur, type de challenges
  • Narrateur = "Le Bug" (araignée, mascotte micro-entreprise) avec arc de révélation progressive (silhouette sombre → araignée complète en 5 étapes liées à la progression)
  • Page résumé 30s (/resume) : URL directe pour candidatures, accès sans passer par la landing
  • Déblocage contact après 2 zones visitées (pas de blocage excessif)
  • Challenge final optionnel (jamais bloquant l'accès au contact)
  • Challenge post-formulaire ("En attendant que le dev retrouve sa boîte mail...")
  • "Monde de Code" : révélation finale — paysage en blocs de code ASCII art, avatar Célian au centre
  • Navigation mobile : "Chemin Libre" vertical (ZoneCards scrollables) au lieu de Konva.js
  • Bottom bar mobile fixe : Carte, Progression, Paramètres (thumb zone)
  • Tous les feedbacks système passent par le narrateur (pas de toasts/notifications classiques)
  • Headless UI / Radix UI pour composants standards accessibles (modals, tooltips, toggles, menus)
  • Design tokens Tailwind : sky-dark (noir→bleu), sky-accent (#fa784f orange), sky-text (blanc cassé→jaune)
  • Polices : serif élégante (narrateur/PNJ/narration) + sans-serif moderne (interface/UI)
  • Approche Mobile First CSS
  • WCAG AA : contraste ≥ 4.5:1, touch targets 44x44px min, skip links, aria-live="polite" narrateur, navigation clavier complète
  • Sortie de zone par choix narratif du narrateur (pas de bouton "retour" froid)
  • Couleurs par zone sur la carte (teintes uniques par section)
  • Espacement aéré : spacing scale de 4px à 128px

Brainstorming :

  • Schéma BDD détaillé : 8 tables (projects, skills, skill_project, testimonials, narrator_texts, easter_eggs, user_progress, translations)
  • Personnalités PNJ : sage, sarcastique, enthousiaste, professionnel
  • Easter eggs : triggers variés (click, hover, konami, scroll, sequence)
  • Rewards easter eggs : snippet, anecdote, image, badge
  • Sauvegarde cloud progression par email (optionnel, phase 2)
  • Rappel email narratif après X jours (hors scope MVP)

FR Coverage Map

FR Epic Description
FR1 Epic 1 Double entrée Aventure / Mode Express
FR2 Epic 1 Transitions de page animées seamless
FR3 Epic 3 Narrateur-guide contextuel
FR4 Epic 3 Carte interactive navigation non-linéaire
FR5 Epic 2 Arbre de compétences interactif
FR6 Epic 2 Compétences cliquables → projets liés
FR7 Epic 2 Témoignages dialogues PNJ
FR8 Epic 3 Barre de progression globale
FR9 Epic 4 Choix binaires créant parcours multiples
FR10 Epic 4 Challenge/puzzle avant contact
FR11 Epic 4 Easter eggs cachés
FR12 Epic 3 Sauvegarde progression LocalStorage
FR13 Epic 1 Bilingue FR/EN
FR14 Epic 4 Contact comme récompense finale

Epic List

Epic 1 : Fondations & Double Entrée

Le visiteur arrive sur le site, choisit son héros et son mode (Aventure ou Express), et peut naviguer entre les pages avec des transitions immersives. Le site est bilingue et fonctionnel en SSR. FRs couverts : FR1, FR2, FR13

Epic 2 : Contenu & Découverte

Le visiteur explore les zones de contenu : projets (galerie + détail), compétences organisées par catégories avec liens vers les projets associés, témoignages en dialogues PNJ, et parcours en timeline narrative. FRs couverts : FR5, FR6, FR7

Epic 3 : Navigation Gamifiée & Progression

Le visiteur navigue via la carte interactive (Konva.js desktop / Chemin Libre mobile), est accompagné par le narrateur-guide (Le Bug), et voit sa progression sauvegardée automatiquement avec une barre XP. FRs couverts : FR3, FR4, FR8, FR12

Epic 4 : Chemins Narratifs, Challenge & Contact

Le visiteur fait des choix qui créent son parcours unique, relève un challenge optionnel, et accède à la révélation finale "Monde de Code" + formulaire de contact comme récompense narrative. Les easter eggs récompensent l'exploration. FRs couverts : FR9, FR10, FR11, FR14


Epic 1 : Fondations & Double Entrée

Le visiteur arrive sur le site, choisit son héros et son mode (Aventure ou Express), et peut naviguer entre les pages avec des transitions immersives. Le site est bilingue et fonctionnel en SSR.

Story 1.1 : Initialisation du monorepo et infrastructure

As a développeur, I want un projet monorepo Nuxt 4 + Laravel 12 initialisé avec les configurations de base, So that le développement peut commencer sur des fondations solides.

Acceptance Criteria:

Given un nouveau repository Git When le projet est initialisé Then la structure monorepo frontend/ (Nuxt 4) + api/ (Laravel 12) est en place And Nuxt 4 est configuré avec SSR activé, TypeScript, et les modules @nuxtjs/i18n, @nuxtjs/tailwindcss, @pinia/nuxt, nuxt/image, @nuxtjs/sitemap And Laravel 12 est configuré en mode API-only avec CORS autorisant le domaine frontend And le middleware API Key (X-API-Key) est en place sur les routes API And les fichiers .env.example existent pour frontend et backend And TailwindCSS est configuré avec les design tokens (sky-dark, sky-accent #fa784f, sky-text) And les polices sont définies (serif narrateur + sans-serif UI) And le .gitignore est approprié pour les deux applications

Story 1.2 : Base de données et migrations initiales

As a développeur, I want le schéma de base de données MariaDB avec les tables nécessaires à l'Epic 1, So that l'API peut servir du contenu bilingue.

Acceptance Criteria:

Given une connexion MariaDB configurée dans Laravel When php artisan migrate est exécuté Then la table translations est créée (id, lang, key_name, value, timestamps) avec index unique (lang, key_name) And la table projects est créée (id, slug, title_key, description_key, short_description_key, image, url, github_url, date_completed, is_featured, display_order, timestamps) And la table skills est créée (id, slug, name_key, description_key, icon, category, max_level, display_order) And la table skill_project est créée (id, skill_id, project_id, level_before, level_after, level_description_key) avec foreign keys And les Models Eloquent sont définis avec leurs relations (Project belongsToMany Skill, etc.) And des Seeders de base sont disponibles avec données de test en FR et EN And php artisan db:seed fonctionne correctement

Story 1.3 : Système i18n frontend + API bilingue

As a visiteur, I want voir le site dans ma langue (FR ou EN), So that je comprends le contenu.

Acceptance Criteria:

Given le module @nuxtjs/i18n configuré avec stratégie prefix_except_default When le visiteur accède à / ou /en Then le contenu statique UI est affiché dans la langue correspondante via fichiers JSON (i18n/fr.json, i18n/en.json) And les URLs FR sont par défaut (/, /projets, /competences, /contact) And les URLs EN sont préfixées (/en, /en/projects, /en/skills, /en/contact) And useI18n(), $t(), localePath(), switchLocalePath() fonctionnent en SSR And les tags hreflang sont générés automatiquement dans le <head> And l'attribut lang du <html> est dynamique (fr/en) And le middleware Laravel extrait Accept-Language et joint la table translations pour le contenu dynamique And les API Resources Laravel renvoient le contenu traduit selon la langue demandée And le fallback est FR si langue non supportée

Story 1.4 : Layouts, routing et transitions de page

As a visiteur, I want une navigation fluide entre les pages avec des transitions immersives, So that l'expérience ressemble à un changement de zone, pas à un rechargement.

Acceptance Criteria:

Given la structure de pages Nuxt 4 (app/pages/) When le visiteur navigue entre les pages Then les transitions de page sont animées (fade + slide) via pageTransition dans nuxt.config.ts And la navigation utilise <NuxtLink> pour l'hydration SPA (pas de rechargement) And le layout par défaut (default.vue) inclut le header avec barre de progression (placeholder) et sélecteur de langue And un layout minimal.vue existe pour le mode express And le scrollBehavior est personnalisé (smooth scroll, retour position sauvegardée) And prefers-reduced-motion désactive les animations de transition via media query CSS And une page 404 (error.vue) bilingue est en place And les meta tags SEO dynamiques fonctionnent via useHead() et useSeoMeta() And le favicon est configuré

Story 1.5 : Landing page et choix du héros

As a visiteur, I want choisir entre l'aventure et le mode express, puis sélectionner mon héros, So that mon expérience est adaptée à mon profil et mon temps disponible.

Acceptance Criteria:

Given le visiteur arrive sur la landing page (/) When la page se charge Then deux CTA distincts sont visibles : "Partir à l'aventure" et "Mode express" And un texte d'accroche intrigant bilingue est affiché And une animation d'entrée subtile est présente (respectant prefers-reduced-motion) And le design est responsive (mobile + desktop) And au clic sur "Partir à l'aventure", le composant HeroSelector s'affiche avec 3 cards illustrées (Recruteur, Client, Développeur) avec nom et description courte And le héros sélectionné est stocké dans le store Pinia useProgressionStore (champ hero) And au clic sur "Mode express", le visiteur est redirigé vers la page résumé And le HeroSelector est accessible au clavier (role="radiogroup", flèches pour naviguer, Enter pour sélectionner)

Story 1.6 : Store Pinia progression et bandeau RGPD

As a visiteur, I want que ma progression soit sauvegardée et que mon consentement soit respecté, So that je peux reprendre mon exploration et mes données sont protégées.

Acceptance Criteria:

Given le visiteur accède au site When le consentement RGPD n'a pas encore été donné Then un bandeau de consentement immersif s'affiche (style narratif/dialogue, pas un bandeau classique) And le store Pinia useProgressionStore est initialisé avec : sessionId (UUID v4), hero, currentPath, visitedSections, completionPercent, easterEggsFound, challengeCompleted, contactUnlocked, narratorStage, choices, consentGiven And la persistance LocalStorage est activée via pinia-plugin-persistedstate (uniquement après consentement) And le store est compatible SSR (initialisation vide côté serveur, réhydratation client) And si une progression existante est détectée, un message "Bienvenue à nouveau" est affiché And l'action $reset() permet de réinitialiser la progression

Story 1.7 : Page résumé express et mode pressé

As a visiteur pressé ou recruteur, I want une vue condensée de toutes les informations essentielles, So that je peux évaluer le développeur en 30 secondes.

Acceptance Criteria:

Given le visiteur accède à /resume (FR) ou /en/resume (EN) directement ou via "Mode express" When la page se charge Then le contenu affiché comprend : nom, titre, photo/avatar, accroche (5s) And les compétences clés avec stack technique sont visibles (10s) And 3-4 projets highlights avec liens sont affichés (10s) And un CTA de contact direct est visible (5s) And un bouton discret "Voir l'aventure" invite à l'expérience complète And la page est fonctionnelle en FR et EN And les données sont chargées depuis l'API (projets, skills) And les meta tags SEO sont optimisés pour cette page And le layout minimal.vue est utilisé


Epic 2 : Contenu & Découverte

Le visiteur explore les zones de contenu : projets (galerie + détail), compétences organisées par catégories avec liens vers les projets associés, témoignages en dialogues PNJ, et parcours en timeline narrative.

Story 2.1 : Composant ProjectCard

As a développeur, I want un composant réutilisable de card de projet, So that je peux afficher les projets de manière cohérente sur la galerie et ailleurs dans le site.

Acceptance Criteria:

Given le composant ProjectCard est implémenté When il reçoit les données d'un projet en props Then il affiche l'image du projet (WebP, lazy loading) And il affiche le titre traduit selon la langue courante And il affiche la description courte traduite And un hover effect révèle un CTA "Découvrir" avec animation subtile And le composant est cliquable et navigue vers /projets/{slug} (ou /en/projects/{slug}) And le composant respecte prefers-reduced-motion pour les animations And le composant est responsive (adaptation mobile/desktop) And le composant est accessible (focus visible, role approprié)

Story 2.2 : Page Projets - Galerie

As a visiteur, I want voir la liste des projets réalisés par le développeur, So that je peux évaluer son expérience et choisir lesquels explorer en détail.

Acceptance Criteria:

Given le visiteur accède à /projets (FR) ou /en/projects (EN) When la page se charge Then une grille responsive de ProjectCard s'affiche And les projets sont triés par date avec les "featured" en tête And une animation d'entrée progressive des cards est présente (respectant prefers-reduced-motion) And les données sont chargées depuis l'API /api/projects avec le contenu traduit And les meta tags SEO sont dynamiques pour cette page And le layout s'adapte : grille sur desktop, cards empilées sur mobile

Story 2.3 : Page Projet - Détail

As a visiteur, I want voir les détails d'un projet spécifique, So that je comprends le travail réalisé et les technologies utilisées.

Acceptance Criteria:

Given le visiteur accède à /projets/{slug} (FR) ou /en/projects/{slug} (EN) When la page se charge Then le titre, la description complète et l'image principale du projet s'affichent And la date de réalisation est visible And la liste des compétences utilisées s'affiche avec leurs niveaux (avant/après le projet) And les liens externes sont présents : URL du projet live (si existe), repository GitHub (si existe) And une navigation "Projet précédent / Projet suivant" permet de parcourir les projets And un bouton retour vers la galerie est visible And les meta tags SEO sont dynamiques (titre, description, image Open Graph) And si le slug n'existe pas, une page 404 appropriée s'affiche And le design est responsive (adaptation mobile/desktop)

Story 2.4 : Page Compétences - Affichage par catégories

As a visiteur, I want voir les compétences du développeur organisées par catégorie, So that je comprends son profil technique global.

Acceptance Criteria:

Given le visiteur accède à /competences (FR) ou /en/skills (EN) When la page se charge Then les compétences sont affichées groupées par catégorie (Frontend, Backend, Tools, Soft skills) And chaque compétence affiche : icône, nom traduit, niveau actuel (représentation visuelle) And les données sont chargées depuis l'API /api/skills avec le contenu traduit And une animation d'entrée des éléments est présente (respectant prefers-reduced-motion) And sur desktop : préparé pour accueillir le skill tree vis.js (Epic 3) And sur mobile : liste groupée par catégorie avec design adapté And les meta tags SEO sont dynamiques pour cette page And chaque compétence est visuellement cliquable (affordance)

Story 2.5 : Compétences cliquables → Projets liés

As a visiteur, I want cliquer sur une compétence pour voir les projets qui l'utilisent, So that je peux voir des preuves concrètes de maîtrise.

Acceptance Criteria:

Given le visiteur est sur la page Compétences When il clique sur une compétence Then un panneau/modal s'ouvre avec la liste des projets liés à cette compétence And pour chaque projet lié : titre, description courte, lien vers le détail And l'indication du niveau avant/après chaque projet est visible (progression) And une animation d'ouverture/fermeture fluide est présente (respectant prefers-reduced-motion) And la fermeture est possible par clic extérieur, bouton close, ou touche Escape And le panneau/modal utilise Headless UI pour l'accessibilité And la navigation au clavier est fonctionnelle (Tab, Escape, Enter) And le focus est piégé dans le modal quand ouvert (focus trap) And les données viennent de la relation skill_project via l'API

Story 2.6 : Page Témoignages et migrations BDD

As a visiteur, I want voir les témoignages des personnes ayant travaillé avec le développeur, So that j'ai une validation sociale de ses compétences.

Acceptance Criteria:

Given les migrations Laravel sont exécutées When php artisan migrate est lancé Then la table testimonials est créée (id, name, role, company, avatar, text_key, personality ENUM, project_id FK nullable, display_order, is_active, timestamps) And les seeders de test sont disponibles avec des témoignages en FR et EN

Given le visiteur accède à /temoignages (FR) ou /en/testimonials (EN) When la page se charge Then la liste des témoignages s'affiche depuis l'API /api/testimonials And chaque témoignage affiche : nom, rôle, entreprise, avatar, texte traduit And la personnalité de chaque PNJ est indiquée visuellement (style différent selon personality) And un lien vers le projet associé est présent si pertinent And l'ordre d'affichage respecte display_order And le design est préparé pour accueillir le composant DialoguePNJ (story suivante) And les meta tags SEO sont dynamiques pour cette page

Story 2.7 : Composant Dialogue PNJ

As a visiteur, I want lire les témoignages comme des dialogues de personnages style Zelda, So that l'expérience est immersive et mémorable.

Acceptance Criteria:

Given le composant DialoguePNJ est implémenté When il reçoit les données d'un témoignage en props Then l'avatar du PNJ s'affiche à gauche avec un style illustratif And une bulle de dialogue s'affiche à droite avec le texte And l'effet typewriter fait apparaître le texte lettre par lettre And un clic ou appui sur Espace accélère l'animation typewriter (x3-x5) And la personnalité du PNJ influence le style visuel de la bulle (sage, sarcastique, enthousiaste, professionnel) And la police serif narrative est utilisée pour le texte du dialogue And prefers-reduced-motion affiche le texte complet instantanément And le texte complet est accessible via aria-label pour les screen readers And une navigation entre témoignages est disponible (précédent/suivant) And une transition animée s'effectue entre les PNJ And un indicateur du témoignage actuel est visible (ex: 2/5) And la navigation au clavier est fonctionnelle (flèches gauche/droite)

Story 2.8 : Page Parcours - Timeline narrative

As a visiteur, I want découvrir le parcours professionnel du développeur sous forme de timeline, So that je comprends son évolution et son expérience.

Acceptance Criteria:

Given le visiteur accède à /parcours (FR) ou /en/journey (EN) When la page se charge Then une timeline verticale affiche les étapes chronologiques du parcours And chaque étape affiche : date, titre, description narrative traduite And sur desktop : les étapes alternent gauche/droite pour un effet visuel dynamique And sur mobile : les étapes sont linéaires (toutes du même côté) And une animation d'apparition au scroll est présente (respectant prefers-reduced-motion) And des icônes ou images illustrent les étapes clés And le contenu est bilingue (FR/EN) et chargé depuis l'API ou fichiers i18n And les meta tags SEO sont dynamiques pour cette page And la police serif narrative est utilisée pour les descriptions


Epic 3 : Navigation Gamifiée & Progression

Le visiteur navigue via la carte interactive (Konva.js desktop / Chemin Libre mobile), est accompagné par le narrateur-guide (Le Bug), et voit sa progression sauvegardée automatiquement avec une barre XP.

Story 3.1 : Table narrator_texts et API narrateur

As a développeur, I want une infrastructure pour stocker et servir les textes du narrateur, So that le narrateur peut afficher des messages contextuels variés.

Acceptance Criteria:

Given les migrations Laravel sont exécutées When php artisan migrate est lancé Then la table narrator_texts est créée (id, context, text_key, variant, timestamps) And les contextes définis incluent : intro, transition_projects, transition_skills, transition_testimonials, transition_journey, hint, encouragement_25, encouragement_50, encouragement_75, contact_unlocked, welcome_back And plusieurs variantes par contexte permettent une sélection aléatoire And les seeders insèrent les textes de base en FR et EN dans la table translations

Given l'API /api/narrator/{context} est appelée When un contexte valide est fourni Then un texte aléatoire parmi les variantes de ce contexte est retourné And le texte est traduit selon le header Accept-Language And le ton est adapté au héros (vouvoiement pour Recruteur, tutoiement pour Client/Dev)

Story 3.2 : Composant NarratorBubble (Le Bug)

As a visiteur, I want voir un narrateur-guide qui m'accompagne dans mon exploration, So that je me sens guidé et l'expérience est immersive.

Acceptance Criteria:

Given le composant NarratorBubble est implémenté When le narrateur doit afficher un message Then une bulle apparaît en bas de l'écran (desktop) ou au-dessus de la bottom bar (mobile) And l'avatar du Bug (araignée) s'affiche avec son apparence selon le narratorStage du store And le texte apparaît avec effet typewriter (lettre par lettre) And un clic ou Espace accélère l'animation typewriter And la bulle peut être fermée/minimisée sans bloquer la navigation And le composant utilise aria-live="polite" et role="status" pour l'accessibilité And prefers-reduced-motion affiche le texte instantanément And la police serif narrative est utilisée pour le texte And l'animation d'apparition/disparition est fluide et non-bloquante

Story 3.3 : Textes narrateur contextuels et arc de révélation

As a visiteur, I want que le narrateur réagisse à mes actions et évolue visuellement, So that l'expérience est personnalisée et le narrateur devient familier.

Acceptance Criteria:

Given le visiteur navigue sur le site When il effectue des actions clés Then le narrateur affiche un message d'accueil à l'arrivée (adapté au héros choisi) And des messages de transition s'affichent entre les zones And des encouragements apparaissent à 25%, 50%, 75% de progression And des indices s'affichent si le visiteur semble inactif (> 30s sans action) And un message spécial "Bienvenue à nouveau" s'affiche si progression existante détectée And le message de déblocage du contact s'affiche après 2 zones visitées

Given le visiteur progresse dans l'exploration When le completionPercent atteint certains seuils Then le narratorStage du store est mis à jour (1→5) And l'apparence du Bug évolue : silhouette sombre (1) → forme vague (2) → pattes visibles (3) → araignée reconnaissable (4) → mascotte complète révélée (5) And le ton du narrateur évolue de mystérieux à complice

Story 3.4 : Barre de progression globale (XP bar)

As a visiteur, I want voir ma progression dans l'exploration du site, So that je sais combien il me reste à découvrir.

Acceptance Criteria:

Given le visiteur est en mode Aventure When il navigue sur le site Then une barre de progression discrète s'affiche dans le header And le pourcentage est calculé selon les sections visitées (Projets, Compétences, Témoignages, Parcours) And l'animation de la barre est fluide lors des mises à jour And un tooltip au hover indique les sections visitées et restantes And le design évoque une barre XP style RPG (cohérent avec sky-accent) And la barre respecte prefers-reduced-motion (pas d'animation si activé) And sur mobile, la progression est accessible via la bottom bar And la barre n'est pas visible en mode Express/Résumé

Story 3.5 : Logique de progression et déblocage contact

As a visiteur, I want que ma progression débloque l'accès au contact, So that l'exploration est récompensée sans être frustrante.

Acceptance Criteria:

Given le store useProgressionStore est actif When le visiteur visite une nouvelle zone Then la zone est ajoutée à visitedSections And le completionPercent est recalculé automatiquement And la progression est persistée en LocalStorage (si consentement RGPD donné)

Given le visiteur a visité 2 zones ou plus When la condition est atteinte Then contactUnlocked passe à true And le narrateur annonce le déblocage avec un message spécial And la zone Contact s'illumine sur la carte (si visible) And le visiteur peut continuer à explorer ou aller au contact

Given le visiteur revient sur le site When une progression existe en LocalStorage Then le store est réhydraté avec l'état sauvegardé And le narrateur affiche "Bienvenue à nouveau" And la carte affiche l'état correct des zones visitées

Story 3.6 : Carte interactive desktop (Konva.js)

As a visiteur desktop, I want naviguer via une carte interactive visuelle, So that j'explore librement le portfolio comme un monde.

Acceptance Criteria:

Given le visiteur est sur desktop (≥ 1024px) et accède à la carte When la carte se charge Then un canvas Konva.js affiche une carte stylisée avec les zones (Projets, Compétences, Parcours, Témoignages, Contact) And le composant est chargé en lazy-loading (.client.vue) pour respecter le budget JS And chaque zone a une apparence distincte (teinte unique, icône) And les zones visitées ont une apparence différente des zones non visitées And la zone Contact est verrouillée visuellement si contactUnlocked est false And la position actuelle du visiteur est marquée sur la carte And au hover sur une zone : le nom et le statut s'affichent (tooltip) And au clic sur une zone : navigation vers la section correspondante avec transition And un curseur personnalisé indique les zones cliquables And la navigation au clavier est fonctionnelle (Tab entre zones, Enter pour naviguer) And les zones ont des labels ARIA descriptifs

Story 3.7 : Navigation mobile - Chemin Libre et Bottom Bar

As a visiteur mobile, I want naviguer facilement avec une interface adaptée au tactile, So that l'expérience reste immersive sur petit écran.

Acceptance Criteria:

Given le visiteur est sur mobile (< 768px) When il accède à la navigation Then le "Chemin Libre" affiche les zones en cards verticales scrollables (ZoneCard) And chaque ZoneCard affiche : illustration, nom de la zone, statut (visité/nouveau/verrouillé) And une ligne décorative relie les cards visuellement (effet chemin) And un tap sur une zone navigue vers la section correspondante And la zone Contact affiche un cadenas si contactUnlocked est false

Given la bottom bar mobile est affichée When le visiteur interagit Then 3 icônes sont accessibles : Carte (ouvre le Chemin Libre), Progression (affiche le %), Paramètres And les touch targets font au minimum 48x48px And la bottom bar est fixe et toujours visible And le narrateur s'affiche au-dessus de la bottom bar quand actif


Epic 4 : Chemins Narratifs, Challenge & Contact

Le visiteur fait des choix qui créent son parcours unique, relève un challenge optionnel, et accède à la révélation finale "Monde de Code" + formulaire de contact comme récompense narrative. Les easter eggs récompensent l'exploration.

Story 4.1 : Composant ChoiceCards et choix narratifs

As a visiteur, I want faire des choix qui influencent mon parcours, So that mon expérience est unique et personnalisée.

Acceptance Criteria:

Given le composant ChoiceCards est implémenté When le narrateur propose un choix Then 2 cards s'affichent côte à côte (desktop) ou empilées (mobile) And chaque card affiche : icône, texte narratif du choix And un hover/focus highlight la card sélectionnable And un clic enregistre le choix dans choices du store Pinia And une transition animée mène vers la destination choisie And le composant est accessible (role="radiogroup", navigation clavier, focus visible) And prefers-reduced-motion simplifie les animations And le style est cohérent avec l'univers narratif (police serif, couleurs des zones)

Story 4.2 : Intro narrative et premier choix

As a visiteur aventurier, I want une introduction narrative captivante suivie d'un premier choix, So that je suis immergé dès le début de l'aventure.

Acceptance Criteria:

Given le visiteur a sélectionné son héros sur la landing page When il commence l'aventure Then une séquence d'intro narrative s'affiche avec le narrateur (Le Bug) And le texte présente le "héros mystérieux" (le développeur) à découvrir And l'effet typewriter anime le texte (skippable par clic/Espace) And l'ambiance visuelle est immersive (fond sombre, illustrations) And un bouton "Continuer" permet d'avancer And à la fin de l'intro, le premier choix binaire s'affiche via ChoiceCards And le choix propose deux zones à explorer en premier (ex: Projets vs Compétences) And le contenu est bilingue (FR/EN) et adapté au héros (vouvoiement/tutoiement) And la durée de l'intro est courte (15-30s max, skippable)

Story 4.3 : Chemins narratifs différenciés

As a visiteur, I want que mes choix aient un impact visible sur mon parcours, So that je sens que mon expérience est vraiment personnalisée.

Acceptance Criteria:

Given le visiteur fait des choix tout au long de l'aventure When il navigue entre les zones Then 2-3 points de choix binaires créent 4-8 parcours possibles And chaque choix est enregistré dans choices du store And l'ordre suggéré des zones varie selon le chemin choisi And les textes du narrateur s'adaptent au chemin (transitions contextuelles) And tous les chemins permettent de visiter tout le contenu And tous les chemins mènent au contact (pas de "mauvais" choix) And le currentPath du store reflète le chemin actuel And à la fin de chaque zone, le narrateur propose un choix vers la suite

Story 4.4 : Table easter_eggs et système de détection

As a développeur, I want une infrastructure pour gérer les easter eggs cachés, So that je peux ajouter des surprises récompensant l'exploration.

Acceptance Criteria:

Given les migrations Laravel sont exécutées When php artisan migrate est lancé Then la table easter_eggs est créée (id, slug, location, trigger_type ENUM, reward_type ENUM, reward_key, difficulty, is_active, timestamps) And les trigger_types incluent : click, hover, konami, scroll, sequence And les reward_types incluent : snippet, anecdote, image, badge And les seeders insèrent 5-10 easter eggs avec leurs récompenses traduites

Given l'API /api/easter-eggs est appelée When la requête est faite Then les métadonnées des easter eggs actifs sont retournées (slug, location, trigger_type) And les réponses/récompenses ne sont PAS incluses (pour éviter la triche)

Given l'API /api/easter-eggs/{slug}/validate est appelée When un slug valide est fourni Then la récompense traduite est retournée And l'easter egg est marqué comme trouvé côté client (store)

Story 4.5 : Easter eggs - Implémentation UI et collection

As a visiteur curieux, I want découvrir des surprises cachées et voir ma collection, So that l'exploration est récompensée.

Acceptance Criteria:

Given des easter eggs sont placés sur différentes pages When le visiteur déclenche un easter egg (clic, hover, konami, scroll, sequence) Then une animation de découverte s'affiche (popup, effet visuel) And la récompense est affichée (snippet de code, anecdote, image, badge) And le narrateur réagit avec enthousiasme And une notification "Easter egg trouvé ! (X/Y)" s'affiche And le slug est ajouté à easterEggsFound dans le store And un bouton permet de fermer et continuer

Given le visiteur accède à sa collection (via paramètres ou zone dédiée) When la collection s'affiche Then une grille montre les easter eggs trouvés et des silhouettes mystère pour les non-trouvés And les détails sont visibles pour les découverts And un compteur X/Y indique la progression And un badge spécial s'affiche si 100% trouvés

Story 4.6 : Page Challenge - Structure et puzzle

As a visiteur, I want relever un défi optionnel avant d'accéder au contact, So that l'accès au développeur est une récompense méritée (mais pas bloquante).

Acceptance Criteria:

Given le visiteur accède à /challenge (après avoir débloqué le contact) When la page se charge Then une introduction narrative "Une dernière épreuve..." s'affiche And un puzzle logique/code simple est présenté (réordonner, compléter, décoder) And la difficulté est calibrée : 1-3 minutes pour résoudre And le thème est lié au développement/code And un système d'indices est disponible (bouton "Besoin d'aide ?") And 3 niveaux d'indices progressifs sont proposés And après 3 indices, une option "Passer" apparaît And le challenge est TOUJOURS skippable (bouton discret "Passer directement au contact") And une validation avec feedback clair indique succès/échec And une animation de succès célèbre la réussite And challengeCompleted est mis à true dans le store si réussi

Story 4.7 : Révélation "Monde de Code"

As a visiteur ayant complété le parcours, I want vivre un moment waouh de révélation finale, So that la découverte du développeur est mémorable.

Acceptance Criteria:

Given le visiteur accède à la zone Contact (après challenge ou skip) When la révélation se déclenche Then une transition immersive mène vers le "Monde de Code" And un paysage composé de blocs de code ASCII art s'affiche (montagnes, arbres, ville en code) And le code scroll/apparaît progressivement (animation) And l'avatar illustré de Célian est révélé au centre du monde de code And le narrateur (Le Bug) commente : "Tu l'as trouvé !" And le message "Tu m'as trouvé !" s'affiche avec effet de célébration And sur mobile, une version allégée mais émotionnellement équivalente s'affiche And prefers-reduced-motion affiche une version statique And une description alternative est disponible pour les screen readers And un bouton permet de continuer vers le formulaire de contact

Story 4.8 : Page Contact - Formulaire et célébration

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:

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é) And un formulaire de contact s'affiche : nom (requis), email (requis), message (requis) And la validation temps réel est effectuée côté frontend (champs requis, format email) And les erreurs sont communiquées par le narrateur (pas de messages d'erreur classiques) And un champ honeypot invisible est présent (anti-spam) And reCAPTCHA v3 est intégré de manière invisible And le bouton d'envoi utilise la couleur accent (sky-accent)

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 And le rate limiting (5 req/min par IP) est appliqué And l'email est envoyé via Laravel Mail And une animation de célébration s'affiche (confettis ou similaire) And le narrateur confirme l'envoi avec un message personnalisé And en cas d'erreur, le narrateur explique le problème avec bienveillance

Story 4.9 : Challenge post-formulaire

As a visiteur ayant envoyé un message, I want m'amuser en attendant la réponse, So that le temps d'attente est transformé en moment de jeu.

Acceptance Criteria:

Given le formulaire de contact a été envoyé avec succès When la confirmation s'affiche Then un message "En attendant que le développeur retrouve le chemin vers sa boîte mail..." est affiché And un challenge optionnel bonus est proposé And le challenge est différent du challenge principal (mini-jeu, quiz, exploration) And le visiteur peut fermer et quitter à tout moment And la participation est totalement optionnelle And le résultat n'impacte rien (juste pour le fun) And le narrateur commente avec humour