Skip to content

M-ABHIRAM36/Quick-Explore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

18 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🌍 QuickExplore

A full-stack travel & tourism platform for vehicle bookings, rental accommodations, and destination discovery.

Features β€’ Architecture β€’ Getting Started β€’ API Routes β€’ Database β€’ Contributing


πŸ“‹ Table of Contents


πŸ“– About the Project

QuickExplore is a full-stack web application that connects travelers with local vehicle rental services and accommodation providers. Users can browse tourist destinations, book vehicles with assigned drivers, and rent accommodations β€” all through a unified platform.

The platform supports four distinct user roles (User, Admin, Driver, Rental Owner), each with its own dashboard, authentication system, and feature set.

Why QuickExplore?

  • For Travelers β€” Discover places, book vehicles and rooms in one platform
  • For Vehicle Owners β€” Register vehicles and earn through the platform
  • For Rental Owners β€” List properties and manage tenant bookings
  • For Admins β€” Approve/reject requests, assign drivers, manage the ecosystem

✨ Features

πŸ‘€ User Features

  • βœ… User registration & login with hashed passwords (bcrypt)
  • βœ… Browse tourist places across India
  • βœ… Book vehicles at destinations with date selection
  • βœ… Book rental accommodations (Houses, PGs, Apartments, Villas)
  • βœ… View booking history (active, completed, cancelled)
  • βœ… Renew/extend bookings (vehicles & rentals)
  • βœ… Cancel bookings with dynamic cancellation fees
  • βœ… View cancellation charges history
  • βœ… Profile management with password change

πŸ›‘οΈ Admin Features

  • βœ… Secure admin login (env-based credentials)
  • βœ… Review & approve/reject vehicle registration requests
  • βœ… Review & approve/reject rental property requests
  • βœ… Set rental pricing
  • βœ… Add new drivers to the system
  • βœ… Assign/reassign drivers to vehicles
  • βœ… View system architecture docs (DFD)

πŸš— Driver Features

  • βœ… Driver login with phone, email & password
  • βœ… View assigned customer booking details
  • βœ… Mark rides as completed
  • βœ… Cancel rides (with auto fee calculation)
  • βœ… Change password from profile

🏠 Rental Owner Features

  • βœ… Owner login with auto-generated credentials
  • βœ… View tenant/customer details
  • βœ… Mark stays as completed
  • βœ… Cancel bookings (with auto fee calculation)
  • βœ… Change password from profile

πŸ”§ System Features

  • βœ… Server-side sessions stored in MongoDB (connect-mongo)
  • βœ… Image uploads to Cloudinary
  • βœ… Splash screen on first visit
  • βœ… Request status tracking (vehicle & rental)
  • βœ… 404 catch-all error page
  • βœ… Dynamic cancellation fee engine

πŸ—οΈ Architecture

QuickExplore follows the Model-View-Controller (MVC) pattern:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Browser   │────▢│    Routes    │────▢│ Controllers  │────▢│   Models     β”‚
β”‚   (EJS)     │◀────│  (Express)   │◀────│  (Logic)     │◀────│  (Mongoose)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚                    β”‚
                    β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
                    β”‚ Middleware  β”‚       β”‚ Cloudinary  β”‚
                    β”‚  (Auth)    β”‚       β”‚  (Images)   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

MVC Folder Structure

QuickExplore/
β”œβ”€β”€ app.js                  # Express setup, middleware, route mounting (~90 lines)
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ db.js               # MongoDB connection via Mongoose
β”‚   └── cloudinary.js       # Cloudinary + Multer storage config
β”œβ”€β”€ middleware/
β”‚   └── auth.js             # 4 auth middlewares (User, Admin, Driver, Owner)
β”œβ”€β”€ controllers/
β”‚   β”œβ”€β”€ userController.js   # User registration, login, logout, profile
β”‚   β”œβ”€β”€ adminController.js  # Admin auth, panel, documentation routes
β”‚   β”œβ”€β”€ vehicleController.js# Vehicle request CRUD, status checks
β”‚   β”œβ”€β”€ rentalController.js # Rental request CRUD, status checks
β”‚   β”œβ”€β”€ bookingController.js# Vehicle & rental bookings, charges history
β”‚   β”œβ”€β”€ driverController.js # Driver auth, rides, assignment, profile
β”‚   └── ownerController.js  # Owner auth, tenant management, profile
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ users.js            # /register, /login, /logout, /user/profile
β”‚   β”œβ”€β”€ admin.js            # /adminLogin, /admin, /Adminlogout
β”‚   β”œβ”€β”€ vehicles.js         # /vehicleRform, /requestForms/vehicleForms
β”‚   β”œβ”€β”€ rentals.js          # /rentalRform, /requestForms/rentalForms
β”‚   β”œβ”€β”€ bookings.js         # /places2, /book-vehicle, /book-rooms, /my-bookings
β”‚   β”œβ”€β”€ drivers.js          # /driver/* (mounted at /driver prefix)
β”‚   └── owners.js           # /owner/* (mounted at /owner prefix)
β”œβ”€β”€ models/                 # 10 Mongoose schemas
β”œβ”€β”€ views/                  # EJS templates organized by feature
β”œβ”€β”€ public/                 # Static assets (CSS, images)
└── init/                   # Database seeding scripts

System Design Diagram

                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                           β”‚     QuickExplore      β”‚
                           β”‚      (Express)        β”‚
                           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚                         β”‚                         β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
     β”‚    Users    β”‚          β”‚    Admin      β”‚          β”‚   Drivers   β”‚
     β”‚  Register   β”‚          β”‚  Approve/     β”‚          β”‚   Login     β”‚
     β”‚  Login      β”‚          β”‚  Reject       β”‚          β”‚   Rides     β”‚
     β”‚  Book       β”‚          β”‚  Assign       β”‚          β”‚   Cancel    β”‚
     β”‚  Cancel     β”‚          β”‚  Price Set    β”‚          β”‚   Complete  β”‚
     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜          β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
            β”‚                         β”‚                         β”‚
            β”‚                  β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”                  β”‚
            β”‚                  β”‚   Rental    β”‚                  β”‚
            β”‚                  β”‚   Owners    β”‚                  β”‚
            β”‚                  β”‚   Login     β”‚                  β”‚
            β”‚                  β”‚   Manage    β”‚                  β”‚
            β”‚                  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                  β”‚
            β”‚                         β”‚                         β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
     β”‚                         MongoDB Atlas                           β”‚
     β”‚  Users | Drivers | Listings | Vehicles | Rentals | Bookings    β”‚
     β”‚  Transactions | ChargesHistory | RentalChargesHistory          β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                             β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
                             β”‚ Cloudinary  β”‚
                             β”‚  (Images)   β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ› οΈ Tech Stack

Layer Technology
Runtime Node.js
Framework Express.js v4
Database MongoDB (Mongoose ODM)
Template Engine EJS (with ejs-mate layouts)
Authentication bcrypt (password hashing) + express-session
Session Store connect-mongo (MongoDB-backed sessions)
Image Storage Cloudinary (via multer-storage-cloudinary)
File Upload Multer
Environment dotenv
HTTP Method Override method-override (PUT/DELETE via forms)

πŸš€ Getting Started

Prerequisites

Make sure you have the following installed:

  • Node.js (v16 or higher) β€” Download
  • MongoDB (local) or MongoDB Atlas account β€” Atlas
  • Cloudinary account β€” Sign up
  • Git β€” Download

Installation

# 1. Clone the repository
git clone https://github.com/your-username/QuickExplore.git

# 2. Navigate to the project directory
cd QuickExplore

# 3. Install dependencies
npm install

Environment Variables

Create a .env file in the root directory:

# MongoDB Connection
MONGO_ATLAS_URL=mongodb+srv://<username>:<password>@cluster.mongodb.net/quickexplore

# Session Secret
SESSION_SECRET=your_super_secret_session_key_here

# Cloudinary Configuration
CLOUD_NAME=your_cloud_name
CLOUD_API_KEY=your_api_key
CLOUD_API_SECRET=your_api_secret

# Admin Credentials
QuickExploreTeamAdmin_USERNAME=admin
QuickExploreTeamAdmin_EMAIL=admin@quickexplore.com
QuickExploreTeamAdmin_PASSWORD=your_admin_password

# Driver Default Password (assigned when admin creates a new driver)
DRIVER_PASS=default_driver_password

⚠️ Never commit your .env file. It's already in .gitignore.

Seeding Data

The init/ folder contains seed scripts for initial data:

# Seed tourist places
node init/listingP.js

# Seed sample vehicles
node init/vehicleRequestData.js

# Seed sample drivers
node init/driver.js

# Seed sample bookings
node init/bookingVehicle.js

# Seed sample rental requests
node init/rentalRequest.js

# Seed sample users
node init/userinit.js

Running the App

# Start the server
node app.js

# Output: app is listening on port : 8080
# Output: DB CONNECTED TO ATLAS MONGODB!

Open your browser and navigate to: http://localhost:8080


πŸ‘₯ User Roles & Permissions

Feature User Admin Driver Rental Owner
Browse Places βœ… ❌ ❌ ❌
Book Vehicle βœ… ❌ ❌ ❌
Book Rental βœ… ❌ ❌ ❌
Cancel Own Booking βœ… ❌ ❌ ❌
Renew Booking βœ… ❌ ❌ ❌
View Charges History βœ… ❌ ❌ ❌
Approve/Reject Requests ❌ βœ… ❌ ❌
Add Drivers ❌ βœ… ❌ ❌
Assign Drivers to Vehicles ❌ βœ… ❌ ❌
Set Rental Pricing ❌ βœ… ❌ ❌
View Customer Details ❌ ❌ βœ… βœ…
Complete Ride/Stay ❌ ❌ βœ… βœ…
Cancel Ride (Driver-side) ❌ ❌ βœ… ❌
Cancel Booking (Owner-side) ❌ ❌ ❌ βœ…
Change Password βœ… ❌ βœ… βœ…

Authentication Matrix

Role Login Method Session Variable Middleware
User Email + Password req.session.userId requireLogin
Admin Username + Email + Password (from .env) req.session.authenticated isAuthenticated
Driver Phone + Email + Password req.session.driver_id requireDriverLogin
Rental Owner Phone + Email + Password req.session.owner_id requireOwnerLogin

πŸ“‘ API Routes Reference

User Routes (routes/users.js)

Method Endpoint Auth Description
GET / β€” Redirects to /flash
GET /flash β€” Splash screen
GET /register β€” Registration form
POST /register β€” Create new user account
GET /login β€” Login form
POST /login β€” Authenticate user
GET /logout β€” Destroy session & logout
GET /user/profile requireLogin View user profile
POST /user/profile requireLogin Change user password

Admin Routes (routes/admin.js)

Method Endpoint Auth Description
GET /adminLogin β€” Admin login form
POST /adminLogin β€” Authenticate admin
GET /Adminlogout isAuthenticated Admin logout
GET /admin isAuthenticated Admin dashboard
GET /quickexploreDFDd1 isAuthenticated DFD Document 1
GET /quickexploreDFDd2 isAuthenticated DFD Document 2
GET /quickexploreSA isAuthenticated System Architecture doc

Vehicle Routes (routes/vehicles.js)

Method Endpoint Auth Description
GET /vehicleRform requireLogin Vehicle registration form
GET /requestForms/vehicleForms isAuthenticated Admin: view all vehicle requests
POST /requestForms/vehicleForms β€” Submit vehicle request (with image upload)
GET /usercredential requireLogin Show user credentials after vehicle request
POST /updateVehicleStatus/:id β€” Admin: approve/reject vehicle
GET /Vstatus requireLogin Vehicle request status check form
POST /CheckVehicleStatus β€” Fetch vehicle request status

Rental Routes (routes/rentals.js)

Method Endpoint Auth Description
GET /rentalRform requireLogin Rental property registration form
GET /requestForms/rentalForms isAuthenticated Admin: view all rental requests
POST /requestForms/rentalForms β€” Submit rental request (with image upload)
GET /usercredentialR requireLogin Show credentials after rental request
POST /requestForms/updatePrice/:id β€” Admin: set rental price
POST /requestForms/updateStatus/:id β€” Admin: approve/reject rental
GET /Rstatus requireLogin Rental request status check form
POST /CheckRentalStatus β€” Fetch rental request status

Booking Routes (routes/bookings.js)

Method Endpoint Auth Description
GET /places2 β€” Browse all tourist places
GET /listings/:id/viewP requireLogin View single place details
GET /book-vehicle requireLogin Available vehicles at a place
POST /book-vehicle β€” Book a vehicle
GET /my-bookings requireLogin User's vehicle bookings
POST /renew-booking/:bookingId β€” Extend vehicle booking
POST /cancel-booking/:bookingId β€” Cancel vehicle booking
GET /my-charges requireLogin Vehicle cancellation charges history
GET /book-rooms requireLogin Available rentals at a place
POST /bookRental/:rentalId requireLogin Book a rental accommodation
GET /my-Rbookings requireLogin User's rental bookings
POST /renew-rental/:rentalBookingId requireLogin Extend rental booking
POST /cancel-rental/:bookingId β€” Cancel rental booking
GET /my-rentalcharges requireLogin Rental cancellation charges history

Driver Routes (routes/drivers.js β€” mounted at /driver)

Method Endpoint Auth Description
GET /driver/login β€” Driver login form
POST /driver/login β€” Authenticate driver
GET /driver/logout β€” Driver logout
GET /driver/home requireDriverLogin Driver dashboard
GET /driver/customer-details requireDriverLogin View assigned customers
POST /driver/customer-details β€” Fetch customer details by driver ID
POST /driver/complete-ride/:bookingId requireDriverLogin Mark ride as completed
POST /driver/cancel-ride/:bookingId β€” Cancel ride (driver-initiated)
GET /driver/profile requireDriverLogin Driver profile page
POST /driver/profile requireDriverLogin Change driver password
GET /driver/assign-vehicle isAuthenticated Admin: assign vehicle to driver
POST /driver/assign-vehicle β€” Admin: execute assignment
GET /driver/assign-vehicleNewDriver isAuthenticated Admin: reassign driver
POST /driver/assign-vehicleNewDriver β€” Admin: execute reassignment
GET /driver/add isAuthenticated Admin: add driver form
POST /driver/add isAuthenticated Admin: create new driver

Owner Routes (routes/owners.js β€” mounted at /owner)

Method Endpoint Auth Description
GET /owner/login β€” Owner login form
POST /owner/login β€” Authenticate owner
GET /owner/logout β€” Owner logout
GET /owner/home requireOwnerLogin Owner dashboard
GET /owner/customer-details requireOwnerLogin View tenants
POST /owner/complete-booking/:bookingId requireOwnerLogin Mark stay as completed
POST /owner/cancel-booking/:bookingId requireOwnerLogin Cancel tenant booking
GET /owner/profile requireOwnerLogin Owner profile page
POST /owner/profile requireOwnerLogin Change owner password

🧠 Business Logic Deep Dive

1. Vehicle Booking Flow

User selects a place
        β”‚
        β–Ό
GET /book-vehicle?place=XYZ
  β†’ Query: VehicleRequest { adminStatus: "Approved", bookingStatus: "Available", place }
        β”‚
        β–Ό
User picks vehicle & dates β†’ POST /book-vehicle
        β”‚
        β”œβ”€β”€ Verify vehicle exists & is approved + available
        β”œβ”€β”€ Check no existing "Booked" booking for this vehicle
        β”œβ”€β”€ Auto-find assigned driver: Driver.findOne({ currentVehicle: vehicleId })
        β”œβ”€β”€ Calculate: rentalDays = ceil((dropoff - pickup) / 1 day)
        β”œβ”€β”€ Calculate: totalAmount = rentalDays Γ— rentalPricePerDay
        β”œβ”€β”€ Create Booking record (vehicleStatus: "Booked", paymentStatus: "Pending")
        β”œβ”€β”€ Update VehicleRequest.bookingStatus β†’ "Booked"
        └── Redirect β†’ /my-bookings

Key Points:

  • Only admin-approved vehicles with status "Available" are shown
  • Driver is auto-assigned based on the currentVehicle field
  • Vehicle gets locked (bookingStatus: "Booked") immediately upon booking
  • Total amount is calculated server-side to prevent manipulation

2. Rental Booking Flow

User selects a place
        β”‚
        β–Ό
GET /book-rooms?place=XYZ
  β†’ Query: rentalRequest { place: /XYZ/i, adminStatus: "Approved", bookingStatus: "Available" }
        β”‚
        β–Ό
User picks rental & dates β†’ POST /bookRental/:rentalId
        β”‚
        β”œβ”€β”€ Verify rental exists & is approved + available
        β”œβ”€β”€ Check for overlapping bookings:
        β”‚     RentalBooking { rentalId, status: ["Booked","Ongoing"],
        β”‚       checkInDate ≀ checkOutDate AND checkOutDate β‰₯ checkInDate }
        β”œβ”€β”€ Create RentalBooking record (status: "Booked")
        β”œβ”€β”€ Update rentalRequest.bookingStatus β†’ "Booked"
        └── Redirect β†’ /my-Rbookings

Key Points:

  • Place search is case-insensitive using regex
  • Overlap detection prevents double bookings
  • totalAmount is sent from the form (calculated client-side from daily rate Γ— days)

3. Cancellation & Fee Logic

The system implements a tiered cancellation fee structure based on time difference:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              CANCELLATION FEE TIERS                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Time to Pickup   β”‚ Fee                              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ≀ 20 minutes     β”‚ β‚Ή0 (free cancellation)           β”‚
β”‚ 20 min – 24 hrs  β”‚ 10% of total booking amount      β”‚
β”‚ > 24 hours       β”‚ 1 day's rental price              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

For Vehicle Cancellation (POST /cancel-booking/:bookingId):

timeDifference (from request body, in minutes)
  β”‚
  β”œβ”€β”€ > 20 AND ≀ 1440 β†’ fee = totalAmount Γ— 0.10
  β”œβ”€β”€ > 1440          β†’ fee = vehicle.rentalPricePerDay
  └── ≀ 20            β†’ fee = 0
  β”‚
  β”œβ”€β”€ booking.vehicleStatus β†’ "Cancelled"
  β”œβ”€β”€ booking.cancelledBy β†’ "driver" (indicates who initiated)
  β”œβ”€β”€ vehicle.bookingStatus β†’ "Available" (freed up)
  β”œβ”€β”€ Create Transaction record (if fee > 0)
  β”œβ”€β”€ Create UserChargesHistory record (if fee β‰₯ 0)
  └── Render cancel-summary page

For Rental Cancellation (POST /cancel-rental/:bookingId):

  • Same tiered logic, but uses rental.price instead of rentalPricePerDay
  • Records in UserRentalChargesHistory instead
  • Renders rental-cancel-summary page

For Driver-Initiated Cancellation (POST /driver/cancel-ride/:bookingId):

  • Calculates fee based on actual pickup date vs current time (server-side)
  • Sets booking.cancelledBy = "driver"
  • Creates Transaction record but does NOT create UserChargesHistory

For Owner-Initiated Cancellation (POST /owner/cancel-booking/:bookingId):

  • Calculates fee based on checkInDate vs current time (server-side)
  • Sets booking.cancelledBy = "owner"
  • Records in UserRentalChargesHistory (if fee > 0)

4. Renewal Logic

Vehicle Renewal (POST /renew-booking/:bookingId):

additionalDays (from form)
  β”‚
  β”œβ”€β”€ New dropoff = original dropoff + additionalDays
  β”œβ”€β”€ Total days = ceil((newDropoff - pickupDate) / 1 day)
  β”œβ”€β”€ Updated total = totalDays Γ— rentalPricePerDay
  └── Save & redirect to /my-bookings

Rental Renewal (POST /renew-rental/:rentalBookingId):

additionalDays (from form)
  β”‚
  β”œβ”€β”€ Must be the booking owner (userId check)
  β”œβ”€β”€ Must be currently "Booked" status
  β”œβ”€β”€ New checkout = original checkout + additionalDays
  β”œβ”€β”€ Total days = ceil((newCheckout - checkInDate) / 1 day)
  β”œβ”€β”€ Updated total = totalDays Γ— dailyRate (rental.price)
  └── Save & redirect to /my-Rbookings

5. Driver Assignment Logic

Admin assigns driver β†’ POST /driver/assign-vehicle
  β”‚
  β”œβ”€β”€ Clear any existing vehicle assignment for this vehicle:
  β”‚     Driver.updateMany({ currentVehicle: vehicleId }, { currentVehicle: null })
  β”œβ”€β”€ Assign driver:
  β”‚     Driver.findByIdAndUpdate(driverId, { currentVehicle: vehicleId })
  β”œβ”€β”€ Update vehicle:
  β”‚     VehicleRequest.findByIdAndUpdate(vehicleId, { currentDriver: driverId })
  └── Redirect back

Admin reassigns driver β†’ POST /driver/assign-vehicleNewDriver
  β”‚
  β”œβ”€β”€ Same as above PLUS:
  └── Update ALL existing bookings for this vehicle:
        Booking.updateMany({ vehicleId }, { driverId: newDriverId })

Key Points:

  • One vehicle can only have one driver at a time
  • When reassigning, ALL bookings (even past ones) get the new driver ID
  • Driver auto-assignment happens at booking time: Driver.findOne({ currentVehicle: vehicleId })

6. Password & Authentication System

User Passwords:

  • Hashed with bcrypt (12 salt rounds) via a Mongoose pre-save hook
  • Password comparison via user.comparePassword(candidate) instance method
  • On profile update, setting user.password = newPlain triggers the pre-save hook again

Driver Passwords:

  • Same bcrypt pre-save hook and comparePassword method
  • Default password set from process.env.DRIVER_PASS when admin creates driver
  • Drivers can change their password from /driver/profile

Owner Passwords:

  • No pre-save hook β€” hashing is done manually in the controller:
    const hashedPassword = await bcrypt.hash(newPassword, 12);
    owner.password = hashedPassword;
  • comparePassword instance method exists for login verification

Admin Auth:

  • No database record β€” credentials are read directly from environment variables
  • Session flag req.session.authenticated = true upon successful login

7. Rental Owner Onboarding

When a rental property request is submitted:

POST /requestForms/rentalForms
  β”‚
  β”œβ”€β”€ Save rental request with password: "placeholder"
  β”œβ”€β”€ Generate unique password: "QuE9@" + last 5 chars of MongoDB _id
  β”‚     Example: QuE9@a3f8c
  β”œβ”€β”€ Hash generated password with bcrypt (12 rounds)
  β”œβ”€β”€ Update rental record with hashed password
  β”œβ”€β”€ Redirect to /usercredentialR showing:
  β”‚     - Request ID
  β”‚     - Contact
  β”‚     - Email
  β”‚     - Plain-text generated password (shown ONCE)
  └── Owner uses these credentials to login at /owner/login

πŸ“Š Database Schemas

Entity Relationship Diagram

User ──┬──▢ Booking (Vehicle) ──▢ VehicleRequest ◀── Driver
       β”‚                      └──▢ Driver
       β”œβ”€β”€β–Ά RentalBooking ──▢ RentalRequest
       β”œβ”€β”€β–Ά Transaction ──▢ VehicleRequest
       β”œβ”€β”€β–Ά UserChargesHistory ──▢ VehicleRequest + Booking
       └──▢ UserRentalChargesHistory ──▢ RentalRequest + RentalBooking

Driver.currentVehicle ──▢ VehicleRequest
VehicleRequest.currentDriver ──▢ Driver

Models Summary

Model Collection Key Fields Purpose
User users username, email, password, phone Platform users
Driver drivers username, phone, email, currentVehicle, password Vehicle drivers
ListingP listingps title, location, type, images, entryFee Tourist destinations
VehicleRequest vehiclerequests ownerName, vehicleType, brand, model, registrationNumber, rentalPricePerDay, adminStatus, bookingStatus, currentDriver Registered vehicles
RentalRequest rentalrequests ownerName, propertyType, location, price, adminStatus, bookingStatus, password Rental properties
Booking bookings userId, vehicleId, driverId, pickupDate, dropoffDate, totalAmount, vehicleStatus Vehicle bookings
RentalBooking rentalbookings userId, rentalId, checkInDate, checkOutDate, totalAmount, status, cancellationFee Rental bookings
Transaction transactions userId, vehicleId, amount, type Financial transactions
UserChargesHistory userchargeshistories userId, vehicleId, bookingId, destination, cancellationFee Vehicle cancellation history
UserRentalChargesHistory userrentalchargeshistories userId, rentalId, bookingId, destination, cancellationFee Rental cancellation history

Status Enums

Admin Status (vehicles & rentals):

Status Meaning
Pending Awaiting admin review (default)
Approved Admin accepted the request
Rejected Admin denied the request
Flagged Marked for further review

Booking Status (vehicles & rentals):

Status Meaning
Available Ready for booking (default)
Booked Currently booked by a user
Ongoing Trip/stay in progress
Completed Trip/stay finished
Cancelled Booking was cancelled

Payment Status:

Status Meaning
Pending Payment not yet collected (default)
Completed Payment received
Failed Payment attempt failed

πŸ” Middleware

Located in middleware/auth.js:

// Protects user-only routes
requireLogin(req, res, next)
  β†’ Checks: req.session.userId
  β†’ Redirects to: /login

// Protects admin-only routes
isAuthenticated(req, res, next)
  β†’ Checks: req.session.authenticated
  β†’ Redirects to: /adminLogin

// Protects driver-only routes
requireDriverLogin(req, res, next)
  β†’ Checks: req.session.driver_id
  β†’ Redirects to: /driver/login

// Protects owner-only routes
requireOwnerLogin(req, res, next)
  β†’ Checks: req.session.owner_id
  β†’ Redirects to: /owner/login

Global Middleware (in app.js)

// Makes currentUser available to ALL EJS templates
app.use((req, res, next) => {
  res.locals.currentUser = req.session.user || null;
  next();
});

πŸͺ Session Management

Config Value Purpose
Store connect-mongo (MongoDB) Sessions persist across server restarts
Secret process.env.SESSION_SECRET Signs session cookies
Max Age 24 hours (86400000 ms) Auto-logout after 1 day
httpOnly true Prevents client-side JS access to cookies
resave false Don't save session if unmodified
saveUninitialized false Don't create session until data is stored

Session Variables by Role

// User login
req.session.userId = user._id;
req.session.user = { _id, username, email };

// Admin login
req.session.authenticated = true;

// Driver login
req.session.driver_id = driver._id;

// Owner login
req.session.owner_id = rental._id;

// Splash screen
req.session.splashShown = true/false;

☁️ Image Uploads (Cloudinary)

Configuration in config/cloudinary.js:

// Storage Settings
Folder: 'quickexplore_DEV'
Allowed Formats: jpg, jpeg, png
Public ID: Original filename (without extension)

Used in routes:

  • POST /requestForms/vehicleForms β€” Vehicle registration images
  • POST /requestForms/rentalForms β€” Rental property images

Upload middleware: multer with CloudinaryStorage adapter


⚠️ Error Handling

The app uses a two-tier error handling system:

  1. Operational Errors β†’ views/errors/error.ejs

    • User-friendly messages (invalid credentials, not found, etc.)
    • Rendered with: res.render("errors/error", { error: "message" })
  2. Application Errors β†’ views/errors/appError.ejs

    • System-level errors (DB failures, unexpected crashes)
    • Rendered with: res.render("errors/appError.ejs", { error })
  3. 404 Not Found β†’ Catch-all route

    app.get('*', (req, res) => {
      res.status(404).render("errors/appError", { error: 'Page not found', statusCode: 404 });
    });

Every route handler is wrapped in try/catch blocks with appropriate error logging via console.error.


πŸ“ Project Structure (Tree)

Quick-Explore/
β”‚
β”œβ”€β”€ app.js                              # Express app entry point (~90 lines)
β”‚
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ db.js                           # MongoDB connection
β”‚   └── cloudinary.js                   # Cloudinary + Multer storage
β”‚
β”œβ”€β”€ controllers/
β”‚   β”œβ”€β”€ userController.js               # User auth + profile
β”‚   β”œβ”€β”€ adminController.js              # Admin auth + dashboard
β”‚   β”œβ”€β”€ vehicleController.js            # Vehicle request management
β”‚   β”œβ”€β”€ rentalController.js             # Rental request management
β”‚   β”œβ”€β”€ bookingController.js            # All booking operations
β”‚   β”œβ”€β”€ driverController.js             # Driver operations
β”‚   └── ownerController.js              # Rental owner operations
β”‚
β”œβ”€β”€ middleware/
β”‚   └── auth.js                         # 4 authentication middlewares
β”‚
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ User.js                         # User schema
β”‚   β”œβ”€β”€ Driver.js                       # Driver schema
β”‚   β”œβ”€β”€ listingP.js                     # Tourist place schema
β”‚   β”œβ”€β”€ vehicleRequest.js              # Vehicle registration schema
β”‚   β”œβ”€β”€ rentalRequest.js               # Rental property schema
β”‚   β”œβ”€β”€ bookingVehicle.js              # Vehicle booking schema
β”‚   β”œβ”€β”€ bookingRental.js               # Rental booking schema
β”‚   β”œβ”€β”€ Transaction.js                 # Transaction schema
β”‚   β”œβ”€β”€ UserChargesHistory.js          # Vehicle charges history
β”‚   └── UserRentalChargesHistory.js    # Rental charges history
β”‚
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ users.js                        # User routes
β”‚   β”œβ”€β”€ admin.js                        # Admin routes
β”‚   β”œβ”€β”€ vehicles.js                     # Vehicle routes
β”‚   β”œβ”€β”€ rentals.js                      # Rental routes
β”‚   β”œβ”€β”€ bookings.js                     # Booking routes
β”‚   β”œβ”€β”€ drivers.js                      # Driver routes (prefix: /driver)
β”‚   └── owners.js                       # Owner routes (prefix: /owner)
β”‚
β”œβ”€β”€ views/
β”‚   β”œβ”€β”€ flash.ejs                       # Splash screen
β”‚   β”œβ”€β”€ BookingR/                       # Rental booking views
β”‚   β”‚   β”œβ”€β”€ bookRental.ejs
β”‚   β”‚   └── myRbookings.ejs
β”‚   β”œβ”€β”€ BookingV/                       # Vehicle booking views
β”‚   β”‚   β”œβ”€β”€ bookVehicle.ejs
β”‚   β”‚   └── myBookings.ejs
β”‚   β”œβ”€β”€ checkStatus/                    # Status check views
β”‚   β”‚   β”œβ”€β”€ checkRstatusF.ejs
β”‚   β”‚   β”œβ”€β”€ checkVstatusF.ejs
β”‚   β”‚   β”œβ”€β”€ showRstatus.ejs
β”‚   β”‚   └── showVstatus.ejs
β”‚   β”œβ”€β”€ docsqe/                         # Documentation views
β”‚   β”‚   β”œβ”€β”€ Physical_DFD_QuickExplore.ejs
β”‚   β”‚   β”œβ”€β”€ Physical_DFD_QuickExplore2.ejs
β”‚   β”‚   └── QuickExplore_Architecture.ejs
β”‚   β”œβ”€β”€ driver/                         # Driver views
β”‚   β”‚   β”œβ”€β”€ addDriver.ejs
β”‚   β”‚   β”œβ”€β”€ assignNewDriverToVehicle.ejs
β”‚   β”‚   β”œβ”€β”€ assignVehicle.ejs
β”‚   β”‚   β”œβ”€β”€ customerList.ejs
β”‚   β”‚   β”œβ”€β”€ driverLogin.ejs
β”‚   β”‚   β”œβ”€β”€ driverPage.ejs
β”‚   β”‚   β”œβ”€β”€ driverProfile.ejs
β”‚   β”‚   └── enterDriverId.ejs
β”‚   β”œβ”€β”€ errors/                         # Error pages
β”‚   β”‚   β”œβ”€β”€ appError.ejs
β”‚   β”‚   └── error.ejs
β”‚   β”œβ”€β”€ includes/                       # Partial templates
β”‚   β”‚   β”œβ”€β”€ basicCode.ejs
β”‚   β”‚   └── navbar.ejs
β”‚   β”œβ”€β”€ layouts/                        # Layout templates
β”‚   β”‚   └── boilerplate.ejs
β”‚   β”œβ”€β”€ listing/                        # Place & form views
β”‚   β”‚   β”œβ”€β”€ places2.ejs
β”‚   β”‚   β”œβ”€β”€ rentalRform.ejs
β”‚   β”‚   β”œβ”€β”€ usercredential.ejs
β”‚   β”‚   β”œβ”€β”€ usercredentialR.ejs
β”‚   β”‚   β”œβ”€β”€ vehicleRform.ejs
β”‚   β”‚   └── viewP.ejs
β”‚   β”œβ”€β”€ rentalOwner/                    # Owner views
β”‚   β”‚   β”œβ”€β”€ customerList.ejs
β”‚   β”‚   β”œβ”€β”€ ownerLogin.ejs
β”‚   β”‚   β”œβ”€β”€ ownerPage.ejs
β”‚   β”‚   └── ownerProfile.ejs
β”‚   β”œβ”€β”€ requestForms/                   # Admin request views
β”‚   β”‚   β”œβ”€β”€ admin.ejs
β”‚   β”‚   β”œβ”€β”€ adminLogin.ejs
β”‚   β”‚   β”œβ”€β”€ rentalForms.ejs
β”‚   β”‚   └── vehicleForms.ejs
β”‚   └── users/                          # User views
β”‚       β”œβ”€β”€ cancel-summary.ejs
β”‚       β”œβ”€β”€ login.ejs
β”‚       β”œβ”€β”€ my-charges.ejs
β”‚       β”œβ”€β”€ my-rentalcharges.ejs
β”‚       β”œβ”€β”€ register.ejs
β”‚       β”œβ”€β”€ rental-cancel-summary.ejs
β”‚       └── userProfile.ejs
β”‚
β”œβ”€β”€ public/
β”‚   └── images/                         # Static images
β”‚
β”œβ”€β”€ init/                               # Database seed scripts
β”‚   β”œβ”€β”€ bookingVehicle.js
β”‚   β”œβ”€β”€ driver.js
β”‚   β”œβ”€β”€ listingP.js
β”‚   β”œβ”€β”€ rentalRequest.js
β”‚   β”œβ”€β”€ userinit.js
β”‚   └── vehicleRequestData.js
β”‚
β”œβ”€β”€ .env                                # Environment variables (not committed)
β”œβ”€β”€ .gitignore
β”œβ”€β”€ cloudConfig.js                      # Legacy cloud config (kept for compatibility)
β”œβ”€β”€ package.json
└── package-lock.json

πŸ“Έ Screenshots

screenshots of my application are:

Page Screenshot
Landing / Splash image
Places Listing image
Places Listing image
Vehicle Booking image
Rental Booking image
My Bookings image
My Bookings image
Admin Dashboard image
Admin Dashboard image
Admin Dashboard image
Admin Dashboard image
Admin Dashboard image
Admin Dashboard image
Driver Dashboard image
Owner Dashboard image

Development Process

I designed the system flow and database schema on paper before implementation.

The first version was built in a monolithic Express app to understand the data flow clearly.

Later I refactored the project into MVC architecture for better maintainability.

πŸ—ΊοΈ Roadmap

  • Payment gateway integration (Razorpay / Stripe)
  • Real-time notifications (Socket.io)
  • Email notifications for booking confirmations
  • Google Maps integration for place locations
  • Rating & review system for vehicles and rentals
  • Multi-language support
  • Mobile-responsive PWA
  • REST API for mobile app integration
  • Advanced search filters (price range, vehicle type, property type)
  • Dashboard analytics for admin

🀝 Contributing

Contributions make the open-source community an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

How to Contribute

  1. Fork the repository
  2. Clone your fork
    git clone https://github.com/your-username/QuickExplore.git
  3. Create a feature branch
    git checkout -b feature/your-feature-name
  4. Make your changes
  5. Test thoroughly β€” make sure node app.js runs without errors
  6. Commit with a meaningful message
    git commit -m "feat: add payment gateway integration"
  7. Push to your branch
    git push origin feature/your-feature-name
  8. Open a Pull Request

Commit Message Convention

Follow the Conventional Commits format:

Prefix Purpose
feat: New feature
fix: Bug fix
docs: Documentation changes
style: Code formatting (no logic change)
refactor: Code restructuring
test: Adding or updating tests
chore: Build/tooling changes

Contribution Guidelines

  • Do NOT change existing route paths or session variable names
  • Do NOT modify database schemas without discussion
  • Do NOT remove existing features
  • Do add proper error handling with try/catch
  • Do follow the existing MVC pattern (routes β†’ controllers β†’ models)
  • Do test with node app.js before submitting
  • Do update this README if adding new routes or features

Areas Where Help is Needed

Area Description Difficulty
πŸ’³ Payment Integration Add Razorpay/Stripe for actual payments Medium
πŸ“§ Email Service Send booking confirmations via email Easy
πŸ—ΊοΈ Maps Integration Show places on Google Maps Medium
⭐ Review System Let users rate vehicles & rentals Medium
πŸ§ͺ Testing Add unit & integration tests (Jest/Mocha) Medium
πŸ“± Responsive UI Improve mobile experience Easy
πŸ”” Notifications Real-time updates with Socket.io Hard
πŸ“Š Admin Analytics Charts & stats for admin dashboard Medium
🌐 i18n Multi-language support Medium
🐳 Docker Add Dockerfile & docker-compose Easy

Reporting Issues

Found a bug? Please open an issue with:

  • Clear description of the problem
  • Steps to reproduce
  • Expected vs actual behavior
  • Screenshots (if applicable)
  • Browser / Node.js version

πŸ“œ License

This project is licensed under the MIT License β€” see the LICENSE file for details.

MIT License

Copyright (c) 2025 QuickExplore Team

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

πŸ™ Acknowledgements

  • Express.js β€” Fast, unopinionated web framework
  • MongoDB β€” NoSQL database
  • Mongoose β€” Elegant MongoDB ODM
  • EJS β€” Embedded JavaScript templating
  • Cloudinary β€” Image management platform
  • bcrypt β€” Password hashing library
  • connect-mongo β€” MongoDB session store

Made with ❀️ by the QuickExplore Team

⭐ Star this repo if you found it helpful!

About

QuickExplore is a tourism booking platform with vehicle rentals and property rentals, featuring multi-role authentication (User, Admin, Driver, Owner) and MVC architecture using Node.js, Express, and MongoDB.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors