Skip to content

Repository files navigation

Netlify Status

Maison — MERN E‑Commerce Platform

A full‑stack e‑commerce application built with MongoDB, Express, React, and Node.js, with a luxury / editorial storefront (Tailwind CSS, light & dark themes). It covers the complete commerce lifecycle — browse → cart → checkout → payment → order pipeline (place → ship → deliver → return → refund) — plus real‑time order updates, an admin workspace, transactional and scheduled email, Redis caching, and AI‑assisted product features.

🚀 Features

🛒 Customer

  • Authentication & security — JWT (httpOnly cookie) sessions, Google OAuth sign‑in, two‑factor auth (TOTP), password reset by email
  • Product discovery — catalogue with search, filters, and pagination; rich product pages with an image gallery / lightbox
  • Reviews & ratings — customer reviews plus AI‑generated review summaries (Google Gemini)
  • Wishlist — save items for later, with daily wishlist‑reminder emails
  • Cart & checkout — multi‑step checkout with a saved address book (pick a saved shipping address at checkout)
  • Orders — order history, one‑click reorder, and real‑time order status (Processing → Shipped → Delivered) over Socket.io
  • Returns & refunds — request returns and track refund status
  • Plus membership — subscription tier (Cashfree)
  • Newsletter — subscribe / unsubscribe with a weekly digest email

👨‍💼 Admin

  • Dashboard with date‑range analytics (revenue, orders, products, returns, refunds, coupons) and lightweight count stats
  • Products — create, update, delete; image uploads (PNG/JPEG/WebP) to AWS S3
  • Orders — view and advance status (emits real‑time updates), handle returns and refunds
  • Users — management and roles
  • Coupons — create codes with a discount and optional expiry
  • Admin routes are guarded so only authenticated admins can reach them

🔧 Platform & performance

  • Short, URL‑friendly 8‑character document IDs (nanoid)
  • MongoDB indexes for hot query paths (catalogue filter/sort, order history, product text search)
  • Gzip response compression
  • Redis (Upstash) caching for product and order data
  • Rate limiting — a general API limiter plus a strict limiter on auth endpoints (express-rate-limit)
  • Pooled SMTP transport (Nodemailer) so transactional email doesn’t block responses
  • Socket.io for real‑time product and order events
  • Swagger API docs at /api-docs
  • Route‑level frontend code splitting (React lazy loading)

📨 Email (EJS templates)

Account activation, order confirmation, password reset, contact, weekly newsletter, and wishlist reminder.

🛠️ Tech Stack

Backend: Node.js, Express, MongoDB + Mongoose, Socket.io, JWT, speakeasy (2FA), Nodemailer (pooled SMTP) + EJS, Cashfree (payments), Google Generative AI (Gemini), Upstash Redis, express-rate-limit, AWS S3, Swagger.

Frontend: React, Redux + redux‑thunk, React Router, Tailwind CSS, MUI, Axios, Socket.io‑client, Chart.js / Recharts, React‑Toastify.

Payments are integrated via Cashfree (order checkout and membership). Stripe client libraries also remain in the frontend from an earlier integration.

📋 Prerequisites

  • Node.js 18+ (developed on Node 22)
  • MongoDB (local or Atlas)
  • Optional: Upstash Redis (caching), AWS S3 (image storage), SMTP credentials (email), Cashfree, Google OAuth, Gemini API key

🚀 Installation

git clone https://github.com/AnantDuhan/MERN-Ecommerce.git
cd MERN-Ecommerce

# backend dependencies (root package.json)
npm install

# frontend dependencies
cd frontend && npm install && cd ..

Environment setup

Create backend/config/config.env locally. Never commit real secrets.

# Core
PORT=4000
NODE_ENV=development                               # 'production' makes the backend serve the built frontend
FRONTEND_URL=http://localhost:3000
DB_URI=mongodb://localhost:27017/e-commerce      # or DB_HOSTED_URI for Atlas
JWT_SECRET_KEY=your_jwt_secret
JWT_EXPIRES_IN=5d
COOKIE_EXPIRES=5
RESULT_PER_PAGE=8
CRON_SECRET=<random secret>                      # required to trigger the /jobs endpoints
ENABLE_IN_PROCESS_CRON=false                     # true only for a single always-on instance

# Email (pooled SMTP)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_MAIL=your-email@example.com
SMTP_PASSWORD=your-smtp-password
NEWSLETTER_UNSUBSCRIBE_URL=                       # optional; defaults to FRONTEND_URL/api/v1/unsubscribe

# Integrations (optional)
GOOGLE_CLIENT_ID=your_google_oauth_client_id
GEMINI_API_KEY=your_gemini_key
UPSTASH_REDIS_REST_URL=https://<instance>.upstash.io
UPSTASH_REDIS_REST_TOKEN=your_token
REDIS_URL=                                         # or REDIS_HOSTED_URL for a local/remote Redis
CASHFREE_APP_ID=...
CASHFREE_SECRET_KEY=...
CASHFREE_ENVIRONMENT=SANDBOX
CASHFREE_RETURN_URL=...
CASHFREE_WEBHOOK_URL=...
CASHFREE_MONTHLY_AMOUNT=...
CASHFREE_YEARLY_AMOUNT=...
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_BUCKET_NAME=your_bucket_name
AWS_BUCKET_REGION=us-east-1

Frontend (frontend/.env, optional):

REACT_APP_SOCKET_URL=http://localhost:4000        # must match the backend port for real-time features

The frontend dev server proxies API requests to http://localhost:4000, so run the backend on PORT=4000 in development. Socket.io defaults to the same URL.

🏃 Running the app

# Terminal 1 — backend (repo root)
npm run dev            # nodemon, or: npm start

# Terminal 2 — frontend
cd frontend && npm start

Client: http://localhost:3000 · API: http://localhost:4000 · health check: GET /api/v1/health.

Production build

cd frontend && npm run build && cd ..
npm start

⏱️ Background jobs

Two email jobs — weekly newsletter (backend/newsletterJob.js) and wishlist reminders (backend/wishlistJob.js, emails users with saved items).

They can run two ways:

  • Externally triggered (default, recommended for hosts that sleep idle instances). Secret‑protected endpoints run each job on demand:
    • POST /api/v1/jobs/newsletter and POST /api/v1/jobs/wishlist, both requiring an x-cron-secret: <CRON_SECRET> header.
    • .github/workflows/cron.yml calls these on a schedule (daily wishlist, weekly newsletter). Set repo secrets BACKEND_URL and CRON_SECRET. The request wakes a sleeping instance and the endpoint returns 202 immediately, running the batch in the background.
  • In‑process timers. Set ENABLE_IN_PROCESS_CRON=true to run both on a daily setInterval inside the web process — only suitable for a single always‑on instance (multiple instances would send duplicates, and a sleeping instance never fires).

Use one mechanism or the other, not both, to avoid duplicate sends.

🗃️ Maintenance scripts

Run from the repo root with a valid DB_URI (back up the database before any --apply):

node backend/scripts/createIndexes.js             # create the MongoDB indexes the app queries on
node backend/scripts/migrateIds.js                # dry run: preview re-keying documents to short IDs
node backend/scripts/migrateIds.js --apply        # perform the ID migration
node backend/scripts/repairOrderProductRefs.js    # repair order → product references
node backend/scripts/fixRefTypes.js               # (legacy) numeric→string ref type fixes; --apply to write

migrateIds.js is a dry run by default and is re‑runnable (already‑migrated documents are skipped).

📡 API overview

Base path: /api/v1.

Auth

  • POST /register (multipart, image field image) · POST /login · GET /logout
  • POST /password/forgot · PUT /password/reset/:token · GET /me
  • POST /auth/google
  • (auth endpoints are rate‑limited)

Address book

  • GET /addresses · POST /address/new · DELETE /address/:addressId

Products & reviews

  • GET /products · GET /product/:id
  • PUT /admin/update/product/:id (admin) · GET /admin/products (admin)
  • POST /review · GET /reviews · DELETE /review/:reviewId
  • POST /:id/summerize-reviews (admin — AI review summary)

Wishlist

  • GET /wishlist · POST /wishlist/:id · DELETE /wishlist/:id

Orders

  • POST /order/new · GET /orders/me · GET /order/:id
  • POST /order/:id/return · POST /order/reorder/:orderId
  • GET /admin/orders · GET /admin/returns · GET /admin/refunds (admin)

Payments, coupons & membership

  • POST /payment
  • POST /coupon (admin) · GET /coupons/all
  • Cashfree order & membership endpoints (see routes/payment.js, routes/subscription.js)

Admin analytics

  • GET /admin/analytics?range=7d|30d|90d|12m|all · GET /admin/stats

Scheduled jobs (require x-cron-secret header)

  • POST /jobs/newsletter · POST /jobs/wishlist

Docs & health

  • GET /api/v1/health · GET /api-docs (Swagger UI) · GET /api-docs.json

🖼️ Uploads & real‑time

Uploads use Multer memory storage before writing to AWS S3 (PNG/JPEG/WebP). Product pages and order pages open a Socket.io connection to the backend; product/review/summary events and order‑status changes update the UI in real time. Set REACT_APP_SOCKET_URL to the backend origin for any non‑default setup.

🐳 Docker

docker-compose up --build

Starts the app, MongoDB, and Redis. The app is exposed on host port 4001 (container 4000).

🚀 Deployment (same‑origin)

The backend serves the compiled React app, so the whole thing deploys as one service — no separate frontend host, no CORS/cross‑site‑cookie setup.

Render (Docker):

  • The Dockerfile installs backend deps, builds the frontend, and runs node backend/server.js with NODE_ENV=production (which turns on static serving of frontend/build).
  • Set the environment variables above (DB_URI, JWT_SECRET_KEY, FRONTEND_URL, SMTP, Cashfree, AWS, Upstash, CRON_SECRET, …).
  • Any REACT_APP_* the client needs are inlined at build time — pass them as Docker build args (see the ARGs in the Dockerfile). Same‑origin means REACT_APP_SOCKET_URL can be left unset (the client defaults to the current origin in production).

Scheduled jobs: add repo secrets BACKEND_URL and CRON_SECRET so .github/workflows/cron.yml can trigger the email jobs (see Background jobs). On a free tier that sleeps, this is what keeps them running.

Any Node‑friendly host works (Render, Railway, Fly.io, a VPS). On free tiers the instance may cold‑start after idle; the client’s BackendWaker masks the first‑request delay.

🤝 Contributing

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit (git commit -m 'Add AmazingFeature')
  4. Push (git push origin feature/AmazingFeature)
  5. Open a Pull Request

📄 License

Apache License 2.0 — see LICENSE.

👨‍💻 Author

Anant Duhan — GitHub @AnantDuhan · LinkedIn @AnantDuhan


⭐ If you found this project helpful, please give it a star!

About

Architected a polyglot e-commerce platform integrating a React/RTK frontend, a Node.js backend, and a Python ML microservice. The platform's core is a hybrid, real-time recommendation system using Redis and pre-computed models to provide instant, personalized suggestions. The system is built for production with Stripe, AWS S3 & robust security

Topics

Resources

Stars

12 stars

Watchers

1 watching

Forks

Used by

Contributors

Languages