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.
Vue
- ReactPages pour quatre rôles
Contrôleur
- MobilityControllerHTTP seulement
- MobilityRequestHandlerTrouve la commande
- Commands23 classes, une par type de requête
Modèle
- MobilityServiceToute la logique d'affaires
- BookingStateMachineÉtat
- PricingStratégie
- EventBusObservateur
Données et passerelles
- MobilityDataGatewayAdaptateur vers Firestore
- GatewaysCartes, stationnement, transport, paiement
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 Web | React 18, Vite, React Router, Tailwind CSS, Radix UI, Recharts, Google Maps JavaScript API |
|---|---|
| Serveur | Node.js, Express, Firebase Admin SDK, Firestore, Firebase Authentication, Zod |
| Tests et intégration continue | Jest, 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
| Mesure | Résultat | Source |
|---|---|---|
| Patrons de conception utilisés | 8 : Singleton, Observateur, Fabrique, Adaptateur, État, Stratégie, Commande, Visiteur | Documents d'architecture du dépôt |
| Types de requête | 23 classes de commande derrière un seul gestionnaire | Documents d'architecture du dépôt |
| Tests du serveur | 298 cas de test dans 26 fichiers | Compté dans le dépôt |
| Ma part de l'historique | 61 commits sur 151, hors fusions | Historique 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.
Dépôt et liens
abdeljalilsennaoui/SOEN343-Project-W26(ouvre un nouvel onglet)
Ce projet n'a pas de démo hébergée. Le dépôt explique comment l'exécuter.
Fin de l'étude de cas