Project Structure
Choosing a project structure is like picking a house blueprint—it dictates where your code "lives" and how it socializes with neighbors.
Let's check how we can group related classes in Java and what are the recommended approaches.
Packages & the main Class Rule
Packages are Java’s way of grouping classes (like folders).
Critical Rule: Your main class (annotated with @SpringBootApplication) defines the root package.
- All other packages you create must be subpackages of this root (e.g., if your main class is in 
com.your.app, createcom.your.app.domain, notcom.domain). - Why? Spring Boot automatically scans classes in the root package and its subpackages. Classes outside won’t be detected unless explicitly configured.
- Avoid fighting against this default unless necessary: Spring Boot relies on this hierarchy.
 
 
Default Project Structure
When you generate a Spring Boot project (more on how to generate a project in the Spring Initializr section), you get a standardized folder and file structure.
your-project/  
├── src/  
│   ├── main/  
│   │   ├── java/  
│   │   │   └── com/example/demo/  
│   │   │       └── DemoApplication.java
│   │   └── resources/  
│   │       ├── static/
│   │       ├── templates/
│   │       └── application.properties (or application.yml)
│   └── test/  
│       └── java/com/example/demo/  
├── .gitignore
├── pom.xml (or build.gradle)
└── HELP.md
DemoApplication.java: The entry point of your app. Annotated with@SpringBootApplicationto enable autoconfiguration.application.properties(orapplication.yml): Central configuration file for database URLs, server ports, logging, etc.static/andtemplates/, empty by default. Used for web assets:pom.xml(Maven) orbuild.gradle(Gradle): Defines dependencies and plugins.test/: Preconfigured for JUnit tests (More about this in the Unit Testing section). It has a skeleton test classDemoApplicationTests.javathat verifies the app context loads.
Picking an Architecture
Let's do an example of a simple application that:
- Exposes a GET /users REST API endpoint.
 - Gets user information from an H2 database.
 - Supplements that data with information from an external API via FeignClient.
 
For this example, let's assume:
- Our application manages users.
 - Basic user info (id, name, email) is stored in a H2 database.
 - Additional user details (profile picture, status, etc.) are fetched from an external API.
 
Follow Clean Architecture
- Dependencies always point inward.
 - The domain being the most independent layer, and each outer layer depends on the inner ones.
 
src/test folder is omitted for simplicity.
src/
└── main/
    ├── java/
    │   └── com/example/demo/                         // Base package
    │       ├── DemoApplication.java                  // Spring Boot main application class
    │       │
    │       ├── domain/                               // ENTERPRISE BUSINESS RULES
    │       │   ├── entity/
    │       │   │   └── User.java                     // Core domain entity
    │       │   └── repository/
    │       │       └── UserRepository.java           // Repository interface
    │       │
    │       ├── application/                          // APPLICATION BUSINESS RULES
    │       │   ├── dto/
    │       │   │   ├── UserDto.java                  // Application data transfer object
    │       │   │   └── UserProfileDto.java           // Profile data DTO
    │       │   ├── port/
    │       │   │   ├── input/
    │       │   │   │   └── UserService.java          // Input port interface
    │       │   │   └── output/
    │       │   │       └── ExternalUserProfileService.java  // Output port
    │       │   └── service/
    │       │       └── UserServiceImpl.java          // Use case implementation
    │       │
    │       ├── infrastructure/                       // INTERFACE ADAPTERS & FRAMEWORKS/DRIVERS
    │       │   ├── persistence/
    │       │   │   ├── entity/
    │       │   │   │   └── UserEntity.java           // JPA entity (Framework)
    │       │   │   ├── repository/
    │       │   │   │   └── UserJpaRepository.java    // Spring Data repo (Framework)
    │       │   │   └── adapter/
    │       │   │       └── UserRepositoryAdapter.java // DB adapter (Interface Adapter)
    │       │   ├── external/
    │       │   │   ├── client/
    │       │   │   │   └── ExternalUserProfileClient.java  // Feign client (Framework)
    │       │   │   ├── dto/
    │       │   │   │   └── ExternalUserProfileDto.java     // External API DTO (Interface Adapter)
    │       │   │   └── adapter/
    │       │   │       └── ExternalUserProfileAdapter.java // API adapter (Interface Adapter)
    │       │   └── config/
    │       │       └── FeignClientConfig.java        // Config class (Framework)
    │       │
    │       └── presentation/                         // INTERFACE ADAPTERS
    │           ├── rest/
    │           │   └── UserController.java           // REST controller
    │           └── dto/
    │               └── UserResponse.java             // HTTP response DTO
    │
    └── resources/                                    // FRAMEWORKS & DRIVERS
        └── application.properties                    // Application configuration

Follow Hexagonal Architecture
- External actors interacting with the application (driver side).
 - Domain core implementing business logic.
 - External services used by the application (driven side).
 - The ports (interfaces) ensure loose coupling between these layers, making the application more maintainable and testable.
 
src/test folder is omitted for simplicity.
src/
└── main/
    ├── java/
    │   └── com/example/demo/
    │       │── UserManagementApplication.java  // Spring Boot application entry point
    │       │
    │       ├── domain/
    │       │   ├── model/
    │       │   │   ├── User.java                  // Core domain entity representing user
    │       │   │   └── UserDetails.java           // Value object for additional user details
    │       │   ├── port/
    │       │   │   ├── in/
    │       │   │   │   └── UserService.java       // Primary port defining user operations
    │       │   │   └── out/
    │       │   │       ├── UserRepository.java    // Secondary port for database operations
    │       │   │       └── UserDetailsProvider.java // Secondary port for external API operations
    │       │   └── service/
    │       │       └── UserServiceImpl.java       // Implementation of UserService (domain logic)
    │       │
    │       ├── adapter/
    │       │   ├── in/
    │       │   │   └── rest/
    │       │   │       ├── UserController.java    // REST controller adapting HTTP requests
    │       │   │       ├── dto/
    │       │   │       │   └── UserResponseDTO.java // DTO for API responses
    │       │   │       └── mapper/
    │       │   │           └── UserMapper.java    // Maps between domain models and DTOs
    │       │   └── out/
    │       │       ├── jpa/
    │       │       │   ├── entity/
    │       │       │   │   └── UserEntity.java    // JPA entity for database operations
    │       │       │   ├── repository/
    │       │       │   │   └── SpringDataUserRepository.java // Spring Data JPA repository
    │       │       │   ├── mapper/
    │       │       │   │   └── UserEntityMapper.java // Maps between domain User and UserEntity
    │       │       │   └── UserRepositoryAdapter.java // Implements UserRepository using Spring Data
    │       │       └── rest/
    │       │           ├── client/
    │       │           │   └── UserDetailsClient.java // FeignClient for external API
    │       │           ├── dto/
    │       │           │   └── ExternalUserDetailsDTO.java // DTO for external API responses
    │       │           ├── mapper/
    │       │           │   └── UserDetailsMapper.java // Maps between external DTO and domain model
    │       │           └── UserDetailsProviderAdapter.java // Implements UserDetailsProvider using FeignClient
    │       │
    │       └── config/
    │           ├── DatabaseConfig.java         // H2 database configuration
    │           └── FeignClientConfig.java      // FeignClient configuration
    │
    └── resources/
        └── application.properties              // Application configuration properties

Is Mandatory to Follow an Architecture?
No. Spring doesn’t enforce names or layers. You could write everything in a single class. But these conventions solve the readability problem: developers instantly understand a class by its name.
Personal Recommendations
I feel that Hexagonal Architecture makes coding easier to understand (or at least is the one that quickly clicked on me). Having said that, I don't follow it word by word, and that's fine.
- Nobody really follows one architecture to the finest details: Every place I worked tried to follow Clean Architecture but deviated somewhere mid-development and now is whatever.
 - Is ok to bend the rules: Small projects might combine layers.
 - Consistency > perfection: Agree with your team on a structure and stick to it. Refactor later if needed.
- If your team uses different terms (e.g., 
DataManagerinstead ofRepository), consistency matters more than the name itself. 
 - If your team uses different terms (e.g.,