mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-06-28 01:53:40 +02:00
docs(knowledge): capitalisation racine — post-mortems (90_) et ADR (40_) du triage local
Intégration des propositions ciblant les fichiers racine validés. 90_debug_et_postmortem.md (9 post-mortems) : - type métier dupliqué dans package shared + bridge ; flakiness "socket hang up" e2e (recyclage de port éphémère) ; rtk masque la sortie des CLI build/test ; vi.spyOn sur module ESM ; `as const` → TS2769 (jose) ; échec massif suite = template DB corrompu ; séparer 2 chantiers mélangés (barrel partagé) ; modèle Prisma fantôme (migration sans model) + variante effet iceberg CI 40_decisions_et_archi.md (4 ADR) : - CI e2e mobile pas un prérequis prod ; vérifier le modèle de données réel avant spec ; segmenter l'auth par sensibilité d'action ; IdP Keycloak auth-only + RBAC local (Proposed) Dédupliqué vs knowledge/ déjà écrit : les ADR/post-mortems apportent l'angle narratif/décisionnel (le "pourquoi"/"récit de debug"), complémentaire des règles réutilisables en knowledge/, avec cross-références. Blocs déjà couverts ailleurs (113 liste/détail) non réintégrés. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+156
-1
@@ -8,7 +8,7 @@ Objectifs :
|
||||
- éviter de reposer les mêmes questions
|
||||
- assumer les compromis
|
||||
|
||||
Dernière mise à jour : 2026-03-12
|
||||
Dernière mise à jour : 2026-06-25
|
||||
|
||||
---
|
||||
|
||||
@@ -32,6 +32,9 @@ Dernière mise à jour : 2026-03-12
|
||||
- [User views — User public par défaut + MeUser explicite](#decision-user-views)
|
||||
- [Mono-tenant déployable vs SaaS multi-tenant](#decision-mono-tenant-deployable)
|
||||
- [Rollout MCP Lead_tech dans BMAD — Phase 2 partielle (strict ciblé)](#decision-mcp-rollout-phase-2)
|
||||
- [CI e2e mobile : pas un prérequis de mise en prod](#decision-ci-e2e-mobile)
|
||||
- [Vérifier le modèle de données réel avant d'accepter une spec](#decision-modele-donnees-avant-spec)
|
||||
- [Segmenter l'auth par sensibilité d'action (forte vs sans-friction)](#decision-segmentation-auth-sensibilite)
|
||||
|
||||
### 2. Infra
|
||||
|
||||
@@ -51,6 +54,7 @@ Dernière mise à jour : 2026-03-12
|
||||
- [Observabilité minimale obligatoire](#decision-observabilite)
|
||||
- [Authentification et autorisation centrales](#decision-auth-central)
|
||||
- [Idempotence et gestion des retries](#decision-idempotence-retries)
|
||||
- [IdP centralisé (Keycloak) auth-only + RBAC métier local](#decision-idp-keycloak-auth-only)
|
||||
|
||||
### 4. n8n
|
||||
|
||||
@@ -378,6 +382,110 @@ Aligner la doc sur l'implémentation : **déclarer Phase 2 partielle** avec 3 bl
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-ci-e2e-mobile"></a>
|
||||
|
||||
## CI e2e mobile : pas un prérequis de mise en prod
|
||||
|
||||
- Date : 2026-05-21
|
||||
- Statut : Accepted
|
||||
- Périmètre : global / mobile
|
||||
|
||||
### Contexte
|
||||
|
||||
Un job CI qui build l'app mobile + lance un smoke test (Maestro, Detox…) sur émulateur/simulateur est tentant, mais coûteux — surtout iOS, qui exige un runner macOS (~10× le prix d'un runner Linux, ~30-45 min/run). Tranché sur app-alexandrie : les e2e mobile (smoke Maestro iOS/Android) ont été retirés de la CI GitHub après constat que le coût ne se justifiait pas.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Garder un job CI mobile bloquant « par principe »
|
||||
- Garder une CI mobile non bloquante / limitée en coût (paths-filter, iOS sur `push main`)
|
||||
- Retirer les e2e mobile de la CI et diagnostiquer en local au cas par cas
|
||||
|
||||
### Décision
|
||||
|
||||
La CI e2e mobile **n'est pas une porte vers la prod**. Pour un dev solo / petite équipe sur plan CI gratuit, retirer les e2e mobile de la CI est défendable.
|
||||
|
||||
### Justification
|
||||
|
||||
- Les stores (Apple App Review, Google Play) testent le *binaire soumis*, pas la CI GitHub. GitHub ne « refuse » jamais une publication.
|
||||
- Le vrai garde-fou est le **build de release** (EAS / Xcode / Gradle), qui doit passer avant soumission.
|
||||
- Un smoke test CI ne confirme que « l'app build et boote » — ce qu'un build local valide déjà. Le seul delta réel (« marche sur ma machine mais pas sur un env propre ») est déjà couvert par le build cloud EAS.
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Grille de décision à réévaluer selon le contexte :
|
||||
- **Dev solo / petite équipe, plan CI gratuit** → retrait défendable, smoke en local pour diagnostic ponctuel.
|
||||
- **Si on garde une CI mobile** → ne pas la rendre bloquante sans données de flake calibrées (émulateurs sujets au flake) ; limiter le coût macOS via paths-filter ou réserver iOS au `push main`.
|
||||
- **Équipe qui grandit / multiples contributeurs** → la CI mobile reprend de la valeur (env partagé, PR de tiers) — réévaluer.
|
||||
- Anti-pattern à éviter : un job CI mobile coûteux « par principe » sans avoir identifié quelle classe de bug il attrape que le build local n'attrape pas.
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-modele-donnees-avant-spec"></a>
|
||||
|
||||
## Vérifier le modèle de données réel avant d'accepter une spec
|
||||
|
||||
- Date : 2026-06-09
|
||||
- Statut : Accepted
|
||||
- Périmètre : global / méthode
|
||||
|
||||
### Contexte
|
||||
|
||||
Une spec ou une architecture peut supposer une capacité du modèle de données (cumul, multi-valué, relation) qui n'existe pas dans le code réel. Piège récurrent qui fait perdre du temps ou produit une implémentation fausse si on ne vérifie pas. Cas vécu RL799_V2 : l'architecture v2 (décision D1) décrivait une synchro `OfficerMandate → UserRole` supposant un **cumul de rôles**, alors que `User.role` est un enum Postgres **mono-valué** (un seul rôle par user). Dériver un rôle aurait écrasé le rôle existant → violation directe d'une NFR (cumul préservé).
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Accepter la spec telle quelle et coder sur le modèle supposé
|
||||
- Ouvrir le schéma réel (Prisma/SQL) et confirmer la cardinalité du champ avant de cadrer l'implémentation
|
||||
|
||||
### Décision
|
||||
|
||||
Quand une spec suppose « ajouter un rôle / cumuler / multi-valué / relation », **ouvrir le schéma (Prisma/SQL) et confirmer la cardinalité réelle du champ AVANT de cadrer l'implémentation.**
|
||||
|
||||
### Justification
|
||||
|
||||
- La hiérarchie de règles s'applique : **contraintes réelles du code > règles archi**. Une spec ne peut pas créer une capacité que le modèle n'a pas.
|
||||
- Une implémentation sur un modèle supposé produit une régression silencieuse (ici, écrasement de rôle).
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Vérification systématique du schéma déclaratif avant tout cadrage qui suppose une capacité du modèle.
|
||||
- Si contradiction archi ↔ code, **ne pas trancher seul** — remonter au décideur (c'est une décision produit/archi, pas technique).
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-segmentation-auth-sensibilite"></a>
|
||||
|
||||
## Segmenter l'auth par sensibilité d'action (forte vs sans-friction)
|
||||
|
||||
- Date : 2026-06-13
|
||||
- Statut : Accepted
|
||||
- Périmètre : global / auth
|
||||
|
||||
### Contexte
|
||||
|
||||
Deux populations/usages d'une même app peuvent légitimement exiger des régimes d'auth **opposés** : une action sensible (secrétaire, trésorier, admin VM) appelle une auth forte (IdP, MFA) ; un geste trivial à fort besoin d'adoption (répondre présent, RSVP) appelle l'inverse — aucune friction. Cas vécu RL799_V2 : développement de `presence-sans-friction` (quick-link, token opaque) en parallèle d'un cap Keycloak.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Uniformiser l'auth (même régime fort partout) → tue l'adoption du geste trivial
|
||||
- Segmenter par sensibilité d'action : friction proportionnelle à la sensibilité
|
||||
|
||||
### Décision
|
||||
|
||||
**Segmenter l'auth par sensibilité d'action plutôt que d'uniformiser.** La friction acceptable est proportionnelle à la sensibilité de l'action : action sensible → auth forte ; geste trivial → token opaque sans login.
|
||||
|
||||
### Justification
|
||||
|
||||
- Ce n'est pas une contradiction mais une segmentation : exiger une auth forte sur un RSVP tue l'adoption sans gain de sécurité réel.
|
||||
- Condition de coexistence : les deux régimes vivent sur des **plans orthogonaux** (routes protégées vs `/api/public/*`), et le token sans-friction est **souverain** — JAMAIS couplé au système d'auth (ni JWT-maison, ni IdP).
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Test de l'invariant : « le geste sans-friction fonctionne-t-il si l'utilisateur n'a aucun compte / si l'IdP est down ? » → doit être OUI.
|
||||
- Implémentation côté API : voir `pattern-surface-publique-token-opaque` dans `knowledge/backend/patterns/auth.md` (durcissement du token opaque). La présente décision en est le cadrage stratégique.
|
||||
|
||||
---
|
||||
|
||||
## 2. Infra
|
||||
|
||||
<a id="decision-structure-docker"></a>
|
||||
@@ -903,6 +1011,53 @@ Principes :
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-idp-keycloak-auth-only"></a>
|
||||
|
||||
## IdP centralisé (Keycloak) en auth-only + RBAC métier local, pour une architecture multi-instances fédérée
|
||||
|
||||
- Date : 2026-06-12
|
||||
- Statut : Proposed (epic futur, horizon < 1 an)
|
||||
- Périmètre : backend / auth / multi-tenant
|
||||
|
||||
### Contexte
|
||||
|
||||
Application interne (loge maçonnique, RL799_V2) avec auth JWT-maison (cookie httpOnly) et un RBAC mandate-based récent (union `{role} ∪ {offices}` dérivée des `OfficerMandate`). Cap réel à < 1 an : plusieurs instances (1 loge = 1 VPS, données isolées — pas de multi-tenant DB) mais **identité d'authentification centralisée et fédérée** (un Frère membre de 2 loges = 1 identité). Besoin : auth éprouvée (MFA, standards OIDC) + fédération cross-instance, SANS sacrifier l'isolation des données ni le RBAC métier.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- **(a) Durcir l'auth maison** — ne répond pas à la fédération.
|
||||
- **(b) Lib d'auth in-app (type Auth.js)** — ne fédère pas N apps.
|
||||
- **(c) IdP centralisé (Keycloak / Authentik / Zitadel)** — répond au multi-instances fédéré. **Keycloak retenu** (parti pris assumé).
|
||||
|
||||
### Décision
|
||||
|
||||
Keycloak en **auth-only**. Frontière en **3 couches** :
|
||||
|
||||
1. credential + identité = Keycloak (login, MFA, reset, `email_verified`, first-password) ;
|
||||
2. **pont = une seule colonne `User.keycloakSub`** ;
|
||||
3. autorisation métier = app locale (RBAC mandate-based **inchangé**).
|
||||
|
||||
Le token OIDC porte UNIQUEMENT l'identité (`sub`, `email`, état civil, `iss`/`aud`/`exp`) ; **JAMAIS** de grade/office/rôle. **Invariant sacré : aucune donnée d'autorisation ne franchit vers Keycloak.**
|
||||
|
||||
### Justification
|
||||
|
||||
- Le grade/office est local par nature (un Frère peut être Vénérable en loge A et Apprenti en loge B) → ne peut pas vivre dans une identité globale.
|
||||
- Point de jonction code minimal : un `keycloakTokenValidator` (JWKS/issuer/audience) remplace `verifyJwt` EN AMONT du RBAC ; le middleware RBAC et les guards ne changent pas (le `sub` remplace le `userId`).
|
||||
- Simplification nette de l'app : disparition du code credential (first-password, reset, hashing) → migre côté Keycloak. Compense partiellement le coût opérationnel d'un serveur de plus.
|
||||
- Provisioning **app-first** (flux d'enregistrement VM existant + Admin API Keycloak → écrit `keycloakSub`). Rattachement multi-loges par **invitation + login Keycloak prouvé** (jamais auto-rattachement par email). Dé-provision en **ref-count** : identité Keycloak supprimée seulement au départ de la DERNIÈRE loge → croise le chantier RGPD/anonymisation.
|
||||
- Cohabitation avec l'auth-less : les routes guest (`/api/public/*`) restent HORS Keycloak (cf. décision « Segmenter l'auth par sensibilité d'action »).
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Epic à risque → découpage en lots Go/No-Go (PoC OIDC → validation token API → pont identité → login frontend → préservation routes guest → bascule + retrait JWT-maison → déploiement Keycloak prod).
|
||||
- Migration initiale : import des users existants dans Keycloak (par email) + back-fill `keycloakSub` (one-shot à blinder).
|
||||
- UX : l'écran de login devient celui de Keycloak (thème Freemarker/CSS custom ou page distincte) — continuité visuelle à soigner.
|
||||
- Volume multi-appartenance INCONNU → architecture prête (un même `sub` partageable par N `User`) mais flux de rattachement fluide implémenté SEULEMENT si le volume le justifie (ne pas sur-construire).
|
||||
- Points de couture avec l'existant : `invitation-magic-link-v2` (entrée) + anonymisation RGPD (sortie).
|
||||
- Patterns d'implémentation de la membrane fédérée déjà capitalisés : voir `pattern-membrane-auth-federee` et `pattern-pont-identite-federee` dans `knowledge/backend/patterns/auth.md`. La présente entrée en est le cadrage ADR (le « pourquoi ce choix »).
|
||||
|
||||
---
|
||||
|
||||
## 4. n8n
|
||||
|
||||
<a id="decision-n8n-mini-systemes"></a>
|
||||
|
||||
Reference in New Issue
Block a user