cda-ebrairie

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"
  }
}
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)
@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

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.
🌐 View the project

Tech Stack

Backend
Express
Node.js
Bases de donnees (SGBD & SQL)
MySQL
Design Patterns & Architecture
TypeORM
Frontend
TypeScript