Aller au contenu

Tous les projets

Lemme 3

SUMMS — Smart Urban Mobility Management System

Une plateforme Web qui réunit vélopartage, autopartage, trottinettes, stationnement et information sur le transport en commun dans un seul parcours de réservation, où chaque requête suit la même chaîne MVC rigoureuse.

Contexte
Équipe de 6, projet de cours universitaire
Période
Février – avril 2026
Dépôt
abdeljalilsennaoui/SOEN343-Project-W26(ouvre un nouvel onglet)
  1. Vue

    • ReactPages pour quatre rôles
  2. Contrôleur

    • MobilityControllerHTTP seulement
    • MobilityRequestHandlerTrouve la commande
    • Commands23 classes, une par type de requête
  3. Modèle

    • MobilityServiceToute la logique d'affaires
    • BookingStateMachineÉtat
    • PricingStratégie
    • EventBusObservateur
  4. Données et passerelles

    • MobilityDataGatewayAdaptateur vers Firestore
    • GatewaysCartes, stationnement, transport, paiement
Figure 1. Le parcours d'une requête dans le serveur, d'après les documents d'architecture du dépôt.

Aperçu

SUMMS est une plateforme de services de mobilité urbaine. Un usager cherche un vélo, une voiture ou une trottinette, le réserve, paie et termine son trajet; un fournisseur de mobilité gère son parc; les administrateurs de la ville et du système consultent des analyses. S'y ajoutent des informations sur le stationnement et le transport en commun. Réalisée par une équipe de six dans le cadre d'un cours d'architecture et de conception logicielles, elle devait soigner autant la structure du système que ses fonctions.

Le dépôt se trouve sur mon compte. J'ai mis le projet sur pied, écrit l'essentiel de l'architecture du serveur et de ses tests, ainsi qu'une bonne part de l'interface Web.

Problème

Chaque service de mobilité a ses propres règles : un véhicule ne peut être réservé que par une personne pour une plage donnée, une réservation passe d'un état à l'autre sans jamais en sauter, les prix changent aux heures de pointe, et quatre types d'utilisateurs voient des choses différentes. Écrites naïvement, ces règles finissent éparpillées en conditions dans les gestionnaires de routes, et chaque nouvelle fonction les touche toutes.

Objectifs

  • Faire passer chaque requête par une seule chaîne — contrôleur, gestionnaire de requêtes, commande, service, passerelle de données — sans raccourci.
  • Recourir aux patrons de conception là où ils éliminent un vrai problème, et documenter l'utilité de chacun.
  • Placer les services externes — cartes, stationnement, transport en commun, paiement — derrière des interfaces dotées de versions simulées, pour que le système fonctionne et se teste sans eux.
  • Limiter ce que chacun des quatre rôles peut voir et faire, sur le serveur comme dans l'interface.

Technologies

Interface WebReact 18, Vite, React Router, Tailwind CSS, Radix UI, Recharts, Google Maps JavaScript API
ServeurNode.js, Express, Firebase Admin SDK, Firestore, Firebase Authentication, Zod
Tests et intégration continueJest, Supertest, ESLint, Prettier, GitHub Actions, SonarQube Cloud

Architecture

Une interface React dialogue avec une API Express. Dans l'API, une requête devient un objet de requête typé, le gestionnaire trouve la commande correspondante dans un registre, la commande appelle une méthode du service qui détient toute la logique d'affaires, et ce service lit et écrit par l'entremise d'une passerelle de données qui masque le format des documents Firestore.

Huit patrons sont utilisés. Le cycle de vie d'une réservation est une machine à états où chaque état n'autorise que ses propres transitions : une transition illégale est refusée avant toute écriture ou tout débit. La tarification est une stratégie interchangeable à l'exécution. Les analyses sont découplées à deux titres : un bus d'événements tient le suivi à l'écart de la logique d'affaires, et des visiteurs ajoutent de nouvelles opérations aux classes d'événements sans les modifier.

Mes responsabilités

Un projet d'équipe de six membres, dans un dépôt que j'ai créé et tenu à jour. Ma part :

  • La mise en place initiale : l'API Express, l'interface React et le pipeline d'intégration continue.
  • Le passage à Firestore avec Firebase Authentication, puis le système de réservation bâti par-dessus.
  • La refonte MVC qui fait passer chaque requête par la chaîne complète, et les mises en œuvre des patrons État, Stratégie, Commande et Visiteur.
  • Le covoiturage pour les réservations de voitures, la gestion du parc des fournisseurs, la disponibilité fondée sur la capacité et les contrôles d'accès par rôle sur les routes et la navigation.
  • L'infrastructure de test : une simulation de Firestore en mémoire qui conserve son état, des tests d'intégration du cycle de vie des réservations et du contrôle d'accès, et la tâche d'analyse SonarQube Cloud.

61 des 151 commits (hors fusions) sont les miens, dont la machine à états des réservations et la majorité des tests. Des coéquipiers ont réalisé d'autres parties des commandes, de l'interface, des stratégies de tarification et du rapport.

Décisions d'ingénierie

Les transitions illégales échouent avant toute écriture

L'état de base d'une réservation rejette toute action par un 409; chaque état concret ne redéfinit que les transitions qu'il autorise, et les deux états terminaux n'en redéfinissent aucune. Le service reconstruit la machine à états à partir du statut enregistré avant chaque tentative : une réservation ne peut donc pas être terminée deux fois ni confirmée après un échec, et aucun paiement n'est débité pour une transition qui n'a jamais été valide.

Une commande par type de requête, sans instruction switch

Chacun des 23 types de requête est une classe à part qui détient une référence au service et s'inscrit par son nom. Le gestionnaire trouve la commande et appelle execute; il n'importe jamais le service et ignore ce que fait la commande. Ajouter un type de requête revient à ajouter une classe et une entrée au registre.

Une seule lecture plutôt qu’une par option

La disponibilité était d'abord vérifiée par un appel à Firestore pour chaque option de mobilité. Une vérification groupée lit désormais une seule fois les réservations provisoires et actives, puis filtre en mémoire. Pour respecter le quota quotidien de lectures de Firestore, j'ai aussi espacé les actualisations déclenchées par le retour sur la fenêtre, mis à jour les places de stationnement de façon optimiste plutôt que de les recharger, et plafonné les requêtes d'analyse.

Chaque service externe a son double simulé

Cartes, stationnement, transport en commun, paiement et météo se trouvent chacun derrière une interface choisie par une fabrique. Le stationnement et le transport en commun disposent de versions réelles s'appuyant sur des données ouvertes; les cinq ont une version simulée. Le système fonctionne sans aucun compte tiers, et les tests n'atteignent jamais le réseau.

Tests et qualité

Le serveur compte 298 cas de test dans 26 fichiers : 22 fichiers de tests unitaires couvrant la machine à états, les stratégies de tarification, les commandes, les événements et visiteurs d'analyse, le convertisseur de données et le service de disponibilité, et 4 fichiers de tests d'intégration qui pilotent l'API avec Supertest à travers le cycle de vie des réservations, le covoiturage et le contrôle d'accès aux analyses.

Les tests s'exécutent sur une simulation de Firestore en mémoire qui conserve son état et sur une simulation manuelle de la passerelle de données : ils n'exigent ni émulateur ni identifiants. Le pipeline d'intégration continue analyse le code, exécute les tests avec couverture et transmet le rapport à SonarQube Cloud.

Défis

La réservation du mauvais véhicule

Lorsque le véhicule choisi sur la carte n'était plus disponible, l'application en réservait discrètement un autre du même type. La carte indique désormais que le véhicule est déjà réservé, et les données initiales associent chaque véhicule à une seule option réservable.

Une disponibilité périmée sur la carte

Après la confirmation d'une réservation depuis la carte, les marqueurs pouvaient afficher un instant l'ancienne disponibilité et laisser l'utilisateur agir en conséquence. La carte attend désormais les données actualisées avant de fermer la fenêtre de réservation.

Une documentation qui s’éloigne du code

Le diagramme de classes et les documents sur les patrons font partie du livrable, et ils ont pris du retard à mesure que les fonctions arrivaient. Avant la remise finale, je les ai confrontés à l'implémentation — nombre de commandes, listes d'événements, passerelles réelles — et j'ai corrigé chaque écart dans un commit distinct.

Résultats

MesureRésultatSource
Patrons de conception utilisés8 : Singleton, Observateur, Fabrique, Adaptateur, État, Stratégie, Commande, VisiteurDocuments d'architecture du dépôt
Types de requête23 classes de commande derrière un seul gestionnaireDocuments d'architecture du dépôt
Tests du serveur298 cas de test dans 26 fichiersCompté dans le dépôt
Ma part de l'historique61 commits sur 151, hors fusionsHistorique Git

Tableau 1. Les cas de test sont comptés à partir des fichiers de test, et non d'un rapport d'exécution. Aucun pourcentage de couverture n'est cité, car je ne l'ai pas mesuré de nouveau pour cette page.

Fin de l'étude de cas