cda-ebrairie
API de gestion de bibliothèque (auteurs, catégories, membres, emprunts) implémentée avec une architecture TypeScript modulaire orientée use cases, TypeORM, validation DTO et authentification JWT. Le projet illustre une conception backend structurée et maintenable sur une stack Node.js/TypeScript.
🎯 Contexte et objectifs
- Concevoir un backend métier pour gérer les flux de prêt/retour et la consultation des ressources.
- Structurer le code par domaine fonctionnel (
member,ressource,borrowing, etc.) afin de maintenir une base extensible. - Mettre en place des mécanismes de sécurité applicative: hash de mot de passe, authentification et validation de payloads.
🛠️ Réalisations
🧩 Conception
- Le socle technique combine Node.js, Express, TypeScript, TypeORM, MySQL et des briques de sécurité/validation (
argon2,jsonwebtoken,class-validator). Source: cda-ebrairie/package.json
{
"scripts": {
"watch": "npx tsc -w",
"dev": "nodemon dist/index.js",
"build": "npx tsc"
},
"dependencies": {
"argon2": "^0.28.2",
"express": "^4.17.1",
"mysql": "^2.18.1",
"typeorm": "^0.2.34"
},
"devDependencies": {
"class-validator": "^0.13.1",
"dotenv": "^10.0.0",
"jsonwebtoken": "^8.5.1",
"morgan": "^1.10.0",
"typescript": "^4.3.5"
}
}
- Le routeur versionné agrège les modules métier et expose une API segmentée par bounded context. Source: cda-ebrairie/src/app/http/router.ts
const v1Router: Router = Router();
v1Router.use('/members', memberRouter)
v1Router.use('/authors',authorRouter)
v1Router.use('/types', typeRouter)
v1Router.use('/categories', categoryRouter)
v1Router.use('/ressources', ressourceRouter)
v1Router.use('/borrowings', borrowingRouter)
v1Router.use('/wishlists', wishlistRouter)
v1Router.use('/floors', floorRouter)
v1Router.use('/rows', rowRouter)
v1Router.use('/ressource-locations', ressourceLocationRouter)
- La modélisation TypeORM formalise les relations de domaine (membres, emprunts, wishlist, ressources liées à auteur/type/catégorie). Source: cda-ebrairie/src/app/database/typeorm/entities/ressource.ts
@Entity()
export class Ressource extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ nullable: false })
title: string;
@Column({ nullable: false })
quantity: number;
@OneToMany(() => Borrowing, (borrowing) => borrowing.ressource)
borrowings: Borrowing[];
@ManyToOne(() => Author, (author) => author.ressources, { eager: true })
author: Author;
@ManyToOne(() => Type, (type) => type.ressources, { eager: true })
type: Type;
@ManyToOne(() => Category, (category) => category.ressources, { eager: true })
category: Category;
}
💻 Développement
- Backend : La création d’utilisateur applique un pattern use case + repository et chiffre les mots de passe avant persistance. Source: cda-ebrairie/src/modules/member/useCases/createMember/createMember.ts
public async execute(props: createMemberProps) {
const memberAlreadyExists = await this.memberRepo.exists(props.email);
if (memberAlreadyExists) {
return {
success: false,
message: "User already exists",
field: "email",
};
}
const hashPassword = await argon2.hash(props.password);
props.password = hashPassword;
await this.memberRepo.create(props);
return {
success: true,
message: "Member is correctly created",
};
}
L’authentification vérifie Argon2 puis émet un JWT contenant l’identité et le rôle (isAdmin).
Source: cda-ebrairie/src/modules/member/useCases/login/login.ts
const member = await this.memberRepo.getMemberByEmail(email);
if (!member) {
return { success: false, message: "Email or password missmatch" };
}
const passwordMatches = await argon2.verify(member.password, password);
if (!passwordMatches) {
return { success: false, message: "Email or password missmatch" };
}
const jwtToken = sign(
{ id: member.id, isAdmin: member.isAdmin },
JWT_PASSPHRASE
);
return {
success: true,
payload: {
member,
token: jwtToken,
},
};
Les DTO reposent sur class-validator pour appliquer des contraintes de schéma et renvoyer des erreurs de champ cohérentes.
Source: cda-ebrairie/src/modules/member/useCases/createMember/createMemberDto.ts
export class RequestCreateMemberDto extends AbstractDto {
@IsEmail()
@IsDefined({ message: "Email is required" })
public email: string;
@IsDefined({ message: "Password is required" })
@MinLength(3, { message: "Password is too short" })
@MaxLength(15, { message: "Password is too long" })
public password: string;
@IsDefined({ message: "Last Name is required" })
public lastName: string;
@IsDefined({ message: "First Name is required" })
public firstName: string;
}
Le cas d’usage d’emprunt applique une règle métier transactionnelle: décrément de stock ressource et rattachement membre/ressource avant création du prêt. Source: cda-ebrairie/src/modules/borrowing/useCases/createBorrowing/createBorrowing.ts
const foundRessource = await this.ressourceRepo.getRessourceById(props.ressource)
if (!foundRessource) {
return { success: false, message: "Ressource does not exist" };
}
if (foundRessource.quantity <= 0 ) {
return { success: false, message: "Ressource is not available" };
}
await this.ressourceRepo.updateRessource(props.ressource, {
title: foundRessource.title,
author: foundRessource.author,
category: foundRessource.category,
type: foundRessource.type,
quantity: foundRessource.quantity - 1
})
return await this.borrowingRepo.createBorrowing(props)
- Frontend : Ce dépôt ne contient pas d’interface frontend; il expose uniquement l’API de domaine.
🏗️ DevOps & Qualité
- Le projet active un niveau de rigueur TypeScript élevé (strict null checks, noImplicitAny, decorators, metadata), ce qui limite les erreurs runtime sur une base orientée ORM et DTO. Source: cda-ebrairie/tsconfig.json
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"esModuleInterop": true
},
"include": ["./src/**/*.ts"]
}
📈 Résultats
- Sur la base de l’historique Git du dépôt analysé, le travail couvre la période 2021-07-12 -> 2021-07-16, avec 42 commits réalisés par 5 contributeurs. La solution livre une API bibliothèque modulaire avec gestion des membres, authentification sécurisée, catalogue de ressources et flux d’emprunt piloté par règles de disponibilité. L’architecture par use cases/repositories et la modélisation relationnelle TypeORM renforcent la maintenabilité de l’ensemble. Le bénéfice technique est un backend métier structuré, prêt à être consommé par une application web ou mobile.
🔧 Environnement technique
- Backend: Node.js, Express, TypeScript.
- Persistance: TypeORM, MySQL, entités relationnelles et repositories.
- Sécurité: Argon2 (hash), JWT (
jsonwebtoken), variables d’environnement (dotenv). - Validation: class-validator + DTO abstraits.
- Qualité/outillage: Morgan, Nodemon, compilation TS stricte.