capitalisation: intégration 33 propositions RL799_V2 (triage 2026-04-07)

Backend: 21 entrées (general, prisma, contracts, auth, patterns)
Frontend: 9 entrées (navigation, tests, general, performance, patterns)
Workflow: 5 entrées (story-tracking)
Nouveau fichier: backend/patterns/general.md
95_a_capitaliser.md purgé.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
MaksTinyWorkshop
2026-04-07 15:44:36 +02:00
parent 07f39ad433
commit 72758c1adc
15 changed files with 906 additions and 23 deletions

View File

@@ -5,8 +5,8 @@ bucket: patterns
tags: [tests, react-native, jest, styles, ui]
applies_to: [implementation, review]
severity: medium
validated_on: 2026-03-19
source_projects: [app-alexandrie]
validated_on: 2026-04-07
source_projects: [app-alexandrie, RL799_V2]
---
# Frontend — Patterns : Tests
@@ -62,3 +62,31 @@ it('variante primary utilise colors.primary', () => {
1. `.spec.ts` (node) : tokens, valeurs, logique pure
2. `.spec.tsx` (config séparée avec renderer) : rendu visuel, interactions
---
<a id="pattern-niveaux-test-frontend-vue"></a>
## Pattern : Niveaux de test frontend Vue
### Synthèse
- **Objectif** : clarifier quand utiliser chaque niveau de test frontend Vue (structurel, composant monté, E2E).
- **Contexte** : les tests frontend du projet sont du string-matching sur le source `.vue` (`readFileSync` + `includes`). Ce pattern est rapide mais ne valide pas le comportement réel.
- **Quand l'utiliser** : à chaque choix de stratégie de test sur un composant Vue.
### Niveaux
| Niveau | Outil | Quand l'utiliser |
|--------|-------|-----------------|
| Structurel (string-matching) | `node:test` + `readFileSync` | Smoke tests : vérifier qu'un composant contient les imports, props, slots attendus. Acceptable pour MVP/sprint rapide. |
| Composant monté | `@vue/test-utils` + `vitest` | Valider le comportement interactif (toggle, emit, slots conditionnels). Obligatoire dès qu'il y a de la logique UI. |
| E2E | Playwright | Parcours critiques multi-pages. |
### Règle
Si un test vérifie un *comportement* (ex: "le menu se ferme après clic"), il doit monter le composant, pas chercher une string dans le source.
### Validation
- Validé le : 03-04-2026
- Contexte technique : Vue 3 / node:test — RL799_V2 story 6A.8

View File

@@ -10,10 +10,10 @@ Avant toute proposition frontend, identifie le fichier dont le nom et la descrip
|---------|---------|--------------|
| `auth.md` | Auth, guards de rôle, entitlements, OAuth | Auth côté client, loading infini écran gated, bouton OAuth vide, guard rôle flash UX |
| `state.md` | Zustand, state management, erreurs async, optimistic UI | Erreurs silencieuses, catch sans feedback, auto-reset état dégradé, fire-and-forget refresh, boolean UI hardcodé, flag isLoading unique, erreur sans rethrow, optimistic update sous-listes |
| `navigation.md` | Expo Router, deep link, useEffect fetch, contexte store | Store vide deep link/reload, guard incomplet états terminaux, collection sans clé contexte |
| `navigation.md` | Expo Router, Vue Router, deep link, useEffect fetch, contexte store | Store vide deep link/reload, guard incomplet états terminaux, collection sans clé contexte, double route racine, router-link disabled, état local query param |
| `design-tokens.md` | Design tokens, spacing, Tailwind, StyleSheet RN | Double système espacement, dimensions via spacing, inline styles dashboard, classes Tailwind invalides |
| `nextjs.md` | Next.js App Router, SSR, Server Actions, sécurité | useSearchParams sans Suspense, type ViewData dupliqué, composant React .ts, double validation segment, consent state ambigu, script inline XSS, window.location.reload, useTransition snapshot, window.confirm, import type server, img natif, useTransition global liste, formulaire defaultValue sans key |
| `tests.md` | Jest, ts-jest, tests React Native | Config node bloque .tsx, faux test négatif |
| `performance.md` | Re-renders, memoization, useCallback | Sur-renders bundle non maîtrisé, useCallback inutile inline |
| `tests.md` | Jest, ts-jest, tests React Native, Vue | Config node bloque .tsx, faux test négatif, helpers copiés, test écran indirect, test façade flux réel, tests présence textuelle |
| `performance.md` | Re-renders, memoization, useCallback, fetch | Sur-renders bundle non maîtrisé, useCallback inutile inline, fetch sans timeout |
| `react-native.md` | React Native, fetch, ScrollView, TextInput | Focus ring TextInput, contentInset iOS-only, fetch sans response.ok |
| `general.md` | Accessibilité, regex, patterns transversaux | Accessibilité oubliée a11y, regex globale singleton lastIndex |
| `general.md` | Accessibilité, regex, patterns transversaux, monorepo | Accessibilité oubliée a11y, regex globale singleton lastIndex, Alert.prompt iOS-only, primitive UI couplée, migration partielle classes legacy, ARIA roles sans clavier, duplication logique métier monorepo, event listeners globaux modales, boutons imbriqués, fire-and-forget sans feedback |

View File

@@ -129,3 +129,122 @@ function processLinks(content: string) {
- Si un reliquat legacy doit rester temporairement, documenter explicitement son périmètre et sa date de sortie attendue
- En review, traiter toute nouvelle utilisation d'une classe legacy équivalente comme une régression de standardisation
- Contexte technique : Vue 3 / design system léger — RL799_V2, 02-04-2026
---
<a id="risque-aria-roles-sans-clavier"></a>
## ARIA roles sans comportement clavier associé
### Risques
- Poser `role="menu"` / `role="menuitem"` sur un composant sans implémenter le pattern clavier donne une fausse impression d'accessibilité
- Les rôles ARIA trompent les lecteurs d'écran et violent WCAG 2.1 (4.1.2 Name, Role, Value)
### Symptômes
- `role="menu"` sans fermeture via `Escape`
- Pas de navigation `ArrowUp` / `ArrowDown` ni de roving tabindex
### Bonnes pratiques / mitigations
Poser `role="menu"` / `role="menuitem"` implique obligatoirement :
- Fermeture via `Escape`
- Navigation via `ArrowUp` / `ArrowDown`
- Roving tabindex (`tabindex="0"` sur l'item actif, `-1` sur les autres)
- Focus automatique du premier item à l'ouverture
**Règle** : ne jamais poser un `role` ARIA de widget interactif sans implémenter le pattern clavier correspondant (cf. WAI-ARIA Authoring Practices)
- Contexte technique : Vue 3 / accessibilité — RL799_V2 03-04-2026
---
<a id="risque-duplication-logique-metier-monorepo"></a>
## Duplication de logique métier dans les composants UI (monorepo)
### Risques
- Dans un monorepo avec un package partagé (`shared`), les fonctions utilitaires métier (ex: conversion grade → rang) sont redéfinies localement dans les composants ou pages frontend
- Ce type de duplication silencieuse provoque des divergences à terme
### Symptômes
- Fonction `switch/case` ou mapping identique à une fonction déjà exportée par `shared`
- Même signature et même logique dans plusieurs fichiers de couches différentes (composant, page, service)
### Bonnes pratiques / mitigations
- Les fonctions utilitaires métier ne doivent jamais être redéfinies localement dans les composants ou pages frontend
- Importer systématiquement depuis le package partagé (`@monrepo/shared` ou équivalent) plutôt que de copier-coller la logique
- **Signal review** : grep des fonctions utilitaires existantes dans shared avant de valider un nouveau switch/case
- Contexte technique : Vue 3 / monorepo — RL799_V2 06-04-2026
---
<a id="risque-event-listeners-globaux-modales"></a>
## Event listeners globaux pour interactions modales
### Risques
- `window.addEventListener('keydown')` pour capturer Escape dans une modale crée un listener global qui peut confliter avec d'autres modales
- Le listener fuit si le composant est mal démonté
### Symptômes
- `window.addEventListener('keydown', handler)` dans un composant modale
- Cleanup dans `onBeforeUnmount` mais risque de fuite si le démontage échoue
### Bonnes pratiques / mitigations
- Utiliser `@keydown.escape` directement sur l'élément dialog avec `tabindex="-1"` + focus automatique à l'ouverture
- Élimine le besoin de cleanup et scope l'interaction au composant
- **Signal review** : dans tout composant modale, vérifier que les listeners clavier sont sur l'élément, pas sur `window`
- Contexte technique : Vue 3 / modales — RL799_V2 06-04-2026
---
<a id="risque-boutons-imbriques"></a>
## Boutons imbriqués dans les listes interactives
### Risques
- Un `<button>` ou `<a>` contenant un autre élément interactif (bouton, lien) est du HTML invalide
- Casse l'accessibilité et produit un comportement imprévisible selon les navigateurs
### Symptômes
- `<button>` conteneur avec un `<button>` enfant (ex: étoile favori dans une carte cliquable)
- Comportement de clic imprévisible, événements qui ne remontent pas correctement
### Bonnes pratiques / mitigations
- Utiliser un `<div>` conteneur avec des boutons séparés côte à côte
- Si toute la ligne doit être cliquable, séparer la zone de clic principale (bouton content) de l'action secondaire (bouton étoile/action)
- **Signal review** : dans tout composant liste avec actions inline, vérifier qu'aucun élément interactif n'est imbriqué dans un autre
- Contexte technique : HTML / accessibilité — RL799_V2 06-04-2026
---
<a id="risque-fire-and-forget-sans-feedback"></a>
## Fire-and-forget sans feedback sur actions non-critiques
### Risques
- Une action asynchrone non-critique (cache IndexedDB, analytics, sync) lancée en fire-and-forget sans feedback masque les échecs
- L'utilisateur croit que l'action est faite (ex: document disponible hors-ligne) alors qu'elle a échoué
### Symptômes
- `.then(...).catch(() => {})` sur une action secondaire
- `catch { /* ignore */ }` sans log ni feedback visuel
### Bonnes pratiques / mitigations
- Même si l'action est non-bloquante, afficher un feedback discret en cas d'échec (toast, badge absent)
- L'utilisateur doit pouvoir distinguer "fait" de "échoué silencieusement"
- **Signal review** : tout `.catch(() => {})` ou `catch { /* ignore */ }` mérite au minimum un log ou un feedback visuel
- Contexte technique : frontend / actions async — RL799_V2 07-04-2026

View File

@@ -5,7 +5,7 @@ bucket: risques
tags: [navigation, expo-router, vue-router, vue, zustand, useeffect, deep-link, a11y]
applies_to: [implementation, review, debug]
severity: high
validated_on: 2026-04-02
validated_on: 2026-04-07
source_projects: [app-alexandrie, RL799_V2]
---
@@ -232,3 +232,25 @@ const routes = [
- Règle : un élément de navigation désactivé ne doit jamais être un lien
- Utiliser un élément non interactif (`span`) ou un vrai contrôle désactivable (`button disabled`) selon le besoin
- Contexte technique : Vue 3 / Vue Router 4 / accessibilité — RL799_V2, 02-04-2026
---
<a id="risque-etat-local-depuis-query-param"></a>
## État local initialisé depuis un query param de route sans synchronisation réactive
### Risques
- Un formulaire branché sur un query param de route peut soumettre un identifiant obsolète si la prop initiale est copiée une seule fois dans un état local
- Le bug est discret et passe facilement les tests textuels
### Symptômes
- Composant qui copie `route.query.id` dans un `ref()` au montage sans `watch`
- Navigation intra-page (même composant, query param différent) qui soumet l'ancien identifiant
### Bonnes pratiques / mitigations
- Quand un composant initialise un état local depuis une prop liée au router (ex: `route.query.*`), ajouter une synchronisation réactive explicite (`watch` sur la prop) ou utiliser directement la prop si possible
- Ajouter un test qui valide la synchro sur changement de query param (même composant réutilisé, navigation intra-page)
- Contexte technique : Vue 3 / Vue Router 4 — RL799_V2 02-04-2026

View File

@@ -55,3 +55,26 @@ const handleToggle = useCallback((id: string) => { ... }, []); // stable ✓
- Contexte technique : React — app-template-resto 22-03-2026
---
<a id="risque-fetch-sans-timeout"></a>
## Fetch sans timeout pour ressources lourdes
### Risques
- `fetch()` sans timeout pour charger des blobs/fichiers volumineux (PDF, images) laisse l'utilisateur attendre indéfiniment sur connexion dégradée
- Critique sur mobile avec connexion instable ; faux sentiment de freeze pour l'utilisateur
### Symptômes
- `fetch(url)` sans `AbortController` + timeout pour des blobs/fichiers volumineux
- Spinner infini sans message d'erreur
### Bonnes pratiques / mitigations
- Utiliser `AbortController` avec `setTimeout` (15s recommandé)
- Attraper `AbortError` et afficher un message explicite à l'utilisateur
- **Signal review** : tout `fetch` de blob/fichier sans `AbortController` est suspect
- Contexte technique : frontend / mobile — RL799_V2 06-04-2026

View File

@@ -5,8 +5,8 @@ bucket: risques
tags: [tests, jest, react-native, ts-jest, coverage, facade]
applies_to: [analysis, implementation, review, debug]
severity: high
validated_on: 2026-03-31
source_projects: [app-alexandrie, app-template-resto]
validated_on: 2026-04-07
source_projects: [app-alexandrie, app-template-resto, RL799_V2]
---
# Frontend — Risques & vigilance : Tests
@@ -122,3 +122,29 @@ source_projects: [app-alexandrie, app-template-resto]
- **Règle** : un test qui ne vérifie que des helpers adjacents ne peut pas clôturer une tâche d'intégration.
- Contexte technique : TypeScript / Jest — app-template-resto 31-03-2026
---
<a id="risque-tests-presence-textuelle-faux-gardefou"></a>
## Tests de présence textuelle = faux garde-fou de non-régression
### Risques
- Des tests basés uniquement sur `content.includes(...)` valident du texte statique tout en laissant passer des régressions réelles sur auth/API et comportements UI
- Les AC fonctionnels sont déclarés validés alors que le flux réel (autosave, submit, transitions d'état) n'est pas exercé
### Symptômes
- Tests qui lisent le fichier `.vue` et assertent uniquement des chaînes (`includes`) sans exécuter le composant ni ses interactions
- Story cochée malgré des régressions fonctionnelles invisibles aux tests verts
- Services API et guards d'accès validés par des assertions textuelles au lieu de tests comportementaux
### Bonnes pratiques / mitigations
- Exiger au moins un test comportemental par flux critique (montage composant + interaction + assertion d'effet)
- Reléguer les tests textuels au rôle de smoke structurel non bloquant
- Pour les services API et guards d'accès : exiger un test exécutant réellement la fonction (mock fetch/session/router) et validant statuts d'erreur + contrat d'appel
- Pour les templates/checklists critiques : ne pas se limiter à la présence de mots-clés, valider la structure attendue (sections obligatoires, champs non vides, format minimal)
- **Règle** : si un test vérifie un *comportement* (ex: "le menu se ferme après clic"), il doit monter le composant, pas chercher une string dans le source
- Contexte technique : Vue 3 / node:test — RL799_V2 02-04-2026