capitalisation: intégration ~60 entrées RL799_V2 (triage 2026-05-02)

Triage du 95_a_capitaliser.md (~75 propositions) :
- 60 entrées intégrées dans knowledge/ (backend, frontend, workflow)
- 4 nouveaux fichiers : backend/patterns/tests.md, backend/risques/tests.md,
  frontend/patterns/general.md, workflow/patterns/general.md
- 6 doublons rejetés
- Mise à jour des READMEs index pour refléter les nouvelles entrées
- 95_a_capitaliser.md restauré à sa structure initiale
- 40_decisions_et_archi.md : décision mono-tenant déployable vs SaaS multi-tenant
- 90_debug_et_postmortem.md : sub-agents Write indisponible, effet iceberg CI,
  prisma migrate diffs cosmétiques

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MaksTinyWorkshop
2026-05-02 22:12:44 +02:00
parent 02ad0de258
commit b3417ad77b
31 changed files with 5370 additions and 12 deletions

View File

@@ -198,3 +198,82 @@ Sans focus trap, le clavier peut sortir de la sheet/panel et casser l'ordre de n
- Restaurer le focus au trigger à la fermeture.
---
<a id="pattern-factorisation-page-meta-mode"></a>
## Pattern : Factorisation page mode dynamique via `route.meta.mode` typé
### Synthèse
- **Objectif** : factoriser un composant Vue qui partage 95 % de sa logique entre plusieurs routes ne différant que par le wording, sans recourir à `route.name` (fragile) ou query string (manipulable).
- **Contexte** : projet Vue avec deux routes (ex : `/invitation` + `/reset-password`) qui partagent la mécanique technique stricte (validation token + saisie mot de passe + consume) et ne diffèrent que par le wording.
- **Quand l'utiliser** : factorisation justifiée par un partage > 90 % de logique entre routes.
- **Quand l'éviter** : routes qui diffèrent fonctionnellement au-delà du wording — préférer deux composants distincts.
### Analyse
- **Avantages** :
- explicite, déclaratif, type-checkable
- augmenter `RouteMeta` dans `vue-router` pour qu'un mode manquant produise une erreur build
- **Limites / vigilance** :
- wording centralisé en un seul `computed` — pas de `v-if` éparpillés dans le template
- endpoint dynamique en un seul `if/else` dans le handler
### Validation
- Validé le : 28-04-2026
- Contexte technique : Vue 3 / vue-router — RL799_V2
### Implémentation
```typescript
// router/index.ts
{
path: '/invitation',
name: 'invitation',
component: ResetPasswordPage,
meta: { requiresGuest: true, mode: 'invitation' as const },
},
{
path: '/reset-password',
name: 'reset-password',
component: ResetPasswordPage,
meta: { requiresGuest: true, mode: 'reset' as const },
},
```
```typescript
// ResetPasswordPage.vue
const pageMode = computed<PageMode>(() => {
const meta = route.meta as { mode?: PageMode } | undefined;
return meta?.mode === 'invitation' ? 'invitation' : 'reset';
});
const wording = computed(() => {
if (pageMode.value === 'invitation') {
return { eyebrow: 'Bienvenue', title: 'Définissez votre mot de passe', /* … */ };
}
return { eyebrow: 'Réinitialisation', title: '...', /* … */ };
});
const handleSubmit = async () => {
if (pageMode.value === 'invitation') {
await consumeInvitationToken(token.value, newPassword.value);
} else {
await consumeResetToken(token.value, newPassword.value);
}
// Post-consume uniforme : redirige /login pour les deux modes
};
```
### Règles d'or
- `meta.mode` typé en literal union (`'invitation' | 'reset'`)
- A11y obligatoire : autofocus sur le champ password au mount post-validation, `<label for>` associés, `<AppMessage variant="error">` avec `role="alert"`, `<AppMessage variant="success">` avec `aria-live="polite"`
- Test obligatoire : monter la page avec chaque `meta.mode` et vérifier que le wording correspond
### Anti-patterns
- Détecter le mode via `route.name` (fragile, couplage implicite, signal d'intention faible)
- Détecter via query string (pollue URL, manipulable)
---