cda-ebrairie
Library-management API (authors, categories, members, borrowings) built with a modular TypeScript use-case architecture, TypeORM, DTO validation, and JWT authentication. The project illustrates structured and maintainable backend design on a Node.js/TypeScript stack.
π― Context and goals
- Build a business backend to manage borrowing/return workflows and resource retrieval.
- Structure code by functional domain (
member,ressource,borrowing, etc.) to keep the codebase extensible. - Implement application security mechanisms: password hashing, authentication, and payload validation.
π οΈ Deliverables
π§© Design
- The technical foundation combines Node.js, Express, TypeScript, TypeORM, MySQL, and security/validation components (
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"
}
}
- The versioned router aggregates business modules and exposes an API segmented by 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)
- TypeORM domain modeling formalizes key relations (members, borrowings, wishlist, resources linked to author/type/category). 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;
}
π» Development
- Backend : User creation follows a use case + repository pattern and hashes passwords before persistence. 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",
};
}
Authentication verifies Argon2 hashes, then issues a JWT carrying identity and role (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,
},
};
DTOs use class-validator constraints to enforce schema rules and return coherent field-level errors.
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;
}
The borrowing use case applies transactional business logic: decrement resource stock and bind member/resource before creating the borrowing entry. 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 : This repository does not contain frontend UI; it only exposes domain API endpoints.
ποΈ DevOps & Quality
- The project enforces strict TypeScript settings (strict null checks, noImplicitAny, decorators, metadata), reducing runtime issues in an ORM/DTO-heavy codebase. 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"]
}
π Results
- Based on the analyzed Git history, the work spans 2021-07-12 -> 2021-07-16, with 42 commits across 5 contributors. The delivery provides a modular library API covering member management, secure authentication, resource cataloging, and borrowing workflows with availability checks. The use case/repository architecture and TypeORM relational model improve long-term maintainability. The technical benefit is a structured business backend ready to be consumed by web or mobile clients.
π§ Technical environment
- Backend: Node.js, Express, TypeScript.
- Persistence: TypeORM, MySQL, relational entities and repositories.
- Security: Argon2 hashing, JWT (
jsonwebtoken), environment variables (dotenv). - Validation: class-validator with abstract DTO base.
- Quality/tooling: Morgan, Nodemon, strict TS compilation.