Architecture Backend
Ce projet est une API centralisée développée avec NestJS. Elle a pour but de desservir simultanément les trois applications du projet Koudmain :
- L'application Web (Back-office / Dashboard)
- L'application Mobile Client
- L'application Mobile Entreprise (Pro)
L'architecture choisie est un Monolithe Modulaire ("Feature-based"). Toutes les applications consomment le même backend, mais le code est strictement organisé par domaine métier (User, Offer, etc.).
📂 Structure du projet
Voici l'organisation du dossier src/ :
src/
├── core/ # Configurations globales (Guards, Interceptors, Filters...)
├── shared/ # Modules techniques transversaux (Prisma/DB, Mailer, AWS S3...)
├── modules/ # Le cœur de l'application (Dossiers classés par "Feature")
│ ├── users/
│ │ ├── services/ # Logique métier et accès base de données
| | ├── users.controller.ts # Points d'entrée HTTP (Routes)
│ │ └── users.module.ts
│ │
│ └── offers/
│ ├── services/
| ├── offers.controller.ts
│ └── offers.module.ts
│
├── app.module.ts # Chef d'orchestre global qui importe tous les modules métier
└── main.ts # Point d'entrée de l'application (Instanciation NestJS + Express)
🧩 Les 3 composants fondamentaux
Dans ce projet, nous respectons strictement le modèle d'architecture de NestJS, basé sur 3 couches. Chaque couche a une responsabilité unique et stricte.
1. Les Modules (*.module.ts)
Les Modules sont des boîtes hermétiques qui regroupent les éléments liés à un domaine métier précis (ex: UsersModule).
- Leur rôle : Déclarer les Controllers et injecter les Services (Providers).
- Règle d'or : Si le domaine "Offers" a besoin de la logique de "Users", le OffersModule doit importer le UsersModule.
2. Les Controllers (*.controller.ts)
Le Controller s'occupe uniquement de la couche HTTP.
- Leur rôle : Définir les routes (URL), vérifier les requêtes entrantes (Headers, Body, Paramètres), et appeler le Service approprié.
- Règle d'or : Les Controllers ne doivent contenir AUCUNE logique métier ni AUCUNE requête en base de données. Ils font simplement le lien entre le réseau et nos algorithmes.
💡 Gestion Multi-Applications : Par défaut, nous utilisons un Controller générique par domaine (ex:
@Controller('offers')). Si plus tard la logique de routage diverge fortement entre le web et le mobile, nous pourrons créer des Controllers spécifiques dans le même module (ex:offers-web.controller.tsvia@Controller('offers/web')).
3. Les Services (*.service.ts)
Le Service continent toute la "matière grise" de l'application.
- Leur rôle : Exécuter les algorithmes, faire les calculs métiers, et interagir avec la base de données.
- Règle d'or : Un Service ne doit avoir aucune connexion avec Express ou le réseau (pas d'objet HTTP
RequestouResponseici).
💡 Séparer la logique des Services : Si un domaine devient très complexe (ex: Offers), nous découpons le Service principal en plusieurs "Sous-Services" (ex:
offers-crud.service.ts,offers-search.service.ts). Le Controller s'occupera d'appeler le service dont il a besoin.
🛠 Comment ajouter une nouvelle fonctionnalité ?
Imaginons que vous deviez créer la gestion des Paiements. Voici la marche à suivre pas à pas :
Étape 1 : Créer le Module
Générer le module de base via le CLI NestJS (qui mettra automatiquement à jour app.module.ts) :
nest g module modules/payments
Étape 2 : Créer le(s) Service(s)
Générer le service qui contiendra la logique :
nest g service modules/payments/services/payments --flat
Note : Le flag *--flat* évite la création d'un sous-dossier inutile.
Étape 3 : Créer le(s) Controller(s)
Générer le contrôleur qui exposera la route API :
nest g controller modules/payments/controllers/payments --flat
Étape 4 : Développer !
- Vous écrivez votre logique de traitement dans
payments.service.ts. - Vous créez vos routes (ex:
@Post('checkout')) danspayments.controller.ts. - Le controller injecte le service dans son
constructor()pour récupérer le résultat.
🚫 Pièges à éviter
- Le God Service : Ne mettez pas 2000 lignes dans un seul service.ts. Séparez la logique de création (
create()), de la logique de calcul complexe ou d'envois de notifications. - Dépendances circulaires : Si le UsersModule importe OffersModule, et que OffersModule importe UsersModule, NestJS crashera (erreur d'indétermination). Utilisez alors l'outil de NestJS réseau
forwardRef(), ou mieux : repensez l'architecture pour qu'un Module technique ("Shared") fournisse la logique commune aux deux !
💡 Utiliser cette documentation pour approfondir le fonctionnement de NestJS : https://docs.nestjs.com