Dung (Donny) Nguyen

Senior Software Engineer

E-commerce Backend with Spring Boot

A Spring Boot application is a very good choice for building an e-commerce backend. I would recommend designing it as a modular monolith first, rather than immediately splitting it into microservices.

A typical architecture looks like this:

                    ┌──────────────────────┐
                    │      React / Web     │
                    │   Mobile App / etc.  │
                    └──────────┬───────────┘
                               │ HTTPS / REST
                               ▼
                    ┌──────────────────────┐
                    │     Spring Boot      │
                    │      Backend         │
                    ├──────────────────────┤
                    │ Auth / Users         │
                    │ Products             │
                    │ Categories           │
                    │ Cart                 │
                    │ Orders               │
                    │ Payments             │
                    │ Inventory            │
                    │ Shipping             │
                    │ Promotions           │
                    └───────┬───────┬──────┘
                            │       │
              ┌─────────────┘       └──────────────┐
              ▼                                    ▼
       ┌──────────────┐                     ┌──────────────┐
       │ PostgreSQL   │                     │    Redis     │
       │              │                     │              │
       │ Products     │                     │ Cache        │
       │ Orders       │                     │ Sessions     │
       │ Users        │                     │ Cart         │
       │ Payments     │                     │ Rate limits  │
       └──────────────┘                     └──────────────┘
              │
              ▼
       ┌────────────────────────────────────────────┐
       │ External Services                          │
       │                                            │
       │ Stripe / PayPal     AWS S3                 │
       │ Email/SMS           Shipping provider      │
       └────────────────────────────────────────────┘

1. Start with the core domains

I would divide your Spring Boot application into these modules:

com.example.ecommerce
│
├── auth
│   ├── controller
│   ├── service
│   ├── repository
│   ├── entity
│   └── dto
│
├── user
│
├── product
│
├── category
│
├── cart
│
├── order
│
├── payment
│
├── inventory
│
├── shipping
│
├── promotion
│
├── review
│
└── common

This is still one Spring Boot application, but each business area is separated.

That’s a much better starting point than having:

controller/
service/
repository/
entity/

with hundreds of unrelated classes mixed together.


2. Design your database

For a basic e-commerce system, you might have:

Users

users
-----
id
email
password_hash
first_name
last_name
status
created_at
updated_at

Addresses

addresses
---------
id
user_id
address_line1
address_line2
city
state
postal_code
country

Categories

categories
----------
id
name
slug
parent_id

The parent_id allows:

Electronics
 ├── Computers
 │    ├── Laptops
 │    └── Desktops
 └── Phones
      ├── iPhone
      └── Android

Products

products
--------
id
category_id
name
slug
description
brand
status
created_at
updated_at

But don’t put price and inventory directly into products if you expect different product variants.

Instead:

products
   │
   └── product_variants
          │
          ├── SKU
          ├── price
          ├── weight
          └── inventory

For example:

T-Shirt
 ├── Small / Red
 ├── Medium / Red
 ├── Large / Red
 ├── Small / Blue
 └── Medium / Blue

Each variant can have its own SKU and inventory.


3. Product images

Don’t store large images directly in PostgreSQL.

Use something such as AWS S3:

Product
   │
   ├── Image 1 → S3
   ├── Image 2 → S3
   └── Image 3 → S3

Database:

product_images
--------------
id
product_id
url
sort_order
is_primary

Your Spring Boot backend can generate pre-signed S3 URLs when necessary.


4. Shopping cart

A cart could look like:

carts
-----
id
user_id
status
created_at
updated_at

and:

cart_items
----------
id
cart_id
product_variant_id
quantity
unit_price

The API might be:

POST /api/v1/cart/items

GET /api/v1/cart

PUT /api/v1/cart/items/{itemId}

DELETE /api/v1/cart/items/{itemId}

For example:

{
  "productVariantId": 123,
  "quantity": 2
}

5. Order system

This is one of the most important parts of an e-commerce application.

Typical tables:

orders
------
id
user_id
status
subtotal
discount
tax
shipping_fee
total
currency
created_at
updated_at

and:

order_items
-----------
id
order_id
product_variant_id
product_name
sku
quantity
unit_price
total_price

Notice that order_items should store the product name and price at the time of purchase.

Don’t rely on the current product price.

For example:

Product today:
iPhone = $999

Customer bought it:
iPhone = $899

The order must remain $899 even if the product price later becomes $999.


6. Order state machine

Don’t simply use a boolean such as:

boolean paid;

Use a proper order status:

public enum OrderStatus {

    PENDING_PAYMENT,

    PAID,

    PROCESSING,

    SHIPPED,

    DELIVERED,

    CANCELLED,

    REFUNDED
}

Then you can have:

PENDING_PAYMENT
       │
       ▼
     PAID
       │
       ▼
  PROCESSING
       │
       ▼
    SHIPPED
       │
       ▼
   DELIVERED

with cancellation/refund paths as appropriate.


7. Payment integration

I would strongly recommend using an external payment provider rather than handling credit-card information yourself.

For example:

Customer
   │
   ▼
Spring Boot
   │
   ▼
Stripe
   │
   ▼
Payment processor

Your backend creates a payment session/payment intent.

The customer completes payment.

Then the payment provider sends a webhook to your Spring Boot application:

POST /api/v1/payments/webhook

Your backend receives:

payment succeeded

and updates:

Order:
PENDING_PAYMENT
       ↓
PAID

Important

Don’t trust the frontend to tell you that payment succeeded.

For example, don’t do:

POST /orders/123/payment-success

and blindly mark the order as paid.

Use the payment provider’s server-to-server webhook and verify its signature.


8. Inventory

Inventory deserves special attention.

Suppose you have:

SKU: IPHONE-15-BLK-128

Inventory = 5

Two customers simultaneously purchase the last available products.

You need to prevent:

Customer A → sees 5
Customer B → sees 5

A buys 5
B buys 5

Inventory = -5   ❌

Use a transactional approach.

For example, with PostgreSQL:

UPDATE inventory
SET quantity = quantity - :quantity
WHERE product_variant_id = :variantId
  AND quantity >= :quantity;

Then check the number of affected rows.

If:

affected rows = 1

the inventory reservation succeeded.

If:

affected rows = 0

there isn’t enough inventory.

This is much safer than:

inventory.getQuantity();

inventory.setQuantity(
    inventory.getQuantity() - quantity
);

without concurrency protection.


9. Spring Boot technology stack

A good modern stack would be:

Area Technology
Backend Spring Boot
Language Java
API Spring Web
Database PostgreSQL
ORM Spring Data JPA / Hibernate
Security Spring Security
Authentication JWT/OAuth2
Cache Redis
Database migrations Flyway
Validation Jakarta Bean Validation
API documentation OpenAPI/Swagger
Payments Stripe/PayPal
Images AWS S3
Email SES/SendGrid/etc.
Testing JUnit + Mockito + Testcontainers
Build Maven or Gradle
Container Docker

10. API structure

I’d use versioned APIs:

/api/v1/auth
/api/v1/users
/api/v1/products
/api/v1/categories
/api/v1/cart
/api/v1/orders
/api/v1/payments
/api/v1/reviews

For example:

GET    /api/v1/products
GET    /api/v1/products/{id}
POST   /api/v1/products
PUT    /api/v1/products/{id}
DELETE /api/v1/products/{id}

Admin APIs should be protected separately:

/customer
/admin

For example:

GET /api/v1/products

could be public, while:

POST /api/v1/products

requires:

ROLE_ADMIN

11. Authentication and authorization

Spring Security can handle:

Registration
Login
Password hashing
JWT
Roles
Permissions

For example:

public enum Role {
    CUSTOMER,
    ADMIN
}

A JWT might contain:

{
  "sub": "123",
  "roles": [
    "CUSTOMER"
  ]
}

Then Spring Security determines whether the user can access an endpoint.

For a production system, I’d also consider OAuth 2.0/OpenID Connect if you want social login or an external identity provider.


12. Use DTOs instead of exposing entities

Avoid:

@GetMapping("/{id}")
public Product getProduct(@PathVariable Long id) {
    return productRepository.findById(id).orElseThrow();
}

Prefer:

@GetMapping("/{id}")
public ProductResponse getProduct(@PathVariable Long id) {
    return productService.getProduct(id);
}

For example:

public record ProductResponse(
    Long id,
    String name,
    BigDecimal price,
    String description
) {}

This prevents your database entities from becoming your public API contract.


13. Service layer

A typical flow is:

Controller
    ↓
Service
    ↓
Repository
    ↓
PostgreSQL

For example:

@RestController
@RequestMapping("/api/v1/products")
public class ProductController {

    private final ProductService productService;

    @GetMapping("/{id}")
    public ProductResponse getProduct(
            @PathVariable Long id) {

        return productService.getProduct(id);
    }
}

Then:

@Service
public class ProductService {

    private final ProductRepository productRepository;

    public ProductResponse getProduct(Long id) {

        Product product = productRepository
                .findById(id)
                .orElseThrow(ProductNotFoundException::new);

        return ProductMapper.toResponse(product);
    }
}

14. Transactions

Transactions are extremely important for operations such as checkout.

For example:

@Transactional
public Order checkout(Long userId) {

    Cart cart = cartService.getCart(userId);

    validateCart(cart);

    reserveInventory(cart);

    Order order = createOrder(cart);

    clearCart(cart);

    return order;
}

But there’s an important architectural issue:

Don’t put an external payment API call inside a long database transaction.

For example, avoid:

@Transactional
public void checkout() {

    createOrder();

    stripeApi.charge();  // ❌ external network call

    updateOrder();
}

This can create difficult failure scenarios.

Instead, design checkout as a stateful workflow.


15. Checkout workflow

A more robust architecture:

             Customer
                 │
                 ▼
              Checkout
                 │
                 ▼
          Validate Cart
                 │
                 ▼
        Reserve Inventory
                 │
                 ▼
          Create Order
                 │
                 ▼
       Create Payment
                 │
                 ▼
        Customer Pays
                 │
                 ▼
        Payment Webhook
                 │
                 ▼
          Mark PAID
                 │
                 ▼
       Begin Fulfillment

This is much closer to how a production e-commerce system should work.


16. Redis

Redis is useful, but don’t put everything into Redis.

Good candidates include:

Product cache
Category cache
Popular products
Session data
Rate limiting
Temporary cart data
Distributed locks

For example:

GET /products/123

       │
       ▼
     Redis
       │
   ┌───┴────┐
   │ exists │
   └───┬────┘
       │
      yes
       │
       ▼
    return

       no
       │
       ▼
   PostgreSQL
       │
       ▼
     Redis

17. Search

If your store eventually has thousands or millions of products, PostgreSQL alone may not be enough for sophisticated search.

You could introduce:

Spring Boot
     │
     ├── PostgreSQL
     │
     └── Elasticsearch / OpenSearch

Then support:

"black nike running shoes"

with:

Full-text search
Filters
Price range
Brand
Category
Rating
Sorting

But I wouldn’t introduce OpenSearch on day one unless you actually need it.


18. Events

As the system becomes larger, introduce domain events.

For example:

OrderPaidEvent
      │
      ├── Send confirmation email
      ├── Update inventory
      ├── Start fulfillment
      └── Notify shipping system

Initially you can use Spring’s event mechanism.

Later, if the scale requires it:

Spring Boot
     │
     ▼
Kafka / SQS
     │
     ├── Email service
     ├── Inventory service
     ├── Shipping service
     └── Analytics

On AWS, SQS/SNS is often a simpler choice than Kafka for many e-commerce workloads.


19. AWS deployment

Since you’re also working with AWS and Spring Boot, a practical deployment could be:

                   Internet
                      │
                      ▼
                CloudFront
                      │
               ┌──────┴──────┐
               ▼             ▼
            React          ALB
                            │
                            ▼
                     Spring Boot
                       ECS/Fargate
                            │
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
           RDS           ElastiCache      S3
        PostgreSQL         Redis         Images
              │
              │
              ▼
             SQS
              │
              ▼
        Background Workers

And you could use:

Bitbucket
   │
   ▼
Bitbucket Pipelines
   │
   ├── mvn test
   ├── mvn package
   ├── Docker build
   ├── Push to ECR
   └── Deploy to ECS

That would fit very naturally with a Spring Boot project hosted in Bitbucket.


20. Don’t start with microservices

For your first version, I would not create:

product-service
order-service
payment-service
inventory-service
user-service
shipping-service
...

Instead:

                    Spring Boot
                        │
       ┌────────────────┼────────────────┐
       │                │                │
    Product           Order           Payment
       │                │                │
       └────────────────┼────────────────┘
                        │
                    PostgreSQL

This gives you much less operational complexity.

Once you have a real scaling requirement, you can extract modules:

                   API Gateway
                       │
       ┌───────────────┼───────────────┐
       ▼               ▼               ▼
 Product Service   Order Service   Payment Service
       │               │               │
       ▼               ▼               ▼
   PostgreSQL       PostgreSQL       PostgreSQL

21. Recommended development order

If you’re building this as a real project, I’d implement it in this order:

Phase 1 — Foundation

- Spring Boot
- PostgreSQL
- Flyway
- Spring Security
- User registration/login
- Roles
- Global exception handling
- API validation

Phase 2 — Catalog

- Categories
- Products
- Product variants
- Product images
- Product search
- Pagination
- Sorting/filtering

Phase 3 — Shopping

- Cart
- Cart items
- Addresses
- Inventory

Phase 4 — Checkout

- Order creation
- Inventory reservation
- Payment integration
- Payment webhook
- Order state machine

Phase 5 — Fulfillment

- Shipping
- Order tracking
- Email notifications
- Refunds
- Cancellation

Phase 6 — Production

- Redis
- S3
- Async processing
- Monitoring
- Logging
- Metrics
- Docker
- AWS deployment
- CI/CD

A particularly good architecture for your project

If your goal is to build a professional Spring Boot e-commerce project for your portfolio/interviews, I would build something like:

                           React
                             │
                             ▼
                       AWS CloudFront
                             │
                             ▼
                       Application LB
                             │
                             ▼
                  ┌─────────────────────┐
                  │     Spring Boot     │
                  │                     │
                  │ Auth                │
                  │ Product             │
                  │ Category            │
                  │ Cart                │
                  │ Order               │
                  │ Payment             │
                  │ Inventory           │
                  │ Shipping            │
                  │ Review              │
                  └──────────┬──────────┘
                             │
              ┌──────────────┼──────────────┐
              ▼              ▼              ▼
          PostgreSQL       Redis            S3
             RDS         ElastiCache      Images
              │
              ▼
             SQS
              │
              ▼
       Background Workers

External:
   ├── Stripe
   ├── Email
   └── Shipping API

This gives you opportunities to demonstrate Spring Boot, Spring Security, JPA/Hibernate, PostgreSQL, Redis, AWS, Docker, REST APIs, asynchronous processing, payment integration, concurrency/inventory management, and CI/CD—which is a much stronger backend project than simply implementing CRUD for products.