Rent A Car Project is Being Developed for Tobeto
- UI
- Project Description and Objective
- Used Technologies, Libraries and Tools
- Project Download and Opening Steps
- Project Architecture and Structure
- Features
- Database Structure
- Tests
- Contributors
Our project is a Full Stack project covering both the Back-End and Front-End structure of a rental website. We completed the Front-End part of our project using the React library, the Back-End part using the Java Spring framework, and using PostgreSQL as the database. We aimed to improve the user experience by simplifying the interface that users find complex and by easily adapting to new technologies. We developed our project based on the principles of environmental friendliness and sustainability. With its innovative structure, our project aims to minimize environmental impacts and efficiently use natural resources. Additionally, it stands out with its ability to quickly adapt to technological advancements. These features are among the elements that highlight the environmental sensitivity and technological adaptability of our project. Our project benefits the transportation and service sectors by providing car rental services to customers to meet their transportation needs.
In our project, we managed the development process using GitHub and Git Version Control System. GitHub was the main platform we used to store the project's code base, provide version control, and collaborate. Here, we stored different versions of the project, tracked code changes, and effectively collaborated among team members. Git VSC, on the other hand, is the tool we used to run Git commands via the terminal. This allowed us to perform basic Git operations such as creating local copies of the project, managing changes, creating branches, and merging. The terminal-based structure of Git VSC enabled us to perform Git operations quickly and efficiently, making the development process of the project more organized.
In our project, we used Swagger UI to perform HTTP requests. At the same time, we tested the business rules and validations we added.
- Programming Language: Java
- Version: JDK 21
- IDE: IntelliJ IDEA
- Spring Boot Version: 3.2.0
- Project Management Tool: Maven
- Spring Data JPA
- Spring Web
- Spring Boot DevTools
- Spring Security
- PostgreSQL Driver
- Lombok
- ModelMapper 3.2.0
- SpringDoc OpenAPI Starter WebMVC UI 2.2.0
- JJWT API 0.11.5
- JJWT IMPL 0.11.5
- JJWT JACKSON 0.11.5
- Programming Language: TypeScript
- IDE: Visual Studio Code
- Package Manager: NPM
- Project Template: Started with create-react-app
- @googlemaps/js-api-loader 1.16.2
- @react-google-maps/api 2.19.2
- @types/google.maps 3.55.1
- @reduxjs/toolkit 2.0.1
- @types/node 16.18.70
- @types/jest 27.5.2
- web-vitals 2.1.4
- react-redux 9.0.4
- typescript 4.9.5
- react 18.2.0
- react-scripts 5.0.1
- reactstrap 9.2.1
- react-bootstrap 2.9.2
- bootstrap 5.3.2
- bootstrap-icons 1.11.3
- react-dom 18.2.0
- react-router-dom 6.21.1
- react-scripts 5.0.1
- axios 1.6.7
- formik 2.4.5
- yup 1.3.3
- toastr 2.1.4
- react-toastify 10.0.0
- bcryptjs 2.4.3
- Clone the project to your computer:
https://github.com/bedirhanbalci/RentACar-BackEnd.git
- Compile the project with Maven:
mvn clean install
- Run the code to start the project:
mvn spring-boot:run
- Clone the project to your computer:
git clone https://github.com/bedirhanbalci/RentACar-Frontend.git
- Run the command to install project dependencies:
npm install
- Run the code to start the project:
npm start
In our RentACar project, we presented the file structures and contents of both the Back-End and Front-End sections. During the project development process, we adopted a layered architectural approach. This enabled us to manage project dependencies correctly and ensure division of work between layers.
Fundamentally, our project's Back-End structure consists of four main layers: entities, repositories, services, and controllers, along with the auxiliary core layer. These structures interact with each other to form the Back-End architecture of our project.
In this regard, we started with our entities as the first step.
In this layer, we modeled the data structures necessary for our project and created entity classes that represent our data. When creating these classes, we benefited from the principle of encapsulation to ensure data integrity and security. In other words, we controlled access to the necessary fields to protect our entities from external influences.
Furthermore, to effectively utilize object-oriented programming (OOP), we connected all our entity classes to a common base entity. This way, we could manage our common properties in a single point and achieve a more modular structure by preventing code repetition.
In the Repository layer, we created repository interfaces that will interact with the database, thanks to the convenience provided by Spring Data JPA.
The Services layer is the unit where the business logic of our project is managed, encompassing the essential functions required to perform business rules, database operations, and workflow processes. In this layer, we ensured the generation of appropriate responses to user requests. By creating separate service and manager classes for each entity, we adhered to the Single Responsibility Principle. Additionally, we used Model Mapper to transform incoming data from users to fit the existing data model of the application. Thus, we simplified complex transformation processes and reduced code duplication.
We structured the Services layer into 5 sub-modules: abstracts, concretes, constants, dtos, and rules.
The operations performed here can be detailed as follows:
The Abstracts module consists of interfaces where we define methods. These interfaces enable communication between different modules of the project and manage workflows.
Concretes is the concrete business logic module that implements the interfaces found in the abstracts module. Here, we created a separate service class for each entity. With these classes, we generated business rules, utilized ready-made database operations provided by JPA, and handled API requests appropriately.
In the Constants module, we customized business rules, method returns, and error messages used in the project.
To avoid exposing our entities entirely, we created DTOs (Data Transfer Objects). Additionally, we used DTOs to send the necessary properties required by requests from the Front-End.
We created requests from clients such as creating new records or updating and deleting existing records here. Additionally, we included DTOs representing responses sent from APIs to clients.
In the Rules component, we established our business rules. In this folder, we defined specific rules, conditions, and validation processes related to business logic. These business rules were incorporated into our manager classes. An example would be the conditions required for a vehicle to be rented out.
Through our Controller layer, we exposed our APIs to the outside world using Spring Framework's RESTful API features. This allowed us to manage CRUD (Create, Read, Update, Delete) operations using HTTP methods (GET, POST, PUT, DELETE) and various annotations provided by Spring.
By configuring our APIs in this manner, we were able to perform fundamental operations such as data creation, retrieval, updating, and deletion:
- Post Mapping: Used to create new records.
- Put Mapping: Used to update existing records.
- Delete Mapping: Used to delete existing records.
- Get Mapping: Used for data retrieval operations.
Configuration Classes: These are the classes responsible for configuring our application. We mark these classes with the Configuration annotation and configure the application's settings and dependencies.
Filters: This class serves as a JWT (Json Web Token) authentication filter designed for use with Spring Security. We used the JWT Authentication Filter to control incoming HTTP requests and authenticate the JWT tokens in these requests. Then, we authenticated the tokens and stored the authenticated user information in the security context.
Services: In this module, we managed the user authentication processes of the application with the Jwt Service class, handling the creation, verification, and processing of JWT tokens.
Utilities: Helper classes that fulfill our general requirements are found here. Under this package, we have three separate modules: exceptions, mappers, and results.
Exceptions: Alongside the global exception handler, we centrally handled various error situations in our application. For example, we customized our errors with the Business Exception Class. This way, we handled error situations appropriately and displayed meaningful error messages to the user.
Mappers: In this module, we integrated the model mapper class that we wanted to include in our application from the outside.
Results: We used this module to present the results of our application's operations in a more meaningful and organized manner. Additionally, we ensured that the data is displayed in a more understandable and user-friendly manner on the Front-End.
The Application Properties file contains the general configuration settings of our project. We configured the server, database, and security settings here.
In the root directory of our RentACar Front-End project, there are three main folders: node_modules, src, and public.
Node Modules: This directory contains project dependencies and npm packages.
Src: It is the main directory where our source code resides. This folder includes components, pages, services, and other source files.
Public: This directory contains our static files.
For a more modular and readable code structure, we used components in our project. Each component was created to perform a specific function. This accelerated our development process and reduced code repetition. We organized our components under two headings: Common and Layout.
Under the Common heading, we included general components created for reuse in different parts of our project.
Under the Layout heading, we created components that constitute the general layout and structure of our project. This way, we established the overall appearance and page layout of our project in a more understandable manner.
Common Components
Formik Input: Our input field component used in form operations.
Formik Select: Our dropdown menu (select) component providing options in forms.
Layout Components
Background: Our component used to set background videos and images on the homepage.
Branches Card: Our card component displayed on the Branches page.
Branch Map: Our component displaying branch locations on a map on the Branches page.
Campaign Slider: Our component displaying coverages and extras content in slider format on the homepage.
Car Card: Our card component displaying summary information of vehicles.
Contact Card: Our card component displayed on the Contact page.
Contact Map: Our map component holding the location information of our main branch on the Contact page.
Dropdown Card: Our dropdown card component displayed in the navbar.
Footer: Our component fixed at the bottom of the page.
Login Card: Our card component designed for user login.
Main Slider: Our component turning background videos and images on the homepage into a slider.
Navbar: Our navigation bar component located at the top of the page.
Overlay Loader: Our loader component displayed during loading.
User Update Form: Our form component designed to update user information.
In our project, we prioritized access control to ensure user security. In this context, we used "guards" to prevent unauthorized access to private pages. This usage prevents users from accessing private pages without logging in and allows them to access only the pages they are authorized to access.
About: This page elaborates on the company's mission, history, and detailed profiles of team members.
Additional Feature: This page allows users to select additional features during the car rental process and examine their details.
Assurance Package: This page enables users to select assurance packages during the car rental process and examine their details.
Branches: The Branches page allows users to access the location information of our branches and reserve vehicles available at those branches.
Car Detail: The Car Detail page allows users to access detailed information about a specific vehicle.
Car List: The Car List page is where users can list available vehicles for rental.
Contact: The Contact page contains the location information of our main branch and a form for users to get in touch.
Corporate Register: The Corporate Customer Registration page allows corporate users to register.
Individual Register: The Individual Customer Registration page allows individual users to register.
Homepage: The Homepage is the first page that welcomes the user.
Invoice: The Invoice page allows users to view invoice information related to rental transactions.
Not Found: The Not Found page displays an error message to users when an invalid URL is entered.
Order Complete: The Order Complete page confirms to users that they have successfully completed a car rental transaction.
Profile: The Profile page is where users can view and edit their account information.
Rental: The Rental page displays information about the car rental process and allows users to confirm payment.
Reservation: The Reservation page allows users to reserve vehicles based on their selected date range.
The Model represents the data layer of our project. It consists of two sub-layers: requests and responses, where we organize requests and responses.
The Requests component is an area where requests of different data types in our project are organized. For each data type, there are structures that enable the addition or updating of the relevant data. Here, specific requests for each data type are included.
On the other hand, the Responses component is an area where responses of various data types are stored. For each data type, it contains responses used for adding, updating, retrieving all, and retrieving based on a specific identifier.
This structured setup we have created clearly represents the data processing procedures of our project and the API communication. Each file is designed to perform a specific function, and the organization we have created by adopting the single responsibility approach makes it easier to manage and maintain our codebase.
In the services layer of our project, we created modules that communicate with the Back-End. Here, we interacted with APIs. First, we created a Base Service to serve as an interface between other service components and used it to manage CRUD operations (add, update, delete, getall, getbyid) for the relevant entity types. We extended the base service in the service classes created for each entity. This way, we centralized general CRUD operations in one place and enabled reusability.
Additionally, we set up Axios configurations and operations necessary for API communication. This helped us prevent repetitive code in other service classes and reduced code duplication. By using this structure, our aim was to accelerate the software development process and improve code quality.
Managing data flow between different components can be challenging, and to prevent prop drilling, we actively used global state management for rental information and user login details. We utilized local storage to store login and rental process information on the user's browser, ensuring persistence across sessions and allowing easy access for components throughout the application.
In the Config layer, we encrypted email and password information before storing them in local storage using the Password Helper. We managed HTTP requests or responses using Axios Interceptors. Custom Validation Rules were implemented to create password validation rules. With the help of a function written in Format Currency, we made the currency used in the application dynamic.
Users can view the details of a specific car, including the brand, model, price, fuel type, year, color, branch, and plate information. During the reservation stage, they can select assurance packages and additional products they desire. During this stage:
- They cannot rent a car for more than 25 days.
- They cannot rent a car for a date before today.
- They cannot select a return date earlier than the rental date.
- They cannot make a reservation without logging in.
On the "Branches" page, users can view branches on a map and rent a car from their preferred city. This allows users to find the nearest branch to their desired location and easily make a reservation to rent a car.
Users can update their personal information on their profile pages.
The "remember me" feature in the login process saves the email and password to the browser page. This feature allows users to rent a car more quickly.
Users can register with the system either individually or as a corporation. Through these options, users can access their personal or corporate accounts.
Individual and corporate users can only log in from their respective tabs.
We opted for PostgreSQL for database management, and with the help of Spring Data JPA, we automatically created database tables using annotations while creating our entities. We obtained 13 tables. We were careful in determining the types of relationships. We worked with local databases by taking a copy of the database we created.
We conducted unit tests, an important component of software development processes, under the test package. Particularly, we focused on writing tests related to operations of our entities, and by verifying their accuracy, we aimed to improve code quality and reliability.