A full-stack e-commerce platform for selling electric guitars online, built as an end-to-end demonstration of Java + OOP + Spring Boot 3 on the backend and React + TypeScript on the customer storefront and admin console.
The project covers the complete lifecycle of an online store: customer registration, JWT-protected authentication, a searchable guitar catalog, shopping cart, order management with a state machine, a customer-facing storefront, and a polished admin dashboard with sales charts.
π¬ Quick demo: see
docs/screenshots/00-demo.giffor the end-to-end user flow.
- Features
- Tech Stack
- Architecture & OOP
- Project Structure
- Quick Start (Docker)
- Manual Setup
- API Documentation
- Demo Credentials
- Screenshots
- REST Endpoints
- Domain Model
- JWT Authentication with access + refresh tokens (jjwt 0.12)
- Role-based authorization β
ADMINandCUSTOMERwith method-level@PreAuthorize - Product catalog with search by name, category, min/max price + pagination
- Shopping cart per user with stock validation
- Order workflow with state machine:
PENDING β PROCESSING β SHIPPED β DELIVERED(orCANCELLED) - Stock management β automatic decrement on order, restock on cancel
- Soft delete for products
- Global exception handler with consistent JSON error responses
- DTOs everywhere β entities are never exposed
- OpenAPI / Swagger UI auto-generated at
/swagger-ui.html - Bean Validation (Jakarta) on all incoming requests
- Auditing β automatic
createdAt/updatedAtvia JPA Auditing - Optimistic locking via
@VersiononBaseEntity - Data seeder populates 5 categories + 12 real-world guitar models on first run
- JWT-aware Axios client with automatic token refresh on
401 - Protected routes with role check (admin-only)
- Dashboard with KPI cards + Recharts line/bar charts (last 6 months)
- Products β paginated table, search, category filter, modal CRUD with all guitar specs
- Categories β CRUD with image previews
- Orders β table view with valid next-status buttons (state-machine aware)
- Users β list of all registered customers and admins
- Tailwind CSS with custom brand palette
- react-hot-toast notifications
| Layer | Technology |
|---|---|
| Backend | Java 21, Spring Boot 3.3, Spring Security, Spring Data JPA |
| DB | PostgreSQL 16, Hibernate |
| Auth | JWT (jjwt 0.12), BCrypt |
| Docs | SpringDoc OpenAPI 2.6 (Swagger UI) |
| Build | Maven 3.9 |
| Frontend | React 18, TypeScript, Vite 5, Tailwind 3, React Router 6 |
| Charts | Recharts 2 |
| Infra | Docker + Docker Compose |
This project was deliberately structured to demonstrate Object-Oriented Programming in real code, not just CRUD plumbing:
| OOP Concept | Where it shows up |
|---|---|
| Inheritance | BaseEntity (abstract) β User, Product, Category, Order, OrderItem, Cart, CartItem |
| Encapsulation | DTOs hide entities. Domain logic lives in entities (Product.decreaseStock, Cart.getTotal) |
| Polymorphism | User implements UserDetails β Spring Security treats it polymorphically |
| Abstraction | Repository interfaces extend JpaRepository, no implementation written |
| Composition | Cart has a list of CartItems; Order has a list of OrderItems |
| State pattern | OrderStatus enum holds its own canTransitionTo(...) transition table |
| Builder | All entities use Lombok @Builder for fluent construction |
| Custom exceptions | ResourceNotFoundException, BadRequestException, ConflictException extend RuntimeException |
Layered architecture follows classic Spring conventions:
controller β service β repository β entity
β
DTO β entity (via static factory methods)
E-commerce/
βββ backend/ # Spring Boot Maven project
β βββ pom.xml
β βββ Dockerfile
β βββ src/main/
β βββ java/com/javaecommerce/
β β βββ EcommerceApplication.java
β β βββ config/DataSeeder.java
β β βββ controller/ # REST endpoints
β β βββ service/ # business logic
β β βββ repository/ # Spring Data interfaces
β β βββ entity/ # JPA entities + BaseEntity
β β βββ dto/ # request/response records
β β βββ security/ # JWT filter, config, services
β β βββ exception/ # custom exceptions + global handler
β βββ resources/application.yml
β
βββ frontend/ # Vite + React + TS admin panel
β βββ package.json
β βββ Dockerfile + nginx.conf
β βββ src/
β βββ main.tsx, App.tsx
β βββ api/ # axios client + endpoints
β βββ context/AuthContext.tsx
β βββ components/ # AdminLayout, DataTable, Modal, etc.
β βββ pages/ # Login, Dashboard, Products, Orders, Users, Categories
β
βββ docker-compose.yml # Postgres + backend + frontend
βββ .env.example
βββ README.md
The fastest way β everything (Postgres + API + UI) starts with one command.
- Docker Desktop 4+ (Windows / macOS / Linux)
# 1. Clone the repo
git clone <your-repo-url> java-ecommerce
cd java-ecommerce
# 2. Copy env template
cp .env.example .env
# 3. Start all services
docker compose up --buildOnce everything is up:
| Service | URL |
|---|---|
| Admin dashboard | http://localhost:5173 |
| REST API | http://localhost:8080/api |
| Swagger UI | http://localhost:8080/api/swagger-ui.html |
| PostgreSQL | localhost:5432 (postgres/postgres) |
The DataSeeder will automatically create:
- 2 demo users (admin + customer β see Demo Credentials)
- 5 guitar categories (Stratocaster, Les Paul, Telecaster, SG, Superstrat)
- 12 real guitar models (Fender, Gibson, Epiphone, Squier, Ibanez, Jackson, ESP)
If you prefer to run services manually (e.g. for development with hot reload).
# Create the database
psql -U postgres -c "CREATE DATABASE ecommerce_db;"cd backend
cp .env.example .env # adjust DB credentials if needed
./mvnw spring-boot:run
# or: mvn spring-boot:runBackend listens on http://localhost:8080/api.
cd frontend
cp .env.example .env
npm install
npm run devVite dev server runs on http://localhost:5173 and proxies /api to the backend.
Once the backend is running, browse to:
http://localhost:8080/api/swagger-ui.html
You'll find every endpoint grouped by tag (Auth, Products, Categories, Cart, Orders, Users, Stats), with request/response schemas, validation rules, and "Try it out" support.
To test protected endpoints:
POST /auth/loginwith the demo admin credentials- Copy the returned
accessToken - Click the Authorize button at the top of Swagger UI and paste the token
The DataSeeder creates these on first startup:
| Role | Password | |
|---|---|---|
| ADMIN | admin@guitarshop.com |
admin12345 |
| CUSTOMER | customer@guitarshop.com |
customer12345 |
POST /api/auth/register Register a new customer
POST /api/auth/login Login β access + refresh tokens
POST /api/auth/refresh Exchange refresh token for new access token
GET /api/products Search & paginate guitars
GET /api/products/{id} Product detail
GET /api/categories List categories
GET /api/categories/{id} Category detail
GET /api/users/me Current profile
PUT /api/users/me Update profile
GET /api/cart Get cart
POST /api/cart/items Add product to cart
PATCH /api/cart/items/{id} Update item quantity
DELETE /api/cart/items/{id} Remove item
DELETE /api/cart Clear cart
POST /api/orders Create order from cart
GET /api/orders/me My orders (paginated)
GET /api/orders/{id} Order detail (owner or admin)
POST /api/products Create guitar
PUT /api/products/{id} Update guitar
DELETE /api/products/{id} Soft-delete guitar
POST /api/categories Create category
PUT /api/categories/{id} Update category
DELETE /api/categories/{id} Delete category
GET /api/orders List all orders
PATCH /api/orders/{id}/status Update order status (state-machine validated)
GET /api/users List all users
GET /api/users/{id} User detail
GET /api/admin/stats/dashboard Aggregate dashboard metrics
User ββ1:1ββ Cart ββ1:Nββ CartItem ββN:1ββ Product ββN:1ββ Category
β
βββ1:Nββ Order ββ1:Nββ OrderItem ββN:1ββ Product
Product carries guitar-specific attributes: brand, model code, body wood, neck wood, fingerboard, pickup configuration (HH / SSS / HSS / HSH), color, and price.
OrderItem snapshots the product name and unit price at purchase time, so historical orders remain accurate even if the catalog is updated.
OrderStatus owns its own transition table (canTransitionTo), preventing invalid jumps like DELIVERED β PENDING.
Quick sanity check from the command line:
# Login as admin
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@guitarshop.com","password":"admin12345"}'
# Search guitars
curl "http://localhost:8080/api/products?name=strat&page=0&size=5"Released under the MIT License. You are free to study, fork and adapt the code β attribution is appreciated.
Alan Toro β built as a portfolio piece to demonstrate full-stack Java + OOP + Spring Boot proficiency, paired with a modern React + TypeScript frontend.
- GitHub Β· @AlanIsaacToroHolguin








