Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoodToolers

Java Spring Boot Spring Security MariaDB Maven

REST API for a tool and equipment rental platform. Demonstrates Clean Architecture (Onion pattern, Robert C. Martin): strict inward dependency rule, framework-free domain layer, and a pricing engine testable with plain JUnit 5 and no Spring context.

Architecture Overview

flowchart TD
    subgraph ADAPTER["ADAPTER"]
        style ADAPTER fill:#dbeafe,stroke:#3b82f6
        A1["ToolController"]
        A2["RentalController"]
        A3["AuthenticationController"]
        A4["ReviewController / CommentController"]
        A5["CategoryController"]
        A6["ModerationController"]
    end
    subgraph APPLICATION["APPLICATION"]
        style APPLICATION fill:#dcfce7,stroke:#22c55e
        B1["ToolService"]
        B2["RentalService"]
        B3["AuthenticationService / JwtService"]
        B4["ReviewService / CommentService"]
        B5["CategoryService"]
    end
    subgraph DOMAIN["DOMAIN"]
        style DOMAIN fill:#fef9c3,stroke:#eab308
        C1["RentalPriceCalculator"]
        C2["Price"]
        C3["PricingGrid / PricingTier"]
        C4["RentalDuration"]
    end
    A1 --> B1
    A2 --> B2
    A3 --> B3
    A4 --> B4
    A5 --> B5
    B2 --> C1
    C1 --> C2
    C1 --> C3
    C1 --> C4
Loading

Three concentric layers: ADAPTER knows APPLICATION, APPLICATION knows DOMAIN, DOMAIN knows nothing outside itself. The pricing engine lives entirely in DOMAIN and runs under plain JUnit 5 with no Spring context or database.

Clean Architecture

Layer Package Responsibilities
ADAPTER adapter/controller/ adapter/persistence/ adapter/dto/ Spring REST controllers, JPA entity mappings, request/response DTOs, GlobalExceptionHandler
APPLICATION application/service/ application/exception/ Use-case services, JWT authentication, custom exceptions
DOMAIN domain/pricing/ Entities, Value Objects, pricing rules. Zero Spring or JPA imports.

Business rules belong in the domain, not in @NotNull annotations on a DTO:

// DOMAIN layer: zero Spring/JPA dependency
public record Price(float value) {
    public Price {
        if (value < 0) throw new IllegalArgumentException("Price cannot be negative");
    }

    public Price plus(Price other)          { return new Price(value + other.value); }
    public Price multipliedBy(float factor) { return new Price(value * factor); }
}

Architecture Decisions

Clean Architecture: strict inward dependency rule

Context. A REST API that mixes JPA entities, business rules, and HTTP concerns in the same class becomes hard to test and fragile to evolve.

Decision. Three concentric layers with a hard dependency rule: domain/ imports only the Java standard library. application/ imports domain/. adapter/ imports both, but inner layers never import outer ones.

Consequence. The pricing engine is fully testable with plain JUnit 5. Adding a new delivery channel (CLI, messaging) requires only a new adapter: no business logic changes needed.

Domain self-validation via canonical constructors

Context. Validation logic scattered across service methods and DTO annotations leaves the domain object unprotected when instantiated directly in tests or other services.

Decision. Price uses a Java record canonical constructor to enforce invariants at construction time, not at the service layer.

Consequence. An invalid Price cannot exist anywhere in the codebase. Tests that construct domain objects directly receive the same invariant guarantees as production code.

Getting Started

Prerequisites: JDK 21, Maven 3.9+, MariaDB running on port 3306 with database shelton_db.

git clone https://github.com/<your-handle>/GoodToolers.git
cd GoodToolers
mvn spring-boot:run

API available at http://localhost:8080/api/v1.

Tech Stack

Concern Technology
Language Java 21
Framework Spring Boot 3.2.5
Security Spring Security + jjwt 0.12.3
Persistence Spring Data JPA + MariaDB
Build Maven
Testing JUnit Jupiter 5.11.2 + AssertJ 3.26.3

Testing

Domain tests run without Spring context:

# All tests
mvn test

# Single class
mvn test -Dtest=RentalPriceCalculatorTest

Coverage targets domain/pricing/: RentalPriceCalculatorTest and RentalDurationTest cover tier-selection logic and duration-rounding rules.

API

Full endpoint reference with request/response examples: API_REFERENCE.md

Base path: http://localhost:8080/api/v1

Resource Base path
Authentication /api/v1/auth
Tools /api/v1/tools
Categories /api/v1/categories
Rentals /api/v1/rentals
Reviews /api/v1/reviews
Comments /api/v1/comments
Moderation /api/v1/moderation

About

REST API for tool and equipment rental. Spring Boot 3.2 · Java 21 · Clean Architecture (Onion) · JWT · MariaDB

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages