Skip to content

iamgaganam/Realtime_Auction_System

Repository files navigation

Realtime Auction System

A backend for a simplified real-time community charity auction application built with Java Spring Boot and MySQL. Users can list items for auction, place bids, and the system automatically manages the auction lifecycle.


Table of Contents


Getting Started

Prerequisites

  • Java 25 (JDK 25)
  • MySQL 8.0+
  • Maven 3.9+ (or use the included Maven Wrapper)

Tech Stack

Technology Purpose
Spring Boot 4.0.3 Application framework
Spring Data JPA Data persistence (Hibernate)
Spring Security Basic security & password hashing
Spring WebSocket (STOMP) Real-time bid notifications
Spring Validation Input validation
MySQL Relational database
Lombok Boilerplate reduction
Springdoc OpenAPI Swagger UI / API docs

Database Setup

1. Create the MySQL Database

Connect to your MySQL server and create the database:

CREATE DATABASE IF NOT EXISTS auction_db;

2. User Privileges (if not using root)

CREATE USER 'auction_user'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON auction_db.* TO 'auction_user'@'localhost';
FLUSH PRIVILEGES;

3. Configuration

The database connection is configured in src/main/resources/application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/auction_db?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456

Update username and password to match your MySQL credentials.

Hibernate will auto-create/update the tables (spring.jpa.hibernate.ddl-auto=update), so no manual table creation is needed.


Build & Run

Using Maven Wrapper

# Build the project
./mvnw clean package

# Run the application
./mvnw spring-boot:run

Using Maven directly

mvn clean package
mvn spring-boot:run

Windows

mvnw.cmd clean package
mvnw.cmd spring-boot:run

The application starts on http://localhost:8080.

Verify

  • Health check: GET http://localhost:8080/
  • Swagger UI: http://localhost:8080/swagger-ui.html

Architecture & Design

Package Structure

dev.test.realtime_auction_system/
├── config/              # Security & WebSocket configuration
│   ├── SecurityConfig       - Spring Security (BCrypt, permit-all API)
│   └── WebSocketConfig      - STOMP over SockJS configuration
├── controller/          # REST API controllers
│   ├── ItemController       - Item CRUD & bidding endpoints
│   └── UserController       - User registration endpoint
├── dto/                 # Data Transfer Objects
│   ├── request/             - Validated request bodies
│   └── response/            - API response payloads
├── exception/           # Global exception handling
│   ├── GlobalExceptionHandler - @RestControllerAdvice
│   ├── ResourceNotFoundException
│   ├── AuctionClosedException
│   ├── InvalidBidException
│   └── DuplicateResourceException
├── model/               # JPA Entities
│   ├── User, Item, Bid      - Core domain entities
│   └── AuctionStatus        - ACTIVE / CLOSED enum
├── repository/          # Spring Data JPA repositories
│   ├── UserRepository
│   ├── ItemRepository       - With pessimistic locking & specifications
│   └── BidRepository
├── scheduler/           # Background tasks
│   └── AuctionScheduler    - Auto-closes expired auctions
├── service/             # Business logic
│   ├── UserService
│   ├── ItemService
│   └── BidService           - Bid validation & WebSocket notification
├── specification/       # JPA Specifications for dynamic queries
│   └── ItemSpecification
├── HomeController.java  # Health check endpoint
└── RealtimeAuctionSystemApplication.java  # Main entry point

Key Components

Component Type Responsibility
ItemController @RestController Handles all /items/** endpoints (CRUD, bidding, winner)
UserController @RestController Handles /users/register and /users/{id}
ItemService @Service Item creation, listing, search/filter, winner determination
BidService @Service Bid validation, placement with pessimistic locking, WebSocket notification
UserService @Service User registration with BCrypt password encoding
AuctionScheduler @Component Background @Scheduled task that auto-closes expired auctions
GlobalExceptionHandler @RestControllerAdvice Centralized error handling with structured JSON responses
ItemSpecification Utility JPA Specifications for dynamic search/filter queries

Entity Relationships

User (1) ──── (*) Item     [seller relationship]
User (1) ──── (*) Bid      [bidder relationship]
Item (1) ──── (*) Bid      [item-bid relationship]

Design Decisions

  1. DTOs for all responses — Entities are never directly serialized to avoid circular references and to control the API surface.
  2. Pessimistic locking for bids@Lock(PESSIMISTIC_WRITE) on findByIdForUpdate() prevents race conditions during concurrent bid placement.
  3. Optimistic locking as defense-in-depth@Version field on Item provides an additional safety layer.
  4. Stateless security — CSRF disabled, no sessions; suitable for REST API consumption.
  5. Scheduler-based auction closing — A @Scheduled task runs every 10 seconds to close expired auctions, rather than checking on each request.

API Documentation

Swagger UI (Interactive)

Once the app is running, visit:

http://localhost:8080/swagger-ui.html

OpenAPI JSON

http://localhost:8080/api-docs


API Endpoints

User Management

Method Endpoint Description Request Body
POST /users/register Register a new user RegisterUserRequest
GET /users/{userId} Get user details by ID

Register User Request:

{
  "username": "alice_seller",
  "email": "alice@community.org",
  "password": "securePass123"
}

Item Management

Method Endpoint Description Query Params
POST /items Create a new auction item
GET /items List active items (paginated & sorted) page, size, sortBy, sortDir
GET /items/search Search/filter items keyword, status, minPrice, maxPrice, page, size, sortBy, sortDir
GET /items/{itemId} Get item details + recent bid history

Create Item Request:

{
  "name": "Vintage Wall Clock",
  "description": "A beautiful antique wall clock from the 1920s",
  "startingPrice": 50.0,
  "auctionEndTime": "2026-03-10T18:00:00",
  "sellerId": 1
}

Bidding

Method Endpoint Description Request Body
POST /items/{itemId}/bids Place a bid on item PlaceBidRequest

Place Bid Request:

{
  "amount": 75.0,
  "bidderId": 2
}

Bid Validation Rules:

  • Auction must be ACTIVE and not past its auctionEndTime
  • Bid must be >= startingPrice (if first bid)
  • Bid must be > currentHighestBid (if subsequent bid)
  • Seller cannot bid on their own item

Auction Results

Method Endpoint Description
GET /items/{itemId}/winner Get the winning bid (closed auctions only)

Error Response Format

All errors return a structured JSON response:

{
  "status": 400,
  "error": "Invalid Bid",
  "message": "Bid amount must be higher than the current highest bid of 75.00",
  "timestamp": "2026-03-05T14:30:00",
  "validationErrors": null
}

Validation errors include field-level details:

{
  "status": 400,
  "error": "Validation Failed",
  "message": "Request body contains invalid fields",
  "timestamp": "2026-03-05T14:30:00",
  "validationErrors": {
    "name": "Item name is required",
    "startingPrice": "Starting price must be greater than 0"
  }
}

WebSocket (Real-time Updates)

The backend supports real-time notifications using STOMP over WebSocket (with SockJS fallback).

Connection

WebSocket Endpoint: ws://localhost:8080/ws

Topics

Topic Event Payload
/topic/items/{itemId}/bids New high bid placed BidResponse
/topic/items/{itemId}/status Auction closed Status message

Example (JavaScript Client)

const socket = new SockJS("http://localhost:8080/ws");
const stompClient = Stomp.over(socket);

stompClient.connect({}, () => {
  // Subscribe to bid updates for item 1
  stompClient.subscribe("/topic/items/1/bids", (message) => {
    const bid = JSON.parse(message.body);
    console.log(`New high bid: $${bid.amount} by ${bid.bidderUsername}`);
  });

  // Subscribe to auction status changes for item 1
  stompClient.subscribe("/topic/items/1/status", (message) => {
    const status = JSON.parse(message.body);
    console.log(`Auction ${status.status}: ${status.message}`);
  });
});

Note: No actual client-side implementation is included — only the backend WebSocket capability is provided.


Auction Closing Mechanism

Auctions are closed automatically by a background scheduler (AuctionScheduler):

  1. A @Scheduled task runs every 10 seconds (configurable via auction.scheduler.rate in application.properties).
  2. It queries for all ACTIVE items where auctionEndTime <= NOW().
  3. Each expired item's status is set to CLOSED.
  4. A WebSocket notification is sent to /topic/items/{itemId}/status.
  5. The winning bid can then be retrieved via GET /items/{itemId}/winner.

Why scheduled vs. on-demand?

  • Decouples auction closing from user requests
  • Ensures auctions close even if no one is actively querying them
  • Central, predictable closing logic

Concurrency Considerations

Current Implementation

  • Pessimistic Locking: When placing a bid, findByIdForUpdate() acquires a PESSIMISTIC_WRITE lock on the item row. This ensures only one bid transaction proceeds at a time for the same item, preventing the "lost update" problem.
  • Optimistic Locking: The Item entity has a @Version field as an additional safety net.

How It Works

When two users bid simultaneously on the same item:

  1. Transaction A acquires a PESSIMISTIC_WRITE lock on the item row.
  2. Transaction B blocks, waiting for the lock.
  3. Transaction A validates the bid, saves it, updates currentHighestBid, and commits (releasing the lock).
  4. Transaction B acquires the lock, reads the updated currentHighestBid, and validates its bid against the new value.

Real-World Improvements

In a production system with high traffic, consider:

  1. Distributed Locking — Use Redis-based locks (e.g., Redisson) if the application scales horizontally across multiple instances.
  2. Message Queues — Route bids through a message queue (RabbitMQ, Kafka) and process them sequentially per item.
  3. Event Sourcing — Store each bid as an immutable event and derive the current state, providing a complete audit trail.
  4. Database-level constraints — Add a CHECK constraint or trigger to enforce bid monotonicity at the database level as a final safeguard.

Testing

Run Unit Tests

./mvnw test

Test Coverage

Test Class Covers
BidServiceTest Bid validation, placement, error handling
ItemServiceTest Item creation, listing, detail, winner
UserServiceTest Registration, duplicate detection, retrieval
AuctionSchedulerTest Scheduled auction closing logic

Postman Collection

A complete Postman collection is included at:

Realtime_Auction_System.postman_collection.json

Import into Postman

  1. Open Postman → Import → Select the JSON file.
  2. The collection uses a {{baseUrl}} variable defaulting to http://localhost:8080.
  3. Run requests in order: Register users → Create items → Place bids → Check results.

Included Scenarios

  • User registration (seller + bidders)
  • Item creation with various auction end times
  • Bidding with escalating amounts
  • Error cases (validation, low bids, seller self-bidding, not found)
  • Search and filter with pagination
  • Auction winner retrieval
  • Health check and Swagger access

Developer

Name: Gagana Methmal
LinkedIn: https://www.linkedin.com/in/gagana-methmal/


License

This project is licensed under the MIT License. See LICENSE for details.

About

Auction System in Realtime

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages