@workspace/database
Le package @workspace/database fournit un client MongoDB (version 6.12.0) et des modèles pour gérer les données de l’application.
Présentation
Ce package est le cœur de la persistance des données du projet. Il utilise le driver MongoDB officiel avec :
- Pattern Singleton : une seule connexion réutilisée dans toute l’application
- Connection pooling : gestion optimisée des connexions (2-10 connexions)
- Types TypeScript : support complet avec génériques pour les collections
- Index optimisés : index unique sur l’email, index de recherche sur le nom
- Gestion automatique : horodatage et normalisation des données
Installation
Ce package fait partie du monorepo et est automatiquement disponible via l’alias @workspace/database.
Configuration
Variables d’environnement
Créez un fichier .env.local à la racine de l’application web (apps/web/.env.local) :
# Configuration MongoDB
MONGODB_URI=mongodb://localhost:27017
MONGODB_DB_NAME=tp-nextjs| Variable | Description | Défaut | Requis |
|---|---|---|---|
MONGODB_URI | URL de connexion MongoDB | mongodb://localhost:27017 | Non |
MONGODB_DB_NAME | Nom de la base de données | tp-nextjs | Non |
Docker
Le projet utilise Docker Compose pour gérer MongoDB. La configuration lance automatiquement MongoDB 7 dans un container.
Utilisez Docker Compose pour démarrer MongoDB :
# Démarrer MongoDB en arrière-plan
docker-compose up -d
# Vérifier que MongoDB est démarré
docker-compose ps
# Voir les logs
docker-compose logs -f mongodb
# Accéder au shell MongoDB
docker exec -it tp-nextjs-mongodb mongosh
# ArrĂŞter MongoDB
docker-compose downCaractéristiques techniques
- Driver MongoDB : version 6.12.0
- Connection pooling :
- Pool minimum : 2 connexions
- Pool maximum : 10 connexions
- Timeouts :
- Server selection : 5000ms
- Connection : 10000ms
- Pattern Singleton : évite les connexions multiples en développement
Client MongoDB
Connexion
import { getMongoClient, getDatabase, getCollection } from "@workspace/database";
// Récupérer le client MongoDB
const client = await getMongoClient();
// Récupérer la base de données
const db = await getDatabase();
// Récupérer une collection typée
const users = await getCollection<User>("users");Fonctions disponibles
| Fonction | Description |
|---|---|
getMongoClient() | Récupère le client MongoDB (singleton) |
getDatabase() | Récupère la base de données principale |
getCollection<T>(name) | Récupère une collection typée |
closeConnection() | Ferme la connexion |
checkConnection() | Vérifie la connexion |
Modèle User
Interface
interface User {
_id?: ObjectId;
email: string;
name: string;
password?: string;
createdAt: Date;
updatedAt: Date;
}Types utilitaires
// Pour la création
type CreateUserInput = Omit<User, '_id' | 'createdAt' | 'updatedAt'>;
// Pour la mise Ă jour
type UpdateUserInput = Partial<Omit<User, '_id' | 'createdAt' | 'updatedAt'>>;Opérations CRUD
Créer un utilisateur
import { createUser } from "@workspace/database";
const newUser = await createUser({
email: "test@example.com",
name: "Test User",
password: "hashedPassword", // Toujours hasher avant !
});Trouver un utilisateur
import { findUserById, findUserByEmail } from "@workspace/database";
// Par ID
const user = await findUserById("67abc123...");
// Par email (utile pour l'authentification)
const user = await findUserByEmail("test@example.com");Lister les utilisateurs
import { listUsers, countUsers } from "@workspace/database";
// Liste paginée (20 résultats par défaut)
const users = await listUsers(20, 0);
// Nombre total
const total = await countUsers();Mettre Ă jour un utilisateur
import { updateUser } from "@workspace/database";
const updated = await updateUser("67abc123...", {
name: "Nouveau nom",
});Supprimer un utilisateur
import { deleteUser } from "@workspace/database";
const success = await deleteUser("67abc123...");Initialisation
Au démarrage de l’application, initialisez les index :
import { initializeUsersCollection } from "@workspace/database";
// Crée les index nécessaires (email unique, etc.)
await initializeUsersCollection();Bonnes pratiques
1. Hashage des mots de passe
Toujours hasher les mots de passe avant de les stocker :
import { hashPassword } from "@/lib/auth";
import { createUser } from "@workspace/database";
// ❌ JAMAIS faire ça
await createUser({ email, name, password: "plaintext" });
// âś… Toujours hasher avant
const hashedPassword = await hashPassword(password);
await createUser({ email, name, password: hashedPassword });2. Normalisation des emails
Les emails sont automatiquement normalisés (minuscules + trim) par le package :
// Ces deux appels trouvent le mĂŞme utilisateur
await findUserByEmail("USER@EXAMPLE.COM");
await findUserByEmail(" user@example.com ");3. Gestion des erreurs
Gérez les erreurs de connexion et les contraintes d’unicité :
try {
await createUser({ email, name, password });
} catch (error) {
// Erreur d'email dupliqué (code 11000)
if (error.code === 11000) {
console.error("Cet email existe déjà ");
}
}4. Fermeture propre
Appelez closeConnection() à l’arrêt de l’application pour libérer les ressources :
import { closeConnection } from "@workspace/database";
// À l'arrêt de l'application
process.on("SIGTERM", async () => {
await closeConnection();
process.exit(0);
});Sécurité
Protection du mot de passe
findUserById()etlistUsers()excluent automatiquement le mot de passefindUserByEmail()inclut le mot de passe pour l’authentification- Utilisez
projection: { password: 0 }pour exclure manuellement
Index unique sur l’email
Un index unique empêche les doublons d’email :
// Créé automatiquement par initializeUsersCollection()
await collection.createIndex({ email: 1 }, { unique: true });Structure du package
packages/database/
├── src/
│ ├── index.ts # Exports principaux
│ ├── mongodb-client.ts # Client MongoDB singleton
│ └── user.ts # Modèle User et CRUD
├── package.json # Dépendances (mongodb@6.12.0)
├── tsconfig.json # Configuration TypeScript
├── eslint.config.js # Configuration ESLint
└── README.md # DocumentationDépendances
Le package utilise les dépendances suivantes :
mongodb(^6.12.0) : Driver MongoDB officiel@types/node: Types TypeScript pour Node.jstypescript: Compilateur TypeScript
Intégration avec l’authentification
Ce package est conçu pour fonctionner avec le système d’authentification du projet. Voir le guide d’authentification pour plus de détails.
Workflow complet
import { createUser, findUserByEmail } from "@workspace/database";
import { hashPassword, verifyPassword, createSession } from "@/lib/auth";
// 1. Inscription
async function signup(email: string, name: string, password: string) {
// Vérifier si l'email existe
const existing = await findUserByEmail(email);
if (existing) throw new Error("Email déjà utilisé");
// Hasher le mot de passe
const hashedPassword = await hashPassword(password);
// Créer l'utilisateur
const user = await createUser({ email, name, password: hashedPassword });
// Créer la session
await createSession(user._id.toString(), user.email, user.name);
}
// 2. Connexion
async function login(email: string, password: string) {
// Trouver l'utilisateur
const user = await findUserByEmail(email);
if (!user || !user.password) throw new Error("Identifiants invalides");
// Vérifier le mot de passe
const isValid = await verifyPassword(password, user.password);
if (!isValid) throw new Error("Identifiants invalides");
// Créer la session
await createSession(user._id.toString(), user.email, user.name);
}Exemple complet
import {
createUser,
findUserByEmail,
listUsers,
checkConnection,
} from "@workspace/database";
// Vérifier la connexion
const isConnected = await checkConnection();
if (!isConnected) {
console.error("MongoDB non disponible");
return;
}
// Créer un utilisateur
const user = await createUser({
email: "nouveau@example.com",
name: "Nouveau User",
});
// Récupérer tous les utilisateurs
const allUsers = await listUsers();
console.log(`${allUsers.length} utilisateurs trouvés`);