⬅️ Back to Architecture Index

Layers Architecture Overview

Introduction

Smart Supply Pro’s backend is organized into five distinct logical layers, each with specific responsibilities and clear separation of concerns. This layered architecture enables:

  • Maintainability: Changes in one layer don’t cascade to others
  • Testability: Each layer can be tested independently with mocks
  • Scalability: Layers can be scaled independently based on demand
  • Clarity: Clear responsibility boundaries reduce cognitive overhead

The Five Layers

1. Controller Layer (HTTP Entry Point)

Location: src/main/java/.../controller/

Handles all HTTP concerns: routing, request/response mapping, validation triggering, authorization checks.

Key Components: - SupplierController - Supplier CRUD endpoints - InventoryItemController - Inventory management - StockHistoryController - Audit trail queries - AnalyticsController - Reporting endpoints - AuthController - OAuth2 callbacks

Responsibilities: - Route HTTP requests to handlers - Validate incoming DTOs - Check user authorization - Convert HTTP β†”οΈŽ DTOs - Build HTTP responses with proper status codes

Learn More: πŸ“„ Controller Layer


2. Service Layer (Business Logic)

Location: src/main/java/.../service/

The business logic heart of the application. Services orchestrate complex operations, manage transactions, validate business rules, and handle domain logic.

Key Services: - SupplierService - Supplier lifecycle management - InventoryItemService - Item and stock tracking - StockHistoryService - Audit trail management - AnalyticsService - Business intelligence

Responsibilities: - Execute business logic - Manage transaction boundaries - Validate business rules - Translate exceptions to HTTP status codes - Transform between DTOs and entities - Set audit logging

Learn More: πŸ“„ Service Layer


3. Repository Layer (Data Access)

Location: src/main/java/.../repository/

Abstracts database interactions behind repository interfaces. Built on Spring Data JPA, repositories provide CRUD operations and custom queries.

Key Repositories: - SupplierRepository - Supplier data access - InventoryItemRepository - Item persistence and queries - StockHistoryRepository - Audit entry access - AppUserRepository - User authentication data

Responsibilities: - Encapsulate SQL/JPQL queries - Manage entity persistence - Handle pagination and sorting - Provide query results to services - Manage transaction boundaries with database

Learn More: πŸ“„ Repository Layer


4. Domain Model & Data Layer (Entities)

Location: src/main/java/.../model/ and src/main/java/.../enums/

Defines JPA entities that map to database tables. These are the core domain objects representing business concepts.

Key Entities: - Supplier - Goods providers - InventoryItem - Products in inventory - StockHistory - Immutable audit trail - AppUser - OAuth2 principals - Enumerations - Role and StockChangeReason types

Responsibilities: - Map database schema to Java objects - Define entity relationships (foreign keys) - Enforce data constraints (unique, not null) - Track audit information (creator, timestamp) - Support optimistic locking with version fields

Learn More: πŸ“„ Domain Model & Data Layer


5. Infrastructure & Cross-Cutting Concerns (Support Services)

Location: src/main/java/.../config/, src/main/java/.../security/, src/main/java/.../validation/, src/main/java/.../exception/, src/main/java/.../mapper/

Provides foundational services and handles concerns that span multiple layers.

Key Components: - Security: OAuth2 authentication, authorization, @PreAuthorize - Validation: Custom validators for business rules - Exception Handling: Global exception handler, error responses - Data Mapping: DTO β†”οΈŽ Entity converters - Configuration: Spring beans, application properties

Responsibilities: - Authenticate and authorize users - Validate inputs across all layers - Handle exceptions consistently - Transform data between representations - Configure Spring beans and properties

Learn More: πŸ“„ Infrastructure & Cross-Cutting Concerns


Layered Architecture Diagram

graph TB Client["Client
REST Requests"] subgraph "Layer 1: Presentation" Controllers["Controllers
SupplierController
InventoryItemController
AnalyticsController"] end subgraph "Layer 2: Business Logic" Services["Services
SupplierService
InventoryItemService
AnalyticsService"] Validators["Validators
SupplierValidator
InventoryItemValidator"] end subgraph "Layer 3: Data Access" Repositories["Repositories
SupplierRepository
InventoryItemRepository
StockHistoryRepository"] end subgraph "Layer 4: Domain Model" Entities["Entities
Supplier
InventoryItem
StockHistory
AppUser"] end subgraph "Layer 5: Infrastructure" Security["Security
OAuth2, @PreAuthorize"] Exception["Exception Handler
GlobalExceptionHandler"] Mapper["Mappers
DTO ↔ Entity"] Config["Configuration
Spring Beans"] end Database["Database
Oracle/PostgreSQL"] Client -->|HTTP| Controllers Controllers -->|Call| Services Services -->|Call| Validators Services -->|Call| Repositories Repositories -->|Query/Persist| Entities Entities -->|Map| Database Controllers -->|Use| Security Controllers -->|Use| Mapper Services -->|Use| Exception Services -->|Use| Mapper Security -.->|Protect| Controllers Exception -.->|Handle| Services Config -.->|Configure| Controllers Config -.->|Configure| Services style Client fill:#e3f2fd style Controllers fill:#bbdefb style Services fill:#90caf9 style Validators fill:#fff9c4 style Repositories fill:#64b5f6 style Entities fill:#42a5f5 style Security fill:#ef9a9a style Exception fill:#ef9a9a style Mapper fill:#a5d6a7 style Config fill:#c8e6c9 style Database fill:#0277bd

Request Flow Through Layers

Here’s how a typical request (creating a supplier) flows through all layers:

1. HTTP POST /api/suppliers
   Client β†’ Network
   ↓
2. SupplierController.create(CreateSupplierDTO)
   - Receives JSON request body
   - @Valid validates DTO fields
   - @PreAuthorize("hasRole('ADMIN')") checks authorization
   ↓
3. SupplierService.create(CreateSupplierDTO)
   - SupplierValidator validates uniqueness
   - Converts DTO β†’ Entity
   - Sets createdBy from SecurityContext
   ↓
4. SupplierRepository.save(Supplier)
   - Executes INSERT to SUPPLIER table
   - Handles primary key generation
   - Triggers database constraints
   ↓
5. Database executes INSERT
   - Validates UNIQUE constraint on NAME
   - Stores record in SUPPLIER table
   ↓
6. Repository returns saved entity
   - With generated ID
   ↓
7. Service converts Entity β†’ DTO
   ↓
8. Controller builds HTTP response
   - Status: 201 CREATED
   - Body: SupplierDTO
   - Header: Location: /api/suppliers/{id}
   ↓
9. HTTP Response
   Client ← Network

Layer Communication Patterns

Downward Communication (Normal Flow)

Layers call the layer directly below them:

Controller β†’ Service β†’ Repository β†’ Database
  • Controllers delegate to services
  • Services delegate to repositories
  • Repositories delegate to database

Upward Communication (Error Flow)

Exceptions propagate upward to be handled:

Database β†’ Repository β†’ Service β†’ GlobalExceptionHandler β†’ HTTP Response
  • Database constraint violation
  • Repository translates to domain exception
  • Service lets exception propagate
  • GlobalExceptionHandler catches and translates to HTTP response

Cross-Layer Communication (Infrastructure)

Infrastructure components available to all layers:

All Layers ← Security, Validation, Exception Handling, Mapping, Configuration

Benefits of Layered Architecture

1. Separation of Concerns

Each layer has one clear responsibility. You know where to look for specific code.

2. Testability

Each layer can be unit tested in isolation by mocking layers below it.

// Test service without touching database
@ExtendWith(MockitoExtension.class)
class SupplierServiceCreateTest {
    @Mock
    private SupplierRepository repository;
    
    @InjectMocks
    private SupplierService service;
    
    // Tests run without database
}

3. Maintainability

Changes in one layer don’t cascade to others. Update database schema without touching services.

4. Scalability

Layers can be scaled independently. Cache the service layer, scale the database tier separately.

5. Clarity

New developers quickly understand where to add new features.

Dependency Rules

Key Principle: Never skip layers or call downward incorrectly.

βœ… Correct Dependencies:
  Controller β†’ Service β†’ Repository β†’ Database
  
❌ Incorrect Dependencies:
  Controller β†’ Repository (skips service logic)
  Repository β†’ Controller (upward communication)
  Service β†’ Service (cross-service dependencies)

Layer Decision Flow

When adding a new feature, ask:

1. Is it HTTP concern? β†’ Controller
2. Is it business logic? β†’ Service
3. Is it data access? β†’ Repository
4. Is it domain model? β†’ Entity
5. Is it cross-cutting? β†’ Infrastructure

Files in This Directory

File Purpose Audience
controller-layer.html HTTP API handling API developers, Controllers
service-layer.html Business logic Feature developers, Services
repository-layer.html Data persistence Database developers, Queries
model-layer.html Domain entities Data modelers, Entity authors
infrastructure/index.html Cross-cutting concerns All developers, Security/Exceptions

Quick Navigation

By Role:

By Activity:


⬅️ Back to Architecture Index