mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-05-18 08:18:15 +02:00
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:
@@ -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)
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user