|
| 1 | +# Architecture d’un module (pattern `apps/server-nestjs/src/modules/*`) |
| 2 | + |
| 3 | +Les modules NestJS métier vivent dans `src/modules/<nom-du-module>/` et suivent un découpage “vertical slice” avec des responsabilités explicites : **client**, **service**, **controller service (orchestration)**, **datastore**, **utils** et **tests**. |
| 4 | + |
| 5 | +Exemples concrets : |
| 6 | +- Module GitLab : `src/modules/gitlab/` |
| 7 | +- Module Keycloak : `src/modules/keycloak/` |
| 8 | + |
| 9 | +## Structure type |
| 10 | + |
| 11 | +```txt |
| 12 | +src/modules/<module>/ |
| 13 | +├── <module>.module.ts |
| 14 | +├── <module>.constants.ts |
| 15 | +├── <module>-client.service.ts |
| 16 | +├── <module>.service.ts |
| 17 | +├── <module>-controller.service.ts |
| 18 | +├── <module>-datastore.service.ts |
| 19 | +├── <module>.utils.ts |
| 20 | +├── <module>-testing.utils.ts |
| 21 | +└── *.spec.ts |
| 22 | +``` |
| 23 | + |
| 24 | +## Sens des dépendances (flow recommandé) |
| 25 | + |
| 26 | +Objectif : un flux de dépendances lisible et sans cycles. |
| 27 | + |
| 28 | +```txt |
| 29 | +<module>-controller.service.ts |
| 30 | + ↓ |
| 31 | + <module>.service.ts |
| 32 | + ↙ ↘ |
| 33 | +<module>-client <module>-datastore |
| 34 | +.service.ts .service.ts |
| 35 | +``` |
| 36 | + |
| 37 | +Règles pratiques : |
| 38 | +- Le `controller service` orchestre des workflows (cron, events, reconcile) et appelle le `service` et/ou le `datastore`. |
| 39 | +- Le `service` contient les règles métier (décisions, transformations, validations) et s’appuie sur le `client` et le `datastore`. |
| 40 | +- Le `client` encapsule l’accès à une API externe (initialisation + appels + erreurs bas niveau). |
| 41 | +- Le `datastore` encapsule l’accès DB (Prisma) et expose des méthodes de lecture/écriture typées. |
| 42 | +- Les `utils` restent “purs” (pas d’IO, pas d’injection Nest). |
| 43 | +- Les `testing utils` centralisent les factories/fixtures pour réduire la duplication dans les tests. |
| 44 | + |
| 45 | +## Composants |
| 46 | + |
| 47 | +### `<module>.module.ts` |
| 48 | + |
| 49 | +Rôle : |
| 50 | +- Déclare les providers, imports, exports du module. |
| 51 | +- Exporte généralement le service principal du module. |
| 52 | + |
| 53 | +### `<module>-client.service.ts` |
| 54 | + |
| 55 | +Rôle : |
| 56 | +- Adapter vers le système externe (SDK HTTP, client Keycloak, client GitLab, etc.). |
| 57 | +- Conserver un contrat stable pour le reste du module. |
| 58 | +- Mapper/normaliser les erreurs externes si nécessaire. |
| 59 | + |
| 60 | +À éviter : |
| 61 | +- Décisions métier (permissions, synchronisation, règles de purge) : elles vont dans `<module>.service.ts` ou le controller service. |
| 62 | + |
| 63 | +### `<module>.service.ts` |
| 64 | + |
| 65 | +Rôle : |
| 66 | +- Coeur métier du module (logique, mapping, validations, règles). |
| 67 | +- Appels aux dépendances (client/datastore) via des méthodes orientées domaine. |
| 68 | + |
| 69 | +À éviter : |
| 70 | +- Cron/events : c’est le rôle du controller service. |
| 71 | + |
| 72 | +### `<module>-controller.service.ts` |
| 73 | + |
| 74 | +Rôle : |
| 75 | +- Orchestrateur de workflows : `@Cron`, `@OnEvent`, reconcile périodique, tâches “batch”. |
| 76 | +- Coordination entre datastore et service (et parfois appels directs au client pour des opérations transverses). |
| 77 | +- Garde-fous “safety” avant opérations destructrices (ex: suppression de groupes orphelins). |
| 78 | + |
| 79 | +### `<module>-datastore.service.ts` |
| 80 | + |
| 81 | +Rôle : |
| 82 | +- Accès DB via Prisma (select/include, transactions, pagination). |
| 83 | +- Exposition de types agrégés utiles au domaine (ex: `ProjectWithDetails`). |
| 84 | + |
| 85 | +À éviter : |
| 86 | +- Appliquer des règles métier (ex: calcul de permissions) : on garde le datastore centré persistence. |
| 87 | + |
| 88 | +### `<module>.utils.ts` |
| 89 | + |
| 90 | +Rôle : |
| 91 | +- Fonctions utilitaires pures : mapping, helpers de collections, types partagés. |
| 92 | +- Aucune dépendance Nest, aucune lecture/écriture DB, aucun appel réseau. |
| 93 | + |
| 94 | +### `<module>-testing.utils.ts` |
| 95 | + |
| 96 | +Rôle : |
| 97 | +- Factories typées pour les structures fréquemment utilisées en tests. |
| 98 | +- Support d’`overrides` pour construire rapidement des variantes. |
| 99 | +- Centralisation des erreurs/fake responses spécifiques au module (quand utile). |
| 100 | + |
| 101 | +## Tests (Vitest) |
| 102 | + |
| 103 | +### `<module>.service.spec.ts` |
| 104 | + |
| 105 | +Cible : |
| 106 | +- Logique métier : transformations, décisions, mapping d’erreurs. |
| 107 | + |
| 108 | +Approche : |
| 109 | +- Mock du `client` et du `datastore`. |
| 110 | +- Pas d’IO réel. |
| 111 | + |
| 112 | +### `<module>-controller.service.spec.ts` |
| 113 | + |
| 114 | +Cible : |
| 115 | +- Orchestration : séquences d’appels, side-effects attendus, reconcile. |
| 116 | + |
| 117 | +Approche : |
| 118 | +- Mock du `service`, du `datastore`, et des appels externes. |
| 119 | +- Vérification des appels effectués et des paramètres attendus. |
| 120 | + |
| 121 | +### `<module>-datastore.service.spec.ts` (si présent) |
| 122 | + |
| 123 | +Cible : |
| 124 | +- Forme des requêtes Prisma, mapping de résultat, typage de l’agrégat renvoyé. |
| 125 | + |
| 126 | +Approche : |
| 127 | +- Mock de Prisma/DatabaseService, pas de logique métier. |
0 commit comments