Commercial E-Commerce Platform
Decoupled front-end and REST API — full e-commerce from scratch.
Overview
Most e-commerce tutorials build monolithic apps that blur the line between presentation and business logic. This project deliberately architected two separate codebases — a React SPA and a Node.js/Express REST API backed by MySQL — to explore the real challenges of a decoupled system: CORS, JWT auth flows, schema versioning, and cart state reconciliation across guest and authenticated sessions.
The Problem
Tutorial e-commerce apps skip the hard parts: stateless auth with refresh tokens, Sequelize migration strategies for schema evolution, and the UX problem of merging a guest cart with a logged-in user's server-side cart. Building these properly requires understanding both the frontend and backend in depth simultaneously.
The Solution
Split the project into two repositories. The React SPA handles all UI state locally — cart quantities, filter state, pagination cursor — and communicates with the API via Axios with interceptors that automatically attach JWT access tokens and handle 401 refresh flows. The Node.js API uses Sequelize ORM with versioned migrations, express-validator for input validation, bcrypt for password hashing, and a dual-token auth system.
Key Features
- JWT authentication with access token + single-use refresh token rotation
- Product catalogue with full-text search, category filtering, and price sorting
- Shopping cart with localStorage persistence for guests and server sync on login
- Guest-to-user cart merge strategy on authentication
- Order placement with line-item storage and order history view
- Admin product CRUD — create, update, delete with image upload
- Sequelize ORM with migration files for reproducible schema deployments
- express-validator middleware for request body validation on all write endpoints
Challenges & Learnings
The cart merge on login was the most complex state-management problem. A guest adds items to localStorage; when they sign in, those items must reconcile with any existing server-side cart — quantities need merging, not replacing. Implemented a merge function that unions both carts by product ID, summing quantities, then persists the result to the database and clears localStorage. JWT refresh token rotation also required careful design: each refresh issues a new refresh token and invalidates the old one via a server-side revocation list, preventing token replay attacks.
Tech Stack
Frontend
Backend
Database
Auth & Security
More Projects