Prestige Rentals: A Secure Full-Stack Application
October 27, 2025
Project Overview
Prestige Rentals is a full-stack car rental web application that I designed and developed from the ground up. My primary objective was not only to create a functional platform but to architect it with security and resilience as core design principles. As a cybersecurity student, I approached this project as both a software engineer and a security analyst—prioritizing safe coding practices across every layer, from the database schema to the client-side logic.
The platform serves two distinct roles: Customers, who can browse, rent, and review vehicles, and Administrators, who oversee fleet management, user accounts, and rental activity. Supporting these roles required a well-defined system for authentication, authorization, and data protection.
How It Works: Core Functionality
The application is powered by a modular React (JSX) front end that communicates with a custom Node.js (Express) backend API and a MySQL database as the persistent data store.
The Customer Experience
Guests can explore the car catalog and apply filters to refine their search. To rent or interact with listings, users must first create an account. Once authenticated, they gain access to several key features:
- Dashboard: A personalized dashboard for managing user profiles, saved vehicles, rental history, and payment options.
- Rental Flow: A guided multi-step rental process that includes date selection, terms of service acknowledgment, optional add-ons, and payment confirmation.
- Reviews: Verified renters can submit one review per vehicle and have full control to edit or delete their own feedback.
The Admin Panel
Administrators access a dedicated portal that grants elevated privileges through role-based API tokens. From here, staff can:
- Perform full CRUD (Create, Read, Update, Delete) operations on vehicle listings, customer records, and employee accounts.
- Manage maintenance schedules and monitor system-wide rental metrics.
Database Features
The Prestige Rentals backend is designed with robust, secure, and highly functional features that support both business logic and cybersecurity best practices. Key capabilities of the system include:
Security & Server Setup
- Secure HTTP Headers using
helmet. - CORS restricted to specific origins.
- Environment variables for sensitive data management.
- Rate limiting for login, registration, and password reset endpoints.
- Connection pooling to MySQL via
mysql2/promise.
User & Employee Authentication
- Employee and customer login endpoints.
- Customer registration with duplicate email checks.
- Password hashing using
bcrypt. - Password reset system using secure, expiring tokens.
- JWT-based authentication for admin and customer roles.
- Optional authentication for customizing public data access.
Public Data & Car Browsing
- Endpoints for featured cars and testimonials.
- Listing of car types, features, and rental add-ons.
- Filter and search cars with type, make/model, and average rating.
- Fetch complete car details and reviews, including user-specific flags.
Customer Profile & Management (Authenticated)
- View and update customer profile and password.
- Manage payment methods (add, list, delete) with ownership checks.
- Manage favorites (add, list, remove).
- Review system with eligibility checks and CRUD operations.
- Access to active and past rental history.
Rental Workflow (Authenticated)
- Create rentals using database transactions for atomic operations.
- Calculate total cost including add-ons and duration.
- Return rentals safely with status updates and optional fees.
- Delete completed rentals along with associated payments and add-ons.
Admin Panel (Authenticated)
- Dashboard metrics: car availability, revenue, and popular car types.
- CRUD operations for cars, employees, and customers.
- Maintenance management: schedule, complete, update costs, and history tracking.
- Force-return rentals and manage active maintenance records.
Database & Backend Deep Dive
The backend of Prestige Rentals is designed around a relational MySQL database, which serves as the backbone for all persistent data. Every piece of data—from vehicle information to customer profiles—is stored in structured tables with clear relationships, allowing for consistent, safe, and efficient queries. Let’s break down the architecture and implementation.
1. Database Schema & Table Design
The schema models real-world entities, ensuring clarity and maintainability:
- Customers: Stores essential user information including
customer_id,name,email,hashed_password,role, and account status. Passwords are hashed usingbcryptbefore being stored to prevent compromise. - Cars: Maintains details about each vehicle, including
car_id,make,model,year,license_plate,availability_status, and optional maintenance schedules. - Rentals: Maps customers to vehicles with
rental_id,customer_id,car_id,start_date,end_date,status, andtotal_price. - Payments: Tracks payment transactions per rental, storing
payment_id,rental_id,amount,payment_method,timestamp, andstatus. - Reviews: Connects customers to vehicles they’ve rented, with
review_id,customer_id,car_id,rating,comment, andcreated_at. Each customer may submit only one review per vehicle.
2. Relationships & Referential Integrity
Proper relational mapping ensures data consistency:
Rentals.customer_id → Customers.customer_id(foreign key constraint enforces that every rental belongs to a valid customer).Rentals.car_id → Cars.car_id(a rental must reference an existing car).Payments.rental_id → Rentals.rental_id(payments are always linked to rentals).Reviews.customer_id → Customers.customer_idandReviews.car_id → Cars.car_id(reviews must belong to valid customers and cars).
Using foreign keys enforces referential integrity, preventing orphaned records. Cascading rules, such as ON DELETE CASCADE for rentals and reviews, ensure that when a customer or vehicle is removed, related records are automatically cleaned up.
3. Indexing & Query Optimization
To support fast lookups and complex joins, I implemented indexing strategies:
- Primary keys automatically create unique indexes on
customer_id,car_id,rental_id, etc. - Secondary indexes on
email,license_plate, andstart_date/end_dateoptimize search queries and filter operations. - Composite indexes on
customer_id, car_idinRentalsimprove performance for queries like "all rentals for a given customer" or "all rentals of a specific car."
4. SQL Queries & Parameterization
All SQL queries are implemented using mysql2/promise with parameterized statements to prevent SQL injection. Examples:
- Retrieve active rentals for a customer:
SELECT r.rental_id, c.make, c.model, r.start_date, r.end_date FROM Rentals r JOIN Cars c ON r.car_id = c.car_id WHERE r.customer_id = ? AND r.status = 'active'; - Create a new rental:
INSERT INTO Rentals (customer_id, car_id, start_date, end_date, total_price) VALUES (?, ?, ?, ?, ?); - Update vehicle availability after rental:
UPDATE Cars SET availability_status = 'unavailable' WHERE car_id = ?;
5. Transactions & Data Consistency
For multi-step operations like rental creation and payment processing, I use database transactions to ensure atomicity. This guarantees that either all steps complete successfully or none are applied, preventing inconsistent states. Example flow:
- Start transaction.
- Insert rental record.
- Insert payment record.
- Update car availability.
- Commit transaction if all succeed; otherwise, rollback.
6. Backend API & Integration
The backend exposes RESTful endpoints that abstract direct SQL operations, enforce validation, and provide secure data access:
POST /api/rentals– Creates a new rental, validates car availability, and initiates a transaction for payment and availability updates.GET /api/customers/:id/rentals– Returns a customer’s rental history, joiningRentalswithCarsfor readable output.GET /api/admin/cars– Provides admin-only vehicle management data, enforcing RBAC via middleware.POST /api/reviews– Adds a review after verifying rental ownership, ensuring only verified customers can submit feedback.
7. Data Security & Privacy
Beyond SQL injection prevention, sensitive data such as passwords and payment information are never returned to the client. Query results are sanitized, and all data mutations are logged for auditing. User access is strictly controlled using JWTs and role-based middleware.
This backend architecture provides a robust, secure, and scalable foundation for the rental website, supporting both business logic and cybersecurity best practices.
Entity-Relationship (ER) Diagram
Below is a textual representation of the database schema in ER diagram format, detailing entities, weak entities, and relationships used in Prestige Rentals.
Entities (Strong Entities)
- Customers
- Attributes: customer_id (PK), first_name, last_name, email, phone_number, address, city, state, zip_code, date_of_birth, password, reset_token, reset_token_expires
- Cars
- Attributes: car_id (PK), make, model, year, license_plate, daily_rate, status, image_url, mileage, next_service_due_date, next_service_details, purchase_date, previous_owners, car_type_id (FK), location_id (FK)
- Employees
- Attributes: employee_id (PK), first_name, last_name, job_title, hire_date, email, username, password
- Rentals
- Attributes: rental_id (PK), customer_id (FK), car_id (FK), pickup_date, due_date, return_date, total_cost, late_fee
- Car_Types
- Attributes: car_type_id (PK), type_name
- Locations
- Attributes: location_id (PK), name, address
- Addons
- Attributes: addon_id (PK), name, description, price
- Features
- Attributes: feature_id (PK), name
Weak Entities
- Payments – existence dependent on Rentals
- Attributes: payment_id (PK), rental_id (FK), amount, payment_date, payment_method
- Maintenance – existence dependent on Cars
- Attributes: maintenance_id (PK), car_id (FK), service_date, service_type, cost, notes, completion_date
- CustomerPaymentMethods – existence dependent on Customers
- Attributes: payment_method_id (PK), customer_id (FK), card_holder_name, card_type, masked_number, expiry_date, is_primary
- Reviews – existence dependent on Customers and Cars
- Attributes: review_id (PK), car_id (FK), customer_id (FK), rating, review_text, review_date
Relationships
- books – connects Customers to Rentals (1:N)
- is_for – connects Rentals to Cars (N:1)
- is_type_of – connects Cars to Car_Types (N:1)
- is_parked_at – connects Cars to Locations (N:1)
- favorites – connects Customers to Cars (N:M)
- has_features – connects Cars to Features (N:M)
- includes_addons – connects Rentals to Addons (N:M)
Identifying Relationships (for Weak Entities)
- generates – Rentals to Payments (1:N)
- undergoes – Cars to Maintenance (1:N)
- has_method – Customers to CustomerPaymentMethods (1:N)
- writes_review – Customers to Reviews (1:N)
- receives_review – Cars to Reviews (1:N)
Cybersecurity Implementation: A Defensive Deep Dive
Security was the guiding principle behind every architectural decision. Drawing from my coursework and practical labs, I implemented multiple layers of defense to mitigate common web application vulnerabilities.
1. Authentication & Session Management
- Password Hashing: User passwords are never stored in plaintext. Using
bcrypt, each password is hashed with a unique salt to defend against rainbow table and dictionary attacks. - JSON Web Tokens (JWT): Upon successful login, the server issues a signed, stateless JWT containing the user’s ID and role. This token is stored in
sessionStorageand attached to all subsequent requests via theAuthorizationheader.
2. Authorization & Access Control
Authentication verifies identity, but authorization enforces boundaries. I implemented Role-Based Access Control (RBAC) using Express middleware.
- Middleware Validation: Two custom middleware functions—
authenticateCustomerandauthenticateAdmin—validate JWTs and confirm user roles before granting access. - Route Protection: Administrative routes (e.g.,
/api/admin/cars) are restricted to valid admin tokens. Any unauthorized request receives an immediate403 Forbiddenresponse.
3. Mitigating Common Vulnerabilities
- SQL Injection: All database queries use
mysql2/promisewith parameterized queries, ensuring user input is treated strictly as data and not executable SQL code. - Brute-Force Protection: The authentication endpoints employ
express-rate-limitto throttle repeated failed login attempts, mitigating automated password guessing attacks. - HTTP Header Hardening:
helmet.jsis configured to enforce headers likeStrict-Transport-Security,X-Frame-Options, andX-Content-Type-Options, reducing exposure to clickjacking and MIME-sniffing exploits. - Cross-Origin Resource Sharing (CORS): The backend only accepts requests from whitelisted origins, preventing malicious cross-domain API calls.
4. Secure API & Data Handling
- Data Ownership Verification: Before performing destructive actions (e.g., deleting reviews or payment methods), the backend validates ownership by matching the resource’s user ID against the ID from the verified JWT.
- Response Sanitization: All user-facing responses are scrubbed of sensitive data such as password hashes and tokens before being returned to the client.
Technology Stack
- Frontend: React (JSX), Astro, Tailwind CSS, Framer Motion
- Backend: Node.js, Express.js
- Database: MySQL with
mysql2/promise - Security & Auth: JSON Web Tokens (JWT),
bcrypt,helmet.js,express-rate-limit,cors
What I Learned
Developing Prestige Rentals was an opportunity to bridge theory and practice in secure software design. Concepts like SQL injection, rate limiting, and RBAC moved from abstract lessons to real-world implementations that I could test and validate.
This project reinforced the mindset of building defensively—never trusting client input, always validating on the server, and designing APIs to minimize exposure. It deepened my understanding of how security is not a single feature, but a process integrated throughout the software lifecycle.