Skip to content

About

A full-stack travel and property listing web application built with Node.js, Express.js, MongoDB, Mongoose, and EJS. Features include authentication, authorization, CRUD operations, reviews, image uploads with Cloudinary, Joi validation, sessions, middleware, MVC architecture, and centralized error handling.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

31 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿก Wanderlust

Full-Stack Travel & Property Listing Platform

Wanderlust is a full-stack web application inspired by the core experience of platforms like Airbnb, where users can explore property listings, create their own listings, upload images, write reviews, and manage their content through an authenticated account.

This project was built as a hands-on learning project while following the web development course tutorials by Apna College. The project gave me practical experience with backend development, databases, authentication, authorization, MVC architecture, server-side rendering, image handling, validation, middleware, and full-stack application structure.

Learning Project: This repository represents my implementation and practice while following the Apna College course. The project idea and overall development flow were based on the course material.


๐ŸŒ Project Overview

Wanderlust allows users to interact with a travel/property listing platform through a complete web application.

The application provides functionality for:

  • ๐Ÿ‘ค User registration and login
  • ๐Ÿ” Authentication and authorization
  • ๐Ÿ  Creating property listings
  • โœ๏ธ Editing existing listings
  • ๐Ÿ—‘๏ธ Deleting listings
  • ๐Ÿ“ท Uploading listing images
  • โ˜๏ธ Cloud-based image storage using Cloudinary
  • โญ Creating reviews
  • ๐Ÿ—‘๏ธ Deleting reviews
  • ๐Ÿ‘‘ Listing ownership management
  • โœ… Server-side validation
  • โš ๏ธ Custom error handling
  • ๐Ÿ’ฌ Flash messages
  • ๐Ÿ”„ Session management
  • ๐Ÿ—„๏ธ MongoDB database integration
  • ๐Ÿงฉ MVC-based backend architecture
  • ๐ŸŽจ Dynamic EJS views

๐Ÿ› ๏ธ Technology Stack

Backend

Technology Purpose
Node.js JavaScript runtime
Express.js Web server and routing
MongoDB Database
Mongoose MongoDB object modeling
EJS Server-side rendering
EJS-Mate EJS layouts and reusable templates

Authentication & Sessions

Technology Purpose
Passport.js Authentication framework
Passport Local Username/password authentication
Passport Local Mongoose Authentication integration with Mongoose
Express Session Session management
Cookie Parser Cookie handling
Connect Flash Success/error messages

Validation & Error Handling

Technology Purpose
Joi Request/data validation
ExpressError Custom application errors
wrapAsync Async error handling
Middleware Authentication, authorization and validation

Image Upload & Storage

Technology Purpose
Multer Handling multipart/form-data uploads
Cloudinary Cloud-based image storage
Multer Memory Storage Processing uploaded files in memory

Frontend

Technology Purpose
EJS Dynamic HTML rendering
EJS-Mate Layouts and reusable templates
HTML/CSS User interface
JavaScript Client-side functionality

โœจ Key Features

๐Ÿ‘ค Authentication

Users can create an account, log in, and log out.

Authentication is implemented using:

  • Passport.js
  • Passport Local Strategy
  • Passport Local Mongoose
  • Express Session
  • Serialized and deserialized users

The application stores the authenticated user's identity in the session and makes the current user available throughout the application.


๐Ÿ” Authorization

Authentication and authorization are handled separately.

The application verifies that:

  • A user is logged in before performing protected actions.
  • Only the owner of a listing can edit or delete it.
  • Only the author of a review can delete it.

This introduced practical experience with resource ownership and authorization middleware.


๐Ÿ  Listing Management

Users can perform complete CRUD operations on listings.

Create

Authenticated users can create a new listing containing information such as:

  • Title
  • Description
  • Price
  • Location
  • Country
  • Image

Read

Users can:

  • View all listings
  • Open an individual listing
  • View associated reviews
  • View listing ownership information

Update

Listing owners can edit their listings.

Delete

Listing owners can delete their listings.


โญ Review System

Listings can contain multiple reviews.

A review is associated with:

  • A listing
  • An author
  • Review information

The relationship is represented using MongoDB ObjectId references.

When a listing is displayed, its reviews and review authors are populated using Mongoose.

This provided practical experience with:

  • One-to-many relationships
  • MongoDB references
  • Mongoose populate()
  • $pull
  • Related document management

๐Ÿ“ท Image Upload Pipeline

One of the important parts of this project was implementing image uploading.

The application uses Multer to receive uploaded files and Cloudinary for cloud-based image storage.

The general flow is:

User selects image
       โ†“
Multipart form submission
       โ†“
Multer
       โ†“
Memory Storage
       โ†“
Image Buffer
       โ†“
Cloudinary Upload Stream
       โ†“
Cloudinary URL + Public ID
       โ†“
MongoDB Listing Document

The listing stores the Cloudinary information as:

image
โ”œโ”€โ”€ url
โ””โ”€โ”€ filename

This helped me understand how file uploads can be separated from the application's main database storage.


๐Ÿ—„๏ธ Database Design

The application uses MongoDB with Mongoose.

The main models are:

User
  โ”‚
  โ””โ”€โ”€ owns โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Listings
                           โ”‚
                           โ””โ”€โ”€ contains โ”€โ”€โ”€โ”€โ”€โ–บ Reviews
                                                   โ”‚
                                                   โ””โ”€โ”€ written by User

Main Models

User

Handles application users and authentication information.

Listing

Stores property/travel listing information.

A listing contains references to:

  • Its owner
  • Its reviews

Review

Stores review information and references the user who created it.


๐Ÿ”— Mongoose Relationships

The project uses MongoDB references through ObjectId.

For example, a listing contains:

owner: {
    type: Schema.Types.ObjectId,
    ref: "User"
}

and reviews are represented through:

reviews: [
    {
        type: Schema.Types.ObjectId,
        ref: "Review"
    }
]

The application then uses Mongoose population to retrieve related documents.

For example:

.populate({
    path: "reviews",
    populate: {
        path: "author"
    }
})
.populate("owner")

This allowed me to work with relationships between MongoDB collections rather than keeping all information inside a single document.


๐Ÿงน Related Document Cleanup

The project also handles dependent data.

When a listing is deleted, its associated reviews are removed through a Mongoose post middleware:

listingSchema.post("findOneAndDelete", async (listing) => {
    if (listing) {
        await Review.deleteMany({
            _id: {
                $in: listing.reviews
            }
        });
    }
});

This introduced the concept of maintaining referential consistency when working with related MongoDB documents.


๐Ÿงฉ MVC Architecture

The backend follows an MVC-inspired structure.

Request
   โ”‚
   โ–ผ
Routes
   โ”‚
   โ–ผ
Middleware
   โ”‚
   โ–ผ
Controller
   โ”‚
   โ–ผ
Model
   โ”‚
   โ–ผ
MongoDB
   โ”‚
   โ–ผ
Controller
   โ”‚
   โ–ผ
EJS View
   โ”‚
   โ–ผ
Response

The application separates responsibilities into:

models/
controllers/
routes/
views/
utils/
middleware.js

This made the application easier to organize compared with putting all application logic inside a single server file.


๐Ÿ›ก๏ธ Middleware Architecture

Middleware is used extensively throughout the application.

Some of the important middleware responsibilities include:

Authentication

isloggedIn

Checks whether a user is authenticated before accessing protected resources.

Authorization

isOwner

Checks whether the currently authenticated user owns a listing.

Review Authorization

isReviewAuthor

Ensures that only the review author can delete their review.

Validation

validateListing
validateReview

Validates incoming request data using Joi.

Redirect Handling

saveRedirectUrl

Stores the original URL when an unauthenticated user tries to access a protected route, allowing the application to redirect them back after authentication.


โœ… Data Validation

The application uses Joi for server-side validation.

Validation is performed before data reaches the controller.

Request
   โ†“
Joi Validation
   โ†“
Valid โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Controller
   โ”‚
   โ””โ”€โ”€ Invalid โ”€โ”€โ”€โ–บ ExpressError

This helped me understand why validation should not depend only on frontend forms.

Server-side validation provides an additional layer of protection for incoming data.


โš ๏ธ Error Handling

The project includes custom error handling using:

ExpressError
wrapAsync
Centralized Error Middleware

The wrapAsync utility helps handle errors from asynchronous controller functions without repeatedly writing the same try/catch structure.

A custom ExpressError class is used to provide:

  • HTTP status codes
  • Meaningful error messages

The application also contains a centralized Express error-handling middleware.


๐Ÿ’ฌ Flash Messages

The project uses connect-flash to provide user feedback after operations.

Examples include:

Successfully created a new listing!
Successfully updated the listing!
Successfully deleted the listing!
Created new review!
Successfully deleted review!
You must be signed in first!

These messages are passed to EJS through res.locals.


๐Ÿ–ฅ๏ธ Server-Side Rendering with EJS

Instead of using React for the frontend, this project uses EJS (Embedded JavaScript Templates) for server-side rendering.

The views are organized into:

views/
โ”œโ”€โ”€ layouts/
โ”‚   โ””โ”€โ”€ boilerplate.ejs
โ”‚
โ”œโ”€โ”€ includes/
โ”‚   โ”œโ”€โ”€ flash.ejs
โ”‚   โ”œโ”€โ”€ footer.ejs
โ”‚   โ””โ”€โ”€ navbar.ejs
โ”‚
โ”œโ”€โ”€ listings/
โ”‚   โ”œโ”€โ”€ index.ejs
โ”‚   โ”œโ”€โ”€ show.ejs
โ”‚   โ”œโ”€โ”€ new.ejs
โ”‚   โ””โ”€โ”€ edit.ejs
โ”‚
โ”œโ”€โ”€ users/
โ”‚   โ”œโ”€โ”€ login.ejs
โ”‚   โ””โ”€โ”€ signup.ejs
โ”‚
โ””โ”€โ”€ error.ejs

Using EJS helped me understand how dynamic server-rendered applications work and how backend data can be passed directly into templates.


๐Ÿงฑ Project Structure

Wanderlust/
โ”‚
โ”œโ”€โ”€ controllers/
โ”‚   โ”œโ”€โ”€ listings.js
โ”‚   โ”œโ”€โ”€ reviews.js
โ”‚   โ””โ”€โ”€ users.js
โ”‚
โ”œโ”€โ”€ init/
โ”‚   โ”œโ”€โ”€ data.js
โ”‚   โ””โ”€โ”€ index.js
โ”‚
โ”œโ”€โ”€ models/
โ”‚   โ”œโ”€โ”€ listing.js
โ”‚   โ”œโ”€โ”€ review.js
โ”‚   โ””โ”€โ”€ user.js
โ”‚
โ”œโ”€โ”€ public/
โ”‚   โ”œโ”€โ”€ css/
โ”‚   โ”‚   โ”œโ”€โ”€ rating.css
โ”‚   โ”‚   โ””โ”€โ”€ styles.css
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ js/
โ”‚       โ””โ”€โ”€ script.js
โ”‚
โ”œโ”€โ”€ routes/
โ”‚   โ”œโ”€โ”€ listing.js
โ”‚   โ”œโ”€โ”€ review.js
โ”‚   โ””โ”€โ”€ user.js
โ”‚
โ”œโ”€โ”€ uploads/
โ”‚
โ”œโ”€โ”€ utils/
โ”‚   โ”œโ”€โ”€ ExpressError.js
โ”‚   โ””โ”€โ”€ wrapAsync.js
โ”‚
โ”œโ”€โ”€ views/
โ”‚   โ”œโ”€โ”€ includes/
โ”‚   โ”‚   โ”œโ”€โ”€ flash.ejs
โ”‚   โ”‚   โ”œโ”€โ”€ footer.ejs
โ”‚   โ”‚   โ””โ”€โ”€ navbar.ejs
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ layouts/
โ”‚   โ”‚   โ””โ”€โ”€ boilerplate.ejs
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ listings/
โ”‚   โ”‚   โ”œโ”€โ”€ edit.ejs
โ”‚   โ”‚   โ”œโ”€โ”€ index.ejs
โ”‚   โ”‚   โ”œโ”€โ”€ new.ejs
โ”‚   โ”‚   โ””โ”€โ”€ show.ejs
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ users/
โ”‚   โ”‚   โ”œโ”€โ”€ login.ejs
โ”‚   โ”‚   โ””โ”€โ”€ signup.ejs
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ error.ejs
โ”‚
โ”œโ”€โ”€ .env
โ”œโ”€โ”€ app.js
โ”œโ”€โ”€ cloudConfig.js
โ”œโ”€โ”€ middleware.js
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ package-lock.json
โ””โ”€โ”€ schema.js

๐Ÿ”„ Application Flow

A typical listing creation request follows this architecture:

Browser
   โ”‚
   โ–ผ
POST /listings
   โ”‚
   โ–ผ
Authentication Middleware
   โ”‚
   โ–ผ
Joi Validation
   โ”‚
   โ–ผ
Multer
   โ”‚
   โ–ผ
Cloudinary
   โ”‚
   โ–ผ
Listing Controller
   โ”‚
   โ–ผ
Mongoose
   โ”‚
   โ–ผ
MongoDB
   โ”‚
   โ–ผ
Flash Message
   โ”‚
   โ–ผ
Redirect
   โ”‚
   โ–ผ
Listings Page

This project therefore gave me practical exposure to how different layers of a web application communicate with one another.


๐Ÿ“š Concepts Practiced

Building this project allowed me to practice a broad range of web development concepts.

JavaScript & Node.js

  • Node.js fundamentals
  • Modules
  • Async/await
  • Promises
  • Error handling
  • Environment variables

Express.js

  • Express application setup
  • Routing
  • Route parameters
  • Middleware
  • Request/response handling
  • Static files
  • HTTP methods
  • Method override
  • Error-handling middleware

REST & CRUD

  • GET
  • POST
  • PUT
  • DELETE
  • CRUD operations
  • REST-style resource routes

MongoDB & Mongoose

  • MongoDB databases
  • Collections
  • Documents
  • Mongoose schemas
  • Mongoose models
  • ObjectId references
  • Relationships
  • Population
  • Querying
  • Updating documents
  • Deleting documents
  • $pull
  • Middleware/hooks

Authentication

  • Passport.js
  • Local Strategy
  • Passport Local Mongoose
  • Sessions
  • Serialization
  • Deserialization
  • Login/logout
  • Protected routes

Authorization

  • Ownership verification
  • Resource-level authorization
  • Review author verification
  • Authentication vs authorization

Frontend

  • HTML
  • CSS
  • JavaScript
  • EJS
  • EJS layouts
  • EJS partials
  • Dynamic rendering
  • Forms

File Handling

  • Multipart forms
  • Multer
  • Memory storage
  • Buffers
  • Cloudinary
  • Upload streams
  • Cloud-based image storage

Validation & Reliability

  • Joi validation
  • Custom errors
  • Async error handling
  • Express error middleware
  • Flash messages

๐Ÿง  What I Learned From Building It

The biggest value of this project was not simply getting a website to work.

It helped me understand how the individual parts of a full-stack application fit together.

I practiced moving from:

User Interface
      โ†“
HTTP Request
      โ†“
Route
      โ†“
Middleware
      โ†“
Controller
      โ†“
Model
      โ†“
Database
      โ†“
Response
      โ†“
Rendered View

I also gained a better understanding of why applications are separated into different layers and how authentication, authorization, validation, database relationships, file uploads, and error handling work together in a real application.


๐Ÿ” Environment Variables

Sensitive configuration should not be committed to GitHub.

The project uses environment variables through dotenv and Cloudinary configuration.

Create a .env file locally with the required configuration.

Example:

CLOUDINARY_URL=your_cloudinary_configuration

Never commit your actual credentials, API keys, passwords, or secrets to the repository.

For a public repository, a .env.example file can be added containing only placeholder values.


๐Ÿš€ Installation & Setup

1. Clone the Repository

git clone <your-repository-url>
cd Wanderlust

2. Install Dependencies

npm install

3. Configure Environment Variables

Create a .env file and add your required Cloudinary configuration.

4. Start MongoDB

Make sure MongoDB is running locally.

The development database used by the application is:

mongodb://127.0.0.1:27017/wanderlust

5. Start the Application

node app.js

The application runs on:

http://localhost:8080

๐Ÿ“ฆ Main Dependencies

Some of the major packages used in this project include:

express
mongoose
ejs
ejs-mate
passport
passport-local
passport-local-mongoose
express-session
connect-flash
multer
cloudinary
joi
method-override
dotenv
cookie-parser

๐Ÿ”ฎ Possible Future Improvements

Although the application already covers a wide range of full-stack concepts, several improvements could be added in the future:

  • ๐Ÿ”Ž Search and filtering
  • ๐Ÿ—บ๏ธ Interactive maps
  • ๐Ÿ“ Location-based search
  • โญ Improved rating system
  • ๐Ÿ“ฑ More responsive UI
  • โšก Better frontend interactions
  • ๐Ÿ–ผ๏ธ Multiple-image galleries
  • ๐Ÿ”” More advanced notifications
  • ๐Ÿงช Automated testing
  • ๐Ÿš€ Production deployment
  • ๐Ÿ”’ Additional security hardening
  • ๐Ÿ“„ Pagination
  • ๐Ÿง‘โ€๐Ÿ’ผ Improved user profile management
  • ๐Ÿ’ณ Booking/payment functionality

๐ŸŽ“ Learning Context

This project was developed during my learning journey through the Apna College web development course.

The project was built by following the course's video-based development process and implementing the concepts hands-on.

Rather than treating the project as only a final application, I used it as an opportunity to understand and practice the technologies and concepts involved in building a complete web application.

Concepts explored through this project include:

Node.js
Express.js
MongoDB
Mongoose
EJS
MVC Architecture
REST APIs / RESTful Routing
CRUD
Authentication
Authorization
Sessions
Passport.js
Middleware
Joi Validation
Error Handling
Multer
Cloudinary
Server-Side Rendering
Database Relationships

Credit: Apna College โ€” Web Development Course


๐Ÿ“Œ Important Note

This repository is not a MERN application because React is not used in this project.

The frontend of Wanderlust is implemented using EJS server-side rendering, while the backend is built with Node.js + Express.js and the database uses MongoDB/Mongoose.

I have separately studied React as part of my broader web development learning journey, but React is not part of this particular project.


๐Ÿ‘จโ€๐Ÿ’ป Author

Muhammad Ali Saagar

Computer Science Student | Data Science & AI Enthusiast | Full-Stack Development Learner

Connect With Me


โญ Final Thoughts

Wanderlust represents one of my major hands-on full-stack learning projects.

Through this project, I moved beyond individual tutorials and practiced connecting multiple technologies into one working application โ€” from authentication and routing to database relationships, validation, image uploads, cloud storage, error handling, and server-side rendering.

It provided practical experience with the architecture and development workflow involved in building a real-world web application from the ground up.

If you find the project useful or interesting, consider โญ starring the repository.

About

A full-stack travel and property listing web application built with Node.js, Express.js, MongoDB, Mongoose, and EJS. Features include authentication, authorization, CRUD operations, reviews, image uploads with Cloudinary, Joi validation, sessions, middleware, MVC architecture, and centralized error handling.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages