A full-stack e-commerce platform built with the MERN stack.
It supports role-based access control, image uploads, and dynamic product management for retailers and consumers.
-
Retailer
- Upload products with images
- View and purchase other products
-
Consumer
- Browse products
- Add to cart and buy items
- JWT-based User Authentication
- Role-Based Access Control (RBAC)
- Image Uploads using Multer
- Product Listings with Dynamic Rendering
- Cart Functionality with Purchase Flow
| Area | Technology |
|---|---|
| Frontend | React.js, Nginx |
| Backend | Node.js, Express.js |
| Database | MongoDB |
| Containerization | Docker, Docker Compose |
| Registries | Docker Hub, GitHub Container Registry, GCP Artifact Registry |
This project supports multiple package managers:
- npm (
package-lock.json) - yarn (
yarn.lock) - pnpm (
lock.yaml)
1. Clone the repository
git clone "https://github.com/rutu-modha/e-commerce.git"
cd ./e-commerce2. Install dependencies
- using npm
npm install
cd frontend
npm install
cd ..
cd backend
npm installOR
- using yarn
yarn install
cd frontend
yarn install
cd ..
cd backend
yarn installOR
- using pnpm
pnpm install
cd frontend
pnpm install
cd ..
cd backend
pnpm install3. Setup a .env at root file with your own Mongo_URI and JWT_SECRET variables
4. Run both servers
cd ..
npm run startOR
cd ..
yarn run startOR
cd ..
pnpm run startThe application is containerized as three services:
- Frontend: React production build served by unprivileged Nginx
- Backend: Node.js and Express API
- Database: MongoDB with persistent storage
Compose starts MongoDB first, waits for its health check, then starts the backend and waits for the backend /health check before starting the frontend. Every service uses restart: unless-stopped, the json-file logging driver with rotation, and the ecommerce_network bridge network.
Browser
|
v
Frontend container (localhost:${FRONTEND_PORT:-3000} -> 8080)
|
v
Backend container (localhost:${BACKEND_PORT:-5000} -> 5000)
|
v
MongoDB container (localhost:${MONGO_PORT:-27017} -> 27017)
- Multi-stage Dockerfiles reduce the final image size.
- The backend runs as the non-root
nodeuser. - The frontend runs as the non-root
nginxuser. - Only production frontend files are copied to the runtime image.
- Local secrets are stored in
.envand excluded from Git.
All services communicate through the custom bridge network:
ecommerce_network
MongoDB data is stored in the named volume:
ecommerce_mongo_data
This keeps database data available when containers are stopped or recreated. docker compose down removes containers and the Compose network but preserves named volumes. Only the -v option removes the MongoDB volume.
Create a local environment file:
cp .env.example .envThe sample includes the default ports, database, frontend origin, and application image tags. Generate a secret locally:
openssl rand -hex 32Copy the generated value into JWT_SECRET in .env, replacing the placeholder. Compose intentionally has no default JWT secret and will refuse to resolve the configuration if it is missing. Do not commit the real .env file; it is ignored by Git.
The defaults can be changed in .env:
COMPOSE_PROJECT_NAME=ecommerce
FRONTEND_PORT=3000
BACKEND_PORT=5000
MONGO_PORT=27017
MONGO_DATABASE=ecommerce
FRONTEND_URL=http://localhost:3000
FRONTEND_IMAGE=abdelazez66/ecommerce-frontend:v1
BACKEND_IMAGE=abdelazez66/ecommerce-backend:v1Pull the published images and start the stack:
docker compose pull
docker compose up -dTo build the application images from the local Dockerfiles instead:
docker compose up --build -dBoth application services retain build configuration while also using the configurable FRONTEND_IMAGE and BACKEND_IMAGE tags.
- Frontend: http://localhost:3000
- Frontend health check: http://localhost:3000/health
- Backend health check: http://localhost:5000/health
- Backend products API: http://localhost:5000/products
- MongoDB:
localhost:27017
These URLs use the default ports from .env.example. An empty products response ([]) means the backend is connected successfully, but the database has no products yet.
Check the containers:
docker compose psRun the complete Compose verification, which checks configuration, container and health state, HTTP endpoints, service-name networking, and the named network and volume:
./scripts/verify-compose.shVerify rootless execution:
docker exec ecommerce-backend id
docker exec ecommerce-frontend idExpected users:
backend: uid=1000(node)
frontend: uid=101(nginx)
Verify the custom network and volume:
docker network inspect ecommerce_network
docker volume inspect ecommerce_mongo_dataVerify frontend-to-backend communication through the Compose service name:
docker compose exec -T frontend wget -qO- http://backend:5000/healthVerify backend-to-MongoDB communication through the mongo service name and the configured MONGO_URI:
docker compose exec -T backend node -e 'const mongoose = require("mongoose"); mongoose.connect(process.env.MONGO_URI).then(async () => { await mongoose.connection.db.admin().ping(); console.log("backend -> mongo: ok"); await mongoose.disconnect(); }).catch((error) => { console.error(error.message); process.exit(1); });'View logs:
docker compose logs -fRestart the services without recreating them:
docker compose restartThe following creates a small marker document in the default database, removes the containers, starts them again, and confirms the document remains in ecommerce_mongo_data:
docker compose exec -T mongo mongosh --quiet ecommerce --eval \
'db.composePersistence.updateOne({_id: "task-6"}, {$set: {value: "persists"}}, {upsert: true})'
docker compose down
docker compose up -d
docker compose exec -T mongo mongosh --quiet ecommerce --eval \
'db.composePersistence.findOne({_id: "task-6"})'Stop the containers without deleting database data:
docker compose downdocker compose down preserves named volumes, so subsequent docker compose up -d runs reuse the MongoDB data.
DATA-LOSS WARNING: The following command permanently deletes
ecommerce_mongo_dataand all MongoDB data stored in it. Use it only when you intentionally want to erase the database.
docker compose down -vabdelazez66/ecommerce-frontend:v1
abdelazez66/ecommerce-backend:v1
ghcr.io/abdelazezmohamedazez/ecommerce-frontend:v1
ghcr.io/abdelazezmohamedazez/ecommerce-backend:v1
The images were also validated using Google Cloud Artifact Registry. The temporary GCP resources were deleted after verification to avoid unnecessary costs.
Place the task screenshots in docs/images/ using these names:
docs/images/containers-running.png
docs/images/frontend-running.png
docs/images/backend-running.png
docs/images/rootless-containers.png
docs/images/docker-hub-images.png
docs/images/ghcr-images.png
docs/images/gcp-artifact-registry.png
Check service logs when a container fails:
docker compose logs --tail=100 SERVICE_NAMEExamples:
docker compose logs --tail=100 frontend
docker compose logs --tail=100 backend
docker compose logs --tail=100 mongoIf Docker cannot connect to the daemon, open Docker Desktop and wait until the Docker Engine is running.
If a port is already in use, stop the conflicting application or change the host-side port in docker-compose.yml.
- OAuth with Google
- Customer Support Page
- Static About and Contact Pages
This project is licensed under the MIT License.
If you liked this project, then please don't forget to give this repository a star. Your 1 star means a lot for me.
Hrutav Modha (modhahrutav@gmail.com)
Feel free to fork, submit PRs, or open an issue. Let's build something cool together!





