A complete e-commerce web application built using the MERN-like stack (MySQL instead of MongoDB) with separate frontend and backend services, designed for free-tier deployment. Features include product browsing, searching, shopping cart, user authentication, role-based access, basic admin dashboard functionalities, and Stripe payment integration (Test Mode).
π View Live Demo π
(Note: Backend might take ~30s to wake up on the first visit due to Railway's free tier sleeping policy.)
| Page | Screenshot |
|---|---|
| Homepage | ![]() |
| Product Listing | ![]() |
| Product Detail | ![]() |
| Search Results | ![]() |
| Shopping Cart | ![]() |
| Login Page | ![]() |
| Register Page | ![]() |
| User Profile | ![]() |
| Checkout Page | ![]() |
- Frontend (Next.js):
- Server-Side Rendering (SSR) for product listing and details.
- Responsive design for Desktop, Tablet, and Mobile.
- Modern UI built with Tailwind CSS.
- Client-side state management with Zustand.
- Form handling with React Hook Form.
- Backend (Node.js/Express):
- RESTful API endpoints for managing resources.
- MySQL database interaction using
mysql2.
- Core E-commerce:
- Product listing and detailed view pages.
- Product search functionality (by name/description).
- Shopping cart functionality (add, update quantity, remove, clear).
- Basic checkout flow structure.
- Authentication & Authorization:
- User registration and login.
- JWT (JSON Web Token) based authentication.
- Password hashing using
bcrypt. - Role-based access control (user vs. admin).
- Protected routes for authenticated users and admins (
withAuth,withAdminAuthHOCs).
- Admin Panel (Basic):
- Dashboard overview (placeholder stats).
- View all users, orders (basic list).
- Manage products (Add, Edit, Delete - requires UI implementation).
- Admin-only API endpoints protected.
- Payments:
- Stripe Payment Intents integration (Test Mode).
- Secure payment form using Stripe Elements (
PaymentElement). - Backend endpoint to create Payment Intents.
- Order confirmation page displaying payment status.
- Basic Stripe Webhook endpoint structure for verifying payments.
- Frontend:
- Next.js (v15+) - React Framework (Pages Router)
- React (v19+) - UI Library
- Tailwind CSS (v4+) - Utility-First CSS Framework
- Zustand - State Management
- Axios - HTTP Client
- React Hook Form - Form Validation
- @stripe/react-stripe-js & @stripe/stripe-js - Stripe Frontend Libraries
- @heroicons/react - Icons
- Backend:
- Node.js - JavaScript Runtime
- Express.js - Web Framework
- mysql2 - MySQL Client
- jsonwebtoken - JWT Implementation
- bcrypt - Password Hashing
- cors - Cross-Origin Resource Sharing Middleware
- dotenv - Environment Variable Loading
- stripe - Stripe Node.js Library
- Database:
- Deployment:
Follow these instructions to get a copy of the project up and running on your local machine for development and testing purposes.
- Node.js (LTS version recommended, e.g., v18+)
- npm (usually comes with Node.js) or yarn
- Git
- A Railway account (for hosting the database during local development - free tier available)
- A Stripe account (for payment testing - free test mode available)
-
Clone the repository:
git clone https://github.com/Garbii1/ecommerce-platform.git cd ecommerce-platform -
Backend Setup:
- Navigate to the backend directory:
cd backend - Install dependencies:
npm install
- Create a Railway MySQL database service in your Railway project dashboard.
- Create a
.envfile in thebackenddirectory and add the following environment variables (get values from Railway, Stripe, and generate your own JWT secret):# Get from Railway MySQL service -> Variables tab (use the PUBLIC host/port for local dev) DATABASE_URL=mysql://USER:PASSWORD@PUBLIC_HOST:PORT/DATABASE_NAME # Generate a strong random string (e.g., using Node crypto or openssl rand -hex 32) JWT_SECRET=YOUR_REALLY_STRONG_JWT_SECRET_KEY # Optional: JWT Expiration (defaults can be set in code) JWT_EXPIRES_IN=1d # Your LOCAL frontend URL for CORS FRONTEND_URL=http://localhost:3000 # Get from Stripe Dashboard (Test Mode -> Developers -> API Keys) STRIPE_SECRET_KEY=sk_test_YOUR_STRIPE_SECRET_KEY # Get from running `stripe listen --forward-to ...` locally (see Stripe Setup) STRIPE_WEBHOOK_SECRET=whsec_YOUR_LOCAL_STRIPE_CLI_WEBHOOK_SECRET
- Set up the database tables: Connect to your Railway database using an SQL client (like TablePlus, DBeaver) and run the SQL
CREATE TABLEstatements found earlier in the project setup guide (or in a dedicatedschema.sqlfile if you create one). - Start the backend development server:
The backend should be running on
npm run dev
http://localhost:5001(or the port specified in.env).
- Navigate to the backend directory:
-
Frontend Setup:
- Open a new terminal and navigate to the frontend directory:
(If you are inside the
cd frontendbackenddirectory, usecd ../frontend) - Install dependencies:
npm install
- Create a
.env.localfile in thefrontenddirectory and add the following environment variables:# Your LOCAL backend API endpoint NEXT_PUBLIC_API_URL=http://localhost:5001/api # Get from Stripe Dashboard (Test Mode -> Developers -> API Keys) NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_YOUR_STRIPE_PUBLISHABLE_KEY
- Start the frontend development server:
The frontend should be running on
npm run dev
http://localhost:3000.
- Open a new terminal and navigate to the frontend directory:
-
Access the Application: Open your browser and go to
http://localhost:3000.
(Note: Base URL is assumed to be /api)
- Auth:
POST /auth/register: Register a new user.POST /auth/login: Log in a user, returns JWT.GET /auth/profile: Get logged-in user's profile (Requires Auth).
- Products:
GET /products: Get all products.GET /products/search?q={term}: Search products by name/description.GET /products/{id}: Get a single product by ID.POST /products: Create a new product (Admin only).PUT /products/{id}: Update a product (Admin only).DELETE /products/{id}: Delete a product (Admin only).
- Orders:
POST /orders: Create a new order (Requires Auth).GET /orders/mine: Get orders for the logged-in user (Requires Auth).GET /orders/{id}: Get a specific order by ID (Owner or Admin).GET /orders: Get all orders (Admin only).PUT /orders/{id}/status: Update order status (Admin only).
- Payments:
POST /payments/create-payment-intent: Create a Stripe Payment Intent (Requires Auth).
- Admin:
GET /admin/users: Get all users (Admin only).GET /admin/users/{id}: Get a specific user (Admin only).DELETE /admin/users/{id}: Delete a user (Admin only).PUT /admin/users/{id}/role: Update a user's role (Admin only).
- Webhooks:
POST /webhooks/stripe: Listens for events from Stripe (e.g., payment success/failure).
- Backend: Deployed on Railway. Requires environment variables (
DATABASE_URL[usually injected],JWT_SECRET,NODE_ENV=production,FRONTEND_URL_PROD,STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET) set in the Railway service settings. Root directory set to/backend. - Frontend: Deployed on Vercel. Requires environment variables (
NEXT_PUBLIC_API_URL,NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY) set in the Vercel project settings. Root directory set to/frontend. - CORS: Ensure the
FRONTEND_URL_PRODon Railway matches the Vercel deployment URL. - Database: MySQL hosted on Railway (Free tier limitations apply).
- Stripe Webhook: A production webhook endpoint needs to be configured in Stripe pointing to the deployed backend URL, and the corresponding production
whsec_...key used in the Railway environment variables.
- CORS Errors: Encountered CORS blocking between the deployed Vercel frontend and Railway backend. Solved by ensuring the correct Vercel URL was added to the
FRONTEND_URL_PRODenvironment variable on Railway and restarting the backend service. - Build Failures (ESLint): Vercel builds initially failed due to strict ESLint rules (
react/no-unescaped-entities). Solved by escaping special characters (like"and') in JSX text content using HTML entities (",'). - Build Failures (Module Parsing): Faced "Unexpected token" errors during the build, often pointing to JSX. Typically resolved by ensuring correct file extensions (
.js/.jsx) and fixing any subtle syntax errors preceding the problematic JSX. - Tailwind CSS Class Issues: Encountered errors where custom or even default Tailwind classes ("Cannot apply unknown utility class") were not recognized. Resolved by ensuring correct Tailwind/PostCSS configuration (
tailwind.config.js,postcss.config.mjs), verifying compatible package versions (especially with Tailwind v4), and clearing the Next.js cache (.nextfolder) before restarting the development server. - Database Connection Errors (
ENOTFOUND,ECONNRESET):ENOTFOUND: Occurred when trying to connect from local machine/Node.js to the database using the internal Railway hostname. Solved by finding and using the public database connection URL/host/port provided by Railway in the local.envfile.ECONNRESET: Connection reset by the database server, often due to idle timeouts on free tiers. Mitigated by implementing a basic retry mechanism (queryWithRetry) in the backend controllers for read operations.
- React Hydration Errors: Faced "Hydration failed" and "Maximum update depth exceeded" errors.
- Caused by discrepancies between server-rendered HTML and initial client render, often due to nested invalid HTML (like
<a>inside<a>,<form>inside<form>) or accessinglocalStorage/Zustand state too early on the client. - Solved by fixing invalid HTML nesting (updating Next.js
<Link>usage, removing nested forms) and implementing anisMountedstate check in_app.jsto delay rendering until the client is ready, allowing state hydration to stabilize.
- Caused by discrepancies between server-rendered HTML and initial client render, often due to nested invalid HTML (like
- Stripe Image/SVG Errors:
next/imagefailed withENOTFOUNDwhen trying to optimize images fromvia.placeholder.com(Node.js DNS issue) anddangerouslyAllowSVGerrors withplacehold.co(returned SVGs). Solved by switching placeholder service topicsum.photos(which Node.js could resolve and returns raster images) and updatingnext.config.mjsremotePatternsaccordingly.
- Implement robust pagination for product lists and order history.
- Add advanced search filters (category, price range, sorting).
- Implement user reviews and ratings for products.
- Detailed order history page for users.
- Replace placeholder images with actual image hosting/upload (e.g., Cloudinary, AWS S3).
- Add comprehensive unit and integration tests (Jest, React Testing Library, Supertest).
- Add end-to-end tests (Cypress, Playwright).
- Implement password reset functionality.
- Allow users to update their profile information.
- Enhance admin dashboard with more features (analytics, user editing).
- Add more payment methods via Stripe.
- Improve accessibility (ARIA attributes, keyboard navigation).
- Consider PWA (Progressive Web App) features.
- Refactor state management if complexity increases.
- Switch to live Stripe keys and webhook secret for production.
- Author: Muhammed Babatunde Garuba
- GitHub: Garbii1








