← Retour

Produit SaaS · Web + Mobile + Backend

Téranga – Nova-Core Mobility

Objectif

Donner aux agences de location automobile sénégalaises une plateforme complète pour gérer leur flotte, leurs réservations, leurs paiements et leur relation client, sans dépendre d’outils manuels (cahier, WhatsApp, virements non tracés).

Rôle

Fondateur de Nova-Core et lead developer : cadrage produit, architecture, développement du backend, du web et du mobile, déploiement et exploitation en production.

Impact

Plateforme en production pour son premier client, Téranga SN Automobile : réservations en ligne avec vérification documentaire, paiement mobile money, contrats de location générés automatiquement et signés électroniquement, navette aéroport (AIBD) et vente de véhicules. Le dashboard d’administration est temps réel : une demande client apparaît chez l’agence sans rechargement.

Technologies clés

Spring Boot 3 / Java 21, MongoDB 7, Kafka, Angular 17, Flutter (Riverpod, GoRouter, Dio), MinIO, PayDunya, Africa’s Talking, SSE + FCM, STOMP/WebSocket, Nginx.

Voir le site en production ↗

Description

Téranga est un SaaS multi-tenant : chaque agence (« parking ») dispose de son catalogue, de ses conditions générales de location versionnées, de son identité visuelle sur les contrats et de ses administrateurs, tout en partageant une seule infrastructure. Les clients réservent depuis le web ou l’application mobile ; l’agence pilote tout depuis un dashboard d’administration.

Le produit couvre trois canaux avec un seul backend :

  • Web Angular 17 (standalone components) — espace client et dashboard agence, temps réel via SSE.
  • Mobile Flutter (Android / iOS) — catalogue, réservation, paiement, navette, chat support, notifications push.
  • Backend Spring Boot 3 — API REST, sécurité, paiements, PDF, notifications, schedulers métier.

Le parcours de réservation est encadré par le backend, qui reste l’unique autorité : documents obligatoires (permis + CNI recto/verso ou passeport), critères d’éligibilité (âge, ancienneté du permis), acceptation des CGL versionnées, contrôle des conflits de dates, puis paiement avec délai limité avant expiration.

Client

Téranga SN Automobile (Dakar) — premier tenant en production

Technologies

  • Backend : Spring Boot 3.3, Java 21, MongoDB 7, Kafka, OpenPDF, Thymeleaf, Bucket4j
  • Web : Angular 17, RxJS (bus d’événements throttlé)
  • Mobile : Flutter, Riverpod, GoRouter, Dio, Firebase Messaging
  • Paiement / SMS : PayDunya SOFTPAY (Wave, Orange Money), Africa’s Talking (OTP)
  • Infra : Linux, Nginx, systemd, MinIO, Sentry, Better Stack

Fonctionnalités & responsabilités

  • Authentification
    • Connexion par téléphone, nom d’utilisateur ou email ; inscription par OTP SMS ou par email (diaspora).
    • JWT avec rotation des refresh tokens, cookie httpOnly sur le web, Bearer sur mobile.
    • Session unique par utilisateur : toute nouvelle connexion révoque les précédentes.
  • Réservations
    • Disponibilités par créneau, blocage des plages qui enjambent une réservation confirmée.
    • Auto-annulation des demandes périmées et des demandes en conflit à l’acceptation (schedulers).
    • Contrat de location PDF généré une seule fois, avec signature et cachet de l’agence.
  • Paiement & notifications
    • Paiement Wave / Orange Money en deux étapes, vérification d’IPN signée.
    • Notifications temps réel (SSE) en premier plan, push FCM en arrière-plan, emails Thymeleaf.
    • Chat support client ↔ agence en STOMP/WebSocket.
  • Autres modules
    • Navette aéroport AIBD avec avis clients, vente de véhicules avec acompte, favoris, gestion documentaire.
    • Contrôle d’accès relationnel (ReBAC) : propriétaire, employé, administrateur par agence.

Défis techniques résolus

Le « réveil » de l’app mobile : une rafale d’erreurs après chaque retour en premier plan

Symptôme : à l’ouverture de l’app après une mise en veille, les premières requêtes échouaient, puis tout fonctionnait quelques secondes plus tard. Les pistes classiques (sockets, keep-alive Nginx, timeouts) n’expliquaient pas tout.

Cause racine : le point d’entrée d’authentification du backend renvoyait un corps 401 en JSON invalide (guillemets simples). Côté mobile, le client HTTP échouait à décoder la réponse et remontait une erreur générique sans code HTTP : l’intercepteur ne voyait jamais le 401 et ne déclenchait jamais le rafraîchissement du token.

Fix : JSON valide côté serveur (une ligne), plus une barrière de reprise côté mobile qui met en attente les requêtes privées jusqu’à ce que le token soit rafraîchi. Règle retenue : un filtre d’authentification n’écrit jamais de réponse bloquante et toujours du JSON valide.

Contamination des connexions HTTP par les erreurs SSE

Symptôme : par intermittence, toutes les requêtes API recevaient un 204 No Content au lieu de leur réponse.

Cause racine : les déconnexions SSE (broken pipe) étaient dispatchées par Tomcat vers /error, dont le contrôleur répondait 204 ; sur des connexions keep-alive entre Nginx et Tomcat, cette réponse était resservie à des requêtes sans rapport.

Fix : /error répond toujours avec un JSON valide et Connection: close, et le bloc Nginx du flux SSE est isolé (HTTP/1.0, sans keep-alive) ; heartbeat toutes les 30 s pour purger les émetteurs morts.

Double acceptation de réservations qui se chevauchent

Symptôme : un administrateur pouvait accepter deux réservations partiellement chevauchantes sur le même véhicule.

Cause racine : la requête de détection ne couvrait que le cas « une réservation existante contient entièrement la nouvelle » et ignorait le statut PAYÉ.

Fix : une seule requête de conflit partagée par la création et l’acceptation (chevauchement correct, statuts ACCEPTÉ + PAYÉ), et auto-annulation, à l’acceptation, des autres demandes en attente sur la même période avec notification du client.

Dashboard temps réel qui tient la charge

Problème : chaque notification SSE déclenchait un rechargement complet du dashboard ; 50 demandes en quelques secondes signifiaient 50 rechargements.

Fix : bus d’événements RxJS throttlé par type (premier rechargement immédiat, puis coalescence sur 800 ms), reconnexion SSE automatique avec backoff et repli en polling.

← Retour aux projets Projet suivant : Bons d’achat →