Portfolio 2026 – Holberton School RENNES
Version : v5.0.0
Spécification : OpenAPI 3.0
Auteur : Stéphane Dinahet
Le projet Loto Tracker API est une application backend de type API REST sécurisée, destinée à centraliser, traiter et exposer les données relatives au Loto français. Il permet à des utilisateurs de créer un compte, de soumettre des tickets de jeu, de consulter l’historique de leurs participations, et de comparer automatiquement leurs tickets avec les résultats officiels de la FDJ afin de déterminer d’éventuels gains.
Ce projet a été conçu comme un projet de fin de parcours à visée RNCP6, démontrant la capacité du candidat à concevoir, implémenter, sécuriser, documenter et préparer au déploiement une application backend professionnelle.
Le projet répond explicitement aux attendus du Titre RNCP Niveau 6 – Développeur Concepteur d’Applications, notamment :
-
analyser un besoin métier et le traduire en fonctionnalités techniques ;
-
concevoir une architecture logicielle robuste ;
-
développer une API REST conforme aux standards actuels ;
-
sécuriser les accès et les données ;
-
gérer plusieurs systèmes de stockage adaptés aux usages ;
-
produire une documentation technique exploitable par un tiers ;
-
préparer un déploiement en environnement réel.
L’API couvre les fonctionnalités suivantes :
-
Authentification sécurisée par JWT ;
-
Gestion des utilisateurs avec rôles (Admin / Utilisateur) ;
-
Gestion des tickets de loto (CRUD complet) ;
-
Comparaison automatique des tickets avec les tirages FDJ ;
-
Calcul des gains (fonctionnalité en cours d’optimisation) ;
-
Historique des tickets utilisateur ;
-
Historique public des résultats FDJ depuis 2019 ;
-
Recherche par date ou plage de dates ;
-
Scraping automatique des résultats officiels ;
-
Administration avancée via endpoints dédiés.
Le backend est développé en Java 21, version LTS moderne, garantissant :
-
stabilité à long terme ;
-
meilleures performances ;
-
sécurité accrue.
Le framework Spring Boot a été retenu pour :
-
sa maturité industrielle ;
-
sa large adoption en entreprise ;
-
son intégration native avec Spring Security ;
-
sa capacité à produire rapidement des API REST robustes.
La sécurité repose sur :
-
Spring Security pour le filtrage des requêtes ;
-
JWT (JSON Web Token) pour l’authentification stateless.
Ce choix permet :
-
une architecture scalable ;
-
une séparation claire client / serveur ;
-
l’absence de session côté serveur.
Les rôles (ADMIN, USER) sont embarqués dans le token afin de contrôler précisément l’accès aux ressources.
L’API est documentée via OpenAPI Specification 3.0, exposée par Swagger UI.
Cette documentation constitue :
-
un contrat technique entre backend et frontend ;
-
une référence pour les tests ;
-
un outil de démonstration lors de la soutenance RNCP.
Base relationnelle (PostgreSQL)
Une base relationnelle est utilisée pour :
-
les utilisateurs ;
-
les tickets ;
-
les gains ;
les relations entre entités.
Ce choix est motivé par :
-
la nécessité d’intégrité référentielle ;
-
la gestion des relations complexes ;
-
la cohérence transactionnelle.
Base NoSQL (MongoDB)
-
MongoDB est utilisée pour :
-
stocker l’historique complet des tirages FDJ ;
-
gérer un volume important de données ;
-
faciliter les recherches par date.
Ce choix est justifié par :
-
la flexibilité du schéma ;
-
les performances en lecture ;
-
l’adéquation aux données historiques.
L’architecture suit un modèle 3-tiers :
-
Frontend Application cliente (navigateur) consommant l’API REST.
-
Backend (API) Cœur du système :
logique métier ;
sécurité ;
orchestration des données.
- Bases de données Stockage persistant, sécurisé et structuré.
Cette architecture permet :
une évolutivité naturelle ;
un déploiement indépendant des composants ;
une maintenance facilitée.
L’application implémente :
-
authentification JWT obligatoire pour les routes sensibles ;
-
contrôle d’accès basé sur les rôles ;
-
séparation claire des endpoints publics et protégés ;
-
pages d’erreur personnalisées (401, 403, 404, 500) ;
-
bonnes pratiques OWASP (principe du moindre privilège).
Linux (Ubuntu)
ou Windows avec WSL2
Ce choix est motivé par :
-
la compatibilité avec les scripts ;
-
la gestion simplifiée des services ;
-
la proximité avec les environnements serveurs.
Les outils suivants sont requis :
-
Java 21
-
Maven
-
PostgreSQL
-
MongoDB
-
Git
Vérification :
java -version
mvn -version
psql --version
mongod --versionsudo apt update
sudo apt install -y \
openjdk-21-jdk \
maven \
postgresql postgresql-contrib \
mongodb \
git
pip install "fastapi[standard]" uvicorn httpx pymongo python-dotenvgit clone [<url-du-depot>](https://github.com/SDINAHET/LOTO_API_v4.git)
cd LOTO_API_v4Démarrer le service :
sudo service postgresql startCréer la base de données :
sudo -u postgres psql
CREATE DATABASE loto_tracker;Configurer les accès dans application.properties ou via variables d’environnement.
Démarrer MongoDB :
sudo service mongod startAucune création manuelle n’est requise : les collections sont créées dynamiquement.
mvn clean installCette étape :
-
télécharge les dépendances ;
-
compile le code ;
-
exécute les tests éventuels.
mvn spring-boot:runLe serveur démarre sur :
Swagger UI accessible http://localhost:8082/swagger-ui/index.html
Endpoint /api/hello répond
Inscription utilisateur fonctionnelle
Connexion JWT valide
Création de ticket possible
Consultation de l’historique FDJ
Le projet est conçu pour être déployé sur Alwaysdata ou équivalent :
-
API exposée via HTTPS ;
-
bases de données sécurisées ;
-
secrets stockés dans des variables d’environnement ;
-
accès public limité aux endpoints nécessaires.
Le projet est prêt pour :
-
conteneurisation Docker ;
-
CI/CD ;
-
montée en charge ;
-
intégration d’IA prédictive ;
-
notifications utilisateur.
Le projet Loto Tracker API démontre :
-
une maîtrise avancée du backend moderne ;
-
une architecture professionnelle et sécurisée ;
-
une capacité de déploiement réel ;
-
une documentation complète et exploitable.
Il répond pleinement aux exigences RNCP6.
Test dans docker
docker compose -f docker-compose.test.yml up --abort-on-container-exit --remove-orphans
docker compose -f docker-compose.test.yml up --build --abort-on-container-exit --remove-orphans --exit-code-from tests
docker compose -f docker-compose.test.yml down -v
docker compose -f docker-compose.test.yml up --build --abort-on-container-exit
root@batriviere-serv1:~/Loto_API_prod/src/main/resources/static# sudo chmod -x /root/.nvm/versions/node/v20.19.2/bin/htt
p-server
root@batriviere-serv1:~/Loto_API_prod/src/main/resources/static# sudo chmod +x /root/.nvm/versions/node/v20.19.2/bin/htt
p-server
root@batriviere-serv1:~/Loto_API_prod/src/main/resources/static# lsof -i :5500
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
apache2 471765 www-data 44u IPv4 156272529 0t0 TCP localhost:57356->localhost:5500 (CLOSE_WAIT)
apache2 471766 www-data 44u IPv4 156282032 0t0 TCP localhost:55852->localhost:5500 (CLOSE_WAIT)
apache2 471767 www-data 44u IPv4 156281107 0t0 TCP localhost:35594->localhost:5500 (CLOSE_WAIT)
apache2 471768 www-data 44u IPv4 156275245 0t0 TCP localhost:57354->localhost:5500 (CLOSE_WAIT)
apache2 471801 www-data 44u IPv4 156272531 0t0 TCP localhost:57360->localhost:5500 (CLOSE_WAIT)
apache2 471968 www-data 44u IPv4 156273245 0t0 TCP localhost:58362->localhost:5500 (CLOSE_WAIT)
apache2 478177 www-data 44u IPv4 156272533 0t0 TCP localhost:57376->localhost:5500 (CLOSE_WAIT)
apache2 478178 www-data 44u IPv4 156273428 0t0 TCP localhost:57342->localhost:5500 (CLOSE_WAIT)
root@batriviere-serv1:~/Loto_API_prod/src/main/resources/static# http-server -p 5500
export default {
async fetch(request) {
const ORIGIN = "https://stephanedinahet.fr";
const MAINTENANCE = "https://maintenance2-30r.pages.dev/";
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 2500);
try {
const url = new URL(request.url);
const target = ORIGIN + url.pathname + url.search;
const res = await fetch(target, {
method: request.method,
headers: request.headers,
body: ["GET", "HEAD"].includes(request.method) ? null : request.body,
signal: controller.signal,
});
clearTimeout(timeout);
if ([502, 503, 504].includes(res.status)) {
return Response.redirect(MAINTENANCE, 302);
}
return res;
} catch (e) {
clearTimeout(timeout);
return fetch(MAINTENANCE);
}
},
};
cd src/main/resources/static
npx http-server -a 0.0.0.0 -p 5500