mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-04-06 13:31:43 +02:00
ajout patterns
This commit is contained in:
@@ -8,27 +8,380 @@ Objectifs :
|
||||
- éviter de reposer les mêmes questions
|
||||
- assumer les compromis
|
||||
|
||||
Dernière mise à jour : 2026-03-10
|
||||
Dernière mise à jour : 2026-03-12
|
||||
|
||||
---
|
||||
|
||||
## Index
|
||||
## Pré-index par section
|
||||
|
||||
1. [Global](#section-global)
|
||||
2. [Infra](#section-infra)
|
||||
3. [Backend](#section-backend)
|
||||
4. [n8n](#section-n8n)
|
||||
|
||||
## Index détaillé
|
||||
|
||||
### 1. Global
|
||||
|
||||
<a id="section-global"></a>
|
||||
|
||||
- [Story sizing — foundations vs qualité non bloquante](#decision-story-sizing-foundations)
|
||||
- [Code review adversariale — contexte frais](#decision-code-review-adversariale)
|
||||
- [Workflows n8n complexes = mini-systèmes](#decision-n8n-mini-systemes)
|
||||
- [Le front-end est un logiciel en production](#decision-frontend-production)
|
||||
- [Le back-end est un logiciel en production](#decision-backend-production)
|
||||
- [Contrats d’API explicites et versionnés](#decision-contrats-api)
|
||||
- [Single source of truth des contrats — schémas runtime partagés (Zod) + z.infer (No-DTO)](#decision-contrats-sso-zod)
|
||||
- [User views — User public par défaut + MeUser explicite](#decision-user-views)
|
||||
|
||||
### 2. Infra
|
||||
|
||||
<a id="section-infra"></a>
|
||||
|
||||
- [Structure Docker et données persistantes](#decision-structure-docker)
|
||||
- [Accès réseau des VM de développement via Tailscale](#decision-reseau-tailscale-vm-dev)
|
||||
|
||||
### 3. Backend
|
||||
|
||||
<a id="section-backend"></a>
|
||||
|
||||
- [Le back-end est un logiciel en production](#decision-backend-production)
|
||||
- [Contrats d’API explicites et versionnés](#decision-contrats-api)
|
||||
- [Gestion standard des erreurs et des statuts HTTP](#decision-erreurs-http)
|
||||
- [Migrations et évolution de schéma maîtrisées](#decision-migrations)
|
||||
- [Observabilité minimale obligatoire](#decision-observabilite)
|
||||
- [Authentification et autorisation centrales](#decision-auth-central)
|
||||
- [Idempotence et gestion des retries](#decision-idempotence-retries)
|
||||
- [Structure Docker et données persistantes](#decision-structure-docker)
|
||||
- [Accès réseau des VM de développement via Tailscale](#decision-reseau-tailscale-vm-dev)
|
||||
|
||||
### 4. n8n
|
||||
|
||||
<a id="section-n8n"></a>
|
||||
|
||||
- [Workflows n8n complexes = mini-systèmes](#decision-n8n-mini-systemes)
|
||||
|
||||
---
|
||||
|
||||
## _Format standard d’une décision_
|
||||
|
||||
## <Titre>
|
||||
|
||||
- Date : YYYY-MM-DD
|
||||
- Statut : Proposed | Accepted | Deprecated
|
||||
- Périmètre : n8n | backend | infra | global
|
||||
|
||||
### Contexte
|
||||
|
||||
### Options envisagées
|
||||
|
||||
### Décision
|
||||
|
||||
### Justification
|
||||
|
||||
### Conséquences
|
||||
|
||||
---
|
||||
|
||||
## 1. Global
|
||||
|
||||
<a id="decision-story-sizing-foundations"></a>
|
||||
|
||||
## Story sizing — foundations bloquantes vs qualité non bloquante (CI mobile)
|
||||
|
||||
- Date : 2026-03-09
|
||||
- Statut : Accepted
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Des items “infra” ont été mis dans des stories foundations d’epic alors qu’aucune story métier suivante n’en dépendait (ex : CI Maestro mobile iOS/Android).
|
||||
Résultat observé : story foundations “never-done”, friction et coût de contexte, sans bénéfice sur le throughput métier.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Mettre toutes les améliorations de qualité dans foundations “par principe”
|
||||
- Séparer les prérequis réellement bloquants du reste (qualité non bloquante)
|
||||
|
||||
### Décision
|
||||
|
||||
On distingue explicitement :
|
||||
|
||||
- **Prérequis bloquants** : à inclure dans foundations (les stories suivantes en dépendent)
|
||||
- **Qualité non bloquante** : story indépendante, en parallèle ou après, sans bloquer le métier
|
||||
|
||||
### Justification
|
||||
|
||||
- Un epic doit pouvoir avancer sur le métier dès que les dépendances techniques minimales sont là
|
||||
- Les chantiers “qualité” (CI mobile, perf, audits…) ont souvent une inertie qui ne doit pas geler l’epic
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Pour chaque AC “infra” en foundations : poser la question “la story X+1 est-elle bloquée si ce n’est pas fait ?”
|
||||
- Si la réponse est non : sortir l’AC en story dédiée (tag qualité / infra), et la planifier à part
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-code-review-adversariale"></a>
|
||||
|
||||
## Code review adversariale — passe dédiée en contexte frais
|
||||
|
||||
- Date : 2026-03-09
|
||||
- Statut : Accepted
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Certaines issues CRITICAL sont invisibles dans le contexte d’implémentation (biais de confirmation : “je sais comment c’est censé marcher”).
|
||||
Elles émergent uniquement en lecture froide : fondations manquantes, usages dépréciés, invariants non respectés (ex : sessions sans TTL).
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Review “au fil de l’eau” dans le même contexte que l’implémentation
|
||||
- Review dédiée, séparée, en contexte frais (nouvelle session / nouveau modèle / reviewer différent)
|
||||
|
||||
### Décision
|
||||
|
||||
La code review doit être une passe **séparée** de l’implémentation, en **contexte frais**, avec un objectif explicite : chercher des CRITICAL sans concession.
|
||||
|
||||
### Justification
|
||||
|
||||
- Les incohérences systémiques (sécurité, idempotence, TTL, drift de contracts) se détectent mieux en lecture froide
|
||||
- Réduit fortement le coût de debug tardif (prod/staging) et les refactors “de fondations”
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Process recommandé :
|
||||
1. Dev termine l’implémentation, marque la story `review`
|
||||
2. Nouvelle session (contexte frais) : charger uniquement story + diff
|
||||
3. Review adversariale : lister CRITICAL + mitigations
|
||||
4. Corriger avant `done`
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-frontend-production"></a>
|
||||
|
||||
## Le front-end est un logiciel en production
|
||||
|
||||
- Date : 2026-01-25
|
||||
- Statut : Accepted
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Les applications front-end modernes (SPA, webapps) portent une part significative
|
||||
de la logique applicative : state, validations, permissions, erreurs, performance,
|
||||
sécurité côté client, expérience utilisateur.
|
||||
|
||||
Les traiter comme une simple “couche UI” conduit régulièrement à :
|
||||
|
||||
- une dette technique rapide,
|
||||
- des bugs difficiles à diagnostiquer,
|
||||
- une expérience utilisateur incohérente,
|
||||
- une maintenance coûteuse dans le temps.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Traiter le front-end comme une couche de rendu légère, peu structurée
|
||||
- Traiter le front-end comme un logiciel à part entière, avec des exigences similaires au backend
|
||||
|
||||
### Décision
|
||||
|
||||
Le front-end est traité comme un **logiciel en production**.
|
||||
|
||||
Il est soumis aux mêmes principes que le backend :
|
||||
|
||||
- architecture explicite,
|
||||
- gestion des erreurs,
|
||||
- conventions de code,
|
||||
- tests au bon niveau,
|
||||
- attention portée à la maintenabilité et à l’évolution.
|
||||
|
||||
### Justification
|
||||
|
||||
- Le front concentre une logique métier et technique réelle
|
||||
- Les bugs front ont un impact direct sur les utilisateurs
|
||||
- La complexité augmente mécaniquement avec le produit
|
||||
- Les choix initiaux conditionnent fortement la maintenabilité future
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Mise en place de patterns front validés et documentés
|
||||
- Gestion explicite des états UI, erreurs et formulaires
|
||||
- Attention portée à la performance et à l’accessibilité
|
||||
- Acceptation d’un léger surcoût initial pour réduire la dette long terme
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-contrats-sso-zod"></a>
|
||||
|
||||
## Single source of truth des contrats — schémas runtime partagés (Zod) + z.infer (No-DTO)
|
||||
|
||||
- Date : 2026-03-10
|
||||
- Statut : Proposed
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
TypeScript ne valide pas les payloads HTTP au runtime (les types disparaissent à l’exécution).
|
||||
Quand on maintient à la fois des DTO/back (ex. Nest + decorators) et des types/contracts côté clients, on obtient une double source de vérité → drift, régressions, temps de debug.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- DTO NestJS + `class-validator` (validation runtime OK côté API, mais non partageable tel quel côté clients → duplication ou génération)
|
||||
- Schémas runtime partagés dans un package `contracts` + types dérivés (validation + types alignés)
|
||||
- OpenAPI/JSON Schema “first” + codegen (artefact contractuel unique, mais pipeline/outillage à maintenir)
|
||||
|
||||
### Décision
|
||||
|
||||
La source de vérité des contrats API↔clients est un package `contracts` contenant des **schémas runtime** (Zod), et les types TypeScript sont **dérivés** via `z.infer` (No-DTO / pas de redéfinition locale).
|
||||
|
||||
Principe opérationnel :
|
||||
|
||||
- validation concentrée aux frontières (ex. pipe/guard de validation côté API),
|
||||
- le reste du code consomme des **types** (et non des classes DTO redondantes),
|
||||
- les contrats restent “wire-level” (pas de métier, pas de stores, pas de classes Nest).
|
||||
|
||||
### Justification
|
||||
|
||||
- Un seul artefact sert à la fois de validation runtime et de typage compile-time
|
||||
- Propagation des changements plus fiable (compile + tests) → réduction du temps de debug
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Dépendance assumée à Zod dans `contracts`
|
||||
- Les clients consomment les types; la validation côté client reste optionnelle (utile surtout sur entrées non-API : storage, deeplinks, etc.)
|
||||
- En contexte non-mobile (Nest/React), OpenAPI-first + codegen reste une alternative valide si multi-clients/externe ou besoin fort de contrat public/documenté
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-user-views"></a>
|
||||
|
||||
## User views — User public par défaut + MeUser explicite
|
||||
|
||||
- Date : 2026-03-10
|
||||
- Statut : Proposed
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Un “User” complet est rarement un bon contrat universel : il peut contenir des champs sensibles (email, adresse, téléphone, flags internes…).
|
||||
Les dérivations TypeScript seules (`Omit<User, "password">`) ne protègent pas au runtime et favorisent les fuites accidentelles.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Un type `User` “god object” + dérivations TS (Omit/Pick) au cas par cas
|
||||
- Des “views” explicites par contexte (public, self, admin…), dérivées depuis les schémas runtime
|
||||
- Un modèle unique côté DB + sérialisation implicite (risque élevé de fuite)
|
||||
|
||||
### Décision
|
||||
|
||||
`User` (dans les contracts) est **public par défaut** et minimal (safe-by-default).
|
||||
La vue self/compte est un contrat séparé `MeUser`.
|
||||
Toute vue plus riche est créée explicitement et nommée (ex. `AdminUser`, `UserDirectoryEntry`).
|
||||
|
||||
Règles associées :
|
||||
|
||||
- les vues sont dérivées depuis les schémas runtime (extend/pick/omit) + `z.infer`
|
||||
- `password` (et assimilés) n’existe que dans des requêtes d’auth (login/register/reset/change), jamais dans un `User*`
|
||||
|
||||
### Justification
|
||||
|
||||
- Réduit le risque de fuite de données et clarifie les permissions/UX
|
||||
- Évite les champs optionnels ambigus et les contrats “implicites”
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Chaque endpoint choisit explicitement la vue renvoyée (et côté DB, un `select` explicite par vue)
|
||||
- Les clients typent “public” vs “mon compte” distinctement
|
||||
- Des tests “no secret keys” sur réponses user/auth deviennent simples et efficaces
|
||||
|
||||
---
|
||||
|
||||
## 2. Infra
|
||||
|
||||
<a id="decision-structure-docker"></a>
|
||||
|
||||
## Convention de structure pour les projets Docker et les données persistantes
|
||||
|
||||
- Date : 2026-03-06
|
||||
- Statut : Accepted
|
||||
- Périmètre : infra
|
||||
|
||||
### Contexte
|
||||
|
||||
Sur un serveur de développement (NUC / VM docker-dev), Docker mélange facilement
|
||||
code applicatif, données persistantes, volumes et backups si aucune convention
|
||||
n’est définie.
|
||||
|
||||
Avec le temps cela rend :
|
||||
|
||||
- les sauvegardes ambiguës
|
||||
- le nettoyage risqué
|
||||
- la compréhension de l’infrastructure difficile
|
||||
- la reconstruction d’un environnement compliquée
|
||||
|
||||
Une structure simple et explicite permet d’éviter ces problèmes.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Laisser Docker gérer implicitement les volumes (`/var/lib/docker/volumes`)
|
||||
- Laisser chaque projet organiser librement ses dossiers
|
||||
- Définir une convention globale claire séparant code, données et sauvegardes
|
||||
|
||||
### Décision
|
||||
|
||||
La structure standard suivante est adoptée sur les machines d’infrastructure
|
||||
(NUC / serveurs de développement) :
|
||||
|
||||
```
|
||||
/srv
|
||||
├ projects
|
||||
├ docker-data
|
||||
└ backups
|
||||
```
|
||||
|
||||
Principes :
|
||||
|
||||
- `/srv/projects`
|
||||
contient les projets applicatifs (code, `docker-compose.yml`, `.env`, scripts).
|
||||
|
||||
- `/srv/docker-data`
|
||||
contient les données persistantes des conteneurs (bases de données, uploads,
|
||||
état applicatif).
|
||||
|
||||
- `/srv/backups`
|
||||
contient les dumps, archives et exports destinés à la sauvegarde.
|
||||
|
||||
### Justification
|
||||
|
||||
- séparation claire **code / données / sauvegardes**
|
||||
- sauvegardes plus simples et plus fiables
|
||||
- nettoyage d’un projet possible sans risque pour les autres
|
||||
- lisibilité immédiate de l’infrastructure
|
||||
- reproductibilité de l’environnement
|
||||
|
||||
### Conséquences
|
||||
|
||||
Les conteneurs utilisent en priorité des **bind mounts explicites**, par exemple :
|
||||
|
||||
```txt
|
||||
/srv/docker-data/monapp-postgres:/var/lib/postgresql/data
|
||||
```
|
||||
|
||||
Les volumes Docker implicites (`/var/lib/docker/volumes`) sont évités quand la
|
||||
lisibilité et la maintenabilité priment.
|
||||
|
||||
Les données critiques à sauvegarder se trouvent principalement dans :
|
||||
|
||||
```
|
||||
/srv/projects
|
||||
/srv/docker-data
|
||||
```
|
||||
|
||||
Convention de nommage recommandée pour les dossiers de données :
|
||||
|
||||
```
|
||||
ex :
|
||||
rl799-postgres
|
||||
monapp-redis
|
||||
n8n-postgres
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -129,190 +482,7 @@ Cette convention est recommandée pour toutes les nouvelles VM du NUC, notamment
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-story-sizing-foundations"></a>
|
||||
|
||||
## Story sizing — foundations bloquantes vs qualité non bloquante (CI mobile)
|
||||
|
||||
- Date : 2026-03-09
|
||||
- Statut : Accepted
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Des items “infra” ont été mis dans des stories foundations d’epic alors qu’aucune story métier suivante n’en dépendait (ex : CI Maestro mobile iOS/Android).
|
||||
Résultat observé : story foundations “never-done”, friction et coût de contexte, sans bénéfice sur le throughput métier.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Mettre toutes les améliorations de qualité dans foundations “par principe”
|
||||
- Séparer les prérequis réellement bloquants du reste (qualité non bloquante)
|
||||
|
||||
### Décision
|
||||
|
||||
On distingue explicitement :
|
||||
|
||||
- **Prérequis bloquants** : à inclure dans foundations (les stories suivantes en dépendent)
|
||||
- **Qualité non bloquante** : story indépendante, en parallèle ou après, sans bloquer le métier
|
||||
|
||||
### Justification
|
||||
|
||||
- Un epic doit pouvoir avancer sur le métier dès que les dépendances techniques minimales sont là
|
||||
- Les chantiers “qualité” (CI mobile, perf, audits…) ont souvent une inertie qui ne doit pas geler l’epic
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Pour chaque AC “infra” en foundations : poser la question “la story X+1 est-elle bloquée si ce n’est pas fait ?”
|
||||
- Si la réponse est non : sortir l’AC en story dédiée (tag qualité / infra), et la planifier à part
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-code-review-adversariale"></a>
|
||||
|
||||
## Code review adversariale — passe dédiée en contexte frais
|
||||
|
||||
- Date : 2026-03-09
|
||||
- Statut : Accepted
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Certaines issues CRITICAL sont invisibles dans le contexte d’implémentation (biais de confirmation : “je sais comment c’est censé marcher”).
|
||||
Elles émergent uniquement en lecture froide : fondations manquantes, usages dépréciés, invariants non respectés (ex : sessions sans TTL).
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Review “au fil de l’eau” dans le même contexte que l’implémentation
|
||||
- Review dédiée, séparée, en contexte frais (nouvelle session / nouveau modèle / reviewer différent)
|
||||
|
||||
### Décision
|
||||
|
||||
La code review doit être une passe **séparée** de l’implémentation, en **contexte frais**, avec un objectif explicite : chercher des CRITICAL sans concession.
|
||||
|
||||
### Justification
|
||||
|
||||
- Les incohérences systémiques (sécurité, idempotence, TTL, drift de contracts) se détectent mieux en lecture froide
|
||||
- Réduit fortement le coût de debug tardif (prod/staging) et les refactors “de fondations”
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Process recommandé :
|
||||
1. Dev termine l’implémentation, marque la story `review`
|
||||
2. Nouvelle session (contexte frais) : charger uniquement story + diff
|
||||
3. Review adversariale : lister CRITICAL + mitigations
|
||||
4. Corriger avant `done`
|
||||
|
||||
---
|
||||
|
||||
## Format standard d’une décision
|
||||
|
||||
## <Titre>
|
||||
|
||||
- Date : YYYY-MM-DD
|
||||
- Statut : Proposed | Accepted | Deprecated
|
||||
- Périmètre : n8n | backend | infra | global
|
||||
|
||||
### Contexte
|
||||
|
||||
### Options envisagées
|
||||
|
||||
### Décision
|
||||
|
||||
### Justification
|
||||
|
||||
### Conséquences
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-n8n-mini-systemes"></a>
|
||||
|
||||
## Workflows n8n complexes = mini-systèmes
|
||||
|
||||
- Date : 2025-12-19
|
||||
- Statut : Accepted
|
||||
- Périmètre : n8n
|
||||
|
||||
### Contexte
|
||||
|
||||
Certains workflows n8n dépassent le simple enchaînement de nodes et deviennent
|
||||
de véritables systèmes applicatifs (orchestration, état, branches, retries, intégrations multiples).
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Traiter ces workflows comme de simples automatisations “low-code”
|
||||
- Les considérer comme du code à part entière (discipline, patterns, doc, prudence sur upgrades)
|
||||
|
||||
### Décision
|
||||
|
||||
Les considérer comme du code.
|
||||
|
||||
### Justification
|
||||
|
||||
- Complexité réelle (logique, état, orchestration)
|
||||
- Sensibilité aux versions n8n (upgrade-risk)
|
||||
- Besoin de maintenabilité et de capitalisation
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Prudence accrue lors des upgrades
|
||||
- Documentation minimale mais ciblée
|
||||
- Patterns explicitement identifiés et partagés
|
||||
- On accepte d’utiliser du Code (JS) quand nécessaire
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-frontend-production"></a>
|
||||
|
||||
## Le front-end est un logiciel en production
|
||||
|
||||
- Date : 2026-01-25
|
||||
- Statut : Accepted
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Les applications front-end modernes (SPA, webapps) portent une part significative
|
||||
de la logique applicative : state, validations, permissions, erreurs, performance,
|
||||
sécurité côté client, expérience utilisateur.
|
||||
|
||||
Les traiter comme une simple “couche UI” conduit régulièrement à :
|
||||
|
||||
- une dette technique rapide,
|
||||
- des bugs difficiles à diagnostiquer,
|
||||
- une expérience utilisateur incohérente,
|
||||
- une maintenance coûteuse dans le temps.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Traiter le front-end comme une couche de rendu légère, peu structurée
|
||||
- Traiter le front-end comme un logiciel à part entière, avec des exigences similaires au backend
|
||||
|
||||
### Décision
|
||||
|
||||
Le front-end est traité comme un **logiciel en production**.
|
||||
|
||||
Il est soumis aux mêmes principes que le backend :
|
||||
|
||||
- architecture explicite,
|
||||
- gestion des erreurs,
|
||||
- conventions de code,
|
||||
- tests au bon niveau,
|
||||
- attention portée à la maintenabilité et à l’évolution.
|
||||
|
||||
### Justification
|
||||
|
||||
- Le front concentre une logique métier et technique réelle
|
||||
- Les bugs front ont un impact direct sur les utilisateurs
|
||||
- La complexité augmente mécaniquement avec le produit
|
||||
- Les choix initiaux conditionnent fortement la maintenabilité future
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Mise en place de patterns front validés et documentés
|
||||
- Gestion explicite des états UI, erreurs et formulaires
|
||||
- Attention portée à la performance et à l’accessibilité
|
||||
- Acceptation d’un léger surcoût initial pour réduire la dette long terme
|
||||
|
||||
---
|
||||
## 3. Backend
|
||||
|
||||
<a id="decision-backend-production"></a>
|
||||
|
||||
@@ -407,91 +577,6 @@ Minimum attendu :
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-contrats-sso-zod"></a>
|
||||
|
||||
## Single source of truth des contrats — schémas runtime partagés (Zod) + z.infer (No-DTO)
|
||||
|
||||
- Date : 2026-03-10
|
||||
- Statut : Proposed
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
TypeScript ne valide pas les payloads HTTP au runtime (les types disparaissent à l’exécution).
|
||||
Quand on maintient à la fois des DTO/back (ex. Nest + decorators) et des types/contracts côté clients, on obtient une double source de vérité → drift, régressions, temps de debug.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- DTO NestJS + `class-validator` (validation runtime OK côté API, mais non partageable tel quel côté clients → duplication ou génération)
|
||||
- Schémas runtime partagés dans un package `contracts` + types dérivés (validation + types alignés)
|
||||
- OpenAPI/JSON Schema “first” + codegen (artefact contractuel unique, mais pipeline/outillage à maintenir)
|
||||
|
||||
### Décision
|
||||
|
||||
La source de vérité des contrats API↔clients est un package `contracts` contenant des **schémas runtime** (Zod), et les types TypeScript sont **dérivés** via `z.infer` (No-DTO / pas de redéfinition locale).
|
||||
|
||||
Principe opérationnel :
|
||||
|
||||
- validation concentrée aux frontières (ex. pipe/guard de validation côté API),
|
||||
- le reste du code consomme des **types** (et non des classes DTO redondantes),
|
||||
- les contrats restent “wire-level” (pas de métier, pas de stores, pas de classes Nest).
|
||||
|
||||
### Justification
|
||||
|
||||
- Un seul artefact sert à la fois de validation runtime et de typage compile-time
|
||||
- Propagation des changements plus fiable (compile + tests) → réduction du temps de debug
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Dépendance assumée à Zod dans `contracts`
|
||||
- Les clients consomment les types; la validation côté client reste optionnelle (utile surtout sur entrées non-API : storage, deeplinks, etc.)
|
||||
- En contexte non-mobile (Nest/React), OpenAPI-first + codegen reste une alternative valide si multi-clients/externe ou besoin fort de contrat public/documenté
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-user-views"></a>
|
||||
|
||||
## User views — User public par défaut + MeUser explicite
|
||||
|
||||
- Date : 2026-03-10
|
||||
- Statut : Proposed
|
||||
- Périmètre : global
|
||||
|
||||
### Contexte
|
||||
|
||||
Un “User” complet est rarement un bon contrat universel : il peut contenir des champs sensibles (email, adresse, téléphone, flags internes…).
|
||||
Les dérivations TypeScript seules (`Omit<User, "password">`) ne protègent pas au runtime et favorisent les fuites accidentelles.
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Un type `User` “god object” + dérivations TS (Omit/Pick) au cas par cas
|
||||
- Des “views” explicites par contexte (public, self, admin…), dérivées depuis les schémas runtime
|
||||
- Un modèle unique côté DB + sérialisation implicite (risque élevé de fuite)
|
||||
|
||||
### Décision
|
||||
|
||||
`User` (dans les contracts) est **public par défaut** et minimal (safe-by-default).
|
||||
La vue self/compte est un contrat séparé `MeUser`.
|
||||
Toute vue plus riche est créée explicitement et nommée (ex. `AdminUser`, `UserDirectoryEntry`).
|
||||
|
||||
Règles associées :
|
||||
|
||||
- les vues sont dérivées depuis les schémas runtime (extend/pick/omit) + `z.infer`
|
||||
- `password` (et assimilés) n’existe que dans des requêtes d’auth (login/register/reset/change), jamais dans un `User*`
|
||||
|
||||
### Justification
|
||||
|
||||
- Réduit le risque de fuite de données et clarifie les permissions/UX
|
||||
- Évite les champs optionnels ambigus et les contrats “implicites”
|
||||
|
||||
### Conséquences
|
||||
|
||||
- Chaque endpoint choisit explicitement la vue renvoyée (et côté DB, un `select` explicite par vue)
|
||||
- Les clients typent “public” vs “mon compte” distinctement
|
||||
- Des tests “no secret keys” sur réponses user/auth deviennent simples et efficaces
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-erreurs-http"></a>
|
||||
|
||||
## Gestion standard des erreurs et des statuts HTTP
|
||||
@@ -703,92 +788,41 @@ Principes :
|
||||
|
||||
---
|
||||
|
||||
<a id="decision-structure-docker"></a>
|
||||
## 4. n8n
|
||||
|
||||
## Convention de structure pour les projets Docker et les données persistantes
|
||||
<a id="decision-n8n-mini-systemes"></a>
|
||||
|
||||
- Date : 2026-03-06
|
||||
## Workflows n8n complexes = mini-systèmes
|
||||
|
||||
- Date : 2025-12-19
|
||||
- Statut : Accepted
|
||||
- Périmètre : infra
|
||||
- Périmètre : n8n
|
||||
|
||||
### Contexte
|
||||
|
||||
Sur un serveur de développement (NUC / VM docker-dev), Docker mélange facilement
|
||||
code applicatif, données persistantes, volumes et backups si aucune convention
|
||||
n’est définie.
|
||||
|
||||
Avec le temps cela rend :
|
||||
|
||||
- les sauvegardes ambiguës
|
||||
- le nettoyage risqué
|
||||
- la compréhension de l’infrastructure difficile
|
||||
- la reconstruction d’un environnement compliquée
|
||||
|
||||
Une structure simple et explicite permet d’éviter ces problèmes.
|
||||
Certains workflows n8n dépassent le simple enchaînement de nodes et deviennent
|
||||
de véritables systèmes applicatifs (orchestration, état, branches, retries, intégrations multiples).
|
||||
|
||||
### Options envisagées
|
||||
|
||||
- Laisser Docker gérer implicitement les volumes (`/var/lib/docker/volumes`)
|
||||
- Laisser chaque projet organiser librement ses dossiers
|
||||
- Définir une convention globale claire séparant code, données et sauvegardes
|
||||
- Traiter ces workflows comme de simples automatisations “low-code”
|
||||
- Les considérer comme du code à part entière (discipline, patterns, doc, prudence sur upgrades)
|
||||
|
||||
### Décision
|
||||
|
||||
La structure standard suivante est adoptée sur les machines d’infrastructure
|
||||
(NUC / serveurs de développement) :
|
||||
|
||||
```
|
||||
/srv
|
||||
├ projects
|
||||
├ docker-data
|
||||
└ backups
|
||||
```
|
||||
|
||||
Principes :
|
||||
|
||||
- `/srv/projects`
|
||||
contient les projets applicatifs (code, `docker-compose.yml`, `.env`, scripts).
|
||||
|
||||
- `/srv/docker-data`
|
||||
contient les données persistantes des conteneurs (bases de données, uploads,
|
||||
état applicatif).
|
||||
|
||||
- `/srv/backups`
|
||||
contient les dumps, archives et exports destinés à la sauvegarde.
|
||||
Les considérer comme du code.
|
||||
|
||||
### Justification
|
||||
|
||||
- séparation claire **code / données / sauvegardes**
|
||||
- sauvegardes plus simples et plus fiables
|
||||
- nettoyage d’un projet possible sans risque pour les autres
|
||||
- lisibilité immédiate de l’infrastructure
|
||||
- reproductibilité de l’environnement
|
||||
- Complexité réelle (logique, état, orchestration)
|
||||
- Sensibilité aux versions n8n (upgrade-risk)
|
||||
- Besoin de maintenabilité et de capitalisation
|
||||
|
||||
### Conséquences
|
||||
|
||||
Les conteneurs utilisent en priorité des **bind mounts explicites**, par exemple :
|
||||
|
||||
```txt
|
||||
/srv/docker-data/monapp-postgres:/var/lib/postgresql/data
|
||||
```
|
||||
|
||||
Les volumes Docker implicites (`/var/lib/docker/volumes`) sont évités quand la
|
||||
lisibilité et la maintenabilité priment.
|
||||
|
||||
Les données critiques à sauvegarder se trouvent principalement dans :
|
||||
|
||||
```
|
||||
/srv/projects
|
||||
/srv/docker-data
|
||||
```
|
||||
|
||||
Convention de nommage recommandée pour les dossiers de données :
|
||||
|
||||
```
|
||||
ex :
|
||||
rl799-postgres
|
||||
monapp-redis
|
||||
n8n-postgres
|
||||
```
|
||||
- Prudence accrue lors des upgrades
|
||||
- Documentation minimale mais ciblée
|
||||
- Patterns explicitement identifiés et partagés
|
||||
- On accepte d’utiliser du Code (JS) quand nécessaire
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user