Parkly is a full-stack web application for parking management and reservations, a project developed during the Web Technologies and Systems course at Sapienza University of Rome.
- Architecture and technologies used
- Project structure
- Database schema
- Features
- Views
- Installation
- Authors
- License
The project is structured according to a client-server architecture, separating the user interface from the APIs and data management.
The frontend is based on Vue.js and Vite. The user interface is built with Bootstrap, while Leaflet was used for rendering and integrating the geographic map.
The backend is a Node.js server based on Express. For authentication, we used express-session and cookies, protecting passwords with bcrypt.
Regarding data, we chose a relational database, PostgreSQL (hosted via Supabase). In addition to the database, we use the Supabase Storage bucket (interfaced via multer in memory on the server) to manage static files, such as user profile pictures.
Finally, Socket.IO was integrated for real-time chat functionality.
parkly/
โโโ client/
โ โโโ src/
โ โโโ assets/ # Images and icons
โ โโโ components/ # Reusable UI components
โ โโโ composables/ # Encapsulated reactive logic
โ โโโ router/ # Client-side routing
โ โโโ store/ # Application state
โ โโโ utils/ # Helper functions
โ โโโ views/ # Views
โโโ server/
โโโ database/
โ โโโ parkly.sql # Schema definition
โ โโโ seed.sql # Sample data
โโโ middleware/
โ โโโ authMiddleware.js
โโโ routes/ # API endpoints
โโโ index.js
The database consists of eight tables. Utente is the central entity: a user with the GESTORE role can own one or more Garage entities, each consisting of multiple PostoAuto spots. Spots can be temporarily excluded from availability via ManutenzionePosto. A Prenotazione associates a user with a spot for a defined time interval and serves as the prerequisite for dependent entities: Messaggio, Recensione, and Transazione. Below is the ER diagram:
- Parking spot reservations with time slot selection and automatic wallet charging.
- Garage search by geographic location on an interactive map and list, with filters for vehicle type, disabled access, electric charging, and covered parking.
- Integrated wallet with manual top-up and full transaction history.
- Real-time chat between customer and manager, contextualized to active reservations.
- Review system tied to completed reservations.
- Manager dashboard with real-time occupancy, monthly statistics, and an interactive garage floor plan.
- Parking spot maintenance management with automatic exclusion from availability.
Authentication is handled via sessions and encrypted passwords. Users can manage their profile, customize their avatar, update personal details, or request the Manager role. The system also supports account deletion via soft-delete to preserve the integrity of historical data.
Search combines geographic positioning and time availability. On the client side, the system calculates the distance between destination and garage, sorting results by proximity. Reactive filters allow users to refine the search by vehicle type and additional amenities such as electric charging, disabled access, and covered parking spots.
On the backend, the system verifies actual spot availability by querying the database using the OVERLAPS clause. This time cross-referencing excludes garages that are already occupied during the selected hours, ensuring users only see bookable results.
The reservation flow guarantees maximum data consistency through atomic transactions. The user selects a spot from the interactive floor plan, and the client formally validates the data by calculating the price quote.
To prevent simultaneous booking conflicts, the server applies a row-level lock on the database. Within the same transaction, the system verifies the balance, charges the cost to the wallet, and generates the ticket.
Parkly integrates a virtual wallet to simplify payments, allowing top-ups between โฌ5 and โฌ1000. The use of atomic transactions in the backend ensures that updating the balance and recording the transaction in the history occur simultaneously.
Users can view the full history of their activities through a paginated chronological list that explicitly distinguishes between top-ups, payments, and refunds.
The dedicated dashboard for managers allows publishing new garages on Parkly through a guided three-step flow.
In the first step, the garage location is defined: starting from an address, the system queries a geocoding API and generates coordinates; to ensure maximum accuracy, the user can manually refine the coordinates by clicking directly on the map.
The second step involves the technical configuration of the parking spots. The manager defines each parking spot by specifying the vehicle type and included amenities, such as electric charging, wheelchair accessibility, or covered parking. To speed up data entry and improve user experience, the system can automatically generate spot identification codes based on the selected category.
The final step consists of drawing the floor plan using an interactive grid. Each spot occupies space proportional to the vehicle's dimensions, and the PlanimetriaGarage component renders a real-time preview by processing the entered data. The final layout is saved in the database as a text string, allowing the client to faithfully reconstruct the floor plan during the reservation process.
At the end of a stay, users can rate their experience by giving a score from 1 to 5 stars and leaving a review. To ensure the reliability and authenticity of feedback shown to other users, the system only allows reviews for garages where a reservation has actually been completed.
To facilitate coordination between users, Parkly integrates a real-time messaging system based on Socket.IO.
The chat is strictly tied to a specific reservation: the backend routes messages through private "rooms" and verifies the identity of participants before each transmission.
Managers can report unavailability periods for individual parking spots by specifying a time window. During these intervals, the affected spots are automatically excluded from search results and cannot be booked. The system checks for any overlap between maintenance and existing reservations before confirming the schedule.
| Route | Component | Description |
|---|---|---|
/ |
HomeView |
Homepage |
/garage |
GarageView |
Garage list with interactive map and filters |
/garage/:id |
GarageDetailView |
Garage details, availability, and reservation |
/prenotazioni |
BookingsView |
User's active reservations and history |
/portafoglio |
WalletView |
Balance management and transaction history |
/dashboard-gestore |
GestoreDashboardView |
Manager dashboard |
/profile |
ProfileView |
Account settings and deletion |
/register |
RegisterView |
Platform registration |
/diventa-gestore |
BecomeGestoreView |
Manager role request |
Node.js and a PostgreSQL instance, either local or remote.
git clone https://github.com/chitvs/parkly.git
cd parkly
cd server && npm install
cd ../client && npm installAfter creating the database instance (local or remote), create the tables using the code in parkly.sql and populate them with seed.sql to have test data.
Create a .env file in server/ with the following variables:
DB_USER
DB_PASSWORD
DB_HOST
DB_PORT
DB_NAME
SESSION_SECRET
PORT
SUPABASE_URL
SUPABASE_SERVICE_KEYNote
Environment variables may vary depending on the database configuration.
During the development of Parkly, Supabase was used to create the PostgreSQL instance and simplify collaboration, which is why the SUPABASE_URL and SUPABASE_SERVICE_KEY variables are present.
Make sure you are in the project root and run:
npm run devThe client will be available at http://localhost:5173, and the server at http://localhost:3000. To test the server, visit localhost:3000/test-db.
If the server responds successfully, the application is connected properly.
Developed by Andrea Carbone, Alessandro Chitarrini, Matteo Crugliano, and Davide Gaglione.
See the LICENSE file.