Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

⚡️ Node.js – Installation, Core & Déploiement

Guide complet IDEO‑Lab sur l'runtime JavaScript (Event Loop, NPM, Async, Express, PM2).

1.1

Vue d'ensemble

Runtime JS (V8), I/O non-bloquant, backend.

V8 Backend
1.2

Event Loop (Cœur)

Boucle d'événements, non-bloquant, single-thread.

Event Loop Non-blocking
1.3

Installation (NVM)

nvm (Node Version Manager) (reco), LTS.

nvm LTS
2.1

NPM & package.json

npm init, install, scripts, dependencies.

npm package.json
2.2

Modules (CJS vs ESM)

require (CommonJS) vs import (ESM).

require import
2.3

Core : fs & path

File System (async/sync), gestion des chemins.

fs path
2.4

Core : http & events

Serveur HTTP (natif), EventEmitter.

http events
2.5

Core : Buffers & Streams

Données binaires (Buffer), .pipe() (Streams).

Buffer Stream
3.1

Callbacks

Le style "Callback Hell" (pyramide).

Callback Callback Hell
3.2

Promises (Promesses)

.then(), .catch(), Promise.all().

Promise .then
3.3

Async / Await

Syntaxe moderne (async function, await, try/catch).

async await
4.1

Express.js (Intro)

Installation, Hello World, app.listen.

Express npm i express
4.2

Express (Routing)

app.get, app.post, req.params, req.body.

Router req.params
4.3

Express (Middleware)

app.use(), express.json(), CORS, logger.

Middleware CORS
5.1

Base de Données (Postgres)

npm install pg, Pool de connexions, pool.query.

node-postgres Pool
5.2

API Client (Axios)

npm install axios, axios.get, axios.post.

Axios Fetch
5.3

Process Manager (PM2)

pm2 start, clustering, --watch, logs, restart.

PM2 Cluster
5.4

Déploiement (Nginx)

Reverse proxy Nginx vers PM2 (localhost).

Nginx proxy_pass
6.1

Cheat-sheet Node

Commandes NPM, NVM, Core modules.

cheat npm
1.1 Vue d'ensemble : JavaScript côté serveur
Runtime JavaScript (Backend)

Node.js est un **runtime** (environnement d'exécution) JavaScript open-source, multiplateforme, qui permet d'exécuter du JavaScript **côté serveur** (backend).

Créé par Ryan Dahl en 2009, il prend le moteur JavaScript V8 (le cœur de Google Chrome) et l'intègre dans un programme C++, en y ajoutant des modules pour le système (fichiers, réseau...).

Node.js n'est PAS un framework. C'est l'environnement sur lequel tournent les frameworks (comme Express.js).

Philosophie
  • I/O Asynchrone (Non-bloquant) : C'est sa caractéristique principale. Node est conçu pour gérer des milliers de connexions simultanées (ex: chat, API) avec une faible empreinte mémoire.
  • Single-Threaded (Mono-processus) : Node s'exécute sur un seul thread principal.
  • Écosystème (NPM) : Le plus grand registre de paquets (librairies) au monde.
Node vs. PHP (FPM) vs. Python (Gunicorn)

La différence fondamentale est la gestion des requêtes.

CritèreNode.js (Async I/O)PHP-FPM / Python (Sync I/O)
ModèleAsynchrone (Event Loop)Synchrone (Multi-processus/threads)
Requête 1 (I/O Lente)Démarre l'I/O (ex: BDD), libère le thread.Démarre l'I/O, bloque le thread en attendant la BDD.
Requête 2 (Rapide)Le même thread prend la Req 2 (pendant que Req 1 attend).Doit attendre qu'un autre worker/thread soit libre.
ConcurrenceGère des milliers de connexions (I/O) sur 1 thread.Gère N connexions (où N = nb de workers).
UsageAPIs, temps-réel (Sockets), microservices.Applications métiers, CMS, CPU-bound tasks.
1.2 Le Cœur : La Boucle d'Événements (Event Loop)
L'Event Loop (Schéma simplifié)

Node est "mono-thread", mais il délègue les opérations I/O (lentes) au système (via libuv). L'Event Loop gère les retours (callbacks).

[Image d'un schéma Event Loop]
+----------------------+
| Call Stack           |  <-- (Code JS exécuté ici)
| (Ex: funcA())        |
+----------------------+
       |
       | (Opération I/O, ex: fs.readFile)
       ▼
+----------------------+
| API Node (libuv)     |  <-- (Géré par le Système/Threads C++)
| (Ex: "Lire fichier X") |
+----------------------+
       |
       | (Fichier lu, prêt)
       ▼
+----------------------+
| Callback Queue       |  <-- (Callback "fichierLu" attend)
| (FIFO)               |
+----------------------+
       |
       | (Si Call Stack est vide...)
       ▼
+----------------------+
| EVENT LOOP           |  <-- (Prend le callback et l'envoie
| (Tourne en permanence) |      au Call Stack)
+----------------------+
Code Bloquant (Synchrone) - MAUVAIS

readFileSync bloque le thread. Pendant 5 secondes, le serveur ne peut *rien* faire d'autre.

const fs = require('fs');

// 1. Le serveur bloque ici pendant 5s
const data = fs.readFileSync('/gros_fichier.txt');
console.log(data);

// 2. Cette ligne n'est atteinte qu'après 5s
console.log("Terminé");
Code Non-Bloquant (Asynchrone) - BON

readFile délègue l'opération et passe un "callback". Le serveur continue de travailler.

const fs = require('fs');

// 1. Démarre la lecture (non-bloquant)
fs.readFile('/gros_fichier.txt', (err, data) => {
  // 3. (Callback) Ceci s'exécute 5s plus tard
  console.log(data);
});

// 2. Cette ligne s'affiche IMMÉDIATEMENT
console.log("Terminé");
1.3 Installation : NVM (Node Version Manager)
NVM (Node Version Manager)

La meilleure pratique. NVM permet d'installer et de basculer entre plusieurs versions de Node.js (ex: projet A en Node 18, projet B en Node 20).

Installation NVM (Linux/macOS)
# 1. Télécharger et exécuter le script
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# 2. Recharger le shell
source ~/.bashrc
# (ou source ~/.zshrc)

# 3. Vérifier
nvm --version
Utilisation NVM
# Installer la dernière version LTS (Long Term Support)
nvm install --lts

# (ou Installer une version spécifique)
nvm install 20

# Lister les versions installées
nvm ls

# Utiliser une version
nvm use 20

# Définir la version par défaut
nvm alias default 20
NVM for Windows

Un projet différent, mais avec le même objectif.
Allez sur : github.com/coreybutler/nvm-windows

  1. Téléchargez l'installeur (nvm-setup.exe).
  2. Exécutez-le.
Utilisation (Windows)
(Dans cmd ou PowerShell, en Admin)
nvm list available

nvm install 20.10.0

nvm use 20.10.0

nvm list
Alternative : Installeur Officiel

Sur nodejs.org. Installe Node globalement sur le système. Moins flexible que NVM.

Alternative : Docker

Idéal pour l'isolation et la production.

# Lancer un shell dans un conteneur Node
docker run -it --rm -v $(pwd):/app -w /app node:20-alpine sh

# (Dans le conteneur)
node -v
npm install
2.1 NPM (Node Package Manager) & package.json
package.json

Le fichier manifeste de tout projet Node. Il décrit le projet, ses dépendances et ses scripts.

{
  "name": "mon-projet-api",
  "version": "1.0.0",
  "description": "API pour IDEO-Lab",
  "main": "app.js",
  "type": "commonjs", // "commonjs" (require) ou "module" (import)
  
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js",
    "test": "jest"
  },
  
  "dependencies": {
    "express": "^4.18.2",
    "pg": "^8.11.3"
  },
  
  "devDependencies": {
    "nodemon": "^3.0.1",
    "jest": "^29.7.0"
  }
}
  • scripts : Raccourcis (npm run dev).
  • dependencies : Requis pour la production (ex: Express).
  • devDependencies : Requis pour le développement (ex: Nodemon).
Commandes npm
# 1. Initialiser un projet (crée package.json)
npm init -y

# 2. Installer une dépendance (Prod)
# (Ajoute à 'dependencies' et au dossier 'node_modules')
npm install express
# (ou 'npm i express')

# 3. Installer une dépendance (Dev)
npm install --save-dev nodemon
# (ou 'npm i -D nodemon')

# 4. Installer toutes les dépendances (depuis package.json)
npm install

# 5. Lancer un script
npm run dev
npm start # (Raccourci pour 'npm run start')

# 6. Lister les paquets
npm list --depth=0

# 7. Désinstaller un paquet
npm uninstall express

# 8. 'npx' (Exécute un paquet sans l'installer)
npx create-react-app mon-app
package-lock.json (Crucial)

Ce fichier est auto-généré. Ne *jamais* le modifier manuellement.

Rôle : Il "verrouille" (lock) les versions exactes de *toutes* les dépendances (et sous-dépendances) qui ont été installées.

Pourquoi ?
package.json : "express": "^4.18.2" (^ = version 4.18.2 ou supérieure, mais < 5.0).
package-lock.json : "express": "4.18.2" (la version exacte installée).

Quand vous lancez npm install, c'est le package-lock.json qui est utilisé pour garantir que tous les développeurs (et le serveur de prod) ont exactement le même node_modules. (Garantit la reproductibilité).

2.2 Modules (CommonJS vs ES Modules)
CommonJS (CJS) (Le "classique")

Le système de modules original de Node. Basé sur require() (synchrone).

math.js
function addition(a, b) {
  return a + b;
}

const PI = 3.14;

// Exporter
module.exports = {
  addition,
  PI
};
app.js
// Importer
const math = require('./math.js');

console.log(math.addition(10, 5)); // 15
console.log(math.PI); // 3.14

Mode par défaut si "type": "commonjs" (ou absent) dans package.json.

ES Modules (ESM) (Le standard JavaScript)

Le système de modules standard de JavaScript (utilisé par les navigateurs et React). Basé sur import/export (asynchrone).

Activation : Ajoutez "type": "module" dans package.json.

math.mjs (ou .js)
export function addition(a, b) {
  return a + b;
}

export const PI = 3.14;

// (Export par défaut)
// export default MonObjet;
app.mjs (ou .js)
// Importer (destructuring)
import { addition, PI } from './math.mjs';

// (Import par défaut)
// import MonObjet from './math.mjs';

console.log(addition(10, 5)); // 15
console.log(PI); // 3.14

C'est la norme moderne. Node.js supporte les deux, mais l'écosystème migre vers ESM.

2.3 Core : fs (File System) & path
fs (File System)

Le module fs fournit des méthodes asynchrones (non-bloquantes, avec callback) et synchrones (bloquantes, ...Sync).

Synchrone (Bloquant) - Pour les scripts
const fs = require('fs');
try {
  const data = fs.readFileSync('config.txt', 'utf8');
  console.log(data);
} catch (err) {
  console.error(err);
}
Asynchrone (Callback) - Pour les serveurs
const fs = require('fs');
fs.readFile('config.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});
fs/promises (La méthode moderne)

Depuis Node 14, fs/promises expose les méthodes fs en version Promise (utilisable avec async/await).

import { readFile, writeFile } from 'fs/promises';

async function main() {
  try {
    const data = await readFile('config.txt', 'utf8');
    console.log(data);
    
    await writeFile('output.txt', data.toUpperCase());
    console.log('Fichier écrit !');
  } catch (err) {
    console.error(err);
  }
}
main();
path (Gestion des chemins)

Ne concaténez jamais les chemins (/ vs \). Utilisez path.

const path = require('path');

// 1. Joindre des chemins (multi-OS)
const configPath = path.join('/home', 'user', 'config.txt');
// '/home/user/config.txt'

// 2. Résoudre un chemin (depuis la racine)
const absPath = path.resolve('..', 'logs', 'app.log');
// '/home/ideo_user/projets/logs/app.log'

// 3. Obtenir le nom du dossier/fichier
path.dirname(configPath);  // '/home/user'
path.basename(configPath); // 'config.txt'
path.extname(configPath);  // '.txt'

// 4. __dirname (CJS)
// Le dossier du fichier actuel
const dbPath = path.join(__dirname, 'db.sqlite');

// (ESM - L'équivalent)
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
2.4 Core : http & events
http (Serveur natif)

Le module http permet de créer un serveur web "bas niveau". (Express.js l'utilise en interne).

const http = require('http');

// 'req' (Request), 'res' (Response)
const server = http.createServer((req, res) => {
  
  if (req.url === '/') {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Accueil\n');
  } else if (req.url === '/json') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'ok' }));
  } else {
    res.writeHead(404);
    res.end('Not Found\n');
  }
  
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Serveur démarré sur http://127.0.0.1:3000');
});
events (EventEmitter)

De nombreux objets Node (streams, http) héritent de EventEmitter. C'est le pattern "Observer" (Pub/Sub).

const EventEmitter = require('events');

class MonEmetteur extends EventEmitter {}
const emetteur = new MonEmetteur();

// 1. S'abonner à l'événement 'alerte'
emetteur.on('alerte', (data) => {
  console.log('Alerte reçue !', data);
});

// (Une seule fois)
emetteur.once('connexion', () => {
  console.log('Connecté !');
});

// 2. Émettre les événements
emetteur.emit('connexion');
emetteur.emit('alerte', { code: 'rouge' });
emetteur.emit('connexion'); // (Ne fait rien)
2.5 Core : Buffers & Streams
Buffer (Données Binaires)

JavaScript n'était pas conçu pour les données binaires. Node a introduit Buffer pour gérer les octets (ex: lire une image, données TCP).

// Alloue un buffer de 10 octets (vide)
const buf1 = Buffer.alloc(10);

// Crée un buffer depuis un string
const buf2 = Buffer.from('Bonjour');

console.log(buf2);
//  (Hex)

console.log(buf2.toString('utf8'));
// 'Bonjour'
Stream (Flux de données)

Pour gérer des données volumineuses (ex: un fichier de 5Go), on ne peut pas tout charger en RAM (Buffer). On utilise un Stream (flux).

.pipe() est la méthode la plus efficace pour "tuyauter" un flux lisible (Readable) vers un flux écrivable (Writable).

const fs = require('fs');
const http = require('http');

// Cas 1: Mauvais (bloque 5Go de RAM)
http.createServer((req, res) => {
  const data = fs.readFileSync('video.mp4'); // 5Go
  res.end(data);
});

// Cas 2: Bon (Stream)
http.createServer((req, res) => {
  // Crée un flux de lecture
  const readStream = fs.createReadStream('video.mp4');
  
  // "Pipe" le flux du fichier vers la réponse HTTP
  // (La RAM reste faible)
  readStream.pipe(res);
});
3.1 Callbacks (L'enfer des callbacks)
Le "Callback Hell" (Pyramide)

L'ancienne méthode de gestion asynchrone consistait à passer des fonctions (callbacks) en dernier argument. Pour chaîner des opérations, on tombe dans le "Callback Hell".

Logique : 1. Lire config -> 2. Lire BDD -> 3. Écrire fichier

const fs = require('fs');

fs.readFile('config.json', 'utf8', (err1, configData) => {
  if (err1) {
    console.error("Erreur config", err1);
  } else {
    
    // (Supposez que 'db.query' est aussi async)
    db.query(configData.sql, (err2, dbData) => {
      if (err2) {
        console.error("Erreur BDD", err2);
      } else {
        
        fs.writeFile('output.txt', dbData, (err3) => {
          if (err3) {
            console.error("Erreur écriture", err3);
          } else {
            console.log("Terminé !");
          }
        });
        
      }
    });
    
  }
});
3.2 Promises (Promesses)
Consommer des Promises (.then)

Une "Promise" est un objet qui représente une opération future. On "aplatit" le Callback Hell en chaînant les .then().

const { readFile, writeFile } = require('fs/promises');

readFile('config.json', 'utf8')
  .then((configData) => {
    // 1. Config lue
    return db.query(configData.sql); // (Suppose que db.query retourne une Promise)
  })
  .then((dbData) => {
    // 2. BDD lue
    return writeFile('output.txt', dbData);
  })
  .then(() => {
    // 3. Fichier écrit
    console.log("Terminé !");
  })
  .catch((err) => {
    // 4. Gère TOUTES les erreurs
    console.error("Une erreur est survenue:", err);
  })
  .finally(() => {
    // (Optionnel: s'exécute toujours)
    db.close();
  });
Créer une Promise (Wrapper)

Pour "promisifier" une ancienne fonction à callback.

function oldCallbackFunc(callback) {
  setTimeout(() => {
    // callback(erreur, resultat)
    callback(null, "OK");
  }, 1000);
}

function promiseFunc() {
  return new Promise((resolve, reject) => {
    
    oldCallbackFunc((err, data) => {
      if (err) {
        reject(err); // En cas d'erreur
      } else {
        resolve(data); // En cas de succès
      }
    });
    
  });
}
Promise.all (Parallèle)

Exécute plusieurs promises en parallèle et attend qu'elles soient *toutes* terminées.

const p1 = fetch('https://api.example.com/users');
const p2 = fetch('https://api.example.com/products');

Promise.all([p1, p2])
  .then(([usersResponse, productsResponse]) => {
    // 'usersResponse' et 'productsResponse' sont prêts
  })
  .catch(err => {
    // Échoue si UNE SEULE promise échoue
  });
3.3 Async / Await (Syntaxe moderne)
Sucre syntaxique pour les Promises

async/await (ES2017) est une syntaxe qui permet d'écrire du code asynchrone (basé on Promises) comme s'il était synchrone.

  • async function : Déclare une fonction qui retourne implicitement une Promise.
  • await : Met en "pause" l'exécution de la fonction (sans bloquer le thread) en attendant que la Promise soit résolue.
  • try...catch : Gère les erreurs (les "rejects").
Exemple (remplace 3.2)
const { readFile, writeFile } = require('fs/promises');

// 1. 'async'
async function main() {
  try {
    // 2. 'await' (attend la résolution)
    const configData = await readFile('config.json', 'utf8');
    
    // 3. 'await' (attend la BDD)
    const dbData = await db.query(configData.sql);
    
    // 4. 'await' (attend l'écriture)
    await writeFile('output.txt', dbData);
    
    console.log("Terminé !");
    
  } catch (err) {
    // 5. 'catch' (gère les erreurs)
    console.error("Une erreur est survenue:", err);
  } finally {
    db.close();
  }
}

// Lancer la fonction
main();
4.1 Framework : Express.js (Introduction)
Le framework web de facto

Personne n'utilise le module http (cf 2.4) en production. Express.js est un micro-framework minimaliste qui simplifie le routage, la gestion des middlewares et les réponses.

Installation
npm install express
app.js (Hello World)
const express = require('express');

// 1. Créer l'application
const app = express();
const port = 3000;

// 2. Définir une route (le "Routing")
// (req = Request, res = Response)
app.get('/', (req, res) => {
  // .send() est plus simple que .end()
  res.send('Bonjour, IDEO-Lab !');
});

app.get('/json', (req, res) => {
  // .json() gère le Content-Type auto
  res.json({ status: 'ok' });
});

// 3. Démarrer le serveur
app.listen(port, () => {
  console.log(`Serveur démarré sur http://localhost:${port}`);
});
4.2 Express : Routage & Middleware
Routage (req.params, req.query, req.body)
const express = require('express');
const app = express();

// Middleware (requis pour parser le JSON des 'POST')
app.use(express.json());

// 1. GET (Query params: /search?q=test)
app.get('/search', (req, res) => {
  const query = req.query.q; // "test"
  res.json({ search: query });
});

// 2. GET (Path params: /users/123)
app.get('/users/:id', (req, res) => {
  const userId = req.params.id; // "123"
  res.json({ user_id: userId });
});

// 3. POST (Body: { "nom": "Alice" })
app.post('/users', (req, res) => {
  const nom = req.body.nom; // "Alice"
  // (Nécessite 'app.use(express.json())')
  res.status(201).json({ status: 'créé', nom: nom });
});

// 4. PUT
app.put('/users/:id', (req, res) => {
  // ...
});

// 5. DELETE
app.delete('/users/:id', (req, res) => {
  // ...
});
Middleware

Un "middleware" est une fonction qui s'exécute **entre** la requête et la route. ((req, res, next) => ...).

Middleware intégré (CORS)
# npm install cors
const cors = require('cors');
app.use(cors()); // Autorise toutes les origines
Middleware Custom (Logger)
// Ce middleware s'exécute sur TOUTES les requêtes
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  
  // 'next()' passe à la route suivante (ou au middleware suivant)
  next();
});

// Servir des fichiers statiques
app.use(express.static('public'));
// (http://localhost:3000/images/logo.png -> /public/images/logo.png)
5.1 Base de Données (node-postgres)
npm install pg

node-postgres (pg) est le driver principal pour PostgreSQL. Il est entièrement asynchrone (basé sur Promises).

Configuration (Pool de connexions)

Ne créez pas un client par requête. Créez un **Pool** (singleton) et réutilisez-le.

// db.js
const { Pool } = require('pg');

const pool = new Pool({
  user: 'db_user',
  host: 'localhost',
  database: 'ideo_lab_db',
  password: 'db_password',
  port: 5432,
});

module.exports = {
  query: (text, params) => pool.query(text, params),
};
Utilisation (Async/Await)
// app.js
const express = require('express');
const db = require('./db');
const app = express();

app.get('/users', async (req, res) => {
  try {
    const { rows } = await db.query('SELECT * FROM users');
    res.json(rows);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.get('/users/:id', async (req, res) => {
  try {
    const { id } = req.params;
    
    // Protection contre l'injection SQL
    const { rows } = await db.query(
      'SELECT * FROM users WHERE id = $1',
      [id]
    );
    
    res.json(rows[0]);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});
5.2 API Client (Axios)
Axios

Pour appeler d'autres APIs (microservices, APIs externes) depuis Node, axios est la librairie la plus populaire (basée sur Promises).

npm install axios
GET
const axios = require('axios');

async function getUsers() {
  try {
    const response = await axios.get('https://api.example.com/users');
    console.log(response.data); // Données JSON
  } catch (error) {
    console.error(error.response.data); // Erreur de l'API
  }
}
POST
async function createUser(nom) {
  try {
    const response = await axios.post('https://api.example.com/users', {
      nom: nom,
      status: 'actif'
    });
    console.log(response.data);
  } catch (error) {
    console.error(error);
  }
}

// (axios.put, axios.delete...)
5.3 Process Manager (PM2)
Le problème de node app.js

Si vous lancez node app.js en production :

  1. Si l'app crashe (erreur), le processus s'arrête. Le site est mort.
  2. Si le serveur reboote, le site ne redémarre pas.
  3. Il ne tourne que sur 1 cœur de CPU.
Solution : PM2 (Process Manager)

PM2 est un gestionnaire de processus pour Node.js. Il gère :

  • Clustering : Lance 1 processus par cœur de CPU (Mode Cluster) et répartit la charge (load balancing).
  • Monitoring : Surveille l'état (RAM, CPU) des processus.
  • Auto-Restart : Redémarre l'app si elle crashe.
  • Startup Script : Redémarre l'app au boot du serveur.
  • Logs : Centralise les logs (stdout/stderr).
Commandes PM2 (Production)
# 1. Installer PM2 (Globalement)
sudo npm install -g pm2

# 2. Démarrer l'application (Mode Cluster)
# (-i max = 1 worker par coeur CPU)
pm2 start app.js -i max --name "api-ideo-lab"

# 3. Lister les processus
pm2 list
# (ou 'pm2 ls')

# 4. Voir les logs (en direct)
pm2 logs api-ideo-lab
# (ou 'pm2 logs')

# 5. Redémarrer (0-downtime reload)
pm2 reload api-ideo-lab

# 6. Arrêter
pm2 stop api-ideo-lab

# 7. Supprimer
pm2 delete api-ideo-lab

# 8. (Crucial) Générer le script de démarrage
pm2 startup
# (Copiez/Collez la commande générée)
pm2 save
5.4 Déploiement : Nginx (Reverse Proxy)
Architecture de Production

PM2 (Node.js) écoute sur un port local (ex: 3000). Nginx écoute sur le port public (80/443) et agit en "reverse proxy".

[Internet] (Port 80/443)
    |
    ▼
[Nginx (Reverse Proxy)]
 (TLS, Cache, Compression)
    |
    | (proxy_pass)
    ▼
[PM2 / Node.js] (Port 3000)
 (Clustered)
Configuration Nginx
# /etc/nginx/sites-available/node-app
upstream nodejs_app {
    # PM2 écoute ici (localhost:3000)
    server 127.0.0.1:3000;
}

server {
    listen 80;
    server_name node-app.ideolab.com;
    
    location / {
        proxy_pass http://nodejs_app;
        
        # Headers essentiels
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Pour les WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
6.1 Cheat-sheet Node.js
NVM (Gestionnaire de versions)
nvm install --lts
nvm install 20
nvm use 20
nvm ls
nvm alias default 20
NPM (Gestionnaire de paquets)
npm init -y
npm install express
npm i -D nodemon
npm install # (ou 'npm i')
npm run dev
npm run start
npm list --depth=0
npm uninstall express
Modules (Core)
// CJS (Défaut)
const fs = require('fs');
module.exports = { ... };

// ESM ("type": "module")
import fs from 'fs';
export { ... };
export default ...;

// FS (Async/Promise)
import { readFile, writeFile } from 'fs/promises';
const data = await readFile('file.txt', 'utf8');

// Path
const path = require('path');
path.join(__dirname, 'views');
path.resolve('..', 'file.txt');