kapi-mvc-blank 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1147 @@
1
+ # API MVC Node - Documentation Développeurs
2
+
3
+ Bienvenue dans le projet **API MVC Node**. Cette documentation est destinée aux développeurs pour comprendre l'architecture, les conventions et les procédures de développement.
4
+
5
+ ## 📋 Table des matières
6
+
7
+ - [Vue d'ensemble](#vue-densemble)
8
+ - [Architecture](#architecture)
9
+ - [Installation](#installation)
10
+ - [Configuration](#configuration)
11
+ - [Démarrage](#démarrage)
12
+ - [Structure du projet](#structure-du-projet)
13
+ - [API Endpoints](#api-endpoints)
14
+ - [Versioning](#versioning)
15
+ - [Authentification](#authentification)
16
+ - [Téléchargement de fichiers](#téléchargement-de-fichiers)
17
+ - [Logging](#logging)
18
+ - [Tests](#tests)
19
+ - [Documentation Swagger](#documentation-swagger)
20
+ - [Conventions de code](#conventions-de-code)
21
+ - [Dépannage](#dépannage)
22
+
23
+ ---
24
+
25
+ ## 🎯 Vue d'ensemble
26
+
27
+ Ce projet est une API REST construite avec **Express.js** en utilisant le pattern **MVC** (Model-View-Controller). Elle supporte le **versioning d'API** avec des routes séparées pour chaque version (v1, v2, etc.).
28
+
29
+ **Stack technologique :**
30
+ - Node.js (ES modules)
31
+ - Express 5.x
32
+ - JWT pour l'authentification
33
+ - Multer pour les uploads de fichiers
34
+ - Pino pour le logging
35
+ - Jest pour les tests
36
+ - Swagger/OpenAPI pour la documentation
37
+ - Rate limiting pour la protection
38
+
39
+ ---
40
+
41
+ ## 🏗️ Architecture
42
+
43
+ ### Pattern MVC
44
+
45
+ Le projet suit une architecture MVC structurée par version d'API :
46
+
47
+ ```
48
+ src/
49
+ ├── v1/ # API Version 1
50
+ │ ├── controllers/ # Logique métier
51
+ │ ├── routes/ # Définition des routes
52
+ │ ├── middlewares/ # Middlewares personnalisés
53
+ │ ├── models/ # Schémas de données
54
+ │ └── services/ # Services réutilisables
55
+ ├── v2/ # API Version 2
56
+ │ ├── controllers/ # Logique métier
57
+ │ ├── routes/ # Définition des routes
58
+ │ ├── middlewares/ # Middlewares personnalisés
59
+ │ ├── models/ # Schémas de données
60
+ │ └── services/ # Services réutilisables
61
+ ├── config/ # Configuration (Swagger, etc.)
62
+ ├── services/ # Services partagés (JWT, etc.)
63
+ ├── utils/ # Utilitaires (Logger, etc.)
64
+ ├── app.js # Configuration Express
65
+ └── server.js # Entrée du serveur
66
+ ```
67
+
68
+ ### Détails des répertoires
69
+
70
+ | Répertoire | Rôle |
71
+ |-----------|------|
72
+ | `controllers/` | Traitement des requêtes, appel de services, envoi de réponses |
73
+ | `routes/` | Définition des endpoints, validation, middleware d'authentification |
74
+ | `middlewares/` | Authentification, autorisation, validation |
75
+ | `models/` | Schémas et validations de données |
76
+ | `services/` | Logique métier réutilisable, requêtes BD, calculs |
77
+ | `config/` | Configuration globale (Swagger, BD, etc.) |
78
+
79
+ ### Principes architecturaux
80
+
81
+ - **Séparation des préoccupations** : Chaque couche a une responsabilité unique
82
+ - **Réutilisabilité** : Services partagés entre versions
83
+ - **Versioning** : Maintenance parallèle de plusieurs versions
84
+ - **Maintenabilité** : Code organisé et facile à naviguer
85
+
86
+ ---
87
+
88
+ ## 💻 Installation
89
+
90
+ ### Prérequis
91
+
92
+ - **Node.js** >= 16.x
93
+ - **npm** ou **yarn**
94
+ - Un gestionnaire d'environnement (`.env`)
95
+
96
+ ### Étapes
97
+
98
+ 1. **Cloner le repository**
99
+ ```bash
100
+ git clone <repository-url>
101
+ cd api-mvc-node
102
+ ```
103
+
104
+ 2. **Installer les dépendances**
105
+ ```bash
106
+ npm install
107
+ ```
108
+
109
+ 3. **Configurer l'environnement**
110
+ ```bash
111
+ cp .env.example .env
112
+ # Éditer .env avec vos configurations
113
+ ```
114
+
115
+ 4. **Configurer Prisma**
116
+ ```bash
117
+ npx prisma migrate dev --name init
118
+ npx prisma generate
119
+ # if is their some trouble please read prisma doc
120
+ # you probable nead model in schema.prisma or complete tour DSN in tour .env
121
+ ```
122
+
123
+ 5. **Vérifier l'installation**
124
+ ```bash
125
+ npm run dev
126
+ ```
127
+ Le serveur devrait démarrer sur `http://localhost:3000`
128
+
129
+ ---
130
+
131
+ ## ⚙️ Configuration
132
+
133
+ ### Variables d'environnement (`.env`)
134
+
135
+ ```bash
136
+ # Serveur
137
+ PORT=3000
138
+ NODE_ENV=development
139
+
140
+ # JWT
141
+ JWT_SECRET=your_super_secret_key_change_in_production
142
+
143
+ # Téléchargements
144
+ UPLOAD_DIR=uploads
145
+ UPLOAD_MAX_SIZE=5242880 # 5MB en bytes
146
+
147
+ # Logging
148
+ LOG_DIR=logs
149
+ LOG_FILE=app.log
150
+ LOG_LEVEL=info # debug, info, warn, error
151
+ ```
152
+
153
+ ### .env.example
154
+
155
+ Créez un fichier `.env.example` à la racine avec les variables modèles :
156
+
157
+ ```bash
158
+ # Server Configuration
159
+ PORT=3000
160
+ NODE_ENV=development
161
+
162
+ # Security
163
+ JWT_SECRET=change_me_in_production
164
+
165
+ # File Upload
166
+ UPLOAD_DIR=uploads
167
+ UPLOAD_MAX_SIZE=5242880
168
+
169
+ # Logging
170
+ LOG_DIR=logs
171
+ LOG_FILE=app.log
172
+ LOG_LEVEL=info
173
+ ```
174
+
175
+ ### Variables importantes
176
+
177
+ | Variable | Description | Défaut |
178
+ |----------|-------------|--------|
179
+ | `PORT` | Port du serveur | `3000` |
180
+ | `JWT_SECRET` | Clé secrète JWT | (obligatoire) |
181
+ | `UPLOAD_DIR` | Répertoire des uploads | `uploads` |
182
+ | `UPLOAD_MAX_SIZE` | Taille max des fichiers (bytes) | `5242880` (5MB) |
183
+ | `LOG_LEVEL` | Niveau de log | `info` |
184
+
185
+ ---
186
+
187
+ ## 🚀 Démarrage
188
+
189
+ ### Mode développement (avec auto-reload)
190
+
191
+ ```bash
192
+ npm run dev
193
+ ```
194
+
195
+ - Utilise **Nodemon** pour redémarrer le serveur automatiquement
196
+ - Parfait pour le développement local
197
+ - Les modifications sont détectées en temps réel
198
+
199
+ ### Mode production
200
+
201
+ ```bash
202
+ npm start
203
+ ```
204
+
205
+ - Lance directement le serveur sans surveillance
206
+ - Port par défaut : `3000` (configurable via `PORT`)
207
+ - Optimisé pour les performances
208
+
209
+ ### Vérifier le démarrage
210
+
211
+ Une fois démarré, vous verrez dans la console :
212
+
213
+ ```
214
+ 🚀 Server running on port 3000
215
+ ✓ Route registered: /api/v1/auth
216
+ ✓ Route registered: /api/v1/users
217
+ ✓ Route registered: /api/v1/uploads
218
+ ✓ Route registered: /api/v2/auth
219
+ ✓ Route registered: /api/v2/users
220
+ ✓ Route registered: /api/v2/uploads
221
+ ```
222
+
223
+ ---
224
+
225
+ ## 📁 Structure du projet
226
+
227
+ ### Fichiers racine
228
+
229
+ | Fichier | Objectif |
230
+ |---------|----------|
231
+ | `package.json` | Dépendances et scripts npm |
232
+ | `.env` | Variables d'environnement (à créer) |
233
+ | `.env.example` | Modèle de configuration |
234
+ | `.gitignore` | Fichiers à ignorer dans Git |
235
+ | `jest.config.cjs` | Configuration des tests |
236
+
237
+ ### Répertoires principaux
238
+
239
+ ```
240
+ src/
241
+ ├── app.js # Instance Express + initialisation routes
242
+ ├── server.js # Point d'entrée (PORT + démarrage)
243
+ ├── config/
244
+ │ └── swagger.js # Configuration OpenAPI/Swagger
245
+ ├── services/
246
+ │ └── jwt.service.js # Gestion des JWT
247
+ ├── utils/
248
+ │ └── logger.js # Configuration Pino logger
249
+ ├── v1/ et v2/ # Versions de l'API
250
+ └── __tests__/
251
+ └── user.controller.test.js # Tests unitaires
252
+
253
+ logs/ # Fichiers journaux (généré à runtime)
254
+ uploads/ # Fichiers uploadés (généré à runtime)
255
+ test-api/ # Scripts de test API
256
+ ```
257
+
258
+ ### Fichiers d'exécution
259
+
260
+ ```
261
+ compare-versions.js # Script pour comparer v1 vs v2
262
+ test-endpoints.js # Script pour tester les endpoints
263
+ test-setup.js # Configuration des tests
264
+ ```
265
+
266
+ ---
267
+
268
+ ## 🔌 API Endpoints
269
+
270
+ ### Endpoints v1
271
+
272
+ | Méthode | Endpoint | Description | Auth |
273
+ |---------|----------|-------------|------|
274
+ | `GET` | `/api/v1/users/info` | Info basique de l'API | ❌ |
275
+ | `GET` | `/api/v1/users/profile` | Profil utilisateur | ✅ JWT |
276
+ | `POST` | `/api/v1/uploads/:name` | Upload une image | ❌ |
277
+
278
+ ### Endpoints v2
279
+
280
+ | Méthode | Endpoint | Description | Différences |
281
+ |---------|----------|-------------|-------------|
282
+ | `GET` | `/api/v2/users/info` | Info enrichie (OS, hostname) | Inclut api_version, os, arch, hostname |
283
+ | `GET` | `/api/v2/users/profile` | Profil utilisateur | Identique à v1 |
284
+ | `POST` | `/api/v2/uploads/:name` | Upload une image | Identique à v1 |
285
+
286
+ ### Exemples de requêtes
287
+
288
+ **v1 - Info basique :**
289
+ ```bash
290
+ curl http://localhost:3000/api/v1/users/info
291
+ ```
292
+ Réponse (200) :
293
+ ```json
294
+ {
295
+ "msg": "ok"
296
+ }
297
+ ```
298
+
299
+ **v2 - Info enrichie :**
300
+ ```bash
301
+ curl http://localhost:3000/api/v2/users/info
302
+ ```
303
+ Réponse (200) :
304
+ ```json
305
+ {
306
+ "msg": "ok",
307
+ "api_version": "v2",
308
+ "os": "linux",
309
+ "arch": "x64",
310
+ "hostname": "server-01"
311
+ }
312
+ ```
313
+
314
+ **Profil utilisateur (avec JWT) :**
315
+ ```bash
316
+ curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
317
+ http://localhost:3000/api/v1/users/profile
318
+ ```
319
+ Réponse (200) :
320
+ ```json
321
+ {
322
+ "id": "user123",
323
+ "role": "admin"
324
+ }
325
+ ```
326
+
327
+ **Upload d'image :**
328
+ ```bash
329
+ curl -X POST -F "file=@image.jpg" \
330
+ http://localhost:3000/api/v1/uploads/my-image
331
+ ```
332
+ Réponse (201) :
333
+ ```json
334
+ {
335
+ "url": "uploads/my-image.jpg",
336
+ "size": 15234,
337
+ "mimetype": "image/jpeg"
338
+ }
339
+ ```
340
+
341
+ ---
342
+
343
+ ## RAD-api
344
+
345
+ Pour générer les routes, controller, models vous pouvez utiliser notre rad
346
+
347
+ ### Route
348
+ Générez un fichier de route complet pour une table spécifique :
349
+
350
+ ```bash
351
+ npx kapi generate route <tableName>
352
+ ```
353
+
354
+ #### Exemple :
355
+
356
+ ```bash
357
+ npx kapi generate route citations
358
+ ```
359
+
360
+ ### Controller
361
+ Générez un fichier de controller complet pour une table spécifique :
362
+
363
+ ```bash
364
+ npx kapi generate controller <tableName>
365
+ ```
366
+
367
+ #### Exemple :
368
+
369
+ ```bash
370
+ npx kapi generate controller citations
371
+ ```
372
+
373
+ ### Model
374
+ Générez un fichier de model complet pour une table spécifique :
375
+
376
+ ```bash
377
+ npx kapi generate model <tableName>
378
+ ```
379
+
380
+ #### Exemple :
381
+
382
+ ```bash
383
+ npx kapi generate model citations
384
+ ```
385
+
386
+ ---
387
+
388
+ ## 🔄 Versioning
389
+
390
+ ### Stratégie de versioning
391
+
392
+ - **Compatibilité descendante** : Les clients utilisant v1 ne sont pas affectés par les changements en v2
393
+ - **Évolution progressive** : Déployer des améliorations sans briser l'API existante
394
+ - **Maintenance parallèle** : Pouvoir supporter plusieurs versions pendant la transition
395
+
396
+ ### Structure d'une version
397
+
398
+ Chaque version possède sa propre structure indépendante :
399
+
400
+ ```
401
+ src/v1/
402
+ ├── controllers/ # Logique spécifique à v1
403
+ ├── routes/ # Routes v1
404
+ ├── middlewares/ # Middlewares v1
405
+ ├── models/ # Models v1
406
+ └── services/ # Services v1
407
+ ```
408
+
409
+ ### Ajouter une nouvelle version (v3)
410
+
411
+ 1. **Créer la structure**
412
+ ```bash
413
+ mkdir -p src/v3/{controllers,routes,middlewares,models,services}
414
+ ```
415
+
416
+ 2. **Créer les fichiers** (copier depuis v2 et adapter)
417
+ ```
418
+ src/v3/
419
+ ├── controllers/
420
+ ├── routes/
421
+ ├── middlewares/
422
+ ├── models/
423
+ └── services/
424
+ ```
425
+
426
+ 3. **Le système découvre automatiquement** les nouvelles routes grâce au code dans [app.js](src/app.js) :
427
+ ```javascript
428
+ const versionDirs = fs.readdirSync(versionsDir)
429
+ .filter(file => /^v\d+$/.test(file));
430
+ ```
431
+
432
+ 4. **Les endpoints seront disponibles** sur `/api/v3/...`
433
+
434
+ ### Différences entre versions
435
+
436
+ Utilisez `compare-versions.js` pour comparer les réponses entre versions :
437
+
438
+ ```bash
439
+ node compare-versions.js
440
+ ```
441
+
442
+ ---
443
+
444
+ ## 🔐 Authentification
445
+
446
+ ### JWT (JSON Web Tokens)
447
+
448
+ L'authentification utilise **JWT** avec les éléments suivants :
449
+
450
+ **Génération d'un token :**
451
+ ```javascript
452
+ import jwt from 'jsonwebtoken';
453
+
454
+ const token = jwt.sign(
455
+ { id: userId, role: userRole },
456
+ process.env.JWT_SECRET,
457
+ { expiresIn: '24h' }
458
+ );
459
+ ```
460
+
461
+ **Vérification via middleware :**
462
+
463
+ Utilisez le middleware `authMiddleware` sur les routes protégées :
464
+
465
+ ```javascript
466
+ import { Router } from 'express';
467
+ import { profile } from '../controllers/user.controller.js';
468
+ import { authMiddleware } from '../middlewares/auth.middleware.js';
469
+
470
+ const router = Router();
471
+ router.get('/profile', authMiddleware, profile);
472
+
473
+ export default router;
474
+ ```
475
+
476
+ **Header requis pour les endpoints protégés :**
477
+ ```
478
+ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
479
+ ```
480
+
481
+ ### Flux d'authentification
482
+
483
+ 1. **Utilisateur envoie ses identifiants** au endpoint de login
484
+ 2. **Serveur valide et génère un JWT**
485
+ 3. **Client stocke le token** (localStorage, sessionStorage, cookie)
486
+ 4. **Client envoie le token** dans chaque requête protégée
487
+ 5. **Middleware valide le token** avant d'exécuter la route
488
+
489
+ ### Erreurs d'authentification
490
+
491
+ | Code | Message | Cause |
492
+ |------|---------|-------|
493
+ | `401` | `"Token missing"` | Header Authorization absent |
494
+ | `401` | `"Invalid token"` | Token malformé, expiré ou clé incorrecte |
495
+
496
+ ---
497
+
498
+ ## 📤 Téléchargement de fichiers
499
+
500
+ ### Configuration
501
+
502
+ - **Répertoire** : `uploads/` (configurable via `UPLOAD_DIR`)
503
+ - **Taille max** : 5 MB (configurable via `UPLOAD_MAX_SIZE`)
504
+ - **Types autorisés** : JPEG, PNG, GIF, WebP
505
+ - **Sécurité** : Noms de fichiers sanitisés
506
+
507
+ ### Utilisation
508
+
509
+ **Endpoint :**
510
+ ```
511
+ POST /api/v1/uploads/:name
512
+ POST /api/v2/uploads/:name
513
+ ```
514
+
515
+ **Exemple avec curl :**
516
+ ```bash
517
+ curl -X POST -F "file=@photo.png" \
518
+ http://localhost:3000/api/v1/uploads/my-photo
519
+ ```
520
+
521
+ **Exemple avec JavaScript/Fetch :**
522
+ ```javascript
523
+ const formData = new FormData();
524
+ formData.append('file', fileInput.files[0]);
525
+
526
+ const response = await fetch('/api/v1/uploads/my-photo', {
527
+ method: 'POST',
528
+ body: formData
529
+ });
530
+
531
+ const data = await response.json();
532
+ console.log(data.url); // uploads/my-photo.png
533
+ ```
534
+
535
+ **Réponse réussie (201) :**
536
+ ```json
537
+ {
538
+ "url": "uploads/my-photo.png",
539
+ "size": 15234,
540
+ "mimetype": "image/png"
541
+ }
542
+ ```
543
+
544
+ **Erreurs possibles :**
545
+
546
+ | Code | Cause | Solution |
547
+ |------|-------|----------|
548
+ | `400` | Fichier manquant ou type non autorisé | Vérifier le type MIME (JPEG, PNG, GIF, WebP) |
549
+ | `413` | Fichier trop volumineux | Réduire la taille ou augmenter `UPLOAD_MAX_SIZE` |
550
+
551
+ ### Accéder aux fichiers uploadés
552
+
553
+ Une fois uploadés, les fichiers sont accessibles via :
554
+
555
+ ```
556
+ http://localhost:3000/uploads/my-photo.png
557
+ ```
558
+
559
+ Le serveur expose le répertoire `uploads/` en tant que ressource statique.
560
+
561
+ ### Configuration de la taille
562
+
563
+ Pour augmenter la limite de taille d'upload, modifiez `.env` :
564
+
565
+ ```bash
566
+ # 10 MB
567
+ UPLOAD_MAX_SIZE=10485760
568
+
569
+ # 50 MB
570
+ UPLOAD_MAX_SIZE=52428800
571
+ ```
572
+
573
+ ---
574
+
575
+ ## 📊 Logging
576
+
577
+ ### Configuration
578
+
579
+ Le projet utilise **Pino** pour un logging performant et structuré. Les logs sont enregistrés dans des fichiers et affichés dans la console.
580
+
581
+ **Variables d'environnement :**
582
+ ```bash
583
+ LOG_DIR=logs # Répertoire des logs
584
+ LOG_FILE=app.log # Nom du fichier
585
+ LOG_LEVEL=info # Niveaux: debug, info, warn, error
586
+ ```
587
+
588
+ ### Niveaux de log
589
+
590
+ | Niveau | Utilisation | Exemple |
591
+ |--------|------------|---------|
592
+ | `debug` | Informations détaillées pour débogage | Données temporaires, état intermédiaire |
593
+ | `info` | Événements normaux | Requêtes reçues, opérations complétées |
594
+ | `warn` | Avertissements | Erreurs résolubles, fichiers manquants |
595
+ | `error` | Erreurs graves | Exceptions non gérées, BD inaccessible |
596
+
597
+ ### Accéder au logger dans le code
598
+
599
+ **Dans les contrôleurs (via middleware Pino) :**
600
+ ```javascript
601
+ export const profile = (req, res) => {
602
+ req.log?.info({ userId: req.user?.id }, 'profile requested');
603
+ res.json({ id: req.user.id, role: req.user.role });
604
+ };
605
+ ```
606
+
607
+ **Dans les services :**
608
+ ```javascript
609
+ import { logger } from '../utils/logger.js';
610
+
611
+ export const userService = {
612
+ getUser(id) {
613
+ logger.debug({ userId: id }, 'Fetching user');
614
+ // logique métier
615
+ logger.info({ userId: id }, 'User fetched');
616
+ }
617
+ };
618
+ ```
619
+
620
+ ### Changer le niveau de log
621
+
622
+ **Temporairement (en ligne de commande) :**
623
+ ```bash
624
+ LOG_LEVEL=debug npm run dev
625
+ ```
626
+
627
+ **Permanemment (dans .env) :**
628
+ ```bash
629
+ LOG_LEVEL=debug
630
+ ```
631
+
632
+ ### Fichiers générés
633
+
634
+ Les logs sont écrits dans `logs/app.log` et affichés dans la console. Format :
635
+
636
+ ```json
637
+ {"level":30,"time":"2026-01-15T10:30:45.123Z","pid":1234,"hostname":"server-01","msg":"profile requested","userId":"user123"}
638
+ ```
639
+
640
+ ---
641
+
642
+ ## 🧪 Tests
643
+
644
+ ### Exécuter les tests
645
+
646
+ ```bash
647
+ # Mode once (une seule exécution)
648
+ npm test
649
+
650
+ # Mode watch (détecte les changements)
651
+ npm run test:watch
652
+ ```
653
+
654
+ ### Framework et outils
655
+
656
+ - **Jest** : Framework de test avec assertions
657
+ - **Supertest** : Testing des routes HTTP sans serveur externe
658
+
659
+ ### Écrire un test
660
+
661
+ Exemple d'un test d'endpoint :
662
+
663
+ ```javascript
664
+ import request from 'supertest';
665
+ import app, { initializeRoutes } from '../app.js';
666
+
667
+ describe('User Controller', () => {
668
+ beforeAll(async () => {
669
+ // Initialiser les routes avant les tests
670
+ await initializeRoutes();
671
+ });
672
+
673
+ test('GET /api/v1/users/info returns 200 and msg', async () => {
674
+ const res = await request(app)
675
+ .get('/api/v1/users/info')
676
+ .expect(200);
677
+
678
+ expect(res.body).toEqual({ msg: 'ok' });
679
+ });
680
+
681
+ test('GET /api/v2/users/info returns enhanced info', async () => {
682
+ const res = await request(app)
683
+ .get('/api/v2/users/info')
684
+ .expect(200);
685
+
686
+ expect(res.body).toHaveProperty('api_version');
687
+ expect(res.body).toHaveProperty('os');
688
+ expect(res.body).toHaveProperty('arch');
689
+ expect(res.body).toHaveProperty('hostname');
690
+ });
691
+ });
692
+ ```
693
+
694
+ ### Test d'authentification
695
+
696
+ ```javascript
697
+ test('GET /api/v1/users/profile without token returns 401', async () => {
698
+ const res = await request(app)
699
+ .get('/api/v1/users/profile')
700
+ .expect(401);
701
+
702
+ expect(res.body.error).toBe('Token missing');
703
+ });
704
+
705
+ test('GET /api/v1/users/profile with token returns 200', async () => {
706
+ const token = jwt.sign({ id: 'user1', role: 'admin' }, process.env.JWT_SECRET);
707
+
708
+ const res = await request(app)
709
+ .get('/api/v1/users/profile')
710
+ .set('Authorization', `Bearer ${token}`)
711
+ .expect(200);
712
+
713
+ expect(res.body.id).toBe('user1');
714
+ });
715
+ ```
716
+
717
+ ### Localisation des tests
718
+
719
+ Les tests sont organisés dans `src/__tests__/` :
720
+ - `user.controller.test.js` : Tests du contrôleur utilisateur
721
+ - `auth.controller.test.js` : Tests d'authentification (à ajouter)
722
+ - `upload.controller.test.js` : Tests d'upload (à ajouter)
723
+
724
+ ### Configuration Jest
725
+
726
+ Le fichier `src/jest.config.cjs` configure Jest pour ES modules. Vérifiez qu'il contient :
727
+
728
+ ```javascript
729
+ export default {
730
+ testEnvironment: 'node',
731
+ transform: {},
732
+ extensionsToTreatAsEsm: ['.js'],
733
+ };
734
+ ```
735
+
736
+ ---
737
+
738
+ ## 📚 Documentation Swagger
739
+
740
+ ### Accès
741
+
742
+ L'API est documentée avec **Swagger/OpenAPI** et accessible à :
743
+
744
+ ```
745
+ http://localhost:3000/docs
746
+ ```
747
+
748
+ **Format brut JSON :**
749
+ ```
750
+ http://localhost:3000/docs.json
751
+ ```
752
+
753
+ ### Ajouter une documentation pour une route
754
+
755
+ Utilisez les commentaires **JSDoc OpenAPI** au-dessus de vos routes :
756
+
757
+ ```javascript
758
+ /**
759
+ * @openapi
760
+ * /users/profile:
761
+ * get:
762
+ * summary: Get current user profile
763
+ * description: Retrieve the authenticated user's profile information
764
+ * security:
765
+ * - bearerAuth: []
766
+ * responses:
767
+ * 200:
768
+ * description: User profile retrieved successfully
769
+ * content:
770
+ * application/json:
771
+ * schema:
772
+ * type: object
773
+ * properties:
774
+ * id:
775
+ * type: string
776
+ * example: user123
777
+ * role:
778
+ * type: string
779
+ * example: admin
780
+ * 401:
781
+ * description: Unauthorized - Token missing or invalid
782
+ */
783
+ router.get('/profile', authMiddleware, profile);
784
+ ```
785
+
786
+ ### Exemple complet avec upload
787
+
788
+ ```javascript
789
+ /**
790
+ * @openapi
791
+ * /uploads:
792
+ * post:
793
+ * summary: Upload an image file
794
+ * description: Upload an image (JPEG, PNG, GIF, WebP). Max size 5MB.
795
+ * requestBody:
796
+ * required: true
797
+ * content:
798
+ * multipart/form-data:
799
+ * schema:
800
+ * type: object
801
+ * properties:
802
+ * file:
803
+ * type: string
804
+ * format: binary
805
+ * responses:
806
+ * 201:
807
+ * description: File uploaded successfully
808
+ * content:
809
+ * application/json:
810
+ * schema:
811
+ * type: object
812
+ * properties:
813
+ * url:
814
+ * type: string
815
+ * example: uploads/image-123.jpg
816
+ * 400:
817
+ * description: Invalid file type or missing file
818
+ * 413:
819
+ * description: File too large
820
+ */
821
+ router.post('/:name', uploadHandler);
822
+ ```
823
+
824
+ ### Configuration Swagger
825
+
826
+ La configuration se trouve dans [src/config/swagger.js](src/config/swagger.js). Vous pouvez y ajouter :
827
+
828
+ ```javascript
829
+ const swaggerSpec = {
830
+ definition: {
831
+ openapi: '3.0.0',
832
+ info: {
833
+ title: 'API MVC Node',
834
+ version: '1.0.0',
835
+ description: 'REST API with MVC pattern and versioning'
836
+ },
837
+ servers: [
838
+ { url: 'http://localhost:3000', description: 'Development server' }
839
+ ]
840
+ },
841
+ apis: ['./src/**/routes/*.js']
842
+ };
843
+ ```
844
+
845
+ ---
846
+
847
+ ## 📝 Conventions de code
848
+
849
+ ### Nommage des fichiers
850
+
851
+ - **Routes** : `{resource}.routes.js` (ex: `user.routes.js`)
852
+ - **Contrôleurs** : `{resource}.controller.js` (ex: `user.controller.js`)
853
+ - **Middlewares** : `{type}.middleware.js` (ex: `auth.middleware.js`)
854
+ - **Models** : `{resource}.model.js` (ex: `user.model.js`)
855
+ - **Services** : `{resource}.service.js` (ex: `jwt.service.js`)
856
+ - **Tests** : `{resource}.test.js` (ex: `user.controller.test.js`)
857
+
858
+ ### Style de code
859
+
860
+ - **Syntax** : ES Modules (`import`/`export`)
861
+ - **Indentation** : 2 espaces
862
+ - **Quotes** : Guillemets simples (`'`) sauf pour JSDoc
863
+ - **Semicolons** : Oui
864
+ - **Async/await** : Préféré aux callbacks ou `.then()`
865
+
866
+ ### Structure d'une route
867
+
868
+ ```javascript
869
+ import { Router } from 'express';
870
+ import { profile, info } from '../controllers/user.controller.js';
871
+ import { authMiddleware } from '../middlewares/auth.middleware.js';
872
+
873
+ const router = Router();
874
+
875
+ /**
876
+ * @openapi
877
+ * /users/profile:
878
+ * get:
879
+ * summary: Description
880
+ */
881
+ router.get('/profile', authMiddleware, profile);
882
+
883
+ router.get('/info', info);
884
+
885
+ export default router;
886
+ ```
887
+
888
+ ### Structure d'un contrôleur
889
+
890
+ ```javascript
891
+ export const profile = (req, res, next) => {
892
+ try {
893
+ req.log?.info({ userId: req.user?.id }, 'profile requested');
894
+ res.status(200).json({
895
+ id: req.user.id,
896
+ role: req.user.role
897
+ });
898
+ } catch (err) {
899
+ next(err); // Passer les erreurs au middleware d'erreur
900
+ }
901
+ };
902
+
903
+ export const info = (req, res, next) => {
904
+ try {
905
+ res.status(200).json({ msg: 'ok' });
906
+ } catch (err) {
907
+ next(err);
908
+ }
909
+ };
910
+ ```
911
+
912
+ ### Structure d'un service
913
+
914
+ ```javascript
915
+ export const userService = {
916
+ /**
917
+ * Récupère un utilisateur par ID
918
+ * @param {string} id - ID utilisateur
919
+ * @returns {Promise<Object>} Données utilisateur
920
+ */
921
+ async getUser(id) {
922
+ req.log?.debug({ userId: id }, 'Fetching user');
923
+ // logique métier
924
+ return user;
925
+ }
926
+ };
927
+ ```
928
+
929
+ ### Gestion des erreurs
930
+
931
+ ```javascript
932
+ export const createUser = (req, res, next) => {
933
+ try {
934
+ // Validation
935
+ if (!req.body.email) {
936
+ const error = new Error('Email is required');
937
+ error.status = 400;
938
+ throw error;
939
+ }
940
+
941
+ // Logique métier
942
+ const user = userService.create(req.body);
943
+
944
+ res.status(201).json(user);
945
+ } catch (err) {
946
+ // Laisser le middleware d'erreur global gérer
947
+ next(err);
948
+ }
949
+ };
950
+ ```
951
+
952
+ ---
953
+
954
+ ## 🐛 Dépannage
955
+
956
+ ### Le serveur ne démarre pas
957
+
958
+ **Erreur** : `EADDRINUSE: address already in use :::3000`
959
+
960
+ **Cause** : Le port 3000 est déjà utilisé
961
+
962
+ **Solutions** :
963
+
964
+ ```bash
965
+ # Windows : Trouver et tuer le processus
966
+ netstat -ano | findstr :3000
967
+ taskkill /PID <PID> /F
968
+
969
+ # macOS/Linux :
970
+ lsof -i :3000
971
+ kill -9 <PID>
972
+
973
+ # Ou utiliser un port différent
974
+ PORT=3001 npm run dev
975
+ ```
976
+
977
+ ### "Cannot find module" errors
978
+
979
+ **Erreur** : `Cannot find module 'express'`
980
+
981
+ **Cause** : Dépendances non installées
982
+
983
+ **Solution** :
984
+ ```bash
985
+ npm install
986
+ ```
987
+
988
+ ### Erreurs d'import ES modules
989
+
990
+ **Erreur** : `ERR_MODULE_NOT_FOUND`
991
+
992
+ **Cause** : Chemin d'import incorrect
993
+
994
+ **Vérifier** :
995
+ - L'extension `.js` est incluse dans l'import
996
+ - Le chemin relatif est correct
997
+ - `"type": "module"` est présent dans `package.json`
998
+
999
+ ```javascript
1000
+ // ✅ Correct
1001
+ import app from './app.js';
1002
+
1003
+ // ❌ Incorrect
1004
+ import app from './app';
1005
+ ```
1006
+
1007
+ ### Erreurs de JWT
1008
+
1009
+ **Erreur** : `"Invalid token"`
1010
+
1011
+ **Cause** : Token expiré ou clé secrète incorrecte
1012
+
1013
+ **Solution** :
1014
+ ```bash
1015
+ # Vérifier la clé secrète
1016
+ echo $JWT_SECRET # macOS/Linux
1017
+ echo %JWT_SECRET% # Windows
1018
+
1019
+ # Modifier .env
1020
+ JWT_SECRET=new_secret_key
1021
+ ```
1022
+
1023
+ **Erreur** : `"Token missing"`
1024
+
1025
+ **Cause** : Header Authorization absent
1026
+
1027
+ **Solution** : Ajouter le header :
1028
+ ```bash
1029
+ curl -H "Authorization: Bearer YOUR_TOKEN" \
1030
+ http://localhost:3000/api/v1/users/profile
1031
+ ```
1032
+
1033
+ ### Les logs ne s'affichent pas
1034
+
1035
+ **Problème** : `LOG_LEVEL` trop élevé ou fichier non créé
1036
+
1037
+ **Solution** :
1038
+ ```bash
1039
+ # Réduire le seuil
1040
+ LOG_LEVEL=debug npm run dev
1041
+
1042
+ # Ou modifier .env
1043
+ LOG_LEVEL=debug
1044
+
1045
+ # Vérifier que le répertoire existe
1046
+ mkdir -p logs
1047
+ ```
1048
+
1049
+ ### Upload échoue
1050
+
1051
+ **Erreur 413** : `Payload Too Large`
1052
+
1053
+ **Cause** : Fichier dépasse la taille limite
1054
+
1055
+ **Solution** :
1056
+ ```bash
1057
+ # Augmenter la limite dans .env
1058
+ UPLOAD_MAX_SIZE=10485760 # 10MB
1059
+
1060
+ # Ou réduire le fichier
1061
+ ```
1062
+
1063
+ **Erreur 400** : `Only image files are allowed`
1064
+
1065
+ **Cause** : Type de fichier non autorisé
1066
+
1067
+ **Types acceptés** : JPEG, PNG, GIF, WebP
1068
+
1069
+ **Vérifier** :
1070
+ ```bash
1071
+ # Utiliser un fichier valide
1072
+ file image.jpg # Doit afficher : image data
1073
+
1074
+ # Ou utiliser imagemagick
1075
+ identify image.jpg
1076
+ ```
1077
+
1078
+ ### Tests ne passent pas
1079
+
1080
+ **Erreur** : `Test suites: 1 failed`
1081
+
1082
+ **Solution** :
1083
+ ```bash
1084
+ # Vérifier que le serveur n'est pas en cours d'exécution
1085
+ npm test
1086
+
1087
+ # Mode verbose pour plus de détails
1088
+ npm test -- --verbose
1089
+
1090
+ # Exécuter un test spécifique
1091
+ npm test -- user.controller.test.js
1092
+ ```
1093
+
1094
+ ### Base de données introuvable
1095
+
1096
+ **Erreur** : `ECONNREFUSED`
1097
+
1098
+ **Cause** : Service BD non accessible
1099
+
1100
+ **Vérifier** :
1101
+ ```bash
1102
+ # Vérifier la connexion
1103
+ ping database_host
1104
+
1105
+ # Vérifier les ports
1106
+ netstat -an | grep 5432 # PostgreSQL
1107
+ netstat -an | grep 3306 # MySQL
1108
+ ```
1109
+
1110
+ ---
1111
+
1112
+ ## 📞 Support & Contribution
1113
+
1114
+ Pour toute question ou contribution :
1115
+
1116
+ 1. **Consulter la documentation** : [Swagger UI](/docs)
1117
+ 2. **Vérifier les logs** : `logs/app.log`
1118
+ 3. **Exécuter les tests** : `npm test`
1119
+ 4. **Testez manuellement** : `node compare-versions.js` ou `node test-endpoints.js`
1120
+ 5. **Ouvrir une issue** sur le repository
1121
+
1122
+ ---
1123
+
1124
+ ## Scripts utiles
1125
+
1126
+ ### Scripts npm
1127
+
1128
+ ```bash
1129
+ # Démarrage
1130
+ npm start # Mode production
1131
+ npm run dev # Mode développement avec auto-reload
1132
+
1133
+ # Tests
1134
+ npm test # Exécuter les tests une seule fois
1135
+ npm run test:watch # Mode watch (détecte les changements)
1136
+
1137
+ # Utilitaires
1138
+ node compare-versions.js # Comparer v1 vs v2
1139
+ node test-endpoints.js # Tester les endpoints
1140
+ ```
1141
+
1142
+ ---
1143
+
1144
+ **Dernière mise à jour** : Janvier 2026
1145
+ **Version du projet** : 1.0.0
1146
+ **Node.js requis** : >= 16.x
1147
+ **License** : ISC