# Story 4.6: Page Challenge - Structure et puzzle
Status: ready-for-dev
## Story
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
1. **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
2. **And** un puzzle logique/code simple est présenté (réordonner, compléter, décoder)
3. **And** la difficulté est calibrée : 1-3 minutes pour résoudre
4. **And** le thème est lié au développement/code
5. **And** un système d'indices est disponible (bouton "Besoin d'aide ?")
6. **And** 3 niveaux d'indices progressifs sont proposés
7. **And** après 3 indices, une option "Passer" apparaît
8. **And** le challenge est TOUJOURS skippable (bouton discret "Passer directement au contact")
9. **And** une validation avec feedback clair indique succès/échec
10. **And** une animation de succès célèbre la réussite
11. **And** `challengeCompleted` est mis à `true` dans le store si réussi
## Tasks / Subtasks
- [ ] **Task 1: Créer la page challenge** (AC: #1, #8)
- [ ] Créer `frontend/app/pages/challenge.vue`
- [ ] Vérifier que le contact est débloqué
- [ ] Introduction narrative avec Le Bug
- [ ] Bouton discret "Passer" visible en permanence
- [ ] **Task 2: Concevoir le puzzle** (AC: #2, #3, #4)
- [ ] Puzzle type "réordonner les lignes de code"
- [ ] Code simple : une fonction qui affiche un message
- [ ] 5-7 lignes à réordonner dans le bon ordre
- [ ] Thème : débloquer l'accès au développeur
- [ ] **Task 3: Créer le composant CodePuzzle** (AC: #2, #9)
- [ ] Créer `frontend/app/components/feature/CodePuzzle.vue`
- [ ] Drag & drop des lignes de code
- [ ] Support tactile (mobile)
- [ ] Validation visuelle (vert/rouge)
- [ ] **Task 4: Implémenter le système d'indices** (AC: #5, #6, #7)
- [ ] Bouton "Besoin d'aide ?"
- [ ] 3 indices progressifs (révèlent de plus en plus)
- [ ] Après 3 indices : bouton "Passer" plus visible
- [ ] Indices traduits FR/EN
- [ ] **Task 5: Implémenter l'animation de succès** (AC: #10, #11)
- [ ] Confettis ou effet visuel de célébration
- [ ] Message du narrateur
- [ ] Mettre `challengeCompleted = true` dans le store
- [ ] Navigation vers la révélation
- [ ] **Task 6: Gérer le skip** (AC: #8)
- [ ] Skip visible en permanence (discret mais accessible)
- [ ] Skip après indices (plus visible)
- [ ] Dans les deux cas : navigation vers révélation
- [ ] **Task 7: Accessibilité**
- [ ] Navigation clavier pour le drag & drop
- [ ] aria-labels descriptifs
- [ ] Instructions claires
- [ ] **Task 8: Tests et validation**
- [ ] Tester le puzzle complet
- [ ] Tester les 3 indices
- [ ] Vérifier le skip
- [ ] Tester sur mobile (drag & drop tactile)
- [ ] Valider l'animation de succès
## Dev Notes
### Puzzle : Réordonner le code
Le puzzle consiste à remettre dans l'ordre les lignes d'une fonction JavaScript qui "débloque" l'accès au développeur.
```javascript
// Solution correcte
function unlockDeveloper() {
const secret = "SKYCEL";
const key = decode(secret);
if (key === "ACCESS_GRANTED") {
return showDeveloper();
}
return "Keep exploring...";
}
```
Les lignes sont mélangées et le visiteur doit les réordonner.
### Page challenge.vue
```vue
{{ t('challenge.title') }}
{{ t('challenge.intro') }}
{{ t('challenge.puzzleTitle') }}
{{ t('challenge.puzzleInstruction') }}
```
### Composant CodePuzzle
```vue
{{ index + 1 }}⋮⋮{{ line }}
{{ t('challenge.hintLabel') }}:
{{ currentHint }}
{{ t('challenge.wrongOrder') }}
```
### Composant ChallengeSuccess
```vue
🎉
{{ t('challenge.success') }}
{{ t('challenge.successMessage') }}
{{ t('challenge.redirecting') }}
```
### Clés i18n
**fr.json :**
```json
{
"challenge": {
"title": "Une dernière épreuve...",
"intro": "Avant de rencontrer le développeur, prouve que tu maîtrises les bases du code. Rien de bien méchant, promis.",
"accept": "Relever le défi",
"skip": "Passer directement au contact",
"puzzleTitle": "Remets le code dans l'ordre",
"puzzleInstruction": "Glisse les lignes pour reconstituer la fonction qui débloque l'accès au développeur.",
"hint1": "La fonction commence par 'function unlockDeveloper() {'",
"hint2": "La variable 'secret' est définie juste après l'accolade ouvrante",
"hint3": "La dernière ligne avant l'accolade fermante est 'return \"Keep exploring...\";'",
"hintLabel": "Indice",
"needHint": "Besoin d'aide ?",
"validate": "Vérifier",
"validating": "Vérification...",
"wrongOrder": "Ce n'est pas le bon ordre... Essaie encore !",
"moveUp": "Monter",
"moveDown": "Descendre",
"success": "Bravo !",
"successMessage": "Tu as prouvé ta valeur. Le chemin vers le développeur est maintenant ouvert...",
"redirecting": "Redirection en cours..."
}
}
```
**en.json :**
```json
{
"challenge": {
"title": "One last challenge...",
"intro": "Before meeting the developer, prove you understand the basics of code. Nothing too hard, I promise.",
"accept": "Accept the challenge",
"skip": "Skip to contact",
"puzzleTitle": "Put the code in order",
"puzzleInstruction": "Drag the lines to reconstruct the function that unlocks access to the developer.",
"hint1": "The function starts with 'function unlockDeveloper() {'",
"hint2": "The 'secret' variable is defined right after the opening brace",
"hint3": "The last line before the closing brace is 'return \"Keep exploring...\";'",
"hintLabel": "Hint",
"needHint": "Need help?",
"validate": "Check",
"validating": "Checking...",
"wrongOrder": "That's not the right order... Try again!",
"moveUp": "Move up",
"moveDown": "Move down",
"success": "Well done!",
"successMessage": "You've proven your worth. The path to the developer is now open...",
"redirecting": "Redirecting..."
}
}
```
### Dépendances
**Cette story nécessite :**
- Story 3.5 : Store de progression (contactUnlocked, challengeCompleted)
- Story 3.3 : useNarrator
**Cette story prépare pour :**
- Story 4.7 : Révélation (destination après le challenge)
### Project Structure Notes
**Fichiers à créer :**
```
frontend/app/
├── pages/
│ └── challenge.vue # CRÉER
└── components/feature/
├── CodePuzzle.vue # CRÉER
└── ChallengeSuccess.vue # CRÉER
```
**Fichiers à modifier :**
```
frontend/app/stores/progression.ts # AJOUTER challengeCompleted
frontend/package.json # AJOUTER canvas-confetti
frontend/i18n/fr.json # AJOUTER challenge.*
frontend/i18n/en.json # AJOUTER challenge.*
```
### References
- [Source: docs/planning-artifacts/epics.md#Story-4.6]
- [Source: docs/planning-artifacts/ux-design-specification.md#Challenge]
- [Source: docs/brainstorming-gamification-2026-01-26.md#Challenge]
### Technical Requirements
| Requirement | Value | Source |
|-------------|-------|--------|
| Durée puzzle | 1-3 minutes | Epics |
| Indices | 3 niveaux progressifs | Epics |
| Skip | Toujours disponible | Epics |
| Thème | Code/développement | Epics |
## 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