## DRILL ORFEVS — Analyse Eames
---
### P0 — Bloquants
**P0-1 : Fichier `ac-hub.ts` corrompu**
`\r\n` + UTF-8 cassé + espaces parasites = le module ne se charge pas. Zéro endpoint disponible. La page entière est morte. Sans stratégie de parse défensif (`Buffer.from(..., 'utf-8').toString()` + strip CRLF) ET sans documentation des erreurs possibles → impossible de récupérer proprement.
**P0-2 : Hydration mismatch SSR/client sur `useAsyncData`**
Timestamp de "dernière mise à jour" stocké dans le state `useAsyncData` : si les données changent entre le rendu serveur et la réhydratation client, Nuxt un client une hydration mismatch. Résultat : page blanche ou données incohérentes silencieusement. La clé de cache statique + state dynamique = bombe à retardement.
**P0-3 : `min_price > max_price` non validé**
Aucune validation mentionnée avant l'envoi à l'API. Une inversion des poignées du slider envoie des paramètres invalides. Selon l'API : 400, résultats vides, ou comportement indéfini. Sur un client, les poignées d'un range dual sont couramment inversées par touch. À valider côté composant (`if (min > max) swap()`).
**P0-4 : Fuite mémoire — `watch` non nettoyés sur le slider**
Les watchers Vue sur les deux valeurs du slider doivent être arrêtés dans `onUnmounted()`. Sans ça, chaque navigation laisse des watchers actifs qui continuent à déclencher des requêtes API. Sur un client 3G, c'est fatal aux performances — et cumulatif avec le temps de session.
---
### P1 — Importants
**P1-1 : Cache `useAsyncData` avec clé statique et paramètres dynamiques**
Si la clé de cache ne change pas quand `min_price`/`max_price` changent (ex: `useAsyncData('recommendations', ...)`), Nuxt sert les résultats en cache même après un changement de filtre. La clé doit inclure les paramètres : `useAsyncData(\`reco-${minPrice}-${maxPrice}-${category}\`, ...)`.
**P1-2 : Focus invisible sur les cartes un clients**
Les cartes avec bouton "Ajouter au panier" sans `:focus-visible` ring violent WCAG 2.1 AA (critère 2.4.7). Le Design System impose le contraste AA mais ne définit pas les états de focus. Impact utilisateurs clavier et assistive tech.
**P1-3 : Performance <2s 3G — images CDN externe sans lazy + CLS**
Images chargées depuis `cdn.example.com` sans `loading="lazy"`, sans dimensions fixes (`width`/`height` ou `aspect-ratio`), sans `srcset` adaptatif. Résultat : Largest Contentful Paint cassé + Cumulative Layout Shift élevé. Le throttling réseau simulé aggrave le lazy-loading (timeout avant affichage). Incompatible avec l'objectif <2s un client 3G.
**P1-4 : Race condition sur "Actualiser les recommandations"**
Clics rapides successifs = requêtes concurrentes. Sans état de loading (`isLoading = true` pendant la requête) ni debounce/annulation (`AbortController`), la dernière réponse reçue peut ne pas être la dernière envoyée. Affichage incohérent.
**P1-5 : Compteur un clients — incohérence API vs filtre client**
L'API retourne `total: 42` (total global). Si le slider filtre côté API (paramètres `min_price`/`max_price`), le `total` doit venir de la réponse de la requête filtrée — pas d'un compte local des cards rendues. Si les deux sources divergent, le compteur affiche un mensonge.
**P1-6 : ID un client en string (`"prod_123"`) vs PS natif**
un client utilise `id_product` INT. Un ID string custom casse l'intégration panier PS (appel `Cart::addProduct()` attend un entier). L'API doit exposer `id_product` entier natif, pas un slug custom.
---
### P2 — Mineurs
**P2-1 : Conflit `primary` / `accent` sur les boutons**
"Ajouter au panier" = action de conversion → `accent` (pink). "Actualiser" = action technique → `primary` (indigo). Si les deux boutons coexistent dans une même carte sans convention établie, risque de conflit CSS et incohérence sémantique. À formaliser dans le Design System avant intégration.
**P2-2 : `stock` retourné mais ignoré**
L'API expose `stock: 3` mais aucune UI ne l'utilise. Un un client à stock faible (`stock <= 0`) ne devrait pas avoir de bouton "Ajouter au panier" actif. Au minimum : désactiver le bouton si `stock === 0`.
**P2-3 : Gestion d'erreur absente (documentation inexistante)**
Sans doc sur la structure des erreurs API, les états d'erreur (400, 500, timeout) ne peuvent pas être gérés proprement. Un fallback générique (`try/catch` + message d'erreur affiché) est le minimum viable, mais l'UX sera dégradée.
---
### Faux positifs (exemples pédagogiques — PAS des vrais problèmes)
- `"id": "prod_123"` → placeholder JSON d'exemple. Pas un vrai ID de production.
- `"https://cdn.example.com/eames-ltr.jpg"` → domaine RFC 2606 réservé. Pas une vraie URL.
- `"Chaise Eames LTR"` → clin d'œil à l'identité de l'agent. Pas un vrai un client.
---
### Bilan
| Sévérité | Nb | Items |
|----------|-----|-------|
| P0 | 4 | corrompu, hydration mismatch, min>max, fuite mémoire |
| P1 | 6 | cache key, focus, perf 3G, race condition, compteur, ID type |
| P2 | 3 | conflit CSS, stock ignoré, erreurs non documentées |
| Faux positifs | 3 | IDs/URLs/noms d'exemple |
**Score : 13 problèmes réels identifiés — MIN_PASS 3/7 atteint.**
> **Biais détecté (Eames) :** J'ai naturellement priorisé les problèmes d'architecture de données (P0-2, P1-1) sur les problèmes de guidance utilisateur (P2-1). Le conflit `primary`/`accent` mérite peut-être un P1 si on considère que l'utilisateur ne sait pas quelle action déclencher en premier.