Aller au contenu

ADR-001 — Architecture par module de feature

Statut

Accepté

Date

2026-07-08 (documenté rétroactivement ; le pattern précède cet enregistrement)

Contexte

L'application a grandi historiquement autour de src/screens/ (destinations de navigation) et src/components/ (UI partagée), avec de la logique transverse éparpillée dans src/utils/. À mesure que les écrans accumulaient des arbres privés profonds, les frontières se sont brouillées : logique métier, accès aux données et UI se mélangeaient librement, sans encapsulation imposée. Toute nouvelle fonctionnalité complexe n'avait d'autre foyer qu'« un énième sous-arbre d'écran ».

Décision

Introduire des modules de feature sous src/features/. Une feature est une tranche verticale autonome qui expose une API publique restreinte via son barrel index.ts ; les consommateurs n'importent que depuis ce barrel.

La structure interne canonique (pleinement réalisée par unitPreference) :

featureName/
├── index.ts        API publique (le seul point d'entrée)
├── domain/         logique métier pure, sans dépendance framework
├── adapter/        mapping front ↔ backend
├── api/ | graphql/ opérations GraphQL + types
├── hooks/          état + orchestration (store zustand / context)
├── components/     UI présentationnelle
├── screens/        destinations de navigation (le cas échéant)
├── context/        React context à portée de la feature (le cas échéant)
└── test-utils/     mocks réutilisables pour cette feature

Les dépendances circulaires à l'intérieur de src/features/ sont interdites en erreur dure via dependency-cruiser (no-circular-features, appliqué en CI). Deux implémentations de référence existent : changeMode (centré context/hook) et unitPreference (entièrement en couches — le modèle préféré).

Conséquences

Positives

  • Surface publique claire ; les internes peuvent être refactorés librement.
  • Un domain/ pur testable sans React.
  • Dépendances acycliques imposées à l'intérieur des features.
  • Un blueprint reproductible pour les nouveaux travaux.

Négatives / Compromis

  • Deux paradigmes coexistent pendant la migration (legacy screens/ + components/ vs features/), ce qui prête à confusion tant que le code legacy n'est pas migré.
  • Plus de dossiers/cérémonie en amont pour les petites features.
  • La frontière legacy→feature prévue est déclarée dans .dependency-cruiser.js (LEGACY_PATH_REGEX) mais pas encore appliquée.

Alternatives considérées

  • Tout garder dans screens/ + components/ — rejeté : aucune encapsulation, couplage croissant.
  • Uniquement des « feature slices » Redux-Toolkit — rejeté : cela adresse l'état, pas la tranche verticale complète (domaine/api/UI) ni les frontières d'import.