ZyCart: MERN Stack E-Commerce Project
ZyCart: MERN Stack E-Commerce Project
A Project Report
Submitted by
A Project Report
Submitted by
A Project Report
Submitted by
A Project Report
Submitted by
Zycart is a multi-vendor e-commerce web application built using the MERN stack—MongoDB, [Link],
React, and [Link].
The platform allows users to browse products, add items to the cart, place orders, and track their
deliveries.
Zycart uses secure login, role-based access, and real-time data handling through REST APIs.
The frontend is built with React and Tailwind CSS, providing a fast, responsive, and user-friendly interface.
Overall, the system demonstrates how a modern e-commerce platform works using full-stack
development concepts such as API integration, authentication, dynamic rendering, and modular
architecture.
It is designed to be scalable, easy to extend, and suitable for real-world use cases as well as academic
learning.
INTRODUCTION
E-commerce platforms have become an important part of today’s digital world. People now prefer buying
products online because it is fast, easy, and comfortable. To support this trend, businesses need secure,
user-friendly, and well-designed online shopping systems.
Zycart is a fully functional e-commerce application built using the MERN stack (MongoDB, Express,
React, [Link]). The aim of Zycart is to provide an online store where customers can explore products,
add items to their cart, purchase them, and track the status of their orders. The system is designed to be
simple for users but powerful in features.
The platform includes three types of users:
1. Customers – can browse products, manage their cart, place orders, and see order updates.
2. Suppliers – can upload, edit, and manage their own products, and view orders only for items they
supplied.
3. Administrators – have complete control over the system, including managing users, suppliers,
products, and orders.
Zycart uses a clean and organized folder structure, modern UI with Tailwind CSS, and reusable
components to ensure smooth performance and easy maintainability. The project demonstrates key
concepts of full-stack web development such as:
• React routing and component structure
• API requests and server responses
• Authentication using JWT
• Database modeling with MongoDB
• State management with React hooks
• Role-based access control
• Clean and responsive UI design
Overall, Zycart is a complete learning project that shows how a real e-commerce system works from end
to end.
PROJECT OBJECTIVE
1. Develop a secure and scalable full-stack e-commerce platform using the MERN (MongoDB,
[Link], [Link], [Link]) stack.
2. Implement role-based authentication with three roles — User, Supplier, and Admin — each having
separate permissions and functionalities.
3. Allow users to browse products, view details, manage cart items, and place orders smoothly.
4. Provide dedicated dashboards for Users (My Orders), Suppliers (Product Management & Order
Items), and Admins (Product, User & Order Management).
5. Enable supplier-specific control over products and order items, including updating each item’s
delivery status (Packed, Shipped, Delivered, etc.).
6. Create a fully responsive and modern UI using Tailwind CSS, React Hooks, and reusable
components.
7. Build a modular and maintainable backend with clean RESTful APIs built on [Link] & [Link].
8. Support product search, filtering, and sorting for a better shopping experience.
9. Ensure data persistence and reliability using MongoDB with well-designed Mongoose schemas.
10. Implement essential e-commerce features, such as wishlist, reviews, Q&A, and address
management.
FEATURES
➢ User Features
• User registration & login
• Browse all products
• Product details page
• Add to cart / decrease / remove / clear cart
• Secure checkout
• My Orders page
• Item-level delivery status tracking
➢ Supplier Features
• Supplier registration & login
• Add, edit and delete their own products
• View orders that include their own products
• Update status of individual order items (Packed, Shipped, Delivered, etc.)
➢ Admin Features
• Manage all products
• Manage all orders
• Update order statuses
• Manage users & suppliers
• View system analytics (optional future feature)
➢ System Features
• JWT authentication
• Protected Routes
• Clean UI with Tailwind CSS
• LocalStorage-based cart persistence
• Responsive layout
• Real-time updates without page reloads
KEY PRINCIPLES USED
1. Component-Based UI
React splits UI into reusable components for modularity.
3. Role-Based Security
Protect middleware ensures only authorized users access sensitive routes.
6. Responsive Design
Tailwind CSS ensures layouts adapt to all screen sizes.
7. Code Reusability
Shared components (Navbar, Buttons, Modals) reduce duplication.
8. Separation of Concerns
Backend handles logic & APIs, frontend handles UI/UX separately.
1. Requirement Analysis
2. System Design
• ERD for User → Product → Order
3. Frontend Development
• Tailwind configuration
4. Backend Development
• JWT authentication
5. Integration
• Check UI flow
server/
│ │ └── [Link]
├── [Link] │
├── [Link] ├── models/
├── .env │ ├── [Link]
│ │ ├── [Link]
├── config/ │ ├── [Link]
│ ├── [Link] │ ├── [Link]
│ └── [Link] │
│ ├── routes/
├── controllers/ │ ├── [Link]
│ ├── [Link] │ ├── [Link]
│ ├── [Link] │ ├── [Link]
│ ├── [Link] │ ├── [Link]
│ ├── [Link] │ ├── [Link]
│ ├── [Link] │ ├── [Link]
│ ├── [Link] │ └── [Link]
│ └── [Link] │
│ └── utils/
├── middleware/ └── [Link]
│ ├── [Link]
client/ │ │ │
│ │ │ ├── admin/
├── public/ │ │ │ ├── [Link]
│ └── [Link] │ │ │ ├── [Link]
│ │ │ │ ├── [Link]
├── src/ │ │ │ └── [Link]
│ ├── assets/ │ │ │
│ │ └── logo_cart.svg │ │ ├── supplier/
│ │ │ │ ├── [Link]
│ ├── components/ │ │ ├── [Link]
│ │ ├── [Link] │ │ ├── [Link]
│ │ ├── [Link] │ │ └── [Link]
│ │ ├── [Link] │ │
│ │ ├── [Link] │ ├── routes/
│ │ ├── [Link] │ │ └── [Link]
│ │ └── [Link] │ │
│ │ │ ├── utils/
│ ├── context/ │ │ └── [Link]
│ │ ├── [Link] │ │
│ │ └── [Link] │ ├── [Link]
│ │ │ ├── [Link]
│ ├── pages/ │ ├── [Link]
│ │ ├── [Link] │ └── [Link]
│ │ ├── [Link] │
│ │ ├── [Link] ├── [Link]
│ │ ├── [Link] ├── [Link]
│ │ ├── [Link] └── [Link]
│ │ ├── [Link]
│ │ ├── [Link]
│ │ ├── [Link]
[Link]
import React from "react"; {/* User Protected Routes */} <SupplierProducts />
import { Routes, Route } from "react-router-dom"; <Route path="/cart" </ProtectedRoute>
element={ }
import Navbar from "./components/[Link]"; <ProtectedRoute roles={["user"]}> />
import Footer from "./components/[Link]"; <CartPage />
</ProtectedRoute> <Route
// User Pages } path="/supplier/orders"
import Home from "./pages/[Link]"; /> element={
import ProductDetails from <Route <ProtectedRoute roles={["supplier"]}>
"./pages/[Link]"; path="/checkout" <SupplierOrders />
import CartPage from "./pages/[Link]"; element={ </ProtectedRoute>
import CheckoutPage from <ProtectedRoute roles={["user"]}> }
"./pages/[Link]"; <CheckoutPage /> />
import UserOrders from "./pages/[Link]"; </ProtectedRoute>
import UserProfile from "./pages/[Link]"; } {/* Admin Routes */}
import Login from "./pages/[Link]"; /> <Route
import Register from "./pages/[Link]"; path="/admin/dashboard"
<Route element={
// Supplier Pages path="/my-orders" <ProtectedRoute roles={["admin"]}>
import SupplierDashboard from element={ <AdminDashboard />
"./pages/supplier/[Link]"; <ProtectedRoute roles={["user"]}> </ProtectedRoute>
import SupplierProducts from <UserOrders /> }
"./pages/supplier/[Link]"; </ProtectedRoute> />
import SupplierOrders from }
"./pages/supplier/[Link]"; /> <Route
import SupplierApply from path="/admin/users"
"./pages/supplier/[Link]"; <Route element={
path="/profile" <ProtectedRoute roles={["admin"]}>
// Admin Pages element={ <AdminUsers />
import AdminDashboard from <ProtectedRoute roles={["user"]}> </ProtectedRoute>
"./pages/admin/[Link]"; <UserProfile /> }
import AdminUsers from </ProtectedRoute> />
"./pages/admin/[Link]"; }
import AdminSuppliers from /> <Route
"./pages/admin/[Link]"; path="/admin/suppliers"
import AdminOrders from {/* Supplier Apply (only logged-in users with element={
"./pages/admin/[Link]"; role 'user') */} <ProtectedRoute roles={["admin"]}>
<Route <AdminSuppliers />
// Route Guards path="/supplier/apply" </ProtectedRoute>
import ProtectedRoute from element={ }
"./routes/[Link]"; <ProtectedRoute roles={["user"]}> />
<SupplierApply />
const App = () => { </ProtectedRoute> <Route
return ( } path="/admin/orders"
<div className="min-h-screen flex flex-col bg- /> element={
gray-100"> <ProtectedRoute roles={["admin"]}>
<Navbar /> {/* Supplier Routes */} <AdminOrders />
<Route </ProtectedRoute>
<main className="grow container-main"> path="/supplier/dashboard" }
<Routes> element={ />
<ProtectedRoute roles={["supplier"]}>
{/* Public Routes */} <SupplierDashboard /> </Routes>
<Route path="/" element={<Home />} /> </ProtectedRoute> </main>
<Route path="/product/:id" }
element={<ProductDetails />} /> /> <Footer />
<Route path="/login" element={<Login />} </div>
/> <Route );
<Route path="/register" element={<Register path="/supplier/products" };
/>} /> element={
<ProtectedRoute roles={["supplier"]}> export default App;
[Link]
import React, { useEffect, useState } from if (!otp || ![Link] || ![Link] || </div>
"react"; ![Link]) {
import axios from "../utils/[Link]"; return [Link]("Please fill all fields"); <[Link]
import { useNavigate, Link } from "react- } whileTap={{ scale: 0.95 }}
router-dom"; type="submit"
import { toast } from "react-hot-toast"; setLoading(true); disabled={loading}
import { motion, AnimatePresence } from className="
"framer-motion"; try { w-full py-3 rounded-xl text-lg font-
const res = await semibold text-white
const Register = () => { [Link]("/auth/verify-otp", { bg-linear-to-r from-[#6A8EF0] to-
const navigate = useNavigate(); email, [#3F51F4]
otp, hover:opacity-90 transition shadow-
const [step, setStep] = useState(1); ...form, md
const [loading, setLoading] = }); "
useState(false); >
if ([Link]) { {loading ? "Sending OTP..." : "Send
const [email, setEmail] = useState(""); [Link]("Registration OTP"}
const [otp, setOtp] = useState(""); successful!"); </[Link]>
navigate("/login"); </[Link]>
const [form, setForm] = useState({ } );
name: "", } catch (error) {
mobile: "", // ------------------------------
password: "", [Link]([Link]?.data?.message // Step 2 UI (OTP + Details)
}); || "OTP verification failed"); // ------------------------------
} finally { const Step2 = (
// ------------------------------ setLoading(false); <[Link]
// Send OTP } key="step2"
// ------------------------------ }; initial={{ opacity: 0, y: 30 }}
const handleSendOtp = async (e) => { animate={{ opacity: 1, y: 0 }}
[Link](); // ------------------------------ exit={{ opacity: 0, y: -30 }}
// Step 1 UI (Email) onSubmit={handleVerifyOtp}
if (!email) return [Link]("Email is // ------------------------------ className="space-y-5"
required!"); const Step1 = ( >
<[Link] <div>
setLoading(true); key="step1" <label className="font-medium text-
initial={{ opacity: 0, y: 30 }} [#1B2A41]">OTP</label>
try { animate={{ opacity: 1, y: 0 }} <input
const res = await exit={{ opacity: 0, y: -30 }} type="text"
[Link]("/auth/send-otp", { email }); onSubmit={handleSendOtp} className="
className="space-y-5" w-full mt-2 px-4 py-3 rounded-xl
if ([Link]) { > border border-[#8FD6F6]/40 bg-
[Link]("OTP sent to your <div> [#F7FBFF]
email!"); <label className="font-medium text- text-[#1B2A41] placeholder-gray-
setStep(2); [#1B2A41]">Email</label> 400
} <input focus:outline-none focus:ring-2
} catch (error) { type="email" focus:ring-[#6A8EF0]
className=" transition
[Link]([Link]?.data?.message w-full mt-2 px-4 py-3 rounded-xl "
|| "Failed to send OTP"); border border-[#8FD6F6]/40 bg- value={otp}
} finally { [#F7FBFF] onChange={(e) =>
setLoading(false); text-[#1B2A41] placeholder-gray- setOtp([Link])}
} 400 required
}; focus:outline-none focus:ring-2 />
focus:ring-[#6A8EF0] </div>
// ------------------------------ transition
// Verify OTP + Register " <div>
// ------------------------------ value={email} <label className="font-medium text-
const handleVerifyOtp = async (e) => { onChange={(e) => [#1B2A41]">Full Name</label>
[Link](); setEmail([Link])} <input
required type="text"
/> className="
w-full mt-2 px-4 py-3 rounded-xl border border-[#8FD6F6]/40 bg- py-12
border border-[#8FD6F6]/40 bg- [#F7FBFF] "
[#F7FBFF] text-[#1B2A41] placeholder-gray- >
text-[#1B2A41] placeholder-gray- 400
400 focus:outline-none focus:ring-2 <div
focus:outline-none focus:ring-2 focus:ring-[#6A8EF0] className="
focus:ring-[#6A8EF0] transition w-full max-w-md p-10 bg-white
transition " rounded-2xl shadow-xl
" value={[Link]} border border-[#8FD6F6]/40
value={[Link]} onChange={(e) => setForm({ ...form, "
onChange={(e) => setForm({ ...form, password: [Link] })} >
name: [Link] })} required <h1
required /> className="
/> </div> text-3xl font-extrabold text-center
</div> mb-6
<[Link] text-[#1B2A41]
<div> whileTap={{ scale: 0.95 }} "
<label className="font-medium text- type="submit" >
[#1B2A41]">Mobile Number</label> disabled={loading} Register
<input className=" </h1>
type="text" w-full py-3 rounded-xl text-lg font-
className=" semibold text-white <AnimatePresence mode="wait">
w-full mt-2 px-4 py-3 rounded-xl bg-linear-to-r from-[#6A8EF0] to- {step === 1 ? Step1 : Step2}
border border-[#8FD6F6]/40 bg- [#3F51F4] </AnimatePresence>
[#F7FBFF] hover:opacity-90 transition shadow-
text-[#1B2A41] placeholder-gray- md <p className="text-center mt-6 text-
400 " gray-600">
focus:outline-none focus:ring-2 > Already have an account?{" "}
focus:ring-[#6A8EF0] {loading ? "Verifying..." : "Register"} <Link
transition </[Link]> to="/login"
" </[Link]> className="font-semibold text-
value={[Link]} ); [#3F51F4] hover:underline"
onChange={(e) => setForm({ ...form, >
mobile: [Link] })} useEffect(() => { Login
required [Link] = "Register | ZyCart"; </Link>
/> }, []); </p>
</div> </div>
return (
<div> <div </div>
<label className="font-medium text- className=" );
[#1B2A41]">Password</label> min-h-screen flex items-center max-w- };
<input screen-2xl container mx-auto px-14 justify-
type="password" center export default Register;
className=" bg-linear-to-br from-[#C3F2EC] via-
w-full mt-2 px-4 py-3 rounded-xl [#8FD6F6] to-[#3F51F4]
[Link]
import React, { createContext, useContext, [Link]("user", delete
useEffect, useState } from "react"; [Link](user)); [Link]["Authorizati
import axios from "../utils/[Link]"; }; on"];
}
const AuthContext = createContext(); // ------------------------------------------------------ }, [token]);
// Logout user
export const AuthProvider = ({ children }) => // ------------------------------------------------------ const value = {
{ const logout = () => { user,
const [token, setToken] = useState(() => setToken(null); token,
[Link]("token")); setUser(null); login,
const [user, setUser] = useState(() => { logout,
const u = [Link]("user"); [Link]("token"); isAuthenticated: !!token,
return u ? [Link](u) : null; [Link]("user"); };
}); [Link]("cart")
}; return <[Link]
// ------------------------------------------------------ value={value}>{children}</[Link]
// Save login data // ------------------------------------------------------ ider>;
// ------------------------------------------------------ // Attach token to axios headers };
const login = (data) => { // ------------------------------------------------------
const { token, user } = data; useEffect(() => { export const useAuth = () =>
if (token) { useContext(AuthContext);
setToken(token);
setUser(user); [Link]["Authorizati
on"] = `Bearer ${token}`;
[Link]("token", token); } else {
[Link]
import mongoose from "mongoose"; [Link](` MongoDB Connected: ${[Link]}`);
} catch (error) {
const connectDB = async () => { [Link](" MongoDB connection failed:", [Link]);
try { [Link](1);
const conn = await [Link]([Link].MONGO_URI, { }
useNewUrlParser: true, };
useUnifiedTopology: true,
}); export default connectDB;
[Link]
import jwt from "jsonwebtoken"; message: "Not authorized. Token next();
import User from "../models/[Link]"; missing.", } catch (error) {
}); return [Link](401).json({
// -------------------------------------------------------- success: false,
-- // Verify token message: "Not authorized. Invalid or
// AUTHENTICATE USER USING JWT const decoded = [Link](token, expired token.",
// -------------------------------------------------------- [Link].JWT_SECRET); });
-- }
export const protect = async (req, res, next) // Fetch user };
=> { const user = await
try { [Link]([Link]); // --------------------------------------------------------
let token; --
if (!user) // ROLE-BASED PROTECTION
// Token via Authorization header: return [Link](401).json({ // --------------------------------------------------------
"Bearer token" success: false, --
if ( message: "User does not exist.", export const authorize = (...roles) => {
[Link] && }); return (req, res, next) => {
[Link]("B if ()
earer") // Check ban status return [Link](403).json({
){ if ([Link]) { success: false,
token = [Link](" return [Link](403).json({ message: "Forbidden. You do not
")[1]; success: false, have permission.",
} message: "Your account is banned. });
Contact support.",
if (!token) }); next();
return [Link](401).json({ } };
success: false, };
[Link] = user;
Zycart successfully demonstrates a complete multi-role e-commerce platform built with modern
MERN technologies.
The system includes strong authentication, secure database interactions, smooth UI, and
advanced features like supplier-specific product and order handling.
The project reflects industrial-level engineering practices and the practical implementation of
full-stack development concepts.
Moreover, Zycart showcases scalable architecture with modular components, reusable hooks,
protected routing, and optimized state management.
The integration of admin and supplier dashboards highlights real-world workflow separation
and role-based access control.
With features like product reviews, Q&A, address management, analytics, and responsive
design, the platform delivers a professional and user-friendly experience.
FUTURE EXTENSION