DEV Community

Wynn TEO
Wynn TEO

Posted on

Full-Stack E-Commerce App - Part 1: Project setup

Hey! Welcome to Part 1 of this series, where we build a complete, production-ready e-commerce app called ShopFlow — from an empty folder all the way to a live site on AWS.

By the end of this series, ShopFlow will have:

  • User authentication with JWT tokens
  • A product catalogue with search powered by Elasticsearch
  • A shopping cart (stored in Redis) and a full order system
  • AI features — smart search, a chatbot, and product descriptions generated by AI
  • Real payments via Stripe and PayPal
  • Event-driven order processing with Apache Kafka
  • Deployed on AWS with Kubernetes and a CI/CD pipeline

That sounds like a lot — and it is! But we are going to build it one piece at a time. Each part of this series focuses on one thing, explains why we are doing it, and by the end, you have working code.

In this first part, we just focus on getting everything set up. By the end of this post, your backend and frontend will be running, talking to each other, and you'll understand what every piece does.

This series is aimed at developers who know some coding but maybe haven't built a full-stack app before, or want to see how all these technologies fit together in a real project. If you've followed any beginner tutorials but felt lost when it came to "real-world" apps, this series is for you.

Step 1 — Install the tools

Let's get your machine ready. We need four things: Java 21, Node.js 20, Docker Desktop, and an IDE.

Install Java 25

The best way to install Java is through SDKMAN — a tool that lets you easily switch between Java versions.

On macOS or Linux

Open your terminal and run this:

# Install SDKMAN
curl -s "https://get.sdkman.io" | bash

# Restart your terminal, then install Java 25
sdk install java 25.0.2-tem

# Check it worked
java -version
# You should see: openjdk version "25.0.2"
Enter fullscreen mode Exit fullscreen mode

On Windows

Go to https://adoptium.net and download the "Temurin 25 LTS" Windows installer. Run it, and make sure you tick the option to set JAVA_HOME during setup.

After installing, open Command Prompt and check:

java -version
# openjdk version "25.0.2" ...
Enter fullscreen mode Exit fullscreen mode

Install Node.js 22

We use Node.js to run our React frontend. The cleanest way to install it is through NVM (Node Version Manager) — it lets you easily switch between Node versions on the same machine.

On macOS or Linux

# Install NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# Restart your terminal, then:
nvm install 22
nvm use 22

# Check
node -v   # v22.x.x
npm -v    # 10.x.x
Enter fullscreen mode Exit fullscreen mode

On Windows

Download nvm-windows from https://github.com/coreybutler/nvm-windows/releases (get nvm-setup.exe). Install it, then open a new terminal:

Install Docker Desktop

Go to https://docker.com/products/docker-desktop and download Docker Desktop for your OS. Install it and start it up. You'll know it's running when you see the whale icon in your menu bar or taskbar.

Check it's working:

docker -v
# Docker version 29.x.x

docker compose version
# Docker Compose version v2.x.x
Enter fullscreen mode Exit fullscreen mode

Install your IDE

For the backend (Java / Spring Boot): Download IntelliJ IDEA Community Edition for free from https://jetbrains.com/idea

For the frontend (React): Download VS Code for free from https://code.visualstudio.com

Once VS Code is open, install these extensions — they make working with React much nicer:

  • ES7+ React/Redux/React-Native snippets
  • Prettier — Code formatter
  • Tailwind CSS IntelliSense
  • Thunder Client (a Postman alternative built into VS Code — great for testing APIs)

Step 2 — Run MySQL in Docker

Create a new folder anywhere on your computer — call it shopflow. Inside it, create a file called docker-compose.yml and paste this in:

version: "3.8"

services:
  mysql:
    image: mysql:8.0
    container_name: shopflow-mysql
    environment:
      MYSQL_ROOT_PASSWORD: shopflow123
      MYSQL_DATABASE: shopflow_db
      MYSQL_USER: shopflow_user
      MYSQL_PASSWORD: shopflow123
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  mysql_data:
Enter fullscreen mode Exit fullscreen mode

Now open a terminal in that folder and run:

docker compose up -d

# -d means "detached" — runs in the background
# Check it is running:
docker ps

# You should see shopflow-mysql in the list with status "Up"
Enter fullscreen mode Exit fullscreen mode

Let's quickly connect to MySQL to make sure it's working:

docker exec -it shopflow-mysql mysql -u shopflow_user -p
# Type the password: shopflow123

# Once connected:
SHOW DATABASES;
# You should see shopflow_db in the list

EXIT;
Enter fullscreen mode Exit fullscreen mode

Step 3 — Create the Spring Boot backend

Now let's create the backend. We'll use Spring Initializr — a free tool at start.spring.io that generates a ready-to-run Spring Boot project for you.

Generate the project

Go to https://start.spring.io and fill in the settings like this:

  • Project: Maven
  • Language: Java
  • Spring Boot version: 3.3.x (pick the latest stable, not a SNAPSHOT)
  • Group: com.shopflow
  • Artifact: backend
  • Java version: 25

Then click "ADD DEPENDENCIES" and add these:

  • Spring Web
  • Spring Data JPA
  • MySQL Driver
  • Spring Security
  • Spring Boot DevTools
  • Lombok
  • Validation

Click GENERATE — it downloads a zip file. Extract it into your shopflow/backend folder.

Open it in IntelliJ

Open IntelliJ IDEA. Go to File → Open and navigate to your shopflow/backend folder. IntelliJ will detect it's a Maven project and start downloading dependencies automatically. This takes 1–2 minutes the first time.

Connect it to the database

Open the file src/main/resources/application.properties and replace everything in it with:

# App name
spring.application.name=shopflow-backend

# Database connection
spring.datasource.url=jdbc:mysql://localhost:3306/shopflow_db
spring.datasource.username=shopflow_user
spring.datasource.password=shopflow123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA settings
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

# Server port
server.port=8080
Enter fullscreen mode Exit fullscreen mode

Run the app

Find the file  BackendApplication.java  inside src/main/java/com/shopflow/backend/ and click the green ▶ Run button next to the class name.

Watch the console at the bottom. After a few seconds, you should see:

Tomcat started on port(s): 8080 (http)
Started BackendApplication in 2.847 seconds
Enter fullscreen mode Exit fullscreen mode

Open your browser and go to http://localhost:8080. You'll see a login page — that's Spring Security's default. It means the app is running. We'll replace this with our own auth in Part 2.

Step 4 — Create the React frontend

Now let's set up the frontend. We'll use Vite (pronounced "veet") instead of the old Create React App. Vite starts up in under a second and is way faster during development.

Create the project

Open a new terminal, go to your shopflow folder, and run:

npm create vite@latest frontend -- --template react
cd frontend
npm install
Enter fullscreen mode Exit fullscreen mode

Now let's add the libraries we'll use throughout this series:

# Tailwind CSS — for styling without writing tons of CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

# React Router — for navigation between pages
npm install react-router-dom

# Axios — for making API calls to our backend
npm install axios

# React Query — for managing server data in React
npm install @tanstack/react-query
Enter fullscreen mode Exit fullscreen mode

Configure Tailwind

Open tailwind.config.js and update the content section:

export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Then open src/index.css and replace everything with just these three lines:

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Start the React dev server

npm run dev

# You will see:
#   VITE v5.x.x  ready in 300ms
#   ➜  Local:   http://localhost:5173/
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:5173 in your browser. You should see the Vite + React welcome page. That means your frontend is running.

Step 5 — Make the frontend talk to the backend

This is the moment things get real. We're going to make a simple API endpoint in Spring Boot and call it from React.

Create a health check endpoint

In IntelliJ, create a new file: src/main/java/com/shopflow/backend/controller/HealthController.java

package com.shopflow.backend.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
@RequestMapping("/api")
public class HealthController {

    @GetMapping("/health")
    public Map<String, String> health() {
        return Map.of(
            "status", "ok",
            "message", "ShopFlow backend is running!"
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's break down what this does:

  •  @RestController  — tells Spring this class handles HTTP requests and returns data (not HTML pages)
  •  @RequestMapping("/api")  — all endpoints in this class start with /api
  •  @GetMapping("/health")  — when someone calls GET /api/health, run this method

Restart Spring Boot, then open http://localhost:8080/api/health in your browser. You should see:

{
  "status": "ok",
  "message": "ShopFlow backend is running!"
}
Enter fullscreen mode Exit fullscreen mode

Fix CORS so React can call the backend

Right now, if React tries to call the backend, the browser will block it with a CORS error. CORS is a browser security rule that blocks requests from different origins. Our frontend is on port 5173, our backend is on port 8080 — different origins.

Create a new file: src/main/java/com/shopflow/backend/config/CorsConfig.java

package com.shopflow.backend.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("http://localhost:5173");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", config);
        return new CorsFilter(source);
    }
}
Enter fullscreen mode Exit fullscreen mode

Call the API from React

Open src/App.jsx and replace everything with:

import { useState, useEffect } from "react"
import axios from "axios"

function App() {
  const [status, setStatus] = useState("Checking...")

  useEffect(() => {
    axios.get("http://localhost:8080/api/health")
      .then(response => setStatus(response.data.message))
      .catch(() => setStatus("Backend is not running!"))
  }, [])

  return (
    <div className="min-h-screen bg-gray-50 flex items-center justify-center">
      <div className="bg-white rounded-xl shadow-sm border border-gray-100 p-10 text-center">
        <h1 className="text-4xl font-bold text-gray-900 mb-2">ShopFlow</h1>
        <p className="text-gray-400 text-sm mb-4">Full-stack e-commerce app</p>
        <p className="text-gray-500">Backend status:</p>
        <p className="text-green-600 font-semibold mt-1 text-lg">{status}</p>
      </div>
    </div>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Restart Spring Boot (to pick up the CORS config), then open http://localhost:5173. You should see the ShopFlow card with:

"ShopFlow backend is running!"

That's it — your frontend and backend are talking to each other.

Step 6 — Folder structure and Git

Before we go any further, let's organise the project and save our work in Git.

Backend folder structure

This is the structure we'll follow for the whole course. Create these empty folders inside your backend project now so they're ready:

backend/src/main/java/com/shopflow/backend/
├── config/       ← Spring configuration (CORS, Security, etc.)
├── controller/   ← API endpoints
├── service/      ← Business logic
├── repository/   ← Database access
├── model/        ← Entity classes (map to database tables)
│   └── dto/      ← Data Transfer Objects (request/response shapes)
├── security/     ← Auth and JWT
├── exception/    ← Error handling
└── util/         ← Helper utilities
Enter fullscreen mode Exit fullscreen mode

This follows a layered architecture pattern: the request comes in through the Controller, the Controller calls the Service, the Service calls the Repository, the Repository talks to the database. Each layer only talks to the one below it.

Frontend folder structure

frontend/src/
├── api/          ← API call functions (axios)
├── components/   ← Reusable UI pieces (buttons, cards, etc.)
├── pages/        ← Full page components
├── context/      ← React Context (auth state, cart state)
├── hooks/        ← Custom React hooks
└── utils/        ← Helper functions
Enter fullscreen mode Exit fullscreen mode

Set up Git

In your shopflow root folder (the one that contains both backend and frontend), run:

git init
git add .
git commit -m "feat: initial project setup"
Enter fullscreen mode Exit fullscreen mode

Create a .gitignore file in the root:

# Java / Maven
target/
*.class
*.jar

# IntelliJ
.idea/
*.iml

# Node
node_modules/
dist/

# Environment files — NEVER commit these
.env
.env.local

# OS
.DS_Store
Thumbs.db
Enter fullscreen mode Exit fullscreen mode

What's next?

In Part 2 of this series, we build the authentication system. That means:

  • Designing the user and roles database tables
  • Building register and login endpoints
  • Generating JWT tokens so users stay logged in
  • Protecting routes so only logged-in users can access them
  • Building the React login page and keeping auth state globally

Authentication is the foundation of the whole app — every other feature depends on it. See you in Part 2.

Top comments (0)