WanderLust is a full-stack travel listing web app where users can create, browse, filter, and search travel listings, upload photos, and leave reviews. I built this project to practice RESTful routing, authentication, database relationships, server-side validation, file uploads, and map/geocoding features.
Link to actual site:- https://wanderlust-vukx.onrender.com/listings
- Full CRUD for travel listings (create, view, edit, delete)
- Upload listing images using Multer + Cloudinary storage
- Each listing stores:
owner(User reference)category(enum)geometry(GeoJSON Point for mapping)
- Add and delete reviews on listings
- Reviews store an
author(User reference) and are populated when viewing a listing - Cascade delete: when a listing is deleted, its reviews are deleted too
- Category pages like
/listings/category/Arctic(and others) - Search route
/listings/search?q=...that filters listings by title/location/country/category
- Signup/login/logout using Passport (local strategy)
- Flash messages for success/error feedback
- Route protection (must be logged in to create listings/reviews)
- Ownership checks:
- Only the listing owner can edit/delete the listing
- Only the review author can delete their review
- Uses Mapbox Geocoding to create a GeoJSON
geometrypoint from the listing location when creating a listing - Mapbox token is passed to EJS views via
res.locals
Backend
- Node.js, Express
- MongoDB + Mongoose
- Passport + express-session (auth + sessions)
- Joi (server-side validation)
Frontend
- EJS templating + ejs-mate layouts
- Bootstrap + custom CSS
Uploads / Maps
- Multer + Cloudinary storage
- Mapbox SDK (Geocoding)
app.js– Express setup, sessions, Passport, flash, routers, error handlingmodels/– Mongoose models (Listing, Review, User)routes/– Listing, Review, and User routescontrollers/– Route handlers (listings, reviews, users)middleware.js– auth guards + validation + ownership checksschema.js– Joi validation schemascloudConfig.js– Cloudinary + Multer storage configviews/– EJS pages & partials
Create a .env file in the project root and add:
MAP_TOKEN=your_mapbox_token
CLOUD_NAME=your_cloudinary_cloud_name
CLOUD_API_KEY=your_cloudinary_api_key
CLOUD_API_SECRET=your_cloudinary_api_secret
## Author
**Bhushan Sah**
Berea College
Computer Science and Mathematics