A full-stack e-commerce platform built with the MERN stack. Features product browsing, cart and wishlist management, real payment processing, and an AI-powered shopping assistant — with Redux Toolkit handling all client-side state.
Built from scratch without AI-generated code, as a demonstration of applied full-stack React development with real-world integrations: payment gateways, WebSocket-based chat, and AI function calling against a live database.
- Account registration with OTP-based email verification (
nodemailertransport andotplibfor secure TOTP generation) - JWT authentication — stateless, token-based sessions
- Product catalogue — mordern and minimalistic homepage with product cards, filterable by category
- Product detail page — full product info, ratings, and reviews on a single page
- Cart — add, update, remove items; state managed with
Redux Toolkit (RTK) - Wishlist — save products for later; state managed with Redux Toolkit (RTK)
- Orders — placed orders tracked in a dedicated orders section
- Razorpay payment — real payment flow using a
Razorpayaccount; full checkout-to-confirmation cycle - AI Shopping Assistant — real-time chatbot powered by
WebSocketand theGemini APIwith function calling, capable of reading live product and order data from the database to answer user queries conversationally - Fallback page for unmatched routes
- Login with role-based access (
JWT+ role claim) - View all listed products
- Add new products
- View all registered users
- Restrict user accounts
- Terminate (delete) user accounts (UI in place; full implementation in progress)
| Layer | Technology |
|---|---|
| Runtime | Node.js |
| Framework | Express.js |
| Database | MongoDB + Mongoose (ODM) |
| Frontend | React 19 |
| State Management | Redux Toolkit (RTK) |
| Styling | TailwindCSS + DaisyUI |
| Icons | Lucide React, Font Awesome |
| Auth | JWT |
| Payment | Razorpay |
| AI Chatbot | Gemini API |
| Real-time | WebSocket |
| Email / OTP | Nodemailer, otplib |
Client and server live in a single repository — not a monorepo with separate package manifests, but a structured split within one repo. The React frontend is a standard CRA/Vite build that communicates with the Express API over HTTP and WebSocket.
├── client/
│ ├── public/ #Static assets served as-is (favicon, images not processed by Vite)
│ ├── src/
│ │ ├── components/ # Reusable UI components
│ │ ├── features/ # Redux slices — cart, wishlist, auth state
│ │ ├── config/ # Client-side config files — currently holds WebSocket connection config
│ │ ├── hooks/ # Custom React hooks
│ │ ├── pages/ # Page-level components mapped to routes
│ │ ├── styles/ # Global styles and Tailwind base customisations
│ │ ├── utils/ # Utility/helper functions
│ │ ├── app.jsx # Root component — router setup and layout wrappers
│ │ ├── main.jsx # Entry point — mounts React app and Redux Provider to the DOM
│ │ └── store.js # Redux store — registers all slices
│ ├── index.html # Vite HTML entry point
│ ├── .gitignore # Files to ignore from Git
│ ├── tailwind.config.js # Tailwind and DaisyUI plugin configuration
│ ├── vite.config.js
│ ├── package.json
│ └── package-lock.json
│
└── server/
├── config/ # DB connection and environment-level configuration
├── controllers/ # Core logic for admin, auth, cart, payments, chatbot etc.
├── middleware/ # Middleware functions used across the API
├── models/ # Mongoose schemas — User, Product, Order, Review etc.
├── routes/ # Express routers — maps endpoints to controllers
├── scripts/ # DB seed scripts and utility scripts for development/testing
├── socket/ # WebSocket server setup and Gemini function calling handler
├── app.js # Server entry point
├── .gitignore # Files to ignore from Git
├── package-lock.json
└── package.json
- Node.js v18+
- MongoDB (local or Atlas)
- Razorpay account (test mode keys)
- Google Gemini API key
- SMTP email account for OTP delivery
git clone https://github.com/abythomas/shoppr.git
cd shoppr
# Install server dependencies
cd server && npm install
# Install client dependencies
cd ../client && npm installServer — server/.env
PORT = 3000
MONGO_URI = connection_string
SESSION_KEY = session_secret_key
SMTP_HOST = smtp.provider_name.com
SMTP_PORT = port_number
SMTP_USERNAME = username
SMTP_KEY = smtp_key
JWT_SECRET_KEY = jwt_secret_key
RZR_PAY_KEY = razorpay_key
RZR_PAY_SECRET_KEY = razorpay_secret_key
GEMINI_API_KEY = gemini_api_key
Client — client/.env
VITE_RZR_PAY_KEY = razorpay_key
VITE_RZR_PAY_SECRET_KEY = razorpay_secret_keycd server && npm run dev
cd client && npm run devClient: http://localhost:5173
API: http://localhost:5000
All endpoints are prefixed with the base URL (e.g. http://localhost:5000). Protected routes require a valid JWT passed as a Bearer token in the Authorization header.
| Method | Path | Description |
|---|---|---|
POST |
/auth/signup |
Register a new user account |
POST |
/auth/login |
Authenticate user, returns JWT |
POST |
/auth/verify-otp |
Verify OTP to activate account |
GET |
/auth/verify-access |
Validate current JWT, returns user info |
| Method | Path | Description |
|---|---|---|
GET |
/product |
Get all products |
GET |
/product/:id |
Get a single product by ID |
GET |
/product/category/:name |
Get all products under a category |
| Method | Path | Description |
|---|---|---|
GET |
/category |
Get all product categories |
| Method | Path | Description |
|---|---|---|
GET |
/cart |
🔒 Get the current user's cart |
POST |
/cart/add-to-cart/:productId |
🔒 Add a product to cart |
| Method | Path | Description |
|---|---|---|
GET |
/wishlist |
Get the current user's wishlist |
POST |
/wishlist/add-to-wishlist |
Add a product to wishlist |
| Method | Path | Description |
|---|---|---|
POST |
/orders |
Get orders for a user |
POST |
/orders/create-order |
Create a new order |
| Method | Path | Description |
|---|---|---|
POST |
/payments/verify-payment |
Verify Razorpay payment signature after checkout |
GET |
/payments/payment-success |
Payment success confirmation page |
| Method | Path | Description |
|---|---|---|
GET |
/admin/all-products |
Get all listed products |
POST |
/admin/add-product |
Add a new product |
GET |
/admin/all-users |
Get all registered users |
POST |
/admin/add-user |
Manually add a user |
GET |
/admin/status |
Get platform summary stats |
Razorpay Payment Flow
The server creates a Razorpay order via their Node SDK and returns the order_id to the client. The client opens the Razorpay checkout modal using the order details. On success, the client sends the razorpay_payment_id, razorpay_order_id, and razorpay_signature back to the server, which verifies the HMAC signature before marking the order as paid — no payment is trusted without server-side signature verification.
AI Chatbot — Gemini Function Calling
The chatbot is not a simple prompt-response loop. The Gemini API is configured with a set of declared functions (e.g. getProductsByCategory, getOrderStatus) that map to real database queries. When a user asks something like "do you have running shoes under ₹2000?" or "where is my last order?", Gemini decides which function to call, the server executes the DB query, returns the result to Gemini, and Gemini composes a natural-language response — all over a persistent WebSocket connection for low-latency chat feel.
Redux Toolkit State Architecture Cart, wishlist, orders and authenticated user details are all managed as RTK slices handled by a single redux store
OTP Verification Identical flow to the blog app — OTP generated on signup, sent via Nodemailer, verified before account activation. Accounts cannot authenticate until verified.
Functional and complete (admin account termination UI is in place but the backend handler is pending). Not yet deployed — deployment is in progress.
See something you can improve? Submit a PR or raise an issue.