🎉 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>
This commit is contained in:
2026-02-05 02:08:56 +01:00
commit ec1ae92799
116 changed files with 55669 additions and 0 deletions

View File

@@ -0,0 +1,653 @@
# Brainstorming Session - Portfolio Gamifié
**Date** : 26 janvier 2026
**Facilitatrice** : Mary (Business Analyst)
**Techniques utilisées** : Role Playing, SCAMPER, What If Scenarios, Yes And Building
**Stack technique** : PHP 8+ / MariaDB / TailwindCSS / Swup.js / Konva.js / vis.js
**Langues** : Français (défaut) + Anglais
---
## Executive Summary
| Élément | Détail |
|---------|--------|
| **Sujet** | Amélioration portfolio - Fonctionnalités techniques et visuelles |
| **Objectif** | Exploration large |
| **Idées initiales** | Carousel témoignages, Compétences cliquables → projets |
| **Total idées générées** | 40+ |
### Concept Central Retenu
> **Portfolio = Aventure narrative immersive** avec quête principale "Trouver le développeur", chemins multiples à choix, progression gamifiée, et expérience unique par visiteur.
---
## Insights - Role Playing (3 Perspectives)
### Perspective Recruteur Pressé
| Besoin | Insight |
|--------|---------|
| Se démarquer | Design non-conventionnel, éléments surprenants |
| Infos rapides | Compétences visibles immédiatement |
| Preuves concrètes | Lien direct compétences → projets |
| Teasing efficace | Previews projets sans tout révéler |
### Perspective Client Potentiel
| Besoin | Insight |
|--------|---------|
| Confiance technique | Détails techniques par projet |
| Process de travail | Section "Comment je travaille" |
| Confiance humaine | Ton authentique, touche personnelle |
| Personnalité | À propos qui va au-delà du CV |
### Perspective Développeur Pair
| Besoin | Insight |
|--------|---------|
| Impressionner | Animations/interactions avancées |
| Valeur ajoutée | Opinions sur les technos, contenu régulier |
| Mémorable | Élément signature unique et challengeant |
| Dialogue | Interaction qui donne envie de discuter |
---
## SCAMPER - Idées Générées
### S - Substitute (Substituer)
| Élément actuel | Substitution |
|----------------|--------------|
| Textes classiques | Narrateur (toi) qui guide la visite comme une aventure |
| Images statiques | Animations SVG + entrées animées pour les projets |
| Navigation standard | Navigation gamifiée : carte interactive accessible via icône |
| Formulaire contact | "Objectif final" avec célébration à la complétion |
| Contenu bonus | Easter eggs cachés avec récompense globale |
### C - Combine (Combiner)
| Combinaison | Résultat |
|-------------|----------|
| À propos + Timeline | Section "Mon parcours" narrative |
| Gamification + Navigation | Système de progression global sur tout le site |
| Compétences + Projets | Compétences cliquables → projets liés |
### A - Adapt (Adapter)
| Inspiration | Adaptation portfolio |
|-------------|---------------------|
| Zelda BOTW - Quêtes | Objectifs de découverte à accomplir |
| Zelda BOTW - Dialogues PNJ | Témoignages sous forme de dialogues interactifs |
| Portfolios fluides | Transitions de page animées seamless |
### M - Modify/Magnify (Amplifier)
| Élément | Amplification |
|---------|---------------|
| Compétences | Arbre de compétences RPG évoluant avec chaque projet |
| Progression skill | Avant/après projet = niveau qui monte + description |
| Transitions | Animation "changement de zone" immersive (élément signature) |
| Storytelling | Intrigue parallèle au métier de développeur |
| Micro-interactions | Éléments cliquables cachés + easter eggs |
### P - Put to other uses (Autres usages)
| Usage | Implémentation |
|-------|----------------|
| Ressource code | Section snippets/templates réutilisables |
| Networking | Multi-points de contact facilités |
### E - Eliminate (Éliminer)
| À éliminer | Alternative |
|------------|-------------|
| Navigation classique (menu burger) | Carte interactive + narrateur guide |
| Informations redondantes | Chaque info à un seul endroit stratégique |
| Footer classique | Intégrer les liens dans l'expérience |
### R - Reverse/Rearrange (Inverser)
| Inversion | Effet |
|-----------|-------|
| Héros mystérieux au départ | Intrigue dès l'arrivée |
| Révélation progressive | Chaque section dévoile une facette |
| Pas de page "À propos" classique | L'histoire se construit au fil de l'exploration |
---
## What If Scenarios - Concepts Avancés
### Quête Principale
| Concept | Implémentation |
|---------|----------------|
| Quête principale | "Trouver le développeur" = fil rouge |
| Climax narratif | Le visiteur te "trouve" enfin |
| Récompense | Dialogue avec toi = formulaire de contact |
### Double Entrée (Visiteurs Pressés)
| Chemin | Expérience |
|--------|------------|
| **Aventurier** | "Partir à l'aventure" → Expérience complète |
| **Pressé** | "Je cherche..." + éléments loufoques → Roadmap complétée |
### Expérience Unique & Viralité
| Concept | Implémentation |
|---------|----------------|
| Parcours multiples | 2-3 choix binaires = 4-8 parcours différents |
| Même destination | Toutes les fins → Contact développeur |
| Rejouabilité | Chemins différents pour chaque visiteur |
---
## Yes And Building - Affinements
### Système de Challenges
| Type | Description |
|------|-------------|
| Challenge obligatoire | 1 puzzle facile pour accéder au contact |
| Easter eggs | Challenges cachés plus complexes |
| Récompenses | Snippets de code, anecdotes cachées |
| Aide | Système d'indices → réponse si bloqué |
### Dialogues PNJ (Témoignages)
| Élément | Implémentation |
|---------|----------------|
| Format | Avatar + bulle de dialogue style Zelda |
| Interaction | Clic pour "parler" → typewriter effect |
| Personnalités | Mentor sage, collègue sarcastique, client enthousiaste |
| Variété | 3-4 textes aléatoires par PNJ, même sens |
### Sauvegarde & Réengagement
| Fonctionnalité | Implémentation |
|----------------|----------------|
| Sauvegarde locale | LocalStorage JS (transparent) |
| Sauvegarde cloud | Email optionnel (multi-device) |
| Rappel narratif | Email après X jours : "Ta quête t'attend..." |
---
## Architecture Narrative Proposée
```
┌─────────────────────────────────────────────────────────────┐
│ ARRIVÉE SUR LE SITE │
└─────────────────────────────────────────────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ "Partir à │ │ "Je n'ai pas │
│ l'aventure" │ │ le temps..." │
└─────────────────┘ └─────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Intro narrative │ │ Roadmap │
│ Héros mystérieux│ │ "Partie sauvée" │
└─────────────────┘ └─────────────────┘
│ │
▼ │
┌─────────────────┐ │
│ CHOIX 1 │ │
│ Chemin A ou B │ │
└─────────────────┘ │
│ │ │
▼ ▼ │
┌───────┐ ┌───────┐ │
│Projets│ │Skills │ │
│ │ │Tree │ │
└───────┘ └───────┘ │
│ │ │
└───┬───┘ │
▼ │
┌─────────────────┐ │
│ Parcours/ │ │
│ Timeline │◄──────────────────────┘
└─────────────────┘
┌─────────────────┐
│ Témoignages │
│ (Dialogues PNJ) │
└─────────────────┘
┌─────────────────┐
│ CHALLENGE │
│ (Puzzle facile) │
└─────────────────┘
┌─────────────────────────────────────────────────────────┐
│ "TU M'AS TROUVÉ !" │
│ Dialogue avec le dev = Contact │
│ + Célébration finale │
└─────────────────────────────────────────────────────────┘
```
---
## Catégorisation des Idées
### Opportunités Immédiates (Quick Wins)
*Implémentables rapidement avec impact fort*
| # | Idée | Effort |
|---|------|--------|
| 1 | Compétences cliquables → projets | Faible |
| 2 | Carousel témoignages style dialogue | Faible |
| 3 | Transitions de page animées | Moyen |
| 4 | Fusion À propos + Timeline | Faible |
| 5 | Multi-points de contact | Faible |
### Innovations Futures (Phase 2)
*Demandent plus de développement mais réalisables*
| # | Idée | Effort |
|---|------|--------|
| 1 | Narrateur-guide avec textes d'accompagnement | Moyen |
| 2 | Double entrée (Aventure vs Mode pressé) | Moyen |
| 3 | Carte interactive comme navigation | Élevé |
| 4 | Arbre de compétences visuel | Élevé |
| 5 | Barre de progression exploration | Moyen |
| 6 | Sauvegarde LocalStorage | Faible |
### Moonshots (Phase 3)
*Ambitieux, différenciants*
| # | Idée | Effort |
|---|------|--------|
| 1 | Chemins multiples à choix (4-8 parcours) | Élevé |
| 2 | Quête principale "Trouver le dev" | Élevé |
| 3 | Challenge/puzzle obligatoire | Moyen |
| 4 | Easter eggs avec récompenses | Moyen |
| 5 | Système de rappel email narratif | Moyen |
| 6 | Textes PNJ aléatoires + personnalités | Moyen |
---
## Plan d'Action Recommandé
### Phase 1 : Fondations
| # | Action | Priorité |
|---|--------|----------|
| 1 | Implémenter transitions de page seamless | Haute |
| 2 | Créer composant compétences cliquables → projets | Haute |
| 3 | Refondre carousel témoignages en style dialogue | Haute |
| 4 | Fusionner À propos et Timeline | Haute |
| 5 | Concevoir la carte interactive (maquette) | Moyenne |
### Phase 2 : Gamification Light
| # | Action | Priorité |
|---|--------|----------|
| 1 | Ajouter narrateur-guide | Haute |
| 2 | Créer double entrée (Aventure / Pressé) | Haute |
| 3 | Implémenter barre de progression | Moyenne |
| 4 | Système de sauvegarde LocalStorage | Moyenne |
| 5 | Arbre de compétences visuel | Moyenne |
### Phase 3 : Expérience Complète
| # | Action | Priorité |
|---|--------|----------|
| 1 | Système de choix narratifs | Haute |
| 2 | Challenge/puzzle principal | Moyenne |
| 3 | Easter eggs et récompenses | Basse |
| 4 | Personnalités PNJ + textes aléatoires | Basse |
| 5 | Système de rappel email | Basse |
---
## Stack Technique Validée
### Architecture Globale
```
┌─────────────────────────────────────────────────────────────┐
│ BACKEND │
├─────────────────────────────────────────────────────────────┤
│ PHP 8+ Routing, templates, logique │
│ MariaDB Données, i18n, progression │
│ PDO Connexion sécurisée BDD │
│ Custom i18n Helper __('key') + cache │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND │
├─────────────────────────────────────────────────────────────┤
│ TailwindCSS Styling + animations CSS │
│ Swup.js ~5kb Transitions pages seamless │
│ Konva.js ~150kb Carte interactive / minimap │
│ vis.js Network ~150kb Skill tree interactif │
│ GSAP ~60kb Animations avancées (optionnel) │
│ JS Vanilla Logique, localStorage, events │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ INTERNATIONALISATION │
├─────────────────────────────────────────────────────────────┤
│ Langues FR (défaut) + EN │
│ Stockage Table MariaDB `translations` │
│ Détection URL (/en/...) ou cookie/session │
│ Fallback FR si clé manquante en EN │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ ASSETS │
├─────────────────────────────────────────────────────────────┤
│ Images WebP optimisées │
│ Icônes SVG inline ou sprite │
│ Fonts Variable fonts (perf) │
└─────────────────────────────────────────────────────────────┘
```
### Librairies JS - Détail
| Librairie | Version | Poids (gzip) | Usage |
|-----------|---------|--------------|-------|
| [Swup.js](https://swup.js.org/) | 4.x | ~2kb | Transitions de page seamless |
| [Konva.js](https://konvajs.org/) | 9.x | ~50kb | Carte interactive, minimap |
| [vis.js Network](https://visjs.github.io/vis-network/) | 9.x | ~50kb | Skill tree interactif |
| [GSAP](https://greensock.com/gsap/) | 3.x | ~25kb | Animations complexes (optionnel) |
| **Total estimé** | | **~100-125kb** | |
### Routing i18n
| URL | Langue | Page |
|-----|--------|------|
| `/` | FR (défaut) | Accueil |
| `/en` | EN | Accueil |
| `/projets` | FR | Projets |
| `/en/projects` | EN | Projets |
| `/competences` | FR | Skills |
| `/en/skills` | EN | Skills |
| `/a-propos` | FR | À propos |
| `/en/about` | EN | About |
| `/contact` | FR | Contact |
| `/en/contact` | EN | Contact |
---
## Schéma Base de Données MariaDB
### Diagramme Relationnel
```
┌──────────────────┐ ┌──────────────────┐
│ projects │ │ skills │
├──────────────────┤ ├──────────────────┤
│ id │ │ id │
│ slug │ │ slug │
│ title_key (i18n) │ │ name_key (i18n) │
│ description_key │ │ icon │
│ image │ │ max_level │
│ url │ │ category │
│ github_url │ └────────┬─────────┘
│ date_completed │ │
│ is_featured │ │
└────────┬─────────┘ │
│ │
│ ┌───────────────────┴───────────────────┐
│ │ skill_project │
│ ├───────────────────────────────────────┤
└────┤ skill_id │
│ project_id │
│ level_before │
│ level_after │
└───────────────────────────────────────┘
┌──────────────────┐ ┌──────────────────┐
│ testimonials │ │ narrator_texts │
├──────────────────┤ ├──────────────────┤
│ id │ │ id │
│ name │ │ context │
│ role │ │ text_key (i18n) │
│ company │ │ variant │
│ avatar │ └──────────────────┘
│ text_key (i18n) │
│ personality │ ┌──────────────────┐
│ project_id (FK) │ │ easter_eggs │
└──────────────────┘ ├──────────────────┤
│ id │
┌──────────────────┐ │ location │
│ translations │ │ trigger_type │
├──────────────────┤ │ reward_type │
│ id │ │ reward_key (i18n)│
│ lang (fr/en) │ └──────────────────┘
│ key_name │
│ value │ ┌──────────────────┐
└──────────────────┘ │ user_progress │
├──────────────────┤
│ id │
│ session_id │
│ email (nullable) │
│ progress_json │
│ last_visited │
└──────────────────┘
```
### Tables Détaillées
#### Table `translations` (i18n)
```sql
CREATE TABLE translations (
id INT AUTO_INCREMENT PRIMARY KEY,
lang VARCHAR(5) NOT NULL, -- 'fr', 'en'
key_name VARCHAR(255) NOT NULL, -- 'hero.title', 'nav.projects'
value TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY unique_translation (lang, key_name),
INDEX idx_lang (lang)
);
```
#### Table `projects`
```sql
CREATE TABLE projects (
id INT AUTO_INCREMENT PRIMARY KEY,
slug VARCHAR(100) NOT NULL UNIQUE,
title_key VARCHAR(255) NOT NULL, -- Clé i18n
description_key VARCHAR(255) NOT NULL, -- Clé i18n
short_description_key VARCHAR(255), -- Clé i18n (teaser)
image VARCHAR(255),
url VARCHAR(255),
github_url VARCHAR(255),
date_completed DATE,
is_featured BOOLEAN DEFAULT FALSE,
display_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
#### Table `skills`
```sql
CREATE TABLE skills (
id INT AUTO_INCREMENT PRIMARY KEY,
slug VARCHAR(100) NOT NULL UNIQUE,
name_key VARCHAR(255) NOT NULL, -- Clé i18n
description_key VARCHAR(255), -- Clé i18n
icon VARCHAR(100), -- Nom icône ou chemin SVG
category ENUM('frontend', 'backend', 'tools', 'soft') NOT NULL,
max_level INT DEFAULT 5,
display_order INT DEFAULT 0
);
```
#### Table `skill_project` (liaison + progression)
```sql
CREATE TABLE skill_project (
id INT AUTO_INCREMENT PRIMARY KEY,
skill_id INT NOT NULL,
project_id INT NOT NULL,
level_before INT DEFAULT 0,
level_after INT NOT NULL,
level_description_key VARCHAR(255), -- Clé i18n
FOREIGN KEY (skill_id) REFERENCES skills(id) ON DELETE CASCADE,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
UNIQUE KEY unique_skill_project (skill_id, project_id)
);
```
#### Table `testimonials`
```sql
CREATE TABLE testimonials (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
role VARCHAR(100),
company VARCHAR(100),
avatar VARCHAR(255),
text_key VARCHAR(255) NOT NULL, -- Clé i18n
personality ENUM('sage', 'sarcastique', 'enthousiaste', 'professionnel') DEFAULT 'professionnel',
project_id INT,
display_order INT DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET NULL
);
```
#### Table `narrator_texts`
```sql
CREATE TABLE narrator_texts (
id INT AUTO_INCREMENT PRIMARY KEY,
context VARCHAR(100) NOT NULL, -- 'intro', 'transition_projects', 'hint'
text_key VARCHAR(255) NOT NULL, -- Clé i18n
variant INT DEFAULT 1, -- Pour textes aléatoires
INDEX idx_context (context)
);
```
#### Table `easter_eggs`
```sql
CREATE TABLE easter_eggs (
id INT AUTO_INCREMENT PRIMARY KEY,
slug VARCHAR(100) NOT NULL UNIQUE,
location VARCHAR(100) NOT NULL, -- 'header-logo', 'footer-secret'
trigger_type ENUM('click', 'hover', 'konami', 'scroll') NOT NULL,
reward_type ENUM('snippet', 'anecdote', 'image', 'badge') NOT NULL,
reward_key VARCHAR(255) NOT NULL, -- Clé i18n ou chemin fichier
difficulty ENUM('easy', 'medium', 'hard') DEFAULT 'medium',
is_active BOOLEAN DEFAULT TRUE
);
```
#### Table `user_progress`
```sql
CREATE TABLE user_progress (
id INT AUTO_INCREMENT PRIMARY KEY,
session_id VARCHAR(100) NOT NULL UNIQUE,
email VARCHAR(255), -- Optionnel pour sauvegarde cloud
progress_json JSON NOT NULL, -- État complet de la progression
current_path VARCHAR(50), -- Chemin narratif choisi
completion_percent INT DEFAULT 0,
easter_eggs_found JSON, -- Liste des IDs trouvés
last_visited TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
reminder_sent BOOLEAN DEFAULT FALSE,
INDEX idx_email (email)
);
```
### Helper PHP i18n
```php
<?php
// includes/i18n.php
function __($key, $lang = null) {
global $translations_cache;
$lang = $lang ?? $_SESSION['lang'] ?? 'fr';
// Cache check
if (!isset($translations_cache[$lang])) {
// Load from DB or file cache
$translations_cache[$lang] = loadTranslations($lang);
}
return $translations_cache[$lang][$key] ?? $key;
}
function loadTranslations($lang) {
// Priorité : cache fichier > BDD
$cacheFile = __DIR__ . "/../cache/translations_{$lang}.php";
if (file_exists($cacheFile) && filemtime($cacheFile) > time() - 3600) {
return include $cacheFile;
}
// Charger depuis MariaDB
$pdo = getDbConnection();
$stmt = $pdo->prepare("SELECT key_name, value FROM translations WHERE lang = ?");
$stmt->execute([$lang]);
$translations = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$translations[$row['key_name']] = $row['value'];
}
// Sauvegarder en cache
file_put_contents($cacheFile, '<?php return ' . var_export($translations, true) . ';');
return $translations;
}
```
---
## Questions Ouvertes pour la Suite
1. **Design carte interactive** : Quel style visuel ? (minimaliste, illustré, isométrique...)
2. **Contenu narrateur** : Quel ton exact ? Tutoiement confirmé ?
3. **Challenge principal** : Quel type de puzzle ? (code, logique, exploration...)
4. **Easter eggs** : Combien ? Quelles récompenses concrètes ?
5. **Métriques** : Comment mesurer le succès de la gamification ?
---
## Prochaines Étapes Recommandées
| # | Action | Agent suggéré | Priorité |
|---|--------|---------------|----------|
| 1 | Créer le schéma BDD MariaDB | Dev | Haute |
| 2 | Configurer i18n (helper + table translations) | Dev | Haute |
| 3 | Intégrer Swup.js pour transitions seamless | Dev | Haute |
| 4 | Maquettes/Wireframes de l'expérience | UX Expert | Haute |
| 5 | Prototype carte interactive avec Konva.js | Dev | Moyenne |
| 6 | Prototype skill tree avec vis.js | Dev | Moyenne |
| 7 | Rédaction des textes du narrateur (FR + EN) | Analyst/PO | Moyenne |
| 8 | Créer les stories techniques par phase | PM | Moyenne |
---
## Réflexion Session
### Ce qui a bien fonctionné
- Role Playing pour identifier les vrais besoins des visiteurs
- SCAMPER pour structurer l'exploration systématique
- What If pour pousser les concepts audacieux
- Yes And pour affiner et rester pragmatique
- Discussion stack technique pour garder le projet réalisable
### Principes clés dégagés
1. **Immersion avant tout** - Pas de navigation classique
2. **Respect du temps** - Double entrée Aventure/Pressé
3. **Expérience unique** - Chemins multiples, textes aléatoires
4. **Gamification subtile** - Progression discrète, pas un jeu vidéo
5. **Contact = récompense narrative** - Pas une corvée
6. **Stack évolutive** - MariaDB pour faciliter les évolutions futures
7. **International dès le départ** - FR + EN intégrés dans l'architecture
---
*Document généré lors de la session de brainstorming du 2026-01-26*
*Facilitatrice : Mary (Business Analyst) - BMAD Method*