Skip to content

All work

Lemma 3

SUMMS — Smart Urban Mobility Management System

A web platform that puts bike-sharing, car-sharing, scooters, parking and transit information behind one booking flow, with every request passing through the same strict MVC chain.

Context
Team of 6, university course project
Period
February – April 2026
Repository
abdeljalilsennaoui/SOEN343-Project-W26(opens in a new tab)
  1. View

    • ReactPages for four roles
  2. Controller

    • MobilityControllerHTTP only
    • MobilityRequestHandlerLooks up the command
    • Commands23 classes, one per request type
  3. Model

    • MobilityServiceAll business logic
    • BookingStateMachineState
    • PricingStrategy
    • EventBusObserver
  4. Data and gateways

    • MobilityDataGatewayAdapter over Firestore
    • GatewaysMaps, parking, transit, payment
Figure 1. The path of one request through the back end, from the repository’s architecture documents.

Overview

SUMMS is a platform for urban mobility services. A commuter searches for a bike, car or scooter, books it, pays and completes the ride; a mobility provider manages a fleet; city and system administrators read analytics. Parking and transit information sit alongside. It was built by a team of six for a software architecture and design course, so the brief was as much about how the system is structured as about what it does.

The repository is under my account. I set the project up, wrote most of the back-end architecture and its tests, and a large share of the front end.

Problem

Each mobility service has its own rules: a vehicle can only be booked by one person for a given window, a booking moves through states and must never skip one, prices change at peak hours, and four kinds of user see different things. Written naively, those rules end up scattered across route handlers as conditionals, and every new feature touches all of them.

Goals

  • Route every request through one chain — controller, request handler, command, service, data gateway — with no shortcuts.
  • Use design patterns where they remove a real problem, and document what each one is for.
  • Keep external services — maps, parking, transit, payment — behind interfaces with mock implementations, so the system runs and tests without them.
  • Restrict what each of the four roles can see and do, on the server and in the interface.

Technologies

Front endReact 18, Vite, React Router, Tailwind CSS, Radix UI, Recharts, Google Maps JavaScript API
Back endNode.js, Express, Firebase Admin SDK, Firestore, Firebase Authentication, Zod
Testing and CIJest, Supertest, ESLint, Prettier, GitHub Actions, SonarQube Cloud

Architecture

A React front end talks to an Express API. Inside the API, a request becomes a typed request object, the handler looks up the matching command in a registry, the command calls one method on the service that holds all business logic, and the service reads and writes through a data gateway that hides Firestore’s document format.

Eight patterns are in use. A booking’s lifecycle is a state machine in which each state permits only its own transitions, so an illegal one is refused before any write or charge. Pricing is a strategy that can be swapped at run time. Analytics are decoupled twice: an event bus keeps tracking out of the business logic, and visitors add new operations over the event classes without editing them.

My responsibilities

A team project with six members, in a repository I created and maintained. My part:

  • The initial setup: the Express API, the React front end and the CI pipeline.
  • The move to Firestore with Firebase Authentication, and the booking system on top of it.
  • The MVC refactor that put every request through the full chain, and the State, Strategy, Command and Visitor implementations.
  • Ride sharing for car bookings, provider fleet management, capacity-based availability, and role-based guards on routes and navigation.
  • The test infrastructure: a stateful in-memory Firestore mock, integration tests for the booking lifecycle and access control, and the SonarQube Cloud analysis job.

61 of the 151 non-merge commits are mine, including the booking state machine and most of the tests. Teammates built other parts of the commands, the front end, the pricing strategies and the report.

Engineering decisions

Illegal transitions fail before anything is written

The base booking state rejects every action with a 409; each concrete state overrides only the transitions it allows, and the two terminal states override none. The service rebuilds the state machine from the booking’s stored status before each attempt, so a booking cannot be completed twice or confirmed after it failed, and no payment is charged for a transition that was never valid.

One command per request type, no switch statement

Each of the 23 request types is its own class holding a reference to the service, registered by name. The handler looks a command up and calls execute; it never imports the service or knows what the command does. Adding a request type means adding a class and one registry entry.

One read instead of one per option

Availability was first checked with one Firestore call per mobility option. A batch check now reads the draft and active bookings once and filters in memory. To stay within Firestore’s daily read quota I also throttled the refreshes triggered by window focus, updated parking spots optimistically instead of re-fetching them, and put limits on the analytics queries.

Every external service has a mock twin

Maps, parking, transit, payment and weather each sit behind an interface chosen by a factory. Parking and transit have real implementations over open data; all five have mocks. The system runs with no third-party account, and tests never reach the network.

Testing and quality

The back end has 298 test cases in 26 files: 22 unit-test files covering the state machine, pricing strategies, commands, analytics events and visitors, the data mapper and the availability service, and 4 integration-test files that drive the API with Supertest through the booking lifecycle, ride-share flows and analytics access control.

Tests run against a stateful in-memory mock of Firestore and a manual mock of the data gateway, so they need no emulator and no credentials. The CI pipeline lints, runs the tests with coverage and sends the report to SonarQube Cloud.

Challenges

Booking the wrong vehicle

When the vehicle a user picked on the map was no longer available, the app silently booked another vehicle of the same type. The map now says the vehicle is already booked, and the seed data pairs each vehicle with exactly one bookable option.

Stale availability on the map

After a booking was confirmed from the map, markers could briefly show the old availability and let the user act on it. The map now waits for the refreshed data before the booking dialog closes.

Documentation that drifts from the code

The class diagram and pattern documents are part of the deliverable, and they fell behind as features landed. Before the final submission I went through them against the implementation — command counts, event lists, gateway implementations — and corrected each mismatch in its own commit.

Results

MeasureResultSource
Design patterns in use8: Singleton, Observer, Factory Method, Adapter, State, Strategy, Command, VisitorArchitecture documents in the repository
Request types23 command classes behind one handlerArchitecture documents in the repository
Back-end tests298 test cases in 26 filesCounted in the repository
My share of the history61 of 151 non-merge commitsGit history

Table 1. Test cases are counted from the test files, not from a test report. No coverage percentage is quoted because I have not re-measured it for this page.

End of case study