This case study explores the development of an e-commerce application using the MERN stack (MongoDB, Express.js, React.js, and Node.js) while implementing the MVC (Model-View-Controller) architectural pattern. The goal is to demonstrate how the MVC pattern can be effectively utilized in a MERN-based project to create a scalable and maintainable e-commerce platform.
User Registration and Authentication:
Product Browsing and Search:
Product Details:
Shopping Cart:
Checkout and Order Placement:
Product Management:
Order Management:
User Model:
Defines user schema including username, email, password, and role.Product Model:
Defines product schema including name, price, description, category, and stock quantity.Order Model:
Defines order schema including user, order items, shipping address, payment method, and order status.
// User Model (models/User.js)
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
isAdmin: { type: Boolean, default: false }
}, {
timestamps: true
});
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
const User = mongoose.model('User', userSchema);
module.exports = User;
React Components: Structured in a way that separates concerns, with components for the homepage, product listing, product details, cart, and admin dashboard.
Redux: Used for managing application state, including user authentication status, product data, and cart contents.
// ProductList Component (components/ProductList.js)
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { listProducts } from '../actions/productActions';
import Product from './Product';
const ProductList = () => {
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { loading, error, products } = productList;
useEffect(() => {
dispatch(listProducts());
}, [dispatch]);
return (
{loading ? (
Loading...
) : error ? (
{error}
) : (
{products.map((product) => (
))}
)}
);
};
export default ProductList;
Express Routes: Define API endpoints for handling CRUD operations on products, user authentication, and order processing.
Middleware: JWT middleware for protecting routes that require authentication.
// Product Controller (controllers/productController.js)
const asyncHandler = require('express-async-handler');
const Product = require('../models/Product');
// @desc Fetch all products
// @route GET /api/products
// @access Public
const getProducts = asyncHandler(async (req, res) => {
const products = await Product.find({});
res.json(products);
});
// @desc Fetch single product
// @route GET /api/products/:id
// @access Public
const getProductById = asyncHandler(async (req, res) => {
const product = await Product.findById(req.params.id);
if (product) {
res.json(product);
} else {
res.status(404);
throw new Error('Product not found');
}
});
module.exports = {
getProducts,
getProductById,
};
This e-commerce application case study demonstrates the practical implementation of the MVC pattern using the MERN stack. By separating concerns into models, views, and controllers, the application remains modular, scalable, and maintainable. This approach allows developers to manage complex application logic while providing a responsive and dynamic user experience.