Files
_Assistant_Lead_Tech/40_decisions_et_archi.md
MaksTinyWorkshop 019a6d2787 Update :)
2026-03-16 15:24:02 +01:00

26 KiB
Raw Blame History

Décisions techniques & architecture

Ce fichier documente les choix importants (format type ADR mais léger).

Objectifs :

  • garder une trace du raisonnement
  • éviter de reposer les mêmes questions
  • assumer les compromis

Dernière mise à jour : 2026-03-12


Pré-index par section

  1. Global
  2. Infra
  3. Backend
  4. n8n

Index détaillé

1. Global

2. Infra

3. Backend

4. n8n


Format standard dune décision

  • 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

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 depic alors quaucune story métier suivante nen 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 lepic

Conséquences

  • Pour chaque AC “infra” en foundations : poser la question “la story X+1 est-elle bloquée si ce nest pas fait ?”
  • Si la réponse est non : sortir lAC en story dédiée (tag qualité / infra), et la planifier à part

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 dimplémentation (biais de confirmation : “je sais comment cest 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 leau” dans le même contexte que limplé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 limplé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 limplémentation, marque la story review
    2. Nouvelle session (contexte frais) : charger uniquement story + diff
    3. Review adversariale : lister CRITICAL + mitigations
    4. Corriger avant done

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 à laccessibilité
  • Acceptation dun léger surcoût initial pour réduire la dette long terme

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 à lexé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é

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) nexiste que dans des requêtes dauth (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

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 nest définie.

Avec le temps cela rend :

  • les sauvegardes ambiguës
  • le nettoyage risqué
  • la compréhension de linfrastructure difficile
  • la reconstruction dun 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 dinfrastructure (NUC / serveurs de développement) :

/srv
├ helpers
├ infra
├ projects
├ shared
├ docker-data
└ backups

Principes :

  • /srv/helpers contient les dépôts, scripts et bases de connaissance transverses utilisés par plusieurs projets ou par les agents (ex : _Assistant_Lead_Tech).

  • /srv/infra contient les éléments dinfrastructure mutualisés ou transverses à la machine (reverse proxy, stacks techniques partagées, supervision, administration).

  • /srv/projects contient les projets applicatifs (code, docker-compose.yml, .env, scripts).

  • /srv/shared contient les ressources partagées entre plusieurs projets quand elles ne relèvent ni du code dun projet donné ni dune donnée Docker persistante dun seul service.

  • /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
  • séparation explicite entre projets applicatifs, outillage transverse, infrastructure mutualisée et ressources partagées
  • sauvegardes plus simples et plus fiables
  • nettoyage dun projet possible sans risque pour les autres
  • lisibilité immédiate de linfrastructure
  • reproductibilité de lenvironnement

Conséquences

Les conteneurs utilisent en priorité des bind mounts explicites, par exemple :

/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/helpers
/srv/infra
/srv/projects
/srv/shared
/srv/docker-data

Règle de placement :

  • si cest le code ou la config dune application donnée : /srv/projects/<nom>
  • si cest de la donnée persistante dun conteneur : /srv/docker-data/<nom>/...
  • si cest un backup ou un export destiné à la restauration : /srv/backups/<nom>/...
  • si cest un outil, script ou référentiel transverse : /srv/helpers/...
  • si cest une stack ou une configuration infra mutualisée : /srv/infra/...
  • si cest une ressource commune à plusieurs projets, hors données Docker : /srv/shared/...

Convention de nommage recommandée pour les dossiers de données :

ex :
rl799-postgres
monapp-redis
n8n-postgres

Accès réseau des VM de développement via Tailscale

  • Date : 2026-03-12
  • Statut : Accepted
  • Périmètre : infra

Contexte

Les machines de développement personnelles (NUC / homelab) hébergent plusieurs VM :

  • Home Assistant
  • Docker-dev
  • OpenClaw
  • autres services internes

Ces VM exposent parfois :

  • SSH
  • bases de données
  • interfaces web dadministration
  • services de développement

Exposer ces services sur le LAN local ou sur Internet augmente inutilement la surface dattaque et complique la lecture de linfrastructure.

Le réseau privé Tailscale est utilisé comme couche daccès sécurisée entre les machines de confiance.

Options envisagées

  • Exposer certains services sur le LAN local et filtrer “au cas par cas”
  • Utiliser Tailscale comme frontière réseau principale pour les accès dadministration et de développement
  • Lier directement les services à une interface donnée sans politique firewall explicite

Décision

Les VM internes nacceptent les connexions entrantes que via linterface Tailscale.

Le pare-feu local (ufw) applique cette politique avec la configuration minimale suivante :

ufw default deny incoming
ufw default allow outgoing

Les services explicitement nécessaires sont autorisés uniquement sur tailscale0.

Exemples :

ufw allow in on tailscale0 to any port 22
ufw allow in on tailscale0 to any port 8080
ufw allow in on tailscale0 to any port 5432

Tout accès depuis Internet, le LAN local ou une autre interface réseau est refusé par défaut.

Justification

  • Réduit fortement la surface dattaque
  • Évite les expositions accidentelles de services de dev ou dadministration
  • Simplifie laccès distant sans ouvrir de ports ni gérer du NAT
  • Rend la topologie réseau plus lisible et plus cohérente entre les VM

Conséquences

  • Tailscale devient la frontière réseau de confiance pour les VM internes
  • SSH est accessible via Tailscale uniquement
  • Les interfaces web de dev/admin et services de données ne sont ouverts que si un besoin réel existe
  • Les règles ufw font partie de la configuration standard dune nouvelle VM

Quand cest possible, les services doivent écouter directement sur linterface Tailscale plutôt que sur toutes les interfaces.

Exemples :

  • préférable : 100.x.x.x:5432
  • acceptable si le firewall est strict : 0.0.0.0:5432
  • à éviter : écoute large + politique réseau permissive

Certains services restent fermés par défaut tant quun besoin explicite nexiste pas, en particulier :

  • Redis
  • bases de données non nécessaires en accès distant
  • interfaces dadministration

Modèle visé :

Internet  → ❌
LAN local → ❌
Tailscale → ✅

Cette convention est recommandée pour toutes les nouvelles VM du NUC, notamment docker-dev et openclaw.


3. Backend

Le back-end est un logiciel en production (qualité, observabilité, sécurité)

  • Date : 2026-01-25
  • Statut : Accepted
  • Périmètre : backend

Contexte

Le back-end porte la logique métier, laccès aux données, la sécurité et la fiabilité. Les bugs et régressions y ont un impact direct (données, paiements, confidentialité, disponibilité).

Sans cadre explicite, on dérive vers :

  • des erreurs non diagnostiquables,
  • des endpoints incohérents,
  • des migrations risquées,
  • une sécurité “au feeling”.

Options envisagées

  • Traiter le back-end comme un simple “serveur dAPI” avec peu de discipline
  • Traiter le back-end comme un logiciel en production avec exigences explicites

Décision

Le back-end est traité comme un logiciel en production.

Exigences minimales :

  • conventions de code et structure de projet explicites,
  • gestion standard des erreurs (codes, formats, logs),
  • observabilité (logs structurés, corrélation, métriques de base),
  • sécurité par défaut (authn/authz, validation, secrets),
  • migrations et changements de schéma maîtrisés.

Justification

  • Réduction drastique du temps de debug
  • Diminution du risque de régressions et dincidents
  • Base saine pour itérer vite sans casser

Conséquences

  • On documente les décisions structurantes (ce fichier)
  • On capitalise les incidents dans Debug & post-mortems
  • On privilégie des patterns éprouvés plutôt que “créatif”

Contrats dAPI explicites et versionnés

  • Date : 2026-01-25
  • Statut : Accepted
  • Périmètre : backend

Contexte

Les front-ends, automatisations et intégrations dépendent du back-end via des contrats. Quand les contrats sont implicites, les changements cassent silencieusement et coûtent cher à diagnostiquer.

Options envisagées

  • Contrats implicites (docs “à la main”, alignement informel)
  • Contrats explicites (schémas, validations, compatibilité)

Décision

Les contrats dAPI sont explicites et versionnés.

Minimum attendu :

  • formats de requêtes/réponses définis (ex. OpenAPI/JSON Schema),
  • validations côté serveur (entrée) et formats de sortie cohérents,
  • compatibilité gérée (breaking changes évitées ou versionnées).

Justification

  • Réduit les bugs dintégration
  • Permet des évolutions plus sereines
  • Facilite tests, mocks et onboarding

Conséquences

  • Toute évolution de contrat est traitée comme un changement “important”
  • Les breaking changes passent par une décision et/ou une version
  • Les erreurs retournées suivent un format standard (voir décision dédiée)

Gestion standard des erreurs et des statuts HTTP

  • Date : 2026-01-25
  • Statut : Accepted
  • Périmètre : backend

Contexte

Sans standard, chaque endpoint renvoie des erreurs différentes (formats, codes, messages), ce qui complique le front, les automatisations et lobservabilité.

Options envisagées

  • Erreurs “au cas par cas”
  • Format derreur et mapping HTTP standardisés

Décision

Les erreurs HTTP sont standardisées :

  • codes HTTP cohérents (4xx vs 5xx),
  • format de réponse derreur stable,
  • logs corrélés (requestId / traceId),
  • messages utilisateur séparés des détails techniques.

Justification

  • Debug plus rapide
  • UX meilleure (erreurs compréhensibles et gérables côté client)
  • Observabilité fiable

Conséquences

  • Les handlers derreurs sont centralisés
  • Les erreurs applicatives ont des codes internes stables
  • Les détails sensibles ne fuitent pas vers le client

Migrations et évolution de schéma maîtrisées

  • Date : 2026-01-25
  • Statut : Accepted
  • Périmètre : backend

Contexte

Les changements de schéma/DB sont une source majeure dincidents et de downtime, surtout quand on déploie sans discipline (ordre des déploiements, rétrocompatibilité).

Options envisagées

  • Changements manuels / non traçables
  • Migrations versionnées, reproductibles, avec stratégie de compatibilité

Décision

Toute évolution de schéma passe par des migrations versionnées et reproductibles.

Principes :

  • migrations idempotentes quand possible,
  • stratégie de déploiement compatible (expand/contract si nécessaire),
  • rollback envisagé ou plan de mitigation.

Justification

  • Réduit le risque prod
  • Permet de rejouer lhistorique en dev/staging
  • Facilite laudit et la reproductibilité

Conséquences

  • Les changements DB sont revus comme du code
  • Les migrations sont testées (au moins sur staging)
  • Les déploiements tiennent compte de lordre (code vs DB)

Observabilité minimale obligatoire (logs, corrélation, signaux)

  • Date : 2026-01-25
  • Statut : Accepted
  • Périmètre : backend

Contexte

Sans signaux, on “devine” en production : pas de corrélation, pas de métriques, pas de compréhension de limpact utilisateur.

Options envisagées

  • Logs non structurés, pas de corrélation
  • Observabilité minimale standard (logs structurés, IDs, métriques de base)

Décision

Observabilité minimale obligatoire :

  • logs structurés (niveau, événement, contexte),
  • requestId/traceId propagé et présent dans chaque log,
  • métriques de base (taux derreur, latence, throughput),
  • alertes simples sur erreurs 5xx / latence.

Justification

  • Réduit drastiquement le MTTR
  • Permet de prioriser les vrais problèmes
  • Facilite les post-mortems

Conséquences

  • On standardise le middleware de logging/corrélation
  • Les endpoints critiques ont des logs et métriques dédiés
  • Les incidents sont capitalisés dans Debug & post-mortems

Authentification et autorisation comme responsabilités centrales

  • Date : 2026-01-25
  • Statut : Accepted
  • Périmètre : backend

Contexte

Lauthentification (qui est lutilisateur) et lautorisation (ce quil a le droit de faire) sont au cœur de la sécurité applicative. Les traiter de manière dispersée ou implicite conduit à des failles, des incohérences et des bugs difficiles à auditer.

Options envisagées

  • Gestion ad hoc de lauthentification et des permissions (logique dispersée)
  • Centralisation claire des mécanismes dauthentification et dautorisation

Décision

Lauthentification et lautorisation sont des responsabilités centrales du back-end.

Principes :

  • mécanisme dauthentification unique et explicite,
  • règles dautorisation centralisées et testables,
  • séparation claire entre authentification (authn) et autorisation (authz),
  • décisions daccès traçables (logs/audit).

Justification

  • Réduction du risque de failles de sécurité
  • Lisibilité et auditabilité accrues
  • Évolutivité des règles de permissions

Conséquences

  • Les contrôles daccès ne sont pas codés “au fil de leau”
  • Les règles sensibles sont documentées
  • Toute évolution des permissions est traitée comme un changement critique

Idempotence et gestion des retries pour les opérations sensibles

  • Date : 2026-01-25
  • Statut : Accepted
  • Périmètre : backend

Contexte

Les appels réseau peuvent échouer ou être rejoués (timeouts, retries automatiques, webhooks, erreurs client). Sans idempotence, certaines opérations critiques (paiement, création de ressources, envoi dévénements) peuvent être exécutées plusieurs fois.

Options envisagées

  • Gérer les erreurs au cas par cas sans garantie didempotence
  • Concevoir explicitement les opérations sensibles comme idempotentes

Décision

Les opérations sensibles sont conçues pour être idempotentes.

Principes :

  • identification unique des requêtes (idempotency key),
  • protection contre les doublons,
  • comportements définis en cas de retry.

Justification

  • Prévention des doublons et incohérences de données
  • Robustesse face aux pannes réseau
  • Sécurité accrue pour les flux critiques

Conséquences

  • Les endpoints critiques documentent leur stratégie didempotence
  • Les retries sont maîtrisés et prévisibles
  • Les automatisations et intégrations peuvent être rejouées sans risque

4. n8n

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 dutiliser du Code (JS) quand nécessaire