Documented comprehensive implementation plans for the authentication system and database schema, including architecture, module structure, API integration, security measures, and GDPR compliance details.
21 KiB
Guide d'Implémentation du Backend
Ce document présente un guide complet pour l'implémentation du backend de l'application de création de groupes, basé sur les spécifications du cahier des charges et les plans détaillés précédemment établis.
Table des Matières
- Vue d'Ensemble
- Préparation de l'Environnement
- Structure du Projet
- Configuration de Base
- Base de Données
- Authentification
- Modules Fonctionnels
- Communication en Temps Réel
- Sécurité et Conformité RGPD
- Tests et Documentation
- Déploiement
- Calendrier d'Implémentation
1. Vue d'Ensemble
L'application est une plateforme de création et de gestion de groupes qui permet aux utilisateurs de créer des groupes en prenant en compte divers paramètres et de conserver un historique des groupes précédemment créés.
1.1 Architecture Globale
L'application suit une architecture monorepo avec séparation claire entre le frontend et le backend :
- Frontend : Application Next.js avec App Router et Server Components
- Backend : API NestJS avec PostgreSQL et DrizzleORM
- Communication : API REST pour les opérations CRUD et WebSockets pour les mises à jour en temps réel
- Authentification : OAuth 2.0 avec GitHub et JWT pour la gestion des sessions
2. Préparation de l'Environnement
2.1 Installation des Dépendances
# Installation des dépendances principales
pnpm add @nestjs/config @nestjs/passport passport passport-github2 @nestjs/jwt
pnpm add @nestjs/websockets @nestjs/platform-socket.io socket.io
pnpm add drizzle-orm pg
pnpm add @node-rs/argon2 jose
pnpm add class-validator class-transformer
pnpm add zod zod-validation-error
pnpm add uuid
# Installation des dépendances de développement
pnpm add -D drizzle-kit
pnpm add -D @types/passport-github2 @types/socket.io @types/pg @types/uuid
2.2 Configuration de l'Environnement
Créer un fichier .env.example
à la racine du projet backend :
# Application
PORT=3000
NODE_ENV=development
API_PREFIX=api
# Database
DATABASE_URL=postgres://postgres:postgres@localhost:5432/groupmaker
# Authentication
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
GITHUB_CALLBACK_URL=http://localhost:3000/api/auth/github/callback
# JWT
JWT_ACCESS_SECRET=your_access_token_secret
JWT_REFRESH_SECRET=your_refresh_token_secret
JWT_ACCESS_EXPIRATION=15m
JWT_REFRESH_EXPIRATION=7d
# CORS
CORS_ORIGIN=http://localhost:3000
FRONTEND_URL=http://localhost:3000
3. Structure du Projet
La structure du projet backend suivra l'organisation suivante :
backend/
├── src/
│ ├── main.ts # Point d'entrée de l'application
│ ├── app.module.ts # Module principal
│ ├── config/ # Configuration de l'application
│ │ ├── app.config.ts # Configuration générale
│ │ ├── database.config.ts # Configuration de la base de données
│ │ ├── auth.config.ts # Configuration de l'authentification
│ │ └── env.validation.ts # Validation des variables d'environnement
│ ├── common/ # Utilitaires partagés
│ │ ├── decorators/ # Décorateurs personnalisés
│ │ ├── filters/ # Filtres d'exception
│ │ ├── guards/ # Guards d'authentification et d'autorisation
│ │ ├── interceptors/ # Intercepteurs
│ │ ├── pipes/ # Pipes de validation
│ │ └── utils/ # Fonctions utilitaires
│ ├── modules/ # Modules fonctionnels
│ │ ├── auth/ # Module d'authentification
│ │ ├── users/ # Module de gestion des utilisateurs
│ │ ├── projects/ # Module de gestion des projets
│ │ ├── persons/ # Module de gestion des personnes
│ │ ├── groups/ # Module de gestion des groupes
│ │ ├── tags/ # Module de gestion des tags
│ │ └── websockets/ # Module de gestion des WebSockets
│ └── database/ # Configuration de la base de données
│ ├── migrations/ # Migrations de base de données
│ ├── schema/ # Schéma de base de données (DrizzleORM)
│ └── database.module.ts # Module de base de données
├── test/ # Tests
│ ├── e2e/ # Tests end-to-end
│ └── unit/ # Tests unitaires
└── .env.example # Exemple de fichier d'environnement
4. Configuration de Base
4.1 Point d'Entrée de l'Application
Mettre à jour le fichier src/main.ts
:
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService = app.get(ConfigService);
// Configuration globale des pipes de validation
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
}),
);
// Configuration CORS
app.enableCors({
origin: configService.get<string>('CORS_ORIGIN'),
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
credentials: true,
});
// Préfixe global pour les routes API
app.setGlobalPrefix(configService.get<string>('API_PREFIX', 'api'));
const port = configService.get<number>('PORT', 3000);
await app.listen(port);
console.log(`Application is running on: http://localhost:${port}`);
}
bootstrap();
4.2 Module Principal
Mettre à jour le fichier src/app.module.ts
:
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { APP_GUARD } from '@nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from './database/database.module';
import { AuthModule } from './modules/auth/auth.module';
import { UsersModule } from './modules/users/users.module';
import { ProjectsModule } from './modules/projects/projects.module';
import { PersonsModule } from './modules/persons/persons.module';
import { GroupsModule } from './modules/groups/groups.module';
import { TagsModule } from './modules/tags/tags.module';
import { WebSocketsModule } from './modules/websockets/websockets.module';
import { JwtAuthGuard } from './modules/auth/guards/jwt-auth.guard';
import { validate } from './config/env.validation';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
validate,
}),
DatabaseModule,
AuthModule,
UsersModule,
ProjectsModule,
PersonsModule,
GroupsModule,
TagsModule,
WebSocketsModule,
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_GUARD,
useClass: JwtAuthGuard,
},
],
})
export class AppModule {}
4.3 Validation des Variables d'Environnement
Créer le fichier src/config/env.validation.ts
:
import { plainToClass } from 'class-transformer';
import { IsEnum, IsNumber, IsString, validateSync } from 'class-validator';
enum Environment {
Development = 'development',
Production = 'production',
Test = 'test',
}
class EnvironmentVariables {
@IsEnum(Environment)
NODE_ENV: Environment;
@IsNumber()
PORT: number;
@IsString()
API_PREFIX: string;
@IsString()
DATABASE_URL: string;
@IsString()
GITHUB_CLIENT_ID: string;
@IsString()
GITHUB_CLIENT_SECRET: string;
@IsString()
GITHUB_CALLBACK_URL: string;
@IsString()
JWT_ACCESS_SECRET: string;
@IsString()
JWT_REFRESH_SECRET: string;
@IsString()
JWT_ACCESS_EXPIRATION: string;
@IsString()
JWT_REFRESH_EXPIRATION: string;
@IsString()
CORS_ORIGIN: string;
@IsString()
FRONTEND_URL: string;
}
export function validate(config: Record<string, unknown>) {
const validatedConfig = plainToClass(
EnvironmentVariables,
{
...config,
PORT: config.PORT ? parseInt(config.PORT as string, 10) : 3000,
},
{ enableImplicitConversion: true },
);
const errors = validateSync(validatedConfig, {
skipMissingProperties: false,
});
if (errors.length > 0) {
throw new Error(errors.toString());
}
return validatedConfig;
}
5. Base de Données
5.1 Configuration de DrizzleORM
Créer le fichier drizzle.config.ts
à la racine du projet backend :
import type { Config } from 'drizzle-kit';
import * as dotenv from 'dotenv';
dotenv.config();
export default {
schema: './src/database/schema/*.ts',
out: './src/database/migrations',
driver: 'pg',
dbCredentials: {
connectionString: process.env.DATABASE_URL || 'postgres://postgres:postgres@localhost:5432/groupmaker',
},
verbose: true,
strict: true,
} satisfies Config;
5.2 Module de Base de Données
Créer le fichier src/database/database.module.ts
:
import { Module, Global } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { Pool } from 'pg';
import { drizzle } from 'drizzle-orm/node-postgres';
import * as schema from './schema';
export const DATABASE_POOL = 'DATABASE_POOL';
export const DRIZZLE = 'DRIZZLE';
@Global()
@Module({
imports: [ConfigModule],
providers: [
{
provide: DATABASE_POOL,
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
const pool = new Pool({
connectionString: configService.get<string>('DATABASE_URL'),
});
// Test the connection
const client = await pool.connect();
try {
await client.query('SELECT NOW()');
console.log('Database connection established successfully');
} finally {
client.release();
}
return pool;
},
},
{
provide: DRIZZLE,
inject: [DATABASE_POOL],
useFactory: (pool: Pool) => {
return drizzle(pool, { schema });
},
},
],
exports: [DATABASE_POOL, DRIZZLE],
})
export class DatabaseModule {}
5.3 Script de Migration
Créer le fichier src/database/migrate.ts
:
import { drizzle } from 'drizzle-orm/node-postgres';
import { migrate } from 'drizzle-orm/node-postgres/migrator';
import { Pool } from 'pg';
import * as dotenv from 'dotenv';
dotenv.config();
const main = async () => {
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
const db = drizzle(pool);
console.log('Running migrations...');
await migrate(db, { migrationsFolder: './src/database/migrations' });
console.log('Migrations completed successfully');
await pool.end();
};
main().catch((err) => {
console.error('Migration failed');
console.error(err);
process.exit(1);
});
5.4 Schéma de Base de Données
Créer les fichiers de schéma dans le dossier src/database/schema/
selon le plan détaillé dans le document DATABASE_SCHEMA_PLAN.md.
5.5 Scripts pour les Migrations
Ajouter les scripts suivants au package.json
du backend :
{
"scripts": {
"db:generate": "drizzle-kit generate:pg",
"db:migrate": "ts-node src/database/migrate.ts",
"db:studio": "drizzle-kit studio"
}
}
6. Authentification
6.1 Module d'Authentification
Créer le fichier src/modules/auth/auth.module.ts
selon le plan détaillé dans le document AUTH_IMPLEMENTATION_PLAN.md.
6.2 Stratégies d'Authentification
Implémenter les stratégies d'authentification (GitHub, JWT, JWT Refresh) selon le plan détaillé dans le document AUTH_IMPLEMENTATION_PLAN.md.
6.3 Service d'Authentification
Implémenter le service d'authentification selon le plan détaillé dans le document AUTH_IMPLEMENTATION_PLAN.md.
6.4 Contrôleur d'Authentification
Implémenter le contrôleur d'authentification selon le plan détaillé dans le document AUTH_IMPLEMENTATION_PLAN.md.
6.5 Guards et Décorateurs
Implémenter les guards et décorateurs d'authentification selon le plan détaillé dans le document AUTH_IMPLEMENTATION_PLAN.md.
7. Modules Fonctionnels
7.1 Module Utilisateurs
7.1.1 Service Utilisateurs
// src/modules/users/services/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { DRIZZLE } from '../../../database/database.module';
import { Inject } from '@nestjs/common';
import { eq } from 'drizzle-orm';
import * as schema from '../../../database/schema';
import { CreateUserDto } from '../dto/create-user.dto';
import { UpdateUserDto } from '../dto/update-user.dto';
@Injectable()
export class UsersService {
constructor(@Inject(DRIZZLE) private readonly db: any) {}
async create(createUserDto: CreateUserDto) {
const [user] = await this.db
.insert(schema.users)
.values(createUserDto)
.returning();
return user;
}
async findAll() {
return this.db.select().from(schema.users);
}
async findById(id: string) {
const [user] = await this.db
.select()
.from(schema.users)
.where(eq(schema.users.id, id));
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
async findByGithubId(githubId: string) {
const [user] = await this.db
.select()
.from(schema.users)
.where(eq(schema.users.githubId, githubId));
return user;
}
async update(id: string, updateUserDto: UpdateUserDto) {
const [user] = await this.db
.update(schema.users)
.set({
...updateUserDto,
updatedAt: new Date(),
})
.where(eq(schema.users.id, id))
.returning();
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
async remove(id: string) {
const [user] = await this.db
.delete(schema.users)
.where(eq(schema.users.id, id))
.returning();
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
async updateGdprConsent(id: string) {
return this.update(id, { gdprTimestamp: new Date() });
}
async exportUserData(id: string) {
const user = await this.findById(id);
const projects = await this.db
.select()
.from(schema.projects)
.where(eq(schema.projects.ownerId, id));
return {
user,
projects,
};
}
}
7.1.2 Contrôleur Utilisateurs
// src/modules/users/controllers/users.controller.ts
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
UseGuards,
} from '@nestjs/common';
import { UsersService } from '../services/users.service';
import { CreateUserDto } from '../dto/create-user.dto';
import { UpdateUserDto } from '../dto/update-user.dto';
import { GetUser } from '../../auth/decorators/get-user.decorator';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../../auth/guards/roles.guard';
import { Roles } from '../../auth/decorators/roles.decorator';
import { Role } from '../../auth/enums/role.enum';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
findAll() {
return this.usersService.findAll();
}
@Get('profile')
@UseGuards(JwtAuthGuard)
getProfile(@GetUser() user) {
return user;
}
@Get(':id')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
findOne(@Param('id') id: string) {
return this.usersService.findById(id);
}
@Patch(':id')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(id, updateUserDto);
}
@Delete(':id')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
remove(@Param('id') id: string) {
return this.usersService.remove(id);
}
@Post('gdpr-consent')
@UseGuards(JwtAuthGuard)
updateGdprConsent(@GetUser('id') userId: string) {
return this.usersService.updateGdprConsent(userId);
}
@Get('export-data')
@UseGuards(JwtAuthGuard)
exportUserData(@GetUser('id') userId: string) {
return this.usersService.exportUserData(userId);
}
}
7.2 Module Projets
Implémenter le module de gestion des projets avec les opérations CRUD et les relations avec les utilisateurs, les personnes et les groupes.
7.3 Module Personnes
Implémenter le module de gestion des personnes avec les opérations CRUD et les attributs spécifiés (niveau technique, genre, âge, etc.).
7.4 Module Groupes
Implémenter le module de gestion des groupes avec les opérations CRUD et les algorithmes de création automatique de groupes équilibrés.
7.5 Module Tags
Implémenter le module de gestion des tags avec les opérations CRUD et la gestion des types de tags (PROJECT, PERSON).
8. Communication en Temps Réel
8.1 Module WebSockets
Implémenter le module WebSockets selon le plan détaillé dans le document WEBSOCKET_IMPLEMENTATION_PLAN.md.
8.2 Gateways WebSocket
Implémenter les gateways WebSocket (Projets, Groupes, Notifications) selon le plan détaillé dans le document WEBSOCKET_IMPLEMENTATION_PLAN.md.
8.3 Service WebSocket
Implémenter le service WebSocket selon le plan détaillé dans le document WEBSOCKET_IMPLEMENTATION_PLAN.md.
9. Sécurité et Conformité RGPD
9.1 Sécurité
9.1.1 Protection contre les Attaques Courantes
- Implémenter la protection CSRF pour les opérations sensibles
- Configurer les en-têtes de sécurité (Content-Security-Policy, X-XSS-Protection, etc.)
- Utiliser des paramètres préparés avec DrizzleORM pour prévenir les injections SQL
- Mettre en place le rate limiting pour prévenir les attaques par force brute
9.1.2 Gestion des Tokens
- Implémenter la révocation des tokens JWT
- Configurer la rotation des clés de signature
- Mettre en place la validation complète des tokens (signature, expiration, émetteur)
9.2 Conformité RGPD
9.2.1 Gestion du Consentement
- Implémenter l'enregistrement du timestamp d'acceptation RGPD
- Mettre en place le renouvellement du consentement tous les 13 mois
9.2.2 Droits des Utilisateurs
- Implémenter l'export des données personnelles
- Mettre en place la suppression de compte avec option de conservation ou suppression des projets
10. Tests et Documentation
10.1 Tests
10.1.1 Tests Unitaires
Écrire des tests unitaires pour les services et les contrôleurs en utilisant Jest.
10.1.2 Tests E2E
Développer des tests end-to-end pour les API en utilisant Supertest.
10.2 Documentation
10.2.1 Documentation API
Générer la documentation API avec Swagger en utilisant les décorateurs NestJS.
10.2.2 Documentation Technique
Documenter l'architecture, les modèles de données et les flux d'interaction.
11. Déploiement
11.1 Conteneurisation
Créer un Dockerfile pour le backend :
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install
COPY . .
RUN pnpm build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/package.json /app/pnpm-lock.yaml ./
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/main"]
11.2 CI/CD
Configurer un workflow CI/CD avec GitHub Actions pour l'intégration et le déploiement continus.
12. Calendrier d'Implémentation
-
Semaine 1: Configuration et Base de Données
- Configuration de l'environnement
- Mise en place de la base de données avec DrizzleORM
- Définition du schéma et création des migrations
-
Semaine 2: Authentification et Utilisateurs
- Implémentation de l'authentification GitHub OAuth
- Développement du module utilisateurs
- Mise en place de la gestion des JWT
-
Semaine 3: Modules Principaux
- Développement des modules projets, personnes et groupes
- Implémentation des opérations CRUD
- Mise en place des relations entre entités
-
Semaine 4: Fonctionnalités Avancées
- Implémentation des WebSockets pour la communication en temps réel
- Développement des algorithmes de création de groupes
- Mise en place des fonctionnalités de sécurité et de conformité RGPD
-
Semaine 5: Tests et Finalisation
- Écriture des tests unitaires et e2e
- Documentation de l'API
- Optimisation des performances et correction des bugs