Data Access Layer (Repositories)
Relevant source files
The following files were used as context for generating this wiki page:- src/main/java/com/paymaster/backend/domain/repository/CustomerRepository.java
- src/main/java/com/paymaster/backend/domain/repository/ContractRepository.java
- src/main/java/com/paymaster/backend/domain/repository/InstallmentRepository.java
- src/main/java/com/paymaster/backend/domain/entity/Customer.java
- src/main/java/com/paymaster/backend/domain/service/DashboardService.java
- src/main/java/com/paymaster/backend/presentation/controller/HomeController.java
The Data Access Layer (DAL) in the PayMaster application is built upon the Spring Data JPA framework. It is responsible for all database interactions, providing a clean abstraction layer between the business logic (services) and the persistence layer. The DAL consists of several repository interfaces that extend JpaRepository, which automatically provides standard CRUD (Create, Read, Update, Delete) operations for the application's core entities: Customer, Contract, and Installment.
This layer also defines custom query methods using both Spring Data's query derivation mechanism and explicit JPQL queries via the @Query annotation. These custom methods encapsulate complex database lookups, aggregations, and searches, which are consumed by services like DashboardService and CustomerService to fulfill business requirements.
Architecture Overview
The following diagram illustrates the flow of data from the presentation layer through the service layer to the repositories.
Sources: src/main/java/com/paymaster/backend/presentation/controller/HomeController.java, src/main/java/com/paymaster/backend/domain/service/DashboardService.java, src/main/java/com/paymaster/backend/domain/repository/CustomerRepository.java, src/main/java/com/paymaster/backend/domain/repository/ContractRepository.java, src/main/java/com/paymaster/backend/domain/repository/InstallmentRepository.java
Entity Relationship Diagram
The repositories manage entities that are interconnected. The diagram below shows the relationships between the main entities.
Core Repositories
CustomerRepository
This repository manages persistence for the Customer entity. It provides methods for finding customers by unique identifiers, checking for existence, and performing paginated searches.
Sources: src/main/java/com/paymaster/backend/domain/repository/CustomerRepository.java
Key Methods
| Method Signature | Description |
|---|---|
Optional<Customer> findByNationalCode(String nationalCode) | Finds a customer by their unique national code. |
Optional<Customer> findByMobile(String mobile) | Finds a customer by their mobile number. |
boolean existsByNationalCodeAndIdNot(String nationalCode, Long id) | Checks if a national code is used by another customer (useful for updates). |
boolean existsByMobileAndIdNot(String mobile, Long id) | Checks if a mobile number is used by another customer. |
long countByStatus(CustomerStatus status) | Counts customers with a specific status (e.g., ACTIVE). |
List<Customer> findByStatus(CustomerStatus status) | Retrieves all customers with a specific status. |
Page<Customer> search(String keyword, Pageable pageable) | Performs a case-insensitive search on customer's full name, national code, or mobile number, with pagination. |
Custom Search Query
The search method uses a custom JPQL query to look for a keyword across multiple fields.
// src/main/java/com/paymaster/backend/domain/repository/CustomerRepository.java:36-41
@Query("SELECT c FROM Customer c WHERE " +
"LOWER(c.fullName) LIKE LOWER(CONCAT('%', :keyword, '%')) OR " +
"c.nationalCode LIKE CONCAT('%', :keyword, '%') OR " +
"c.mobile LIKE CONCAT('%', :keyword, '%')")
Page<Customer> search(@Param("keyword") String keyword, Pageable pageable);
Sources: src/main/java/com/paymaster/backend/domain/repository/CustomerRepository.java:36-41
ContractRepository
This repository is responsible for the Contract entity. It includes methods for retrieving contracts based on customer, status, and for complex financial reporting, such as finding overdue contracts.
Sources: src/main/java/com/paymaster/backend/domain/repository/ContractRepository.java
Key Methods
| Method Signature | Description |
|---|---|
List<Contract> findByCustomerId(Long customerId) | Finds all contracts associated with a specific customer ID. |
Page<Contract> findByStatus(ContractStatus status, Pageable pageable) | Retrieves a paginated list of contracts filtered by status. |
long countByStatus(ContractStatus status) | Counts contracts with a specific status. |
List<Contract> findOverdueContracts(LocalDate today) | Finds all contracts that have at least one unpaid installment with a due date before today. |
Long sumTotalAmountByStatus(ContractStatus status) | Calculates the sum of totalAmount for all contracts of a given status. |
Overdue Contracts Query
The findOverdueContracts method uses a subquery to identify contracts with overdue installments. This is a critical query for financial monitoring.
// src/main/java/com/paymaster/backend/domain/repository/ContractRepository.java:29-34
@Query("SELECT DISTINCT c FROM Contract c JOIN c.installments i WHERE " +
"c.status = 'ACTIVE' AND " +
"i.status = 'UNPAID' AND " +
"i.dueDate < :today")
List<Contract> findOverdueContracts(@Param("today") LocalDate today);
Sources: src/main/java/com/paymaster/backend/domain/repository/ContractRepository.java:29-34
InstallmentRepository
This repository handles the Installment entity. It provides essential methods for financial calculations, finding installments by date ranges, and identifying overdue payments. These methods are heavily used by the DashboardService to generate system statistics.
Sources: src/main/java/com/paymaster/backend/domain/repository/InstallmentRepository.java
Key Methods
| Method Signature | Description |
|---|---|
List<Installment> findByContractIdOrderByDueDateAsc(Long contractId) | Retrieves all installments for a contract, sorted by due date. |
List<Installment> findDueInDateRange(LocalDate start, LocalDate end) | Finds all unpaid installments due within a specific date range. |
List<Installment> findOverdue(LocalDate today) | Finds all unpaid installments with a due date before today. |
long countByStatus(InstallmentStatus status) | Counts installments with a specific status (e.g., OVERDUE). |
@Query("SELECT COALESCE(SUM(i.paidAmount), 0) FROM Installment i") Long sumPaidAmount() | Calculates the total amount paid across all installments. |
@Query(...) Long sumOverdueAmount(LocalDate today) | Calculates the total remaining amount of all overdue installments. |
@Query("SELECT COALESCE(SUM(i.paidPenalty), 0) FROM Installment i") Long sumPaidPenalty() | Calculates the total penalty fees paid across all installments. |
Usage in Services
The service layer, particularly DashboardService, relies heavily on the aggregation methods in the repositories to compile statistics for the main dashboard.
This diagram shows how DashboardService uses the repositories to gather stats.
Summary
The Data Access Layer of the PayMaster application effectively leverages Spring Data JPA to create a robust and maintainable persistence layer. By extending JpaRepository, it reduces boilerplate code for standard operations. Furthermore, it defines clear, purpose-driven custom queries that encapsulate complex business logic, such as financial reporting and searching. This design allows the service layer to remain clean and focused on orchestrating business processes without being concerned with the underlying database implementation details.