A full-stack e-commerce application built as a learning project, made up of a Node.js/Express REST API, a MongoDB data layer, and two separate React (Vite) front ends — one for customers and one for store admins. A parallel PostgreSQL schema is also included as a relational-database design exercise for the same domain.
ecommerce/
├── e-commerce_api/ # Node.js + Express + MongoDB REST API (the backend)
├── e-commerce_postgreSQL/ # PostgreSQL schema, views, seed data & ERD (design reference)
└── e-commerce_react-app/
├── admin-panel/ # React (Vite) dashboard for store admins
└── customer-website/ # React (Vite) storefront for customers
It's a small-scale online store platform that lets:
- Customers register/login, browse products by category and price, manage a shopping cart, save multiple shipping addresses, place orders, pay for them, and leave product reviews.
- Admins manage the product catalog (create/update/delete products & categories, including image uploads) and manage order statuses.
The backend is a stateless REST API secured with JWT authentication, using MongoDB/Mongoose as the primary datastore, Zod for request validation, Multer for image uploads, and Socket.IO wired in for real-time features (e.g. order/payment notifications).
Note on the two databases: the live API in
e-commerce_apiruns on MongoDB (seeconfig/database.js). Thee-commerce_postgreSQLfolder is a separate relational-schema exercise for the same domain (tables, views, transactions, an ERD diagram) — it isn't wired up to the running API, but it's a useful reference if you want to see the data model expressed relationally or want to port the API to Postgres later.
| Layer | Technology |
|---|---|
| Backend runtime | Node.js, Express 5 |
| Database (API) | MongoDB + Mongoose |
| Alternate schema | PostgreSQL (schema/views/seed only) |
| Auth | JSON Web Tokens (jsonwebtoken) + bcryptjs |
| Validation | Zod |
| File uploads | Multer (local /uploads folder) |
| Real-time | Socket.IO |
| Security/misc | Helmet, CORS, dotenv |
| Frontend | React 19 + Vite, React Router, Axios, Socket.IO client |
| Admin extras | react-data-table-component |
- Node.js ≥ 18 and npm
- MongoDB instance — local (
mongod) or a free MongoDB Atlas cluster - (Optional) PostgreSQL ≥ 14, only if you want to explore the relational schema in
e-commerce_postgreSQL - Postman (or any REST client) to try the API using the collection provided below
git clone https://github.com/Sayman369/ecommerce.git
cd ecommercecd e-commerce_api
npm installCreate a .env file inside e-commerce_api/ (there's no .env.example in the repo, so use this template):
PORT=5000
MONGO_URI=mongodb://127.0.0.1:27017/ecommerce
JWT_SECRET=replace_with_a_long_random_secret
JWT_EXPIRE=7dPORT— port the API listens on.MONGO_URI— your MongoDB connection string (local or Atlas).JWT_SECRET— any long random string, used to sign auth tokens.JWT_EXPIRE— token lifetime (e.g.7d,1h), passed straight tojsonwebtoken.
Also make sure an uploads/ folder exists (product/category images are stored here and served at /uploads):
mkdir -p uploadsRun it:
npm run dev # nodemon, auto-restarts on changes
# or
npm start # plain nodeThe API will start on http://localhost:5000 (or whatever PORT you set), and all routes are mounted under /api.
cd ../e-commerce_react-app/customer-website
npm install
npm run devcd ../admin-panel
npm install
npm run devBoth are Vite apps — by default they'll be served on http://localhost:5173 (Vite will bump the port automatically if it's taken, since two Vite apps can't share one). Point their API calls (via Axios, wherever the base URL is configured in src/) at your running backend, e.g. http://localhost:5000/api.
If you want to explore the relational design:
cd ../../e-commerce_postgreSQL
psql -U your_user -d your_db -f schema.sql
psql -U your_user -d your_db -f views.sql
psql -U your_user -d your_db -f seed.sqlerd.png in that folder is the entity-relationship diagram for this schema.
The API uses Bearer token auth. After registering/logging in you get a JWT — send it on every protected request:
Authorization: Bearer <your_token>
Two roles exist: customer (default) and admin. Admin-only routes are marked below. There's no separate admin-signup endpoint — the role field can be set at registration (see Auth endpoints), which is fine for local development/testing but you'd want to lock that down before shipping to production.
Base URL: http://localhost:5000/api
All responses are JSON. Endpoints marked 🔒 require a valid Bearer token, and 👑 additionally require the admin role.
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| POST | /auth/register |
– | name, email, password, phone, role? |
Create a new account. phone must match an Egyptian mobile format (01[0125]XXXXXXXX). Returns the created user + token. |
| POST | /auth/login |
– | email, password |
Log in, returns { token }. |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| GET | /profile |
🔒 | – | Get the logged-in user's profile. |
| PUT | /profile |
🔒 | name?, email?, phone? |
Update profile fields. |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| POST | /addresses |
🔒 | label (home/work), street, city, country, isDefault |
Add a shipping address. |
| GET | /addresses |
🔒 | – | List the user's saved addresses. |
| PUT | /addresses/:id |
🔒 | label, street, city, country |
Update an address. |
| DELETE | /addresses/:id |
🔒 | – | Soft-delete an address (at least one address must remain). |
| PATCH | /addresses/:id/default |
🔒 | – | Toggle an address as the default one. |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| POST | /categories |
👑 | multipart/form-data: name, description, image |
Create a category. |
| GET | /categories |
– | query: name? |
List categories (optionally filter by name). |
| GET | /categories/:id |
– | – | Get one category. |
| PUT | /categories/:id |
👑 | multipart/form-data: name, description, image? |
Update a category. |
| DELETE | /categories/:id |
👑 | – | Soft-delete a category (blocked if products still reference it). |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| POST | /products |
👑 | multipart/form-data: name, description, price, stock, category, image |
Create a product. |
| GET | /products |
– | query: category?, name?, minPrice?, maxPrice?, stock? |
List/search/filter products. |
| GET | /products/:id |
– | – | Get one product. |
| PUT | /products/:id |
👑 | multipart/form-data: same as create |
Update a product. |
| DELETE | /products/:id |
👑 | – | Soft-delete a product. |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| POST | /products/:id/reviews |
🔒 | rating (1-5), comment |
Leave a review (one per customer per product). |
| GET | /products/:id/reviews |
– | – | List reviews for a product + average rating. |
| DELETE | /products/:productId/reviews/:reviewId |
🔒 | – | Delete your own review. |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| POST | /cart/items |
🔒 | items: { product, price, quantity } |
Add an item to the cart (decrements product stock). |
| GET | /cart |
🔒 | – | View the current cart. |
| PUT | /cart/items/:id |
🔒 | quantity |
Update quantity of an item (:id = product id). |
| DELETE | /cart/items/:id |
🔒 | – | Remove one item from the cart (restocks the product). |
| DELETE | /cart |
🔒 | – | Clear/soft-delete the whole cart. |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| POST | /orders |
🔒 | shippingAddress |
Place an order from the current cart. Creates a pending Payment too. |
| GET | /orders |
🔒 | – | List your orders (admins see all orders). |
| GET | /orders/:id |
🔒 | – | Get one order. |
| PUT | /orders/:id/status |
🔒 | status (pending/confirmed/shipped/delivered/cancelled) |
Update order status. |
| DELETE | /orders/:id |
🔒 | – | Cancel an order (only if pending/confirmed) and restock items. |
| Method | Endpoint | Auth | Body | Description |
|---|---|---|---|---|
| GET | /payments/:orderId |
🔒 | – | Get the payment record for an order. |
| POST | /payments/:orderId |
🔒 | method (card/wallet/cash) |
Pay for an order — marks payment paid, order confirmed, and clears the cart. |
A ready-to-use Postman collection (ecommerce-egypt.postman_collection.json) is provided alongside this README, pre-filled with realistic Egyptian sample data (Cairo/Giza/Alexandria addresses, Egyptian mobile numbers, EGP prices, and Egyptian retail brands like Fresh appliances and Vodafone Cash-style wallet payments).
How to use it:
- Open Postman → Import → select
ecommerce.postman_collection.json. - It defines a collection variable
baseUrl(defaults tohttp://localhost:5000/api) — change it if your API runs elsewhere. - Run Auth → Register Customer and Auth → Login Customer first. The requests have a small test script that automatically saves the returned JWT into the
tokencollection variable, so every subsequent request is authenticated for you. - Run Auth → Register Admin / Login Admin the same way to populate
adminTokenfor the 👑 admin-only requests (create category/product, etc.). - IDs returned from "create" requests (category, product, address, order, review) are also auto-saved into variables (
categoryId,productId,addressId,orderId,reviewId) and reused by later requests in the collection, so you can run folders top-to-bottom without copy-pasting IDs manually.