Bienvenue sur le projet de gestion de bibliothèque ! Ce projet consiste à développer un backend moderne avec Java, Spring Boot et PostgreSQL/MySQL.
Pour comprendre les concepts et règles métiers clés du projet, vous pouvez consulter la 📄 Documentation Fonctionnelle.
Ce projet est découpé et organisé en tâches réparties entre 5 membres de l'équipe :
- Matricule 24068 (Leader) : Architecture, Sécurité (Spring Security), Gestion Globale des Exceptions.
- Matricule 24139 : Entités de références (Category, Author, Publisher) et CRUD basique.
- Matricule 24238 : Gestion des Livres (Book) et Exemplaires (BookItem), Optimistic Locking.
- Matricule 24014 : Gestion des Membres (Member) et des Emprunts (Borrow), Limites métiers.
- Matricule 24157 : Gestion des Réservations (Reservation), File d'attente, Validations complexes.
Chaque membre possède un fichier [Matricule].md dans ce dépôt qui détaille le code et les tâches qu'il doit accomplir.
Le diagramme suivant représente la structure de la base de données et les relations entre les tables :
erDiagram
LANGUAGE {
string code PK
string name
}
NATIONALITY {
string code PK
string name
}
CATEGORY {
bigint id PK
string name
boolean deleted
}
PUBLISHER {
bigint id PK
string name
string email
boolean deleted
}
AUTHOR {
bigint id PK
string name
string nationality_code FK
boolean deleted
}
BOOK {
bigint id PK
string title
string isbn
string language_code FK
bigint category_id FK
bigint publisher_id FK
boolean deleted
}
BOOK_ITEM {
bigint id PK
string barcode
string status
bigint version
boolean deleted
}
MEMBER {
bigint id PK
string email
string member_type
int max_borrows
boolean deleted
}
BOOK_AUTHOR {
bigint book_id PK, FK
bigint author_id PK, FK
string role
}
RESERVATION {
bigint id PK
bigint member_id FK
bigint book_id FK
int queue_position
datetime reservation_date
datetime expiration_date
string status
}
BORROW {
bigint id PK
bigint member_id FK
bigint book_item_id FK
int renewal_count
datetime borrow_date
date due_date
datetime return_date
string status
}
LANGUAGE ||--o{ BOOK : "possède"
NATIONALITY ||--o{ AUTHOR : "a"
CATEGORY ||--o{ BOOK : "contient"
PUBLISHER ||--o{ BOOK : "publie"
BOOK ||--o{ BOOK_AUTHOR : "rédigé par"
AUTHOR ||--o{ BOOK_AUTHOR : "a rédigé"
BOOK ||--o{ BOOK_ITEM : "contient exemplaires"
MEMBER ||--o{ BORROW : "effectue"
BOOK_ITEM ||--o{ BORROW : "est associé à"
MEMBER ||--o{ RESERVATION : "fait"
BOOK ||--o{ RESERVATION : "est concerné par"
L'application suit une architecture en couches :
Controller (@RestController) → endpoints REST
↓
Service (@Service) → logique métier, @Transactional
↓
Repository (Spring Data JPA) → interfaces JpaRepository
↓
Base de données (MySQL/PostgreSQL/H2)
- controllers/ — 16 contrôleurs REST
- services/ — 15 services métier (dont EmailService, NotificationService)
- dto/ — 12 DTOs + 9 DTOs de réponse
- data/entities/ — 13 entités JPA (dont BaseEntity, 5 enums)
- data/repositories/ — 13 interfaces Spring Data JPA
- dto/response/ — 9 DTOs de réponse (pas d'exposition directe des entités)
- security/ — Configuration JWT (Spring Security)
- exceptions/ — Gestion globale des erreurs (4 exceptions métier)
- websocket/ — Notifications temps réel via STOMP/SockJS
- config/ — Configuration globale (OpenAPI, Cache)
- scheduling/ — Tâches planifiées (vérification retards, expiration réservations)
Le projet utilise 3 profils Spring pour s'adapter aux différents environnements :
| Profil | Base de données | Port | Usage |
|---|---|---|---|
dev (défaut) |
MySQL local (library_db) |
8081 |
Développement local |
prod |
PostgreSQL (via variables d'env) | $PORT ou 8080 |
Déploiement (Render) |
test |
H2 (base mémoire) | - | Tests unitaires |
Fichier : src/main/resources/application-dev.properties
spring.datasource.url=jdbc:mysql://localhost:3306/library_db?createDatabaseIfNotExist=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=supnum
spring.datasource.password=Supnum
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
server.port=8081Détails :
- URL : Se connecte sur
localhostau port3306. La baselibrary_dbest créée automatiquement. - User :
supnum/ Password :Supnum - DDL :
update(Hibernate synchronise automatiquement le schéma) - Des données de démo sont chargées via
data-dev.sql
Fichier : src/main/resources/application-prod.properties
spring.datasource.url=jdbc:${SPRING_DATASOURCE_URL}
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
server.port=${PORT:8080}Fichier : src/test/resources/application-test.properties
spring.datasource.url=jdbc:h2:mem:library_test;MODE=MySQL
spring.jpa.hibernate.ddl-auto=create-dropLe projet utilise JWT (JSON Web Tokens) pour sécuriser l'API :
- Login :
POST /api/auth/login(public) — retourne un token Bearer - Requêtes authentifiées : toutes les autres requêtes nécessitent un en-tête
Authorization: Bearer <token> - Rôles :
ADMIN(accès/api/admin/**) etUSER - Admin - Enregistrement d'utilisateurs :
POST /api/admin/users(réservé ADMIN) - Seed des données de référence :
POST /api/admin/seed(réservé ADMIN) — insère les 18 langues et 89 nationalités en base - Mise à jour du profil :
PUT /api/auth/profile(authentifié) — changer username/password - Les mots de passe sont hachés avec BCrypt
| Username | Rôle |
|---|---|
abdy |
ADMIN |
hassen |
USER |
baba |
USER |
haja |
USER |
abdselam |
USER |
# 1. Démarrer MySQL
docker compose up -d mysql
# 2. Lancer l'application
./mvnw spring-boot:run -Dspring-boot.run.profiles=devL'API est accessible sur : http://localhost:8082
# Build
./mvnw clean package -DskipTests
# Lancer avec les vars d'env PostgreSQL
java -jar target/Library-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod| Méthode | Endpoint | Description |
|---|---|---|
| GET | /api/languages |
Liste des langues (lecture seule) |
| GET | /api/nationalities |
Liste des nationalités (lecture seule) |
| GET/POST/PUT/DELETE | /api/categories[/{id}] |
CRUD catégories |
| GET/POST/PUT/DELETE | /api/publishers[/{id}] |
CRUD éditeurs |
| GET/POST/PUT/DELETE | /api/authors[/{id}] |
CRUD auteurs |
| Méthode | Endpoint | Description |
|---|---|---|
| GET/POST/PUT/DELETE | /api/books[/{id}] |
CRUD livres |
| GET/POST/PUT/DELETE | /api/books/{bookId}/items[/{id}] |
CRUD exemplaires |
| GET/POST/DELETE | /api/books/{bookId}/authors[/{authorId}] |
Gestion auteurs d'un livre |
| Méthode | Endpoint | Description |
|---|---|---|
| GET/POST/PUT/DELETE | /api/members[/{id}] |
CRUD membres |
| GET | /api/borrows |
Liste paginée des emprunts |
| POST | /api/borrows/checkout?memberId=&barcode= |
Emprunter un livre |
| POST | /api/borrows/{id}/return |
Retourner un livre |
| POST | /api/borrows/{id}/renew |
Renouveler (max 3x) |
| GET/POST | /api/reservations[/{id}] |
Liste / Créer réservation |
| POST | /api/reservations/{id}/cancel |
Annuler réservation |
| GET | /api/reservations/queue/{bookId} |
File d'attente d'un livre |
| Méthode | Endpoint | Description |
|---|---|---|
| GET | /api/external/books/search?q=&max= |
Recherche de livres |
| GET | /api/external/books/isbn/{isbn} |
Recherche par ISBN |
| Méthode | Endpoint | Description |
|---|---|---|
| GET | /api/qrcode/book-item/{id}?size= |
QR code d'un exemplaire |
| GET | /api/qrcode/text?text=&size= |
QR code pour texte personnalisé |
L'API est documentée automatiquement avec Swagger UI :
- URL :
http://localhost:8082/swagger-ui.html - Endpoints : Tous les endpoints REST sont documentés avec schémas JSON
- Authentification : Cliquez sur "Authorize" et entrez votre token JWT pour tester les endpoints sécurisés
L'application utilise STOMP over WebSocket (SockJS) pour envoyer des notifications en direct.
const socket = new SockJS('/ws');
const stomp = Stomp.over(socket);| Topic | Destinataire | Événements |
|---|---|---|
/topic/notifications/{memberId} |
Membre connecté | Emprunt créé, retour confirmé, livre disponible, réservation annulée |
/topic/admin |
Administrateur | Tous les événements (borrow, return, réservation) |
// Notifications personnelles d'un membre
stomp.subscribe('/topic/notifications/1', msg => {
const event = JSON.parse(msg.body);
// { type: "BORROW_CREATED", message: "...", data: {...}, timestamp: "..." }
});
// Dashboard admin en direct
stomp.subscribe('/topic/admin', msg => {
const event = JSON.parse(msg.body);
});Un cache mémoire Caffeine est utilisé pour accélérer les lectures fréquentes :
| Cache | Durée | Données |
|---|---|---|
books |
10 min | Livres (liste paginée + par ID) |
categories |
10 min | Catégories |
authors |
10 min | Auteurs |
languages |
10 min | Langues |
nationalities |
10 min | Nationalités |
publishers |
10 min | Éditeurs |
bookItems |
10 min | Exemplaires |
Les caches sont automatiquement invalidés lors des opérations d'écriture (create/update/delete).
Des notifications par email sont envoyées automatiquement :
| Événement | Destinataire | Déclencheur |
|---|---|---|
| Confirmation d'emprunt | Membre | POST /api/borrows/checkout |
| Confirmation de retour | Membre | POST /api/borrows/{id}/return |
| Livre réservé disponible | Membre (1er file) | Retour d'un exemplaire |
| Rappel de retard | Membre | Tâche planifiée (8h chaque jour) |
Configuration :
- Dev : MailHog (
localhost:1025, sans auth) - Prod : SMTP via variables d'environnement (
MAIL_HOST,MAIL_PORT,MAIL_USERNAME,MAIL_PASSWORD)
Les tâches suivantes s'exécutent automatiquement :
| Horaire | Tâche | Action |
|---|---|---|
0 0 8 * * ? (8h) |
Vérification retards | Envoie un email pour chaque emprunt en retard |
0 0 6 * * ? (6h) |
Expiration réservations | Annule les réservations PENDING de plus de 7 jours |
Des endpoints de monitoring sont exposés :
| Endpoint | Accès | Description |
|---|---|---|
/actuator/health |
Public | Health check de l'application |
/actuator/info |
Public | Informations sur l'application |
/actuator/metrics |
ADMIN | Métriques JVM, cache, etc. |
/actuator/prometheus |
ADMIN | Métriques au format Prometheus |
Recherche de livres via l'API Google Books :
| Méthode | Endpoint | Description |
|---|---|---|
| GET | /api/external/books/search?q=&max= |
Recherche par titre/auteur/isbn |
| GET | /api/external/books/isbn/{isbn} |
Recherche par ISBN exact |
Note : Endpoints publics (sans authentification)
Génération de QR codes pour les exemplaires :
| Méthode | Endpoint | Description |
|---|---|---|
| GET | /api/qrcode/book-item/{id}?size= |
QR code d'un exemplaire (JSON : id + barcode) |
| GET | /api/qrcode/text?text=&size= |
QR code pour un texte personnalisé |
docker compose up -d| Service | Port | Accès |
|---|---|---|
| MySQL | 3306 |
Base de données |
| phpMyAdmin | 8080 |
http://localhost:8080 |
| MailHog | 1025 (SMTP), 8025 (UI) |
http://localhost:8025 |
Bon développement à toute l'équipe ! Lisez vos fichiers Markdown personnels pour démarrer.
Salut l'équipe 👋
Voici comment on va travailler ensemble sur le projet. Lisez bien avant de commencer à coder.
────────────────────────── 🔧 WORKFLOW À SUIVRE ──────────────────────────
1️⃣ Récupérer le projet
git clone <lien-du-repo>
cd <nom-du-repo>2️⃣ Créer votre branche (OBLIGATOIRE)
git checkout -b feature/votre-nomExemple : git checkout -b feature/taches-24139
2️⃣ bis — Se mettre à jour depuis main (important !)
Faites ça régulièrement pour éviter les conflits avec le travail des autres :
git checkout main
git pull origin main
git checkout feature/votre-branche
git merge main3️⃣ Coder + committer
git add .
git commit -m "Description de ce que vous avez fait"4️⃣ Pusher votre branche
git push origin feature/votre-nom5️⃣ Ouvrir une Pull Request sur GitHub → Allez sur le repo GitHub → Cliquez sur "Compare & pull request" → Décrivez ce que vous avez fait → Attendez mon approbation
────────────────────────── ⛔ RÈGLES IMPORTANTES ──────────────────────────
❌ Ne jamais pusher directement sur main
❌ Ne jamais merger vous-mêmes
✅ Toujours travailler sur votre propre branche
✅ Une PR par fonctionnalité
✅ Se synchroniser avec main régulièrement
Si vous avez des questions, contactez le leader.