
Yelp Camp
Campground Review Platform
As part of my journey in a web development course, I built YelpCamp: a project that showcases my skills in full-stack development. This application is a result of my passion for coding and learning new technologies. Built with MongoDB for database management, Express.js and Node.js for the backend, and EJS for templating, YelpCamp allows users to post, view, and review campgrounds. For user authentication, I integrated Passport.js, ensuring a secure user experience. The UI was designed with Bootstrap for a responsive layout. I've also utilized Cloudinary for image uploads, enhancing the visual appeal of campground listings.
Key Features
Campground Management
Complete CRUD operations for campgrounds with detailed information, location data, pricing, and comprehensive campground profiles.
Review System
User-generated review and rating system with star ratings, detailed comments, and review management for authentic campground feedback.
User Authentication
Secure user authentication and authorization using Passport.js with registration, login, and protected routes for user security.
Image Upload
Cloudinary integration for image upload, storage, and optimization with multiple image support and automatic image processing.
Interactive Maps
Mapbox integration for interactive campground location visualization with custom markers and location-based features.
Responsive Design
Bootstrap-powered responsive design ensuring optimal user experience across all devices and screen sizes.
Development Journey
Backend Setup
Set up the Express.js server, MongoDB database connection, and basic routing structure with RESTful API design principles.
Authentication System
Implemented user authentication with Passport.js, session management, and authorization middleware for protected routes.
CRUD Operations
Developed complete CRUD functionality for campgrounds and reviews with proper data validation and error handling.
Advanced Features
Added image upload with Cloudinary, interactive maps with Mapbox, and responsive design with Bootstrap styling.
Challenges & Solutions
Image Upload Management
Implementing efficient image upload and storage with proper file handling, validation, and cloud storage integration.
Integrated Cloudinary for cloud-based image storage with automatic optimization, multiple image support, and proper error handling for upload failures.
Authentication & Authorization
Implementing secure user authentication with proper session management and role-based access control for campground operations.
Used Passport.js for authentication with bcrypt password hashing, session-based login, and middleware for protecting routes and ensuring user authorization.
Geolocation Integration
Adding interactive maps and location-based features with accurate geocoding and responsive map visualization.
Integrated Mapbox for interactive maps with geocoding API for location conversion, custom markers, and responsive map design across devices.
// Campground model with Mongoose
export const campgroundSchema = new Schema({
title: {
type: String,
required: true
},
images: [{
url: String,
filename: String
}],
geometry: {
type: {
type: String,
enum: ['Point'],
required: true
},
coordinates: {
type: [Number],
required: true
}
},
price: Number,
description: String,
location: String,
author: {
type: Schema.Types.ObjectId,
ref: 'User'
},
reviews: [{
type: Schema.Types.ObjectId,
ref: 'Review'
}]
});
// Route for creating new campground
router.post('/', isLoggedIn, upload.array('image'), validateCampground, catchAsync(async (req, res, next) => {
export const geoData = await geocoder.forwardGeocode({
query: req.body.campground.location,
limit: 1
}).send();
export const campground = new Campground(req.body.campground);
campground.geometry = geoData.body.features[0].geometry;
campground.images = req.files.map(f => ({ url: f.path, filename: f.filename }));
campground.author = req.user._id;
await campground.save();
req.flash('success', 'Successfully made a new campground!');
res.redirect(`/campgrounds/${campground._id}`);
}));
// Authentication middleware
export const isLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
req.session.returnTo = req.originalUrl;
req.flash('error', 'You must be signed in first!');
return res.redirect('/login');
}
next();
}