Aller au contenu

Guide Architecture DDD — Référence universelle

Résumé

Référence universelle pour tous les projets TypeScript/Node.js de Bernard. Documente l'architecture DDD stricte avec Express 5 + Prisma + Redis + BullMQ + Winston, issue de la fusion de DDD_Module (entités, ServiceValidation, ports HTTP, DI robuste) et ProjetFilleMere (auto-discovery déclaratif, multi-tenant, CUID). Contient 26 règles absolues issues de bugs réels, une checklist en 8 phases et une table de nommage exhaustive.

Contenu structuré

Stack technique

  • Runtime : Express 5, TypeScript 5, tsx watch
  • ORM : Prisma (db push — jamais migrate dev)
  • IDs : CUID via @paralleldrive/cuid2 — jamais UUID
  • Queue : BullMQ + ioredis
  • Logs : Winston via AppLogger
  • Validation : Zod (deux niveaux distincts)

Structure des couches #ddd

domain/            ← zéro dépendance externe
application/       ← uniquement interfaces domain + shared
infrastructure/    ← Prisma, Redis, BullMQ ici uniquement
interface-adapters/← pont HTTP ↔ domaine

Voir shared/architecture/shared-infra-docker pour l'infrastructure partagée VPS.

Couche Domain

  • Entité : constructeur private, factory static creer(), reconstitution static depuisDB()
  • Entité : versObjetPlain() (interne) ET versObjetPlainPublic() (HTTP) distincts — ne jamais exposer versObjetPlain() en HTTP
  • Value Object : constructeur private, static creer() avec validation, equals(), immuable
  • Exception : extends ErreurMetier (jamais extends Error), union type pour les codes d'erreur
  • domain/schemas/ : constantes string uniquement — zéro import Zod ici

Couche Application — Use Case en 5 étapes

1. Validation (Zod + règles métier via ServiceValidation)
2. executerLogique() — logique métier, peut lancer ErreurXxx typée
3. auditer() — try/catch séparé, JAMAIS de throw
4. construireResultat() — appelle versObjetPlainPublic()
5. gererErreur() — retourne TOUJOURS ResultatXxx, jamais de re-throw

Interface Use Case — 4 sections obligatoires : DonneesXxx, ResultatXxx, CodeErreurXxx (union type), interface avec JSDoc.

Couche Infrastructure

  • Repository : idUtilisateur dans le WHERE de toutes les requêtes (multi-tenant)
  • Repository : updateMany/deleteMany (pas update/delete) pour multi-tenant
  • ServiceValidation : un par module, Map, deux sous-étapes (Zod → règles métier)
  • Module DI : ordre init obligatoire — repositories → services → use cases → controllers

Couche Interface-Adapters

  • Handler : extends BaseActionHandler, hooks obligatoires executeBusinessLogic() + getActionName()
  • Controller : 3 lignes max par méthode, factory function obligatoire createXxxController(deps)
  • Wrapper module : arrow functions uniquement (préserve le this), lit req.utilisateur (pas req.user)
  • Routes : déclaratives, statiques avant dynamiques (ex: /export avant /:id)

Routing Auto-Discovery

Chaque module expose un fichier {nom}.module.routes.ts déclaratif. Le GestionnaireModulaire monte automatiquement toutes les routes au démarrage via AutoDiscoveryModular.

Voir aussi shared/flow-connexion-auth pour le flow d'authentification transversal.

Points clés

26 règles absolues (sélection critique)

# Règle Piège
3 Méthode use case = toujours executer() Jamais execute(), run(), process()
7 IDs Prisma : z.string().min(1) Jamais z.string().uuid() — CUIDs ≠ UUIDs
8 Lire req.utilisateur?.id Jamais req.user?.id — bug de prod documenté
13 auditer() toujours non-bloquant Jamais de throw dans auditer()
14 construireResultat() appelle versObjetPlainPublic() Jamais versObjetPlain() en HTTP
19 prisma db push uniquement Jamais migrate dev — shadow DB absente
26 sed échoue sur les accents Utiliser python3 -c "..." pour fichiers UTF-8

Checklist création d'un nouveau module (8 phases)

  1. Domain — entité, value objects, exceptions, interfaces, constantes schemas
  2. Schemas Zod — un fichier par action dans infrastructure/schemas/zod/
  3. ServiceValidation — Map + deux sous-étapes
  4. Application — interfaces + implémentations use cases (5 étapes)
  5. Infrastructure repository — Prisma + multi-tenant + mapper()
  6. Interface-Adapters — handlers + controllers + factory functions
  7. Routing + DI — fichier routes déclaratif + module DI
  8. Tests et validation — health check, validation, CRUD, audit non-bloquant

Table de nommage (extraits)

Élément Convention
Interface use case I{Action}{Nom}UseCase.ts
DTO entrée Donnees{Action}{Nom}
DTO sortie Resultat{Action}{Nom}
Codes erreur CodeErreur{Action}{Nom} (union type)
Exception Erreur{Nom} extends ErreurMetier
ServiceValidation ServiceValidation{Nom}.ts
Controller wrapper {Nom}ModuleController.ts
Constante schema schema{Action}{Nom} (string, pas Zod)

Liens connexes