From f34ee622c91f5d08c6f5ff758952c8fd7f920c00 Mon Sep 17 00:00:00 2001
From: Leonardo <leomeireles55@hotmail.com>
Date: Wed, 29 Jan 2025 12:56:40 -0300
Subject: [PATCH] hotfix: enhance analytics endpoints with pagination support
 and update email templates

---
 pom.xml                                       |  39 ++-
 .../analytics/AnalyticsController.java        |  52 ++--
 .../analytics/AnalyticsHelperController.java  | 277 +++++++++---------
 .../BiochemistryAnalyticsController.java      |   8 +-
 .../CoagulationAnalyticsController.java       |  26 +-
 .../HematologyAnalyticsController.java        |  11 +-
 .../repositories/UserRepository.java          |  36 ++-
 .../analytics/AbstractAnalyticService.java    |  23 +-
 .../analytics/AnalyticHelperService.java      | 155 +++++-----
 .../BiochemistryAnalyticService.java          |  70 ++---
 .../analytics/CoagulationAnalyticService.java |  70 ++---
 .../analytics/HematologyAnalyticService.java  |  71 +++--
 .../analytics/IAnalyticHelperService.java     |  52 ++--
 .../services/email/EmailService.java          |  28 +-
 .../services/users/UserService.java           |   7 +-
 .../components/ControlRulesValidators.java    |  39 ++-
 .../utils/constants/EmailTemplate.java        |  10 +
 .../resources/application-local.properties    |   2 +-
 src/main/resources/application.properties     |   7 +-
 .../BiochemistryAnalyticControllerTest.java   | 225 +++++++-------
 .../CoagulationAnalyticControllerTest.java    | 199 +++++++------
 .../HematologyAnalyticControllerTest.java     | 200 ++++++-------
 .../controllers/UsersControllerTest.java      |  66 +++--
 .../services/AnalyticHelperServiceTests.java  |  16 +-
 .../services/UserServiceTest.java             | 195 ++++++------
 25 files changed, 978 insertions(+), 906 deletions(-)

diff --git a/pom.xml b/pom.xml
index 9338de8..cd5efb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,9 +45,10 @@
             <artifactId>spring-boot-starter-hateoas</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.flywaydb</groupId>
-            <artifactId>flyway-core</artifactId>
-            <version>11.2.0</version>
+            <groupId>org.mariadb.jdbc</groupId>
+            <artifactId>mariadb-java-client</artifactId>
+            <version>3.5.1</version>
+            <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.flywaydb</groupId>
@@ -62,11 +63,6 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-validation</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.mariadb.jdbc</groupId>
-            <artifactId>mariadb-java-client</artifactId>
-            <version>3.5.1</version>
-        </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
@@ -142,4 +138,31 @@
             </plugin>
         </plugins>
     </build>
+
+
+    <dependencyManagement>
+    
+
+        <dependencies>
+
+            <dependency>
+                <groupId>com.google.errorprone</groupId>
+                <artifactId>error_prone_annotations</artifactId>
+                <version>2.36.0</version>
+            </dependency>
+
+
+            <dependency>
+                <groupId>org.checkerframework</groupId>
+                <artifactId>checker-qual</artifactId>
+                <version>3.37.0</version>
+            </dependency>
+
+        
+
+            
+
+        </dependencies>
+
+    </dependencyManagement>
 </project>
\ No newline at end of file
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsController.java b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsController.java
index 01c9299..2f812c2 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsController.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsController.java
@@ -28,38 +28,38 @@
 @RestController()
 public abstract class AnalyticsController extends AnalyticsHelperController {
 
-    public AnalyticsController(AnalyticHelperService analyticHelperService) {
-        super(analyticHelperService);
-    }
+	protected AnalyticsController(AnalyticHelperService analyticHelperService) {
+		super(analyticHelperService);
+	}
 
-    @GetMapping()
-    public abstract ResponseEntity<CollectionModel<EntityModel<AnalyticsDTO>>> getAllAnalytics(
-            @PageableDefault(sort = "date",
-                    direction = Sort.Direction.DESC) @ParameterObject Pageable pageable);
+	@GetMapping()
+	public abstract ResponseEntity<CollectionModel<EntityModel<AnalyticsDTO>>> getAllAnalytics(
+			@PageableDefault(sort = "date",
+					direction = Sort.Direction.DESC) @ParameterObject Pageable pageable);
 
 
-    @GetMapping("/date-range")
-    public abstract ResponseEntity<Page<AnalyticsDTO>> getAnalyticsDateBetween(
-            @RequestParam("startDate") LocalDateTime startDate,
-            @RequestParam("endDate") LocalDateTime endDate, @PageableDefault(sort = "date",
-                    direction = Sort.Direction.DESC) @ParameterObject Pageable pageable);
+	@GetMapping("/date-range")
+	public abstract ResponseEntity<Page<AnalyticsDTO>> getAnalyticsDateBetween(
+			@RequestParam("startDate") LocalDateTime startDate,
+			@RequestParam("endDate") LocalDateTime endDate, @PageableDefault(sort = "date",
+					direction = Sort.Direction.DESC) @ParameterObject Pageable pageable);
 
-    @GetMapping("/level-date-range")
-    public abstract ResponseEntity<Page<AnalyticsDTO>> getAllAnalyticsByLevelDateRange(
-            @RequestParam String level, @RequestParam("startDate") LocalDateTime startDate,
-            @RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable);
+	@GetMapping("/level-date-range")
+	public abstract ResponseEntity<Page<AnalyticsDTO>> getAllAnalyticsByLevelDateRange(
+			@RequestParam String level, @RequestParam("startDate") LocalDateTime startDate,
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable);
 
-    @GetMapping("/name-and-level-date-range")
-    public abstract ResponseEntity<List<AnalyticsDTO>> getAllAnalyticsByNameAndLevelDateRange(
-            @RequestParam String name, @RequestParam String level,
-            @RequestParam("startDate") LocalDateTime startDate,
-            @RequestParam("endDate") LocalDateTime endDate);
+	@GetMapping("/name-and-level-date-range")
+	public abstract ResponseEntity<List<AnalyticsDTO>> getAllAnalyticsByNameAndLevelDateRange(
+			@RequestParam String name, @RequestParam String level,
+			@RequestParam("startDate") LocalDateTime startDate,
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable);
 
-    @GetMapping("/mean-standard-deviation")
-    public abstract ResponseEntity<MeanAndStdDeviationDTO> getMeanAndStandardDeviation(
-            @RequestParam String name, @RequestParam String level,
-            @RequestParam("startDate") LocalDateTime startDate,
-            @RequestParam("endDate") LocalDateTime endDate);
+	@GetMapping("/mean-standard-deviation")
+	public abstract ResponseEntity<MeanAndStdDeviationDTO> getMeanAndStandardDeviation(
+			@RequestParam String name, @RequestParam String level,
+			@RequestParam("startDate") LocalDateTime startDate,
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable);
 }
 
 
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsHelperController.java b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsHelperController.java
index b3d3afe..c469597 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsHelperController.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/AnalyticsHelperController.java
@@ -25,145 +25,140 @@
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
 
 public class AnalyticsHelperController {
-    private final AnalyticHelperService analyticHelperService;
-
-    public AnalyticsHelperController(AnalyticHelperService analyticHelperService) {
-        this.analyticHelperService = analyticHelperService;
-    }
-
-    @GetMapping("/{id}")
-    public ResponseEntity<AnalyticsDTO> getAnalyticsById(@PathVariable Long id) {
-        return ResponseEntity.ok(analyticHelperService.findOneById(id));
-    }
-
-    @DeleteMapping("/{id}")
-    @Transactional
-    public ResponseEntity<Void> deleteAnalyticsResultById(@PathVariable Long id) {
-        analyticHelperService.deleteAnalyticsById(id);
-        return ResponseEntity.noContent().build();
-    }
-
-    @PostMapping
-    @Transactional
-    public ResponseEntity<List<AnalyticsDTO>> postAnalytics(
-            @Valid @RequestBody List<@Valid AnalyticsDTO> values) {
-        analyticHelperService.saveNewAnalyticsRecords(values);
-        return ResponseEntity.status(201).build();
-    }
-
-    @PatchMapping()
-    public ResponseEntity<Void> updateAnalyticsMean(
-            @Valid @RequestBody UpdateAnalyticsMeanDTO updateAnalyticsMeanDTO) {
-        analyticHelperService.updateAnalyticsMeanByNameAndLevelAndLevelLot(
-                updateAnalyticsMeanDTO.name(), updateAnalyticsMeanDTO.level(),
-                updateAnalyticsMeanDTO.levelLot(), updateAnalyticsMeanDTO.mean());
-        return ResponseEntity.noContent().build();
-    }
-
-    @GetMapping("/grouped-by-level")
-    public ResponseEntity<List<GroupedResultsByLevelDTO>> getGroupedByLevel(@RequestParam String name,
-                                                                            @RequestParam("startDate") LocalDateTime startDate,
-                                                                            @RequestParam("endDate") LocalDateTime endDate) {
-        List<GroupedResultsByLevelDTO> groupedData =
-                analyticHelperService.findAnalyticsWithGroupedResults(name, startDate, endDate);
-        return ResponseEntity.ok(groupedData);
-    }
-
-    @GetMapping("/grouped-by-level/mean-deviation")
-    public ResponseEntity<List<GroupedMeanAndStdByLevelDTO>> getMeanAndDeviationGrouped(
-            @RequestParam String name, @RequestParam("startDate") LocalDateTime startDate,
-            @RequestParam("endDate") LocalDateTime endDate) {
-        List<GroupedMeanAndStdByLevelDTO> groupedData = analyticHelperService
-                .calculateGroupedMeanAndStandardDeviation(name, startDate, endDate);
-        return ResponseEntity.ok(groupedData);
-    }
-
-    public ResponseEntity<CollectionModel<EntityModel<AnalyticsDTO>>> getAllAnalyticsWithLinks(
-            List<String> names, Pageable pageable) {
-        Page<AnalyticsDTO> resultsList =
-                analyticHelperService.findAnalyticsPagedByNameIn(names, pageable);
-
-        var entityModels = resultsList.getContent().stream()
-                                      .map(record -> createEntityModel(record, pageable)).collect(Collectors.toList());
-
-        var result = addPaginationLinks(CollectionModel.of(entityModels), resultsList, pageable);
-        return ResponseEntity.ok(result);
-    }
-
-    public ResponseEntity<CollectionModel<EntityModel<AnalyticsDTO>>> getAnalyticsByDateBetweenWithLinks(
-            List<String> names, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
-
-        Page<AnalyticsDTO> analyticsRecordPaged = analyticHelperService
-                .findAnalyticsByNameInAndDateBetweenWithLinks(names, startDate, endDate, pageable);
-
-        if (analyticsRecordPaged == null) {
-            return ResponseEntity.noContent().build();
-        }
-
-        var entityModels = analyticsRecordPaged.getContent().stream()
-                                               .map(record -> createEntityModel(record, pageable)).collect(Collectors.toList());
-
-        var collectionModel = CollectionModel.of(entityModels);
-        var result = addPaginationLinks(collectionModel, analyticsRecordPaged, pageable);
-
-        return ResponseEntity.ok(result);
-    }
-
-    EntityModel<AnalyticsDTO> createEntityModel(AnalyticsDTO record, Pageable pageable) {
-        return EntityModel.of(record, Link.of(ServletUriComponentsBuilder.fromCurrentContextPath()
-                                                                         .path("/backend-api")
-                                                                         .path(linkTo(methodOn(getClass()).getAnalyticsById(record.id())).toUri().getPath())
-                                                                         .toUriString()).withSelfRel());
-    }
-
-    private CollectionModel<EntityModel<AnalyticsDTO>> addPaginationLinks(
-            CollectionModel<EntityModel<AnalyticsDTO>> collectionModel,
-            Page<AnalyticsDTO> page, Pageable pageable) {
-
-        UriComponentsBuilder uriBuilder =
-                ServletUriComponentsBuilder.fromCurrentRequest().replacePath("/backend-api"
-                                                                             +
-                                                                             ServletUriComponentsBuilder.fromCurrentRequest().build().getPath());
-
-        // Clear any existing collection-level links to prevent duplication
-        // collectionModel.removeLinks();
-
-        // Link for the first page
-        collectionModel.add(Link.of(uriBuilder.replaceQueryParam("page", 0)
-                                              .replaceQueryParam("size", pageable.getPageSize()).toUriString()
-                                              .replace("%2520", "%20")).withRel("first"));
-
-        // Link for the previous page if it exists
-        if (page.hasPrevious()) {
-            collectionModel
-                    .add(Link.of(uriBuilder.replaceQueryParam("page", pageable.getPageNumber() - 1)
-                                           .replaceQueryParam("size", pageable.getPageSize()).toUriString()
-                                           .replace("%2520", "%20")).withRel("prev"));
-        }
-
-        // Link for the next page if it exists
-        if (page.hasNext()) {
-            collectionModel
-                    .add(Link.of(uriBuilder.replaceQueryParam("page", pageable.getPageNumber() + 1)
-                                           .replaceQueryParam("size", pageable.getPageSize()).toUriString()
-                                           .replace("%2520", "%20")).withRel("next"));
-        }
-
-        // Link for the last page
-        collectionModel.add(Link.of(uriBuilder.replaceQueryParam("page", page.getTotalPages() - 1)
-                                              .replaceQueryParam("size", pageable.getPageSize()).toUriString()
-                                              .replace("%2520", "%20")).withRel("last"));
-
-        // Add metadata about the current page
-        collectionModel.add(Link.of(uriBuilder.replaceQueryParam("page", pageable.getPageNumber())
-                                              .replaceQueryParam("size", pageable.getPageSize()).toUriString()
-                                              .replace("%2520", "%20")).withRel("current-page"));
-
-        // collectionModel.add(Link.of(String.valueOf(page.getTotalPages())).withSelfRel());
-        collectionModel.add(Link.of(String.valueOf(page.getTotalPages()), "totalPages"));
-        collectionModel.add(Link.of(String.valueOf(page.getNumber()), "currentPage"));
-
-
-        return collectionModel;
-    }
+	private final AnalyticHelperService analyticHelperService;
+
+	public AnalyticsHelperController(AnalyticHelperService analyticHelperService) {
+		this.analyticHelperService = analyticHelperService;
+	}
+
+	@GetMapping("/{id}")
+	public ResponseEntity<AnalyticsDTO> getAnalyticsById(@PathVariable Long id) {
+		return ResponseEntity.ok(analyticHelperService.findOneById(id));
+	}
+
+	@DeleteMapping("/{id}")
+	@Transactional
+	public ResponseEntity<Void> deleteAnalyticsResultById(@PathVariable Long id) {
+		analyticHelperService.deleteAnalyticsById(id);
+		return ResponseEntity.noContent().build();
+	}
+
+	@PostMapping
+	@Transactional
+	public ResponseEntity<List<AnalyticsDTO>> postAnalytics(
+			@Valid @RequestBody List<@Valid AnalyticsDTO> values) {
+		analyticHelperService.saveNewAnalyticsRecords(values);
+		return ResponseEntity.status(201).build();
+	}
+
+	@PatchMapping()
+	public ResponseEntity<Void> updateAnalyticsMean(
+			@Valid @RequestBody UpdateAnalyticsMeanDTO updateAnalyticsMeanDTO) {
+		analyticHelperService.updateAnalyticsMeanByNameAndLevelAndLevelLot(
+				updateAnalyticsMeanDTO.name(), updateAnalyticsMeanDTO.level(),
+				updateAnalyticsMeanDTO.levelLot(), updateAnalyticsMeanDTO.mean());
+		return ResponseEntity.noContent().build();
+	}
+
+	@GetMapping("/grouped-by-level")
+	public ResponseEntity<List<GroupedResultsByLevelDTO>> getGroupedByLevel(
+			@RequestParam String name, @RequestParam("startDate") LocalDateTime startDate,
+			@RequestParam("endDate") LocalDateTime endDate, Pageable pageable) {
+		List<GroupedResultsByLevelDTO> groupedData = analyticHelperService
+				.findAnalyticsWithGroupedResults(name, startDate, endDate, pageable);
+		return ResponseEntity.ok(groupedData);
+	}
+
+	@GetMapping("/grouped-by-level/mean-deviation")
+	public ResponseEntity<List<GroupedMeanAndStdByLevelDTO>> getMeanAndDeviationGrouped(
+			@RequestParam String name, @RequestParam("startDate") LocalDateTime startDate,
+			@RequestParam("endDate") LocalDateTime endDate, Pageable pageable) {
+		List<GroupedMeanAndStdByLevelDTO> groupedData = analyticHelperService
+				.calculateGroupedMeanAndStandardDeviation(name, startDate, endDate, pageable);
+		return ResponseEntity.ok(groupedData);
+	}
+
+	public ResponseEntity<CollectionModel<EntityModel<AnalyticsDTO>>> getAllAnalyticsWithLinks(
+			List<String> names, Pageable pageable) {
+		Page<AnalyticsDTO> resultsList =
+				analyticHelperService.findAnalyticsPagedByNameIn(names, pageable);
+
+		var entityModels = resultsList.getContent().stream()
+				.map(record -> createEntityModel(record, pageable)).collect(Collectors.toList());
+
+		var result = addPaginationLinks(CollectionModel.of(entityModels), resultsList, pageable);
+		return ResponseEntity.ok(result);
+	}
+
+	public ResponseEntity<CollectionModel<EntityModel<AnalyticsDTO>>> getAnalyticsByDateBetweenWithLinks(
+			List<String> names, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
+
+		Page<AnalyticsDTO> analyticsRecordPaged = analyticHelperService
+				.findAnalyticsByNameInAndDateBetweenWithLinks(names, startDate, endDate, pageable);
+
+		if (analyticsRecordPaged == null) {
+			return ResponseEntity.noContent().build();
+		}
+
+		var entityModels = analyticsRecordPaged.getContent().stream()
+				.map(record -> createEntityModel(record, pageable)).collect(Collectors.toList());
+
+		var collectionModel = CollectionModel.of(entityModels);
+		var result = addPaginationLinks(collectionModel, analyticsRecordPaged, pageable);
+
+		return ResponseEntity.ok(result);
+	}
+
+	EntityModel<AnalyticsDTO> createEntityModel(AnalyticsDTO record, Pageable pageable) {
+		return EntityModel.of(record, Link.of(ServletUriComponentsBuilder.fromCurrentContextPath()
+				.path("/backend-api")
+				.path(linkTo(methodOn(getClass()).getAnalyticsById(record.id())).toUri().getPath())
+				.toUriString()).withSelfRel());
+	}
+
+	private CollectionModel<EntityModel<AnalyticsDTO>> addPaginationLinks(
+			CollectionModel<EntityModel<AnalyticsDTO>> collectionModel, Page<AnalyticsDTO> page,
+			Pageable pageable) {
+
+		UriComponentsBuilder uriBuilder =
+				ServletUriComponentsBuilder.fromCurrentRequest().replacePath("/backend-api"
+						+ ServletUriComponentsBuilder.fromCurrentRequest().build().getPath());
+
+		// Link for the first page
+		collectionModel.add(Link.of(uriBuilder.replaceQueryParam("page", 0)
+				.replaceQueryParam("size", pageable.getPageSize()).toUriString()
+				.replace("%2520", "%20")).withRel("first"));
+
+		// Link for the previous page if it exists
+		if (page.hasPrevious()) {
+			collectionModel
+					.add(Link.of(uriBuilder.replaceQueryParam("page", pageable.getPageNumber() - 1)
+							.replaceQueryParam("size", pageable.getPageSize()).toUriString()
+							.replace("%2520", "%20")).withRel("prev"));
+		}
+
+		// Link for the next page if it exists
+		if (page.hasNext()) {
+			collectionModel
+					.add(Link.of(uriBuilder.replaceQueryParam("page", pageable.getPageNumber() + 1)
+							.replaceQueryParam("size", pageable.getPageSize()).toUriString()
+							.replace("%2520", "%20")).withRel("next"));
+		}
+
+		// Link for the last page
+		collectionModel.add(Link.of(uriBuilder.replaceQueryParam("page", page.getTotalPages() - 1)
+				.replaceQueryParam("size", pageable.getPageSize()).toUriString()
+				.replace("%2520", "%20")).withRel("last"));
+
+		// Add metadata about the current page
+		collectionModel.add(Link.of(uriBuilder.replaceQueryParam("page", pageable.getPageNumber())
+				.replaceQueryParam("size", pageable.getPageSize()).toUriString()
+				.replace("%2520", "%20")).withRel("current-page"));
+
+		collectionModel.add(Link.of(String.valueOf(page.getTotalPages()), "totalPages"));
+		collectionModel.add(Link.of(String.valueOf(page.getNumber()), "currentPage"));
+
+
+		return collectionModel;
+	}
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/BiochemistryAnalyticsController.java b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/BiochemistryAnalyticsController.java
index 721b021..2373a6c 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/BiochemistryAnalyticsController.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/BiochemistryAnalyticsController.java
@@ -70,9 +70,9 @@ public ResponseEntity<Page<AnalyticsDTO>> getAllAnalyticsByLevelDateRange(
 	public ResponseEntity<List<AnalyticsDTO>> getAllAnalyticsByNameAndLevelDateRange(
 			@RequestParam String name, @RequestParam String level,
 			@RequestParam("startDate") LocalDateTime startDate,
-			@RequestParam("endDate") LocalDateTime endDate) {
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable) {
 		return ResponseEntity.ok(biochemistryAnalyticsService
-				.findAnalyticsByNameAndLevelAndDate(name, level, startDate, endDate));
+				.findAnalyticsByNameAndLevelAndDate(name, level, startDate, endDate, pageable));
 	}
 
 
@@ -81,8 +81,8 @@ public ResponseEntity<List<AnalyticsDTO>> getAllAnalyticsByNameAndLevelDateRange
 	public ResponseEntity<MeanAndStdDeviationDTO> getMeanAndStandardDeviation(
 			@RequestParam String name, @RequestParam String level,
 			@RequestParam("startDate") LocalDateTime startDate,
-			@RequestParam("endDate") LocalDateTime endDate) {
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable) {
 		return ResponseEntity.ok(biochemistryAnalyticsService
-				.calculateMeanAndStandardDeviation(name, level, startDate, endDate));
+				.calculateMeanAndStandardDeviation(name, level, startDate, endDate, pageable));
 	}
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/CoagulationAnalyticsController.java b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/CoagulationAnalyticsController.java
index a6fa107..f3b8af6 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/CoagulationAnalyticsController.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/CoagulationAnalyticsController.java
@@ -55,16 +55,6 @@ public ResponseEntity<Page<AnalyticsDTO>> getAnalyticsDateBetween(
 				.findAnalyticsByNameInAndDateBetween(names, startDate, endDate, pageable));
 	}
 
-	@Override
-	@GetMapping("/name-and-level-date-range")
-	public ResponseEntity<List<AnalyticsDTO>> getAllAnalyticsByNameAndLevelDateRange(
-			@RequestParam String name, @RequestParam String level,
-			@RequestParam("startDate") LocalDateTime startDate,
-			@RequestParam("endDate") LocalDateTime endDate) {
-		return ResponseEntity.ok(coagulationAnalyticsService
-				.findAnalyticsByNameAndLevelAndDate(name, level, startDate, endDate));
-	}
-
 	@Override
 	@GetMapping("/level-date-range")
 	public ResponseEntity<Page<AnalyticsDTO>> getAllAnalyticsByLevelDateRange(
@@ -75,14 +65,24 @@ public ResponseEntity<Page<AnalyticsDTO>> getAllAnalyticsByLevelDateRange(
 	}
 
 
+	@Override
+	@GetMapping("/name-and-level-date-range")
+	public ResponseEntity<List<AnalyticsDTO>> getAllAnalyticsByNameAndLevelDateRange(
+			@RequestParam String name, @RequestParam String level,
+			@RequestParam("startDate") LocalDateTime startDate,
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable) {
+		return ResponseEntity.ok(coagulationAnalyticsService
+				.findAnalyticsByNameAndLevelAndDate(name, level, startDate, endDate, pageable));
+	}
+
+
 	@Override
 	@GetMapping("/mean-standard-deviation")
 	public ResponseEntity<MeanAndStdDeviationDTO> getMeanAndStandardDeviation(
 			@RequestParam String name, @RequestParam String level,
 			@RequestParam("startDate") LocalDateTime startDate,
-			@RequestParam("endDate") LocalDateTime endDate) {
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable) {
 		return ResponseEntity.ok(coagulationAnalyticsService.calculateMeanAndStandardDeviation(name,
-				level, startDate, endDate));
-
+				level, startDate, endDate, pageable));
 	}
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/HematologyAnalyticsController.java b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/HematologyAnalyticsController.java
index 60ccd78..4e8c823 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/HematologyAnalyticsController.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/controllers/analytics/HematologyAnalyticsController.java
@@ -68,18 +68,21 @@ public ResponseEntity<Page<AnalyticsDTO>> getAllAnalyticsByLevelDateRange(
 	public ResponseEntity<List<AnalyticsDTO>> getAllAnalyticsByNameAndLevelDateRange(
 			@RequestParam String name, @RequestParam String level,
 			@RequestParam("startDate") LocalDateTime startDate,
-			@RequestParam("endDate") LocalDateTime endDate) {
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable) {
 		return ResponseEntity.ok(hematologyAnalyticsService.findAnalyticsByNameAndLevelAndDate(name,
-				level, startDate, endDate));
+				level, startDate, endDate, pageable));
 	}
 
+
 	@Override
 	@GetMapping("/mean-standard-deviation")
 	public ResponseEntity<MeanAndStdDeviationDTO> getMeanAndStandardDeviation(
 			@RequestParam String name, @RequestParam String level,
 			@RequestParam("startDate") LocalDateTime startDate,
-			@RequestParam("endDate") LocalDateTime endDate) {
+			@RequestParam("endDate") LocalDateTime endDate, @ParameterObject Pageable pageable) {
 		return ResponseEntity.ok(hematologyAnalyticsService.calculateMeanAndStandardDeviation(name,
-				level, startDate, endDate));
+				level, startDate, endDate, pageable));
 	}
+
+
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/repositories/UserRepository.java b/src/main/java/leonardo/labutilities/qualitylabpro/repositories/UserRepository.java
index f02d241..ac83e0a 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/repositories/UserRepository.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/repositories/UserRepository.java
@@ -10,28 +10,32 @@
 
 @Repository
 public interface UserRepository extends JpaRepository<User, Long> {
-    UserDetails getReferenceByUsername(String username);
-    User findByUsername(String username);
-    User findByEmail(String email);
+	UserDetails getReferenceByUsername(String username);
 
-    User findByUsernameOrEmail(String username, String email);
+	User findByUsername(String username);
 
-    UserDetails getReferenceByUsernameAndEmail(String userName, String Email);
+	User findByEmail(String email);
 
-    boolean existsByUsernameAndEmail(String userName, String Email);
+	User findByUsernameOrEmail(String username, String email);
 
-    @Transactional
-    @Modifying
-    @Query("UPDATE users u SET u.password = ?2 WHERE u.username = ?1")
-    void setPasswordWhereByUsername(String username, String newPassword);
+	boolean existsByUsernameOrEmail(String username, String email);
 
-    @Transactional
-    @Modifying
-    @Query("UPDATE users u SET u.password = ?2 WHERE u.email = ?1")
-    void setPasswordWhereByEmail(String email, String newPassword);
+	UserDetails getReferenceByUsernameAndEmail(String userName, String Email);
 
+	boolean existsByUsernameAndEmail(String userName, String Email);
 
-    boolean existsByUsername(String name);
+	@Transactional
+	@Modifying
+	@Query("UPDATE users u SET u.password = ?2 WHERE u.username = ?1")
+	void setPasswordWhereByUsername(String username, String newPassword);
 
-    boolean existsByEmail(String email);
+	@Transactional
+	@Modifying
+	@Query("UPDATE users u SET u.password = ?2 WHERE u.email = ?1")
+	void setPasswordWhereByEmail(String email, String newPassword);
+
+
+	boolean existsByUsername(String name);
+
+	boolean existsByEmail(String email);
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AbstractAnalyticService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AbstractAnalyticService.java
index 1ebe68b..ad357c1 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AbstractAnalyticService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AbstractAnalyticService.java
@@ -11,19 +11,18 @@
 
 public abstract class AbstractAnalyticService extends AnalyticHelperService {
 
-    public AbstractAnalyticService(AnalyticsRepository analyticsRepository, EmailService emailService,
-                                   ControlRulesValidators controlRulesValidators) {
-        super(analyticsRepository, emailService, controlRulesValidators);
-    }
+	public AbstractAnalyticService(AnalyticsRepository analyticsRepository,
+			EmailService emailService, ControlRulesValidators controlRulesValidators) {
+		super(analyticsRepository, emailService, controlRulesValidators);
+	}
 
-    @Override
-    public abstract List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable,
-                                                                   String name, String level);
+	@Override
+	public abstract List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
+			String level);
 
-    @Override
-    public abstract List<AnalyticsDTO>
-    findAnalyticsByNameAndLevelAndDate(String name,
-                                       String level, LocalDateTime dateStart, LocalDateTime dateEnd);
+	@Override
+	public abstract List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable);
 
-    public abstract String convertLevel(String level);
+	public abstract String convertLevel(String level);
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AnalyticHelperService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AnalyticHelperService.java
index 86425f6..ff3b1fe 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AnalyticHelperService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/AnalyticHelperService.java
@@ -27,39 +27,61 @@ public abstract class AnalyticHelperService implements IAnalyticHelperService {
 
 	private final AnalyticsRepository analyticsRepository;
 	private final EmailService emailService;
-	private final Pageable pageable = PageRequest.of(0, 100);
 	private final ControlRulesValidators controlRulesValidators;
 
 
-	public AnalyticHelperService(AnalyticsRepository analyticsRepository,
-								 EmailService emailService, ControlRulesValidators controlRulesValidators) {
+	protected AnalyticHelperService(AnalyticsRepository analyticsRepository,
+			EmailService emailService, ControlRulesValidators controlRulesValidators) {
 		this.analyticsRepository = analyticsRepository;
 		this.emailService = emailService;
 		this.controlRulesValidators = controlRulesValidators;
 	}
 
+	// VALIDATION METHODS
+	private void validateResultsNotEmpty(List<?> results, String message) {
+		if (results == null || results.isEmpty()) {
+			throw new CustomGlobalErrorHandling.ResourceNotFoundException(message);
+		}
+	}
+
 	public boolean isAnalyticsNonExistent(AnalyticsDTO values) {
 		return !analyticsRepository.existsByDateAndLevelAndName(values.date(), values.level(),
 				values.name());
 	}
 
-	private boolean isRuleBroken(AnalyticsDTO record) {
-		String rules = record.rules();
-		return ("+3s".equals(rules) || "-3s".equals(rules) || "-2s".equals(rules) || "+2s".equals(rules))
-				&& !BLACK_LIST.contains(record.name());
+	private boolean isRuleBroken(AnalyticsDTO analyticsDTO) {
+		String rules = analyticsDTO.rules();
+		return ("+3s".equals(rules) || "-3s".equals(rules) || "-2s".equals(rules)
+				|| "+2s".equals(rules));
 	}
 
-	public List<AnalyticsDTO> validateAnalyticsNameExists(List<AnalyticsDTO> results) {
-		if (results.isEmpty()) {
-			throw new CustomGlobalErrorHandling.ResourceNotFoundException("Results not found.");
+	public void ensureNameExists(String name) {
+		if (!analyticsRepository.existsByName(name.toUpperCase())) {
+			throw new CustomGlobalErrorHandling.ResourceNotFoundException(
+					"AnalyticsDTO by name not found");
 		}
-		return results;
 	}
 
+	// STATISTICS METHODS
+	private MeanAndStdDeviationDTO computeStatistics(List<Double> values) {
+		double sum = values.stream().mapToDouble(Double::doubleValue).sum();
+		int size = values.size();
+		double mean = sum / size;
+		double variance = values.stream().mapToDouble(value -> Math.pow(value - mean, 2)).average()
+				.orElse(0.0);
+		return new MeanAndStdDeviationDTO(mean, Math.sqrt(variance));
+	}
+
+	private List<Double> extractRecordValues(List<AnalyticsDTO> records) {
+		return records.stream().map(AnalyticsDTO::value).toList();
+	}
+
+
+	// BUSINESS LOGIC METHODS
 	public List<GroupedResultsByLevelDTO> findAnalyticsWithGroupedResults(String name,
-																		  LocalDateTime startDate, LocalDateTime endDate) {
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
 		List<GroupedValuesByLevelDTO> analytics =
-				findGroupedAnalyticsByLevel(name, startDate, endDate);
+				findGroupedAnalyticsByLevel(name, startDate, endDate, pageable);
 		Map<String, MeanAndStdDeviationDTO> statsByLevel =
 				analytics.stream().collect(Collectors.toMap(GroupedValuesByLevelDTO::level,
 						group -> computeStatistics(extractRecordValues(group.values()))));
@@ -73,35 +95,20 @@ public List<GroupedResultsByLevelDTO> findAnalyticsWithGroupedResults(String nam
 
 	@Override
 	public List<GroupedValuesByLevelDTO> findGroupedAnalyticsByLevel(String name,
-																	 LocalDateTime startDate, LocalDateTime endDate) {
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
 		List<AnalyticsDTO> records = analyticsRepository
 				.findByNameAndDateBetweenGroupByLevel(name, startDate, endDate, pageable).stream()
 				.map(AnalyticMapper::toRecord).toList();
-		validateResultsNotEmpty(records, "No analytics found for the given parameters");
+		validateResultsNotEmpty(records,
+				"No analytics found for the given name and date between parameters");
 
 		return records.stream().collect(Collectors.groupingBy(AnalyticsDTO::level)).entrySet()
-				.stream().map(entry -> new GroupedValuesByLevelDTO(entry.getKey(), entry.getValue()))
+				.stream()
+				.map(entry -> new GroupedValuesByLevelDTO(entry.getKey(), entry.getValue()))
 				.toList();
 	}
 
-	private MeanAndStdDeviationDTO computeStatistics(List<Double> values) {
-		double sum = values.stream().mapToDouble(Double::doubleValue).sum();
-		int size = values.size();
-		double mean = sum / size;
-		double variance = values.stream().mapToDouble(value -> Math.pow(value - mean, 2)).average()
-				.orElse(0.0);
-		return new MeanAndStdDeviationDTO(mean, Math.sqrt(variance));
-	}
-
-	private List<Double> extractRecordValues(List<AnalyticsDTO> records) {
-		return records.stream().map(AnalyticsDTO::value).toList();
-	}
 
-	private void validateResultsNotEmpty(List<?> results, String message) {
-		if (results == null || results.isEmpty()) {
-			throw new CustomGlobalErrorHandling.ResourceNotFoundException(message);
-		}
-	}
 
 	@Override
 	public List<GroupedMeanAndStdByLevelDTO> returnMeanAndStandardDeviationForGroups(
@@ -114,16 +121,18 @@ public List<GroupedMeanAndStdByLevelDTO> returnMeanAndStandardDeviationForGroups
 
 	@Override
 	public Page<AnalyticsDTO> findAnalyticsByNameInAndDateBetweenWithLinks(List<String> names,
-																		   LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
 		return analyticsRepository.findByNameInAndDateBetweenPaged(names, dateStart, dateEnd,
 				pageable);
 	}
 
 	@Override
 	public List<GroupedValuesByLevelDTO> findFilteredGroupedAnalytics(
-			List<GroupedValuesByLevelDTO> records) {
-		return records.stream().filter(this::isGroupedRecordValid)
-				.map(record -> new GroupedValuesByLevelDTO(record.level(), record.values())).toList();
+			List<GroupedValuesByLevelDTO> groupedValuesByLevelDTO) {
+		return groupedValuesByLevelDTO.stream().filter(this::isGroupedRecordValid)
+				.map(groupedValue -> new GroupedValuesByLevelDTO(groupedValue.level(),
+						groupedValue.values()))
+				.toList();
 	}
 
 	@Override
@@ -133,15 +142,15 @@ public void updateAnalyticsMeanByNameAndLevelAndLevelLot(String name, String lev
 	}
 
 	@Override
-	public boolean isGroupedRecordValid(GroupedValuesByLevelDTO record) {
-		return record.values().stream()
-				.allMatch(genericValuesRecord -> !Objects.equals(genericValuesRecord.rules(), "+3s")
-						&& !Objects.equals(genericValuesRecord.rules(), "-3s"));
+	public boolean isGroupedRecordValid(GroupedValuesByLevelDTO groupedValuesByLevelDTO) {
+		return groupedValuesByLevelDTO.values().stream()
+				.allMatch(groupedValue -> !Objects.equals(groupedValue.rules(), "+3s")
+						&& !Objects.equals(groupedValue.rules(), "-3s"));
 	}
 
 	@Override
-	public boolean isRecordValid(AnalyticsDTO record) {
-		String rules = record.rules();
+	public boolean isRecordValid(AnalyticsDTO analyticsDTO) {
+		String rules = analyticsDTO.rules();
 		return (!Objects.equals(rules, "+3s") || !Objects.equals(rules, "-3s"));
 	}
 
@@ -155,7 +164,7 @@ public AnalyticsDTO findOneById(Long id) {
 	@Override
 	public void saveNewAnalyticsRecords(List<AnalyticsDTO> valuesOfLevelsList) {
 		var newAnalytics = valuesOfLevelsList.stream().filter(this::isAnalyticsNonExistent)
-				.map(AnalyticMapper::toEntity).collect(Collectors.toList());
+				.map(AnalyticMapper::toEntity).toList();
 
 		if (newAnalytics.isEmpty()) {
 			log.warn("No new analytics records to save.");
@@ -170,9 +179,13 @@ public void saveNewAnalyticsRecords(List<AnalyticsDTO> valuesOfLevelsList) {
 		if (notPassedList.isEmpty()) {
 			return;
 		}
+
+		var filteredList = notPassedList.stream()
+				.filter(notPassed -> !BLACK_LIST.contains(notPassed.name())).toList();
+
 		try {
-			var content = controlRulesValidators.validateRules(notPassedList);
-			emailService.sendFailedAnalyticsNotification(notPassedList, content);
+			var content = controlRulesValidators.validateRules(filteredList);
+			emailService.sendFailedAnalyticsNotification(filteredList, content);
 		} catch (Exception e) {
 			log.error("Error sending identifier notification: {}", e.getMessage());
 		}
@@ -196,17 +209,16 @@ public List<AnalyticsDTO> findAnalyticsByNameWithPagination(Pageable pageable, S
 
 	@Override
 	public Page<AnalyticsDTO> findAnalyticsByNameInByLevelBaseMethod(List<String> names,
-																	 String level, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
-		Page<AnalyticsDTO> results = analyticsRepository
-				.findByNameInAndLevelAndDateBetween(names, level, startDate, endDate, pageable);
+			String level, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
+		Page<AnalyticsDTO> results = analyticsRepository.findByNameInAndLevelAndDateBetween(names,
+				level, startDate, endDate, pageable);
 		validateResultsNotEmpty(results.getContent(),
-				"No analytics found for the given parameters");
+				"No analytics found for the given parameters with pagination");
 		return results;
 	}
 
 	@Override
-	public List<AnalyticsDTO> findAnalyticsByDate(LocalDateTime dateStart,
-												  LocalDateTime dateEnd) {
+	public List<AnalyticsDTO> findAnalyticsByDate(LocalDateTime dateStart, LocalDateTime dateEnd) {
 		List<AnalyticsDTO> results = analyticsRepository.findByDateBetween(dateStart, dateEnd)
 				.stream().map(AnalyticMapper::toRecord).toList();
 		validateResultsNotEmpty(results, "No analytics found for the given date range");
@@ -215,14 +227,10 @@ public List<AnalyticsDTO> findAnalyticsByDate(LocalDateTime dateStart,
 
 	@Override
 	public Page<AnalyticsDTO> findAnalyticsByNameInAndDateBetween(List<String> names,
-																  LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
 		return analyticsRepository.findByNameInAndDateBetween(names, dateStart, dateEnd, pageable);
 	}
 
-	@Override
-	public abstract List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable,
-																   String name, String level);
-
 	@Override
 	public void deleteAnalyticsById(Long id) {
 		if (!analyticsRepository.existsById(id)) {
@@ -233,21 +241,22 @@ public void deleteAnalyticsById(Long id) {
 	}
 
 	public MeanAndStdDeviationDTO calculateMeanAndStandardDeviation(String name, String level,
-																	LocalDateTime dateStart, LocalDateTime dateEnd) {
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
 		List<AnalyticsDTO> values =
-				findAnalyticsByNameAndLevelAndDate(name, level, dateStart, dateEnd).stream()
-						.filter(this::isRecordValid).toList();
-        return computeStatistics(extractRecordValues(values));
+				findAnalyticsByNameAndLevelAndDate(name, level, dateStart, dateEnd, pageable)
+						.stream().filter(this::isRecordValid).toList();
+		return computeStatistics(extractRecordValues(values));
 	}
 
-	public List<GroupedMeanAndStdByLevelDTO> calculateGroupedMeanAndStandardDeviation(
-			String name, LocalDateTime startDate, LocalDateTime endDate) {
+	public List<GroupedMeanAndStdByLevelDTO> calculateGroupedMeanAndStandardDeviation(String name,
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
 		List<AnalyticsDTO> records = analyticsRepository
 				.findByNameAndDateBetweenGroupByLevel(name, startDate, endDate, pageable).stream()
 				.map(AnalyticMapper::toRecord).toList();
-		var values = records.stream().collect(Collectors.groupingBy(AnalyticsDTO::level))
-				.entrySet().stream()
-				.map(entry -> new GroupedValuesByLevelDTO(entry.getKey(), entry.getValue())).toList();
+		var values = records.stream().collect(Collectors.groupingBy(AnalyticsDTO::level)).entrySet()
+				.stream()
+				.map(entry -> new GroupedValuesByLevelDTO(entry.getKey(), entry.getValue()))
+				.toList();
 
 		return returnMeanAndStandardDeviationForGroups(values);
 	}
@@ -262,7 +271,7 @@ public Page<AnalyticsDTO> findAnalyticsPagedByNameIn(List<String> names, Pageabl
 	}
 
 	public List<AnalyticsDTO> findAnalyticsByNameAndLevelWithPagination(Pageable pageable,
-																		String name, String level) {
+			String name, String level) {
 		List<AnalyticsDTO> analyticsList =
 				analyticsRepository.findByNameAndLevel(pageable, name.toUpperCase(), level).stream()
 						.map(AnalyticMapper::toRecord).toList();
@@ -271,19 +280,15 @@ public List<AnalyticsDTO> findAnalyticsByNameAndLevelWithPagination(Pageable pag
 	}
 
 	public List<AnalyticsDTO> findAnalyticsByNameLevelAndDate(String name, String level,
-															  LocalDateTime dateStart, LocalDateTime dateEnd) {
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
 		ensureNameExists(name);
 		List<AnalyticsDTO> results = analyticsRepository
 				.findByNameAndLevelAndDateBetween(name, level, dateStart, dateEnd, pageable)
 				.stream().map(AnalyticMapper::toRecord).toList();
-		validateResultsNotEmpty(results, "No analytics found for the given parameters");
+		validateResultsNotEmpty(results,
+				"No analytics found for the given name, level, dateStart, dateEnd -> parameters");
 		return results;
 	}
 
-	public void ensureNameExists(String name) {
-		if (!analyticsRepository.existsByName(name.toUpperCase())) {
-			throw new CustomGlobalErrorHandling.ResourceNotFoundException(
-					"AnalyticsDTO by name not found");
-		}
-	}
+
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/BiochemistryAnalyticService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/BiochemistryAnalyticService.java
index 2ef839d..6cc6672 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/BiochemistryAnalyticService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/BiochemistryAnalyticService.java
@@ -15,39 +15,39 @@
 @Service
 public class BiochemistryAnalyticService extends AbstractAnalyticService {
 
-    public BiochemistryAnalyticService(AnalyticsRepository analyticsRepository, EmailService emailService,
-                                       ControlRulesValidators controlRulesValidators) {
-        super(analyticsRepository, emailService, controlRulesValidators);
-    }
-
-    public Page<AnalyticsDTO> findAnalyticsByNameInByLevel(List<String> names, String level,
-                                                           LocalDateTime startDate, LocalDateTime endDate,
-                                                           Pageable pageable) {
-        return this.findAnalyticsByNameInByLevelBaseMethod(names, this.convertLevel(level),
-                                                           startDate, endDate, pageable);
-    }
-
-    @Override
-    public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
-                                                          String level) {
-        this.ensureNameExists(name);
-        return this.findAnalyticsByNameAndLevelWithPagination(pageable, name,
-                                                              this.convertLevel(level));
-    }
-
-    @Override
-    public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
-                                                                 LocalDateTime dateStart, LocalDateTime dateEnd) {
-        return findAnalyticsByNameLevelAndDate(name, convertLevel(level), dateStart, dateEnd);
-    }
-
-    @Override
-    public String convertLevel(String inputLevel) {
-        return switch (inputLevel) {
-            case "1" -> "PCCC1";
-            case "2" -> "PCCC2";
-            default -> throw new CustomGlobalErrorHandling.ResourceNotFoundException(
-                    "Level not found.");
-        };
-    }
+	public BiochemistryAnalyticService(AnalyticsRepository analyticsRepository,
+			EmailService emailService, ControlRulesValidators controlRulesValidators) {
+		super(analyticsRepository, emailService, controlRulesValidators);
+	}
+
+	public Page<AnalyticsDTO> findAnalyticsByNameInByLevel(List<String> names, String level,
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
+		return this.findAnalyticsByNameInByLevelBaseMethod(names, this.convertLevel(level),
+				startDate, endDate, pageable);
+	}
+
+	@Override
+	public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
+			String level) {
+		this.ensureNameExists(name);
+		return this.findAnalyticsByNameAndLevelWithPagination(pageable, name,
+				this.convertLevel(level));
+	}
+
+	@Override
+	public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
+		return findAnalyticsByNameLevelAndDate(name, convertLevel(level), dateStart, dateEnd,
+				pageable);
+	}
+
+	@Override
+	public String convertLevel(String inputLevel) {
+		return switch (inputLevel) {
+			case "1" -> "PCCC1";
+			case "2" -> "PCCC2";
+			default -> throw new CustomGlobalErrorHandling.ResourceNotFoundException(
+					"Level not found.");
+		};
+	}
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/CoagulationAnalyticService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/CoagulationAnalyticService.java
index e3f444d..003111c 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/CoagulationAnalyticService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/CoagulationAnalyticService.java
@@ -15,39 +15,39 @@
 @Service
 public class CoagulationAnalyticService extends AbstractAnalyticService {
 
-    public CoagulationAnalyticService(AnalyticsRepository analyticsRepository, EmailService emailService, ControlRulesValidators controlRulesValidators) {
-        super(analyticsRepository, emailService, controlRulesValidators);
-    }
-
-    public Page<AnalyticsDTO> findAnalyticsByNameInByLevel(List<String> names, String level,
-                                                           LocalDateTime startDate, LocalDateTime endDate,
-                                                           Pageable pageable) {
-        return this.findAnalyticsByNameInByLevelBaseMethod(names, this.convertLevel(level),
-                                                           startDate, endDate, pageable);
-    }
-
-    @Override
-    public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
-                                                          String level) {
-        this.ensureNameExists(name);
-        return this.findAnalyticsByNameAndLevelWithPagination(pageable, name,
-                                                              this.convertLevel(level));
-    }
-
-    @Override
-    public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
-                                                                 LocalDateTime dateStart, LocalDateTime dateEnd) {
-        return this.findAnalyticsByNameLevelAndDate(name.toUpperCase(), this.convertLevel(level),
-                                                    dateStart, dateEnd);
-    }
-
-    @Override
-    public String convertLevel(String inputLevel) {
-        return switch (inputLevel) {
-            case "1" -> "Normal C. Assayed";
-            case "2" -> "Low Abn C. Assayed";
-            default -> throw new CustomGlobalErrorHandling.ResourceNotFoundException(
-                    "Level not found.");
-        };
-    }
+	public CoagulationAnalyticService(AnalyticsRepository analyticsRepository,
+			EmailService emailService, ControlRulesValidators controlRulesValidators) {
+		super(analyticsRepository, emailService, controlRulesValidators);
+	}
+
+	public Page<AnalyticsDTO> findAnalyticsByNameInByLevel(List<String> names, String level,
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
+		return this.findAnalyticsByNameInByLevelBaseMethod(names, this.convertLevel(level),
+				startDate, endDate, pageable);
+	}
+
+	@Override
+	public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
+			String level) {
+		this.ensureNameExists(name);
+		return this.findAnalyticsByNameAndLevelWithPagination(pageable, name,
+				this.convertLevel(level));
+	}
+
+	@Override
+	public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
+		return findAnalyticsByNameLevelAndDate(name, convertLevel(level), dateStart, dateEnd,
+				pageable);
+	}
+
+	@Override
+	public String convertLevel(String inputLevel) {
+		return switch (inputLevel) {
+			case "1" -> "Normal C. Assayed";
+			case "2" -> "Low Abn C. Assayed";
+			default -> throw new CustomGlobalErrorHandling.ResourceNotFoundException(
+					"Level not found.");
+		};
+	}
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/HematologyAnalyticService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/HematologyAnalyticService.java
index 1f06ada..93c9662 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/HematologyAnalyticService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/HematologyAnalyticService.java
@@ -15,40 +15,39 @@
 @Service
 public class HematologyAnalyticService extends AbstractAnalyticService {
 
-    public HematologyAnalyticService(AnalyticsRepository analyticsRepository, EmailService emailService, ControlRulesValidators controlRulesValidators) {
-        super(analyticsRepository, emailService, controlRulesValidators);
-    }
-
-    public Page<AnalyticsDTO> findAnalyticsByNameInByLevel(List<String> names, String level,
-                                                           LocalDateTime startDate, LocalDateTime endDate,
-                                                           Pageable pageable) {
-        return this.findAnalyticsByNameInByLevelBaseMethod(names, this.convertLevel(level),
-                                                           startDate, endDate, pageable);
-    }
-
-    @Override
-    public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
-                                                          String level) {
-        ensureNameExists(name);
-        return findAnalyticsByNameAndLevelWithPagination(pageable, name, convertLevel(level));
-    }
-
-    @Override
-    public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name,
-                                                                 String level, LocalDateTime dateStart,
-                                                                 LocalDateTime dateEnd) {
-        ensureNameExists(name);
-        return findAnalyticsByNameLevelAndDate(name, convertLevel(level), dateStart, dateEnd);
-    }
-
-    @Override
-    public String convertLevel(String inputLevel) {
-        return switch (inputLevel) {
-            case "1" -> "low";
-            case "2" -> "normal";
-            case "3" -> "high";
-            default -> throw new CustomGlobalErrorHandling.ResourceNotFoundException(
-                    "Level not found.");
-        };
-    }
+	public HematologyAnalyticService(AnalyticsRepository analyticsRepository,
+			EmailService emailService, ControlRulesValidators controlRulesValidators) {
+		super(analyticsRepository, emailService, controlRulesValidators);
+	}
+
+	public Page<AnalyticsDTO> findAnalyticsByNameInByLevel(List<String> names, String level,
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
+		return this.findAnalyticsByNameInByLevelBaseMethod(names, this.convertLevel(level),
+				startDate, endDate, pageable);
+	}
+
+	@Override
+	public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
+			String level) {
+		ensureNameExists(name);
+		return findAnalyticsByNameAndLevelWithPagination(pageable, name, convertLevel(level));
+	}
+
+	@Override
+	public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable) {
+		return findAnalyticsByNameLevelAndDate(name, convertLevel(level), dateStart, dateEnd,
+				pageable);
+	}
+
+	@Override
+	public String convertLevel(String inputLevel) {
+		return switch (inputLevel) {
+			case "1" -> "low";
+			case "2" -> "normal";
+			case "3" -> "high";
+			default -> throw new CustomGlobalErrorHandling.ResourceNotFoundException(
+					"Level not found.");
+		};
+	}
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/IAnalyticHelperService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/IAnalyticHelperService.java
index 58a8cf9..96a6735 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/IAnalyticHelperService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/analytics/IAnalyticHelperService.java
@@ -11,47 +11,45 @@
 
 public interface IAnalyticHelperService {
 
-    List<GroupedValuesByLevelDTO> findGroupedAnalyticsByLevel(String name, LocalDateTime startDate,
-                                                              LocalDateTime endDate);
+	List<GroupedValuesByLevelDTO> findGroupedAnalyticsByLevel(String name, LocalDateTime startDate,
+			LocalDateTime endDate, Pageable pageable);
 
-    List<GroupedMeanAndStdByLevelDTO> returnMeanAndStandardDeviationForGroups(
-            List<GroupedValuesByLevelDTO> records);
+	List<GroupedMeanAndStdByLevelDTO> returnMeanAndStandardDeviationForGroups(
+			List<GroupedValuesByLevelDTO> records);
 
-    Page<AnalyticsDTO> findAnalyticsByNameInAndDateBetweenWithLinks(List<String> names, LocalDateTime dateStart,
-                                                                    LocalDateTime dateEnd, Pageable pageable);
+	Page<AnalyticsDTO> findAnalyticsByNameInAndDateBetweenWithLinks(List<String> names,
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable);
 
-    List<GroupedValuesByLevelDTO> findFilteredGroupedAnalytics(List<GroupedValuesByLevelDTO> records);
+	List<GroupedValuesByLevelDTO> findFilteredGroupedAnalytics(
+			List<GroupedValuesByLevelDTO> records);
 
-    void updateAnalyticsMeanByNameAndLevelAndLevelLot(String name, String level, String levelLot,
-                                                      double mean);
+	void updateAnalyticsMeanByNameAndLevelAndLevelLot(String name, String level, String levelLot,
+			double mean);
 
-    boolean isGroupedRecordValid(GroupedValuesByLevelDTO record);
+	boolean isGroupedRecordValid(GroupedValuesByLevelDTO groupedValuesByLevelDTO);
 
-    boolean isRecordValid(AnalyticsDTO record);
+	boolean isRecordValid(AnalyticsDTO analyticsDTO);
 
-    AnalyticsDTO findOneById(Long id);
+	AnalyticsDTO findOneById(Long id);
 
-    void saveNewAnalyticsRecords(List<AnalyticsDTO> valuesOfLevelsList);
+	void saveNewAnalyticsRecords(List<AnalyticsDTO> valuesOfLevelsList);
 
-    Page<AnalyticsDTO> findAnalytics(Pageable pageable);
+	Page<AnalyticsDTO> findAnalytics(Pageable pageable);
 
-    List<AnalyticsDTO> findAnalyticsByNameWithPagination(Pageable pageable, String name);
+	List<AnalyticsDTO> findAnalyticsByNameWithPagination(Pageable pageable, String name);
 
-    Page<AnalyticsDTO> findAnalyticsByNameInByLevelBaseMethod(List<String> names, String level,
-                                                              LocalDateTime startDate, LocalDateTime endDate,
-                                                              Pageable pageable);
+	Page<AnalyticsDTO> findAnalyticsByNameInByLevelBaseMethod(List<String> names, String level,
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable);
 
-    List<AnalyticsDTO> findAnalyticsByDate(LocalDateTime dateStart, LocalDateTime dateEnd);
+	List<AnalyticsDTO> findAnalyticsByDate(LocalDateTime dateStart, LocalDateTime dateEnd);
 
-    Page<AnalyticsDTO> findAnalyticsByNameInAndDateBetween(List<String> names,
-                                                           LocalDateTime startDate, LocalDateTime endDate,
-                                                           Pageable pageable);
+	Page<AnalyticsDTO> findAnalyticsByNameInAndDateBetween(List<String> names,
+			LocalDateTime startDate, LocalDateTime endDate, Pageable pageable);
 
-    List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name,
-                                                   String level);
+	List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable, String name, String level);
 
-    List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
-                                                          LocalDateTime dateStart, LocalDateTime dateEnd);
+	List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name, String level,
+			LocalDateTime dateStart, LocalDateTime dateEnd, Pageable pageable);
 
-    void deleteAnalyticsById(Long id);
+	void deleteAnalyticsById(Long id);
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/email/EmailService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/email/EmailService.java
index 24920ad..743564b 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/email/EmailService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/email/EmailService.java
@@ -14,6 +14,7 @@
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.mail.javamail.MimeMessageHelper;
 import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
@@ -26,6 +27,7 @@
 
 @RequiredArgsConstructor
 @Slf4j
+@EnableAsync
 @Service
 public class EmailService {
 	private final JavaMailSender javaMailSender;
@@ -50,7 +52,6 @@ private void init() {
 		}
 	}
 
-	@Async
 	public void sendPlainTextEmail(EmailDTO email) {
 		SimpleMailMessage message = new SimpleMailMessage();
 		message.setFrom(emailFrom);
@@ -87,7 +88,8 @@ public void sendHtmlEmail(EmailDTO emailDTO) {
 			helper.setText(buildEmailBody(emailDTO.body()), true);
 
 			javaMailSender.send(mimeMessage);
-			log.info("HTML identifier sent successfully to {} recipients", internetAddresses.length);
+			log.info("HTML identifier sent successfully to {} recipients",
+					internetAddresses.length);
 
 		} catch (MessagingException e) {
 			log.error("Failed to send HTML identifier: {}", e.getMessage(), e);
@@ -131,15 +133,17 @@ public void sendFailedAnalyticsNotification(List<AnalyticsDTO> failedRecords,
 		}
 	}
 
-	public String generateAnalyticsFailedEmailBody(List<AnalyticsDTO> notPassedList, String otherValidations) {
-		String formattedList = notPassedList.stream().map(record -> String.format(
-						"<tr><td style=\"padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;\">%s</td><td style=\"padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;\">%s</td><td style=\"padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;\">%s</td><td style=\"padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;\">%s</td><td style=\"padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;\">%s</td><td style=\"padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;\">%s</td><td style=\"padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;\">%s</td></tr>",
-						record.name(), record.level(), record.value().toString(), record.mean().toString(),
-						record.rules(), record.description(),
-						record.date().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))))
+	public String generateAnalyticsFailedEmailBody(List<AnalyticsDTO> notPassedList,
+			String otherValidations) {
+		String formattedList = notPassedList.stream()
+				.map(analytics -> String.format(TABLE_ROW, analytics.name(), analytics.level(),
+						analytics.value().toString(), analytics.mean().toString(),
+						analytics.rules(), analytics.description(),
+						analytics.date().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))))
 				.collect(Collectors.joining("\n"));
 		return String.format(HTML_TEMPLATE,
-				ANALYTICS_WARNING_HEADER + String.format(TABLE_STYLE, formattedList) + LAST_ANALYTICS_PARAGRAPH + "\n" + otherValidations);
+				ANALYTICS_WARNING_HEADER + String.format(TABLE_STYLE, formattedList)
+						+ LAST_ANALYTICS_PARAGRAPH + "\n" + otherValidations);
 	}
 
 	public void notifyUserLogin(String username, String email, LocalDateTime date) {
@@ -162,11 +166,11 @@ public void notifyUserUpdate(String username, String email, LocalDateTime date)
 		sendUserActionEmail("Account Update", username, email, date);
 	}
 
-	private void sendUserActionEmail(String actionType, String username, String email,
+	public void sendUserActionEmail(String actionType, String username, String email,
 			LocalDateTime date) {
 		String subject = String.format("User %s - %s", username, actionType);
 		String content = createUserActionEmailContent(actionType, username, email, date);
-		sendPlainTextEmail(new EmailDTO(email, subject, content));
+		this.sendPlainTextEmail(new EmailDTO(email, subject, content));
 	}
 
 	private String createUserActionEmailContent(String actionType, String username, String email,
@@ -178,6 +182,6 @@ private String createUserActionEmailContent(String actionType, String username,
 	}
 
 	private String buildEmailBody(String email) {
-		return String.format("\n\n%s\n\nBest regards,\nLabGraph Team", email);
+		return String.format("%n%n%s%n%nBest regards,%nLabGraph Team", email);
 	}
 }
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java b/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java
index 0cde912..a08e26e 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/services/users/UserService.java
@@ -15,7 +15,6 @@
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
@@ -68,9 +67,10 @@ public User signUp(String username, String email, String password) {
 		var user =
 				new User(username, BCryptEncoderComponent.encrypt(password), email, UserRoles.USER);
 
-		if (userRepository.existsByEmail(email)) {
+		if (userRepository.existsByUsernameOrEmail(email, email)) {
 			throw new CustomGlobalErrorHandling.UserAlreadyExistException();
 		}
+
 		try {
 			emailService.notifyUserSignup(user.getUsername(), user.getEmail(), LocalDateTime.now());
 		} catch (Exception e) {
@@ -82,7 +82,8 @@ public User signUp(String username, String email, String password) {
 
 	public TokenJwtDTO signIn(String identifier, String password) {
 
-		final var credential = userRepository.findByUsernameOrEmail(identifier, identifier).getUsername();
+		final var credential =
+				userRepository.findByUsernameOrEmail(identifier, identifier).getUsername();
 
 		final var authToken = new UsernamePasswordAuthenticationToken(credential, password);
 		final var auth = authenticationManager.authenticate(authToken);
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/ControlRulesValidators.java b/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/ControlRulesValidators.java
index 2a5acdf..dc04001 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/ControlRulesValidators.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/utils/components/ControlRulesValidators.java
@@ -30,16 +30,16 @@ public ControlRulesValidators(AnalyticsRepository analyticsRepository) {
 					""";
 
 
-	public String validateRules(List<AnalyticsDTO> records) {
+	public String validateRules(List<AnalyticsDTO> analytics) {
 		StringBuilder errors = new StringBuilder();
 		errors.append("<div style='font-family: Arial, sans-serif;'>");
 
 		// Track already reported violations
 		Set<String> reportedViolations = new HashSet<>();
 
-		for (AnalyticsDTO record : records) {
+		for (AnalyticsDTO analytic : analytics) {
 			// Create unique key for test/level combination
-			String violationKey = record.name() + "-" + record.level();
+			String violationKey = analytic.name() + "-" + analytic.level();
 
 			// Skip if we already reported this violation
 			if (reportedViolations.contains(violationKey)) {
@@ -47,23 +47,31 @@ public String validateRules(List<AnalyticsDTO> records) {
 			}
 
 			var analyticsRecords =
-					analyticsRepository.findLast10ByNameAndLevel(record.name(), record.level());
+					analyticsRepository.findLast10ByNameAndLevel(analytic.name(), analytic.level());
 			var mean = analyticsRecords.getFirst().mean();
 			var stdDev = analyticsRecords.getFirst().sd();
 			var values = analyticsRecords.stream().map(AnalyticsDTO::value).toList();
 
+
+			if (rule1_3s(values, mean, stdDev)) {
+				errors.append(String.format(ERROR_MESSAGE_TEMPLATE, "1-3s", analytic.name(),
+						analytic.level(), "One observation exceeds mean ±3 SD",
+						"Random Error. Reject run and investigate for potential systematic errors."));
+				reportedViolations.add(violationKey);
+			}
+
 			if (rule4_1s(values, mean, stdDev)) {
-				errors.append(String.format(ERROR_MESSAGE_TEMPLATE, "4-1s", record.name(),
-						record.level(),
-						"Four consecutive observations exceed 1 SD on the same side of the mean.",
-						"Investigate possible trends or deviations in the process."));
+				errors.append(String.format(ERROR_MESSAGE_TEMPLATE, "4-1s", analytic.name(),
+						analytic.level(),
+						"Four consecutive measurements exceed ±1 SD on same side of mean",
+						"Systematic Error. Check for calibration drift, reagent lot changes, or environmental conditions."));
 				reportedViolations.add(violationKey);
 			}
 
 			if (rule10x(values, mean, stdDev)) {
-				errors.append(String.format(ERROR_MESSAGE_TEMPLATE, "10x", record.name(),
-						record.level(), "Ten consecutive results are on the same side of the mean.",
-						"Perform maintenance or calibration on the equipment."));
+				errors.append(String.format(ERROR_MESSAGE_TEMPLATE, "10x", analytic.name(),
+						analytic.level(), "Ten consecutive measurements on same side of mean",
+						"Systematic Error. Review calibration, reagent stability, and instrument maintenance. Recalibrate if necessary."));
 				reportedViolations.add(violationKey);
 			}
 		}
@@ -72,6 +80,15 @@ public String validateRules(List<AnalyticsDTO> records) {
 		return errors.toString();
 	}
 
+	public boolean rule1_3s(List<Double> values, double mean, double stdDev) {
+		for (double value : values) {
+			if (value > mean + 3 * stdDev || value < mean - 3 * stdDev) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	public boolean rule4_1s(List<Double> values, double mean, double stdDev) {
 		if (values.size() < 4) {
 			return false;
diff --git a/src/main/java/leonardo/labutilities/qualitylabpro/utils/constants/EmailTemplate.java b/src/main/java/leonardo/labutilities/qualitylabpro/utils/constants/EmailTemplate.java
index 5c820b3..ebb2605 100644
--- a/src/main/java/leonardo/labutilities/qualitylabpro/utils/constants/EmailTemplate.java
+++ b/src/main/java/leonardo/labutilities/qualitylabpro/utils/constants/EmailTemplate.java
@@ -21,6 +21,16 @@ public class EmailTemplate {
                 </tbody>
             </table>
             """;
+	public static final String TABLE_ROW = """
+            <tr>
+                <td style="padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;">%s</td>
+                <td style="padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;">%s</td>
+                <td style="padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;">%s</td>
+                <td style="padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;">%s</td>
+                <td style="padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;">%s</td>
+                <td style="padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;">%s</td>
+                <td style="padding: 12px 15px; text-align: left; border-bottom: 1px solid #dddddd;">%s</td>
+            </tr>""";
 	public static final String ANALYTICS_WARNING_HEADER = """
             <p style="font-size: 16px; color: #d32f2f; margin-bottom: 20px;">
                 <strong>⚠️ Quality Control Alert: Westgard violations</strong>
diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties
index 1d56976..35c0f8c 100644
--- a/src/main/resources/application-local.properties
+++ b/src/main/resources/application-local.properties
@@ -46,4 +46,4 @@ email.to.send.list=${EMAIL_TO_SEND_LIST}
 # = SECURITY CONFIGURATION
 # ===============================
 api.security.token.secret=${API_SECURITY_TOKEN_SECRET}
-api.security.issuer=${API_SECURITY_ISSUER}
\ No newline at end of file
+api.security.issuer=${API_SECURITY_ISSUER}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 392bcdb..31ad475 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -32,10 +32,9 @@ spring.jpa.show-sql=false
 spring.jpa.open-in-view=false
 
 # Database Connection Pool
-spring.datasource.tomcat.validation-query=SELECT 1
-spring.datasource.tomcat.test-on-borrow=true
-spring.datasource.tomcat.test-while-idle=true
-spring.datasource.tomcat.validation-interval=60000
+spring.datasource.hikari.maximum-pool-size=5
+spring.datasource.hikari.minimum-idle=1
+spring.datasource.hikari.idle-timeout=300000
 
 # ===============================
 # = EMAIL CONFIGURATION
diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/BiochemistryAnalyticControllerTest.java b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/BiochemistryAnalyticControllerTest.java
index ebf7e83..6fb671e 100644
--- a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/BiochemistryAnalyticControllerTest.java
+++ b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/BiochemistryAnalyticControllerTest.java
@@ -24,7 +24,8 @@
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.context.bean.override.mockito.MockitoBean;
 import org.springframework.test.web.servlet.MockMvc;
-
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 
 import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createSampleRecordList;
@@ -38,116 +39,114 @@
 @AutoConfigureJsonTesters
 @ActiveProfiles("test")
 public class BiochemistryAnalyticControllerTest {
-    @Autowired
-    private MockMvc mockMvc;
-
-    @MockitoBean
-    private TokenService tokenService;
-
-    @MockitoBean
-    private UserRepository userRepository;
-
-    @MockitoBean
-    private BiochemistryAnalyticService biochemistryAnalyticsService;
-
-    @Autowired
-    private JacksonTester<List<AnalyticsDTO>> jacksonGenericValuesRecord;
-
-    @Autowired
-    private JacksonTester<UpdateAnalyticsMeanDTO> jacksonUpdateAnalyticsMeanRecord;
-
-    @Test
-    @DisplayName("It should return a list of all analytics by level")
-    void getAllAnalytics_by_level_return_list() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-        when(biochemistryAnalyticsService.findAnalyticsByNameInByLevel(anyList(), any(), any(), any(),
-                                                                       any(Pageable.class)))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/biochemistry-analytics/level-date-range")
-                                .param("level", "PCCC1")
-                                .param("startDate", "2025-01-01 00:00:00")
-                                .param("endDate", "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(biochemistryAnalyticsService, times(1))
-                .findAnalyticsByNameInByLevel(anyList(), any(), any(), any(), any(Pageable.class));
-    }
-
-    @Test
-    @DisplayName("It should return HTTP code 201 when analytics records are saved")
-    void analytics_post_return_201() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        mockMvc.perform(post("/biochemistry-analytics").contentType(MediaType.APPLICATION_JSON)
-                                                       .content(jacksonGenericValuesRecord.write(records).getJson()))
-               .andExpect(status().isCreated());
-        verify(biochemistryAnalyticsService, times(1)).saveNewAnalyticsRecords(anyList());
-    }
-
-    @Test
-    @DisplayName("It should return HTTP code 204 when analytics records are updated")
-    void analytics_put_return_204() throws Exception {
-        var mockDto = new UpdateAnalyticsMeanDTO("Glucose", "PCCC1", "1234", 10.5);
-        mockMvc.perform(patch("/biochemistry-analytics").contentType(MediaType.APPLICATION_JSON)
-                                                        .content(jacksonUpdateAnalyticsMeanRecord.write(mockDto).getJson()))
-               .andExpect(status().isNoContent());
-        verify(biochemistryAnalyticsService, times(1))
-                .updateAnalyticsMeanByNameAndLevelAndLevelLot("Glucose", "PCCC1", "1234", 10.5);
-    }
-
-    @Test
-    @DisplayName("It should return a list of all analytics with pagination")
-    void getAllAnalytics_return_list() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-        when(biochemistryAnalyticsService.findAnalyticsPagedByNameIn(anyList(), any(Pageable.class)))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/biochemistry-analytics")
-                                .param("page", "0")
-                                .param("size", "10"))
-               .andExpect(status().isOk());
-
-        verify(biochemistryAnalyticsService, times(1))
-                .findAnalyticsPagedByNameIn(anyList(), any(Pageable.class));
-    }
-
-
-    @Test
-    @DisplayName("It should return analytics records for a date range")
-    @WithMockUser(username = "admin", roles = {"ADMIN"})
-    void getAnalyticsByDateRange_return_analytics() throws Exception {
-        Page<AnalyticsDTO> records = new PageImpl<>(createSampleRecordList());
-
-        when(biochemistryAnalyticsService.findAnalyticsByNameInAndDateBetween(anyList(), any(), any(), any()))
-                .thenReturn(records);
-
-        mockMvc.perform(get("/biochemistry-analytics/date-range")
-                                .param("startDate", "2025-01-01 00:00:00").param("endDate",
-                                                                                 "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(biochemistryAnalyticsService, times(1))
-                .findAnalyticsByNameInAndDateBetween(anyList(), any(), any(), any());
-    }
-
-    @Test
-    @DisplayName("It should return mean and standard deviation for a date range")
-    @WithMockUser(username = "admin", roles = {"ADMIN"})
-    void getMeanAndStandardDeviation_return_result() throws Exception {
-        MeanAndStdDeviationDTO result = new MeanAndStdDeviationDTO(10.5, 2.3);
-        when(biochemistryAnalyticsService.calculateMeanAndStandardDeviation(any(), any(), any(),
-                                                                            any())).thenReturn(result);
-
-        mockMvc.perform(get("/biochemistry-analytics/mean-standard-deviation")
-                                .param("name", "Hemoglobin").param("level", "High")
-                                .param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(biochemistryAnalyticsService, times(1)).calculateMeanAndStandardDeviation(any(),
-                                                                                         any(), any(), any());
-    }
+	@Autowired
+	private MockMvc mockMvc;
+
+	@MockitoBean
+	private TokenService tokenService;
+
+	@MockitoBean
+	private UserRepository userRepository;
+
+	@MockitoBean
+	private BiochemistryAnalyticService biochemistryAnalyticsService;
+
+	@Autowired
+	private JacksonTester<List<AnalyticsDTO>> jacksonGenericValuesRecord;
+
+	@Autowired
+	private JacksonTester<UpdateAnalyticsMeanDTO> jacksonUpdateAnalyticsMeanRecord;
+
+	@Test
+	@DisplayName("It should return a list of all analytics by level")
+	void getAllAnalytics_by_level_return_list() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+		when(biochemistryAnalyticsService.findAnalyticsByNameInByLevel(anyList(), any(), any(),
+				any(), any(Pageable.class))).thenReturn(page);
+
+		mockMvc.perform(get("/biochemistry-analytics/level-date-range").param("level", "PCCC1")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
+				.andExpect(status().isOk());
+
+		verify(biochemistryAnalyticsService, times(1)).findAnalyticsByNameInByLevel(anyList(),
+				any(), any(), any(), any(Pageable.class));
+	}
+
+	@Test
+	@DisplayName("It should return HTTP code 201 when analytics records are saved")
+	void analytics_post_return_201() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		mockMvc.perform(post("/biochemistry-analytics").contentType(MediaType.APPLICATION_JSON)
+				.content(jacksonGenericValuesRecord.write(records).getJson()))
+				.andExpect(status().isCreated());
+		verify(biochemistryAnalyticsService, times(1)).saveNewAnalyticsRecords(anyList());
+	}
+
+	@Test
+	@DisplayName("It should return HTTP code 204 when analytics records are updated")
+	void analytics_put_return_204() throws Exception {
+		var mockDto = new UpdateAnalyticsMeanDTO("Glucose", "PCCC1", "1234", 10.5);
+		mockMvc.perform(patch("/biochemistry-analytics").contentType(MediaType.APPLICATION_JSON)
+				.content(jacksonUpdateAnalyticsMeanRecord.write(mockDto).getJson()))
+				.andExpect(status().isNoContent());
+		verify(biochemistryAnalyticsService, times(1))
+				.updateAnalyticsMeanByNameAndLevelAndLevelLot("Glucose", "PCCC1", "1234", 10.5);
+	}
+
+	@Test
+	@DisplayName("It should return a list of all analytics with pagination")
+	void getAllAnalytics_return_list() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+		when(biochemistryAnalyticsService.findAnalyticsPagedByNameIn(anyList(),
+				any(Pageable.class))).thenReturn(page);
+
+		mockMvc.perform(get("/biochemistry-analytics").param("page", "0").param("size", "10"))
+				.andExpect(status().isOk());
+
+		verify(biochemistryAnalyticsService, times(1)).findAnalyticsPagedByNameIn(anyList(),
+				any(Pageable.class));
+	}
+
+
+	@Test
+	@DisplayName("It should return analytics records for a date range")
+	@WithMockUser(username = "admin", roles = {"ADMIN"})
+	void getAnalyticsByDateRange_return_analytics() throws Exception {
+		Page<AnalyticsDTO> records = new PageImpl<>(createSampleRecordList());
+
+		when(biochemistryAnalyticsService.findAnalyticsByNameInAndDateBetween(anyList(), any(),
+				any(), any())).thenReturn(records);
+
+		mockMvc.perform(get("/biochemistry-analytics/date-range")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
+				.andExpect(status().isOk());
+
+		verify(biochemistryAnalyticsService, times(1))
+				.findAnalyticsByNameInAndDateBetween(anyList(), any(), any(), any());
+	}
+
+	@Test
+	@DisplayName("It should return mean and standard deviation for a date range")
+	void getMeanAndStandardDeviation_return_result() throws Exception {
+		MeanAndStdDeviationDTO result = new MeanAndStdDeviationDTO(10.5, 2.3);
+		LocalDateTime startDate = LocalDateTime.parse("2025-01-01 00:00:00",
+				DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+		LocalDateTime endDate = LocalDateTime.parse("2025-01-05 00:00:00",
+				DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+		when(biochemistryAnalyticsService.calculateMeanAndStandardDeviation(eq("Hemoglobin"),
+				eq("High"), eq(startDate), eq(endDate), any(Pageable.class))).thenReturn(result);
+
+		mockMvc.perform(get("/biochemistry-analytics/mean-standard-deviation")
+				.param("name", "Hemoglobin").param("level", "High")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00")
+				.param("page", "0").param("size", "10")).andExpect(status().isOk());
+
+		verify(biochemistryAnalyticsService).calculateMeanAndStandardDeviation(eq("Hemoglobin"),
+				eq("High"), eq(startDate), eq(endDate), any(Pageable.class));
+	}
 }
diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/CoagulationAnalyticControllerTest.java b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/CoagulationAnalyticControllerTest.java
index 84fb80c..3102a18 100644
--- a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/CoagulationAnalyticControllerTest.java
+++ b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/CoagulationAnalyticControllerTest.java
@@ -19,13 +19,18 @@
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
 import org.springframework.http.MediaType;
+import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.context.bean.override.mockito.MockitoBean;
 import org.springframework.test.web.servlet.MockMvc;
-
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 
 import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createSampleRecordList;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.*;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -38,100 +43,100 @@
 @ActiveProfiles("test")
 public class CoagulationAnalyticControllerTest {
 
-    @Autowired
-    private MockMvc mockMvc;
-
-    @MockitoBean
-    private TokenService tokenService;
-
-    @MockitoBean
-    private UserRepository userRepository;
-
-    @MockitoBean
-    private CoagulationAnalyticService coagulationAnalyticsService;
-
-    @Autowired
-    private JacksonTester<List<AnalyticsDTO>> jacksonGenericValuesRecord;
-
-    @Test
-    @DisplayName("It should return a list of all analytics by level")
-    void getAllAnalytics_by_level_return_list() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-        when(coagulationAnalyticsService
-                     .findAnalyticsByNameInByLevel(anyList(), any(), any(), any(), any(Pageable.class)))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/coagulation-analytics/level-date-range")
-                                .param("level", "PCCC1")
-                                .param("startDate", "2025-01-01 00:00:00")
-                                .param("endDate", "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(coagulationAnalyticsService, times(1))
-                .findAnalyticsByNameInByLevel(anyList(), any(), any(), any(), any(Pageable.class));
-    }
-
-    @Test
-    @DisplayName("It should return HTTP code 201 when analytics records are saved")
-    void analytics_post_return_201() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        mockMvc.perform(post("/coagulation-analytics").contentType(MediaType.APPLICATION_JSON)
-                                                      .content(jacksonGenericValuesRecord.write(records).getJson()))
-               .andExpect(status().isCreated());
-        verify(coagulationAnalyticsService, times(1)).saveNewAnalyticsRecords(anyList());
-    }
-
-    @Test
-    @DisplayName("It should return a list of all analytics with pagination")
-    void getAllAnalytics_return_list() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-        when(coagulationAnalyticsService.findAnalyticsPagedByNameIn(anyList(), any(Pageable.class)))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/coagulation-analytics")
-                                .param("page", "0")
-                                .param("size", "10"))
-               .andExpect(status().isOk());
-
-        verify(coagulationAnalyticsService, times(1))
-                .findAnalyticsPagedByNameIn(anyList(), any(Pageable.class));
-    }
-
-    @Test
-    @DisplayName("It should return analytics records for a date range")
-    void getAnalyticsByDateRange_return_analytics() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-
-        when(coagulationAnalyticsService.findAnalyticsByNameInAndDateBetween(anyList(), any(), any(), any()))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/coagulation-analytics/date-range")
-                                .param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(coagulationAnalyticsService, times(1))
-                .findAnalyticsByNameInAndDateBetween(anyList(), any(), any(), any());
-    }
-
-    @Test
-    @DisplayName("It should return mean and standard deviation for a date range")
-    void getMeanAndStandardDeviation_return_result() throws Exception {
-        MeanAndStdDeviationDTO result = new MeanAndStdDeviationDTO(10.5, 2.3);
-        when(coagulationAnalyticsService.calculateMeanAndStandardDeviation(any(), any(), any(),
-                                                                           any())).thenReturn(result);
-
-        mockMvc.perform(get("/coagulation-analytics/mean-standard-deviation")
-                                .param("name", "Hemoglobin").param("level", "High")
-                                .param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(coagulationAnalyticsService, times(1)).calculateMeanAndStandardDeviation(any(),
-                                                                                        any(), any(), any());
-    }
+	@Autowired
+	private MockMvc mockMvc;
+
+	@MockitoBean
+	private TokenService tokenService;
+
+	@MockitoBean
+	private UserRepository userRepository;
+
+	@MockitoBean
+	private CoagulationAnalyticService coagulationAnalyticsService;
+
+	@Autowired
+	private JacksonTester<List<AnalyticsDTO>> jacksonGenericValuesRecord;
+
+	@Test
+	@DisplayName("It should return a list of all analytics by level")
+	void getAllAnalytics_by_level_return_list() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+		when(coagulationAnalyticsService.findAnalyticsByNameInByLevel(anyList(), any(), any(),
+				any(), any(Pageable.class))).thenReturn(page);
+
+		mockMvc.perform(get("/coagulation-analytics/level-date-range").param("level", "PCCC1")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
+				.andExpect(status().isOk());
+
+		verify(coagulationAnalyticsService, times(1)).findAnalyticsByNameInByLevel(anyList(), any(),
+				any(), any(), any(Pageable.class));
+	}
+
+	@Test
+	@DisplayName("It should return HTTP code 201 when analytics records are saved")
+	void analytics_post_return_201() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		mockMvc.perform(post("/coagulation-analytics").contentType(MediaType.APPLICATION_JSON)
+				.content(jacksonGenericValuesRecord.write(records).getJson()))
+				.andExpect(status().isCreated());
+		verify(coagulationAnalyticsService, times(1)).saveNewAnalyticsRecords(anyList());
+	}
+
+	@Test
+	@DisplayName("It should return a list of all analytics with pagination")
+	void getAllAnalytics_return_list() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+		when(coagulationAnalyticsService.findAnalyticsPagedByNameIn(anyList(), any(Pageable.class)))
+				.thenReturn(page);
+
+		mockMvc.perform(get("/coagulation-analytics").param("page", "0").param("size", "10"))
+				.andExpect(status().isOk());
+
+		verify(coagulationAnalyticsService, times(1)).findAnalyticsPagedByNameIn(anyList(),
+				any(Pageable.class));
+	}
+
+	@Test
+	@DisplayName("It should return analytics records for a date range")
+	void getAnalyticsByDateRange_return_analytics() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+
+		when(coagulationAnalyticsService.findAnalyticsByNameInAndDateBetween(anyList(), any(),
+				any(), any())).thenReturn(page);
+
+		mockMvc.perform(get("/coagulation-analytics/date-range")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
+				.andExpect(status().isOk());
+
+		verify(coagulationAnalyticsService, times(1)).findAnalyticsByNameInAndDateBetween(anyList(),
+				any(), any(), any());
+	}
+
+	@Test
+	@DisplayName("It should return mean and standard deviation for a date range")
+	void getMeanAndStandardDeviation_return_result() throws Exception {
+		MeanAndStdDeviationDTO result = new MeanAndStdDeviationDTO(10.5, 2.3);
+		LocalDateTime startDate = LocalDateTime.parse("2025-01-01 00:00:00",
+				DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+		LocalDateTime endDate = LocalDateTime.parse("2025-01-05 00:00:00",
+				DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+		when(coagulationAnalyticsService.calculateMeanAndStandardDeviation(eq("Hemoglobin"),
+				eq("High"), eq(startDate), eq(endDate), any(Pageable.class))).thenReturn(result);
+
+		mockMvc.perform(get("/coagulation-analytics/mean-standard-deviation")
+				.param("name", "Hemoglobin").param("level", "High")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00")
+				.param("page", "0").param("size", "10")).andExpect(status().isOk());
+
+		verify(coagulationAnalyticsService).calculateMeanAndStandardDeviation(eq("Hemoglobin"),
+				eq("High"), eq(startDate), eq(endDate), any(Pageable.class));
+	}
 }
diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/HematologyAnalyticControllerTest.java b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/HematologyAnalyticControllerTest.java
index f3211d7..8f4a93a 100644
--- a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/HematologyAnalyticControllerTest.java
+++ b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/HematologyAnalyticControllerTest.java
@@ -19,13 +19,18 @@
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.Pageable;
 import org.springframework.http.MediaType;
+import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.context.bean.override.mockito.MockitoBean;
 import org.springframework.test.web.servlet.MockMvc;
-
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 
 import static leonardo.labutilities.qualitylabpro.utils.AnalyticsHelperMocks.createSampleRecordList;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.*;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -38,101 +43,100 @@
 @ActiveProfiles("test")
 public class HematologyAnalyticControllerTest {
 
-    @MockitoBean
-    private TokenService tokenService;
-
-    @MockitoBean
-    private UserRepository userRepository;
-
-    @Autowired
-    private MockMvc mockMvc;
-
-    @MockitoBean
-    private HematologyAnalyticService hematologyAnalyticsService;
-
-    @Autowired
-    private JacksonTester<List<AnalyticsDTO>> jacksonGenericValuesRecord;
-
-    @Test
-    @DisplayName("It should return a list of all analytics by level")
-    void getAllAnalytics_by_level_return_list() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-        when(hematologyAnalyticsService
-                     .findAnalyticsByNameInByLevel(anyList(), any(), any(), any(), any(Pageable.class)))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/hematology-analytics/level-date-range")
-                                .param("level", "PCCC1")
-                                .param("startDate", "2025-01-01 00:00:00")
-                                .param("endDate", "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(hematologyAnalyticsService, times(1))
-                .findAnalyticsByNameInByLevel(anyList(), any(), any(), any(), any(Pageable.class));
-    }
-
-    @Test
-    @DisplayName("It should return HTTP code 201 when analytics records are saved")
-    void analytics_post_return_201() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        mockMvc.perform(post("/hematology-analytics").contentType(MediaType.APPLICATION_JSON)
-                                                     .content(jacksonGenericValuesRecord.write(records).getJson()))
-               .andExpect(status().isCreated());
-        verify(hematologyAnalyticsService, times(1)).saveNewAnalyticsRecords(anyList());
-    }
-
-    @Test
-    @DisplayName("It should return a list of all analytics with pagination")
-    void getAllAnalytics_return_list() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-        when(hematologyAnalyticsService.findAnalyticsPagedByNameIn(anyList(), any(Pageable.class)))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/hematology-analytics")
-                                .param("page", "0")
-                                .param("size", "10"))
-               .andExpect(status().isOk());
-
-        verify(hematologyAnalyticsService, times(1))
-                .findAnalyticsPagedByNameIn(anyList(), any(Pageable.class));
-    }
-
-
-    @Test
-    @DisplayName("It should return analytics records for a date range")
-    void getAnalyticsByDateRange_return_analytics() throws Exception {
-        List<AnalyticsDTO> records = createSampleRecordList();
-        Page<AnalyticsDTO> page = new PageImpl<>(records);
-
-        when(hematologyAnalyticsService.findAnalyticsByNameInAndDateBetween(anyList(), any(), any(), any()))
-                .thenReturn(page);
-
-        mockMvc.perform(get("/hematology-analytics/date-range")
-                                .param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-
-        verify(hematologyAnalyticsService, times(1))
-                .findAnalyticsByNameInAndDateBetween(anyList(), any(), any(), any());
-    }
-
-    @Test
-    @DisplayName("It should return mean and standard deviation for a date range")
-    void getMeanAndStandardDeviation_return_result() throws Exception {
-        MeanAndStdDeviationDTO result = new MeanAndStdDeviationDTO(10.5, 2.3);
-        when(hematologyAnalyticsService.calculateMeanAndStandardDeviation(any(), any(), any(),
-                                                                          any())).thenReturn(result);
-
-        mockMvc.perform(get("/hematology-analytics/mean-standard-deviation")
-                                .param("name", "Hemoglobin").param("level", "High")
-                                .param("startDate", "2025-01-01 00:00:00").param("endDate",
-                                                                                 "2025-01-05 00:00:00"))
-               .andExpect(status().isOk());
-        verify(hematologyAnalyticsService, times(1))
-                .calculateMeanAndStandardDeviation(any(), any(),
-                                                   any(), any());
-    }
+	@MockitoBean
+	private TokenService tokenService;
+
+	@MockitoBean
+	private UserRepository userRepository;
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@MockitoBean
+	private HematologyAnalyticService hematologyAnalyticsService;
+
+	@Autowired
+	private JacksonTester<List<AnalyticsDTO>> jacksonGenericValuesRecord;
+
+	@Test
+	@DisplayName("It should return a list of all analytics by level")
+	void getAllAnalytics_by_level_return_list() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+		when(hematologyAnalyticsService.findAnalyticsByNameInByLevel(anyList(), any(), any(), any(),
+				any(Pageable.class))).thenReturn(page);
+
+		mockMvc.perform(get("/hematology-analytics/level-date-range").param("level", "PCCC1")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
+				.andExpect(status().isOk());
+
+		verify(hematologyAnalyticsService, times(1)).findAnalyticsByNameInByLevel(anyList(), any(),
+				any(), any(), any(Pageable.class));
+	}
+
+	@Test
+	@DisplayName("It should return HTTP code 201 when analytics records are saved")
+	void analytics_post_return_201() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		mockMvc.perform(post("/hematology-analytics").contentType(MediaType.APPLICATION_JSON)
+				.content(jacksonGenericValuesRecord.write(records).getJson()))
+				.andExpect(status().isCreated());
+		verify(hematologyAnalyticsService, times(1)).saveNewAnalyticsRecords(anyList());
+	}
+
+	@Test
+	@DisplayName("It should return a list of all analytics with pagination")
+	void getAllAnalytics_return_list() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+		when(hematologyAnalyticsService.findAnalyticsPagedByNameIn(anyList(), any(Pageable.class)))
+				.thenReturn(page);
+
+		mockMvc.perform(get("/hematology-analytics").param("page", "0").param("size", "10"))
+				.andExpect(status().isOk());
+
+		verify(hematologyAnalyticsService, times(1)).findAnalyticsPagedByNameIn(anyList(),
+				any(Pageable.class));
+	}
+
+
+	@Test
+	@DisplayName("It should return analytics records for a date range")
+	void getAnalyticsByDateRange_return_analytics() throws Exception {
+		List<AnalyticsDTO> records = createSampleRecordList();
+		Page<AnalyticsDTO> page = new PageImpl<>(records);
+
+		when(hematologyAnalyticsService.findAnalyticsByNameInAndDateBetween(anyList(), any(), any(),
+				any())).thenReturn(page);
+
+		mockMvc.perform(get("/hematology-analytics/date-range")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00"))
+				.andExpect(status().isOk());
+
+		verify(hematologyAnalyticsService, times(1)).findAnalyticsByNameInAndDateBetween(anyList(),
+				any(), any(), any());
+	}
+
+	@Test
+	@DisplayName("It should return mean and standard deviation for a date range")
+	void getMeanAndStandardDeviation_return_result() throws Exception {
+		MeanAndStdDeviationDTO result = new MeanAndStdDeviationDTO(10.5, 2.3);
+		LocalDateTime startDate = LocalDateTime.parse("2025-01-01 00:00:00",
+				DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+		LocalDateTime endDate = LocalDateTime.parse("2025-01-05 00:00:00",
+				DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+		when(hematologyAnalyticsService.calculateMeanAndStandardDeviation(eq("Hemoglobin"),
+				eq("High"), eq(startDate), eq(endDate), any(Pageable.class))).thenReturn(result);
+
+		mockMvc.perform(get("/hematology-analytics/mean-standard-deviation")
+				.param("name", "Hemoglobin").param("level", "High")
+				.param("startDate", "2025-01-01 00:00:00").param("endDate", "2025-01-05 00:00:00")
+				.param("page", "0").param("size", "10")).andExpect(status().isOk());
+
+		verify(hematologyAnalyticsService).calculateMeanAndStandardDeviation(eq("Hemoglobin"),
+				eq("High"), eq(startDate), eq(endDate), any(Pageable.class));
+	}
 }
diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/UsersControllerTest.java b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/UsersControllerTest.java
index 15e66a8..7a64832 100644
--- a/src/test/java/leonardo/labutilities/qualitylabpro/controllers/UsersControllerTest.java
+++ b/src/test/java/leonardo/labutilities/qualitylabpro/controllers/UsersControllerTest.java
@@ -1,17 +1,17 @@
 package leonardo.labutilities.qualitylabpro.controllers;
 
-import leonardo.labutilities.qualitylabpro.configs.TestSecurityConfig;
-import leonardo.labutilities.qualitylabpro.controllers.users.UsersController;
-import leonardo.labutilities.qualitylabpro.dtos.authentication.LoginUserDTO;
-import leonardo.labutilities.qualitylabpro.dtos.authentication.TokenJwtDTO;
-import leonardo.labutilities.qualitylabpro.dtos.users.RecoverPasswordDTO;
-import leonardo.labutilities.qualitylabpro.dtos.users.UpdatePasswordDTO;
-import leonardo.labutilities.qualitylabpro.dtos.users.UsersDTO;
-import leonardo.labutilities.qualitylabpro.entities.User;
-import leonardo.labutilities.qualitylabpro.enums.UserRoles;
-import leonardo.labutilities.qualitylabpro.repositories.UserRepository;
-import leonardo.labutilities.qualitylabpro.services.authentication.TokenService;
-import leonardo.labutilities.qualitylabpro.services.users.UserService;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -32,16 +32,19 @@
 import org.springframework.test.context.ActiveProfiles;
 import org.springframework.test.context.bean.override.mockito.MockitoBean;
 import org.springframework.test.web.servlet.MockMvc;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.*;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import leonardo.labutilities.qualitylabpro.configs.TestSecurityConfig;
+import leonardo.labutilities.qualitylabpro.controllers.users.UsersController;
+import leonardo.labutilities.qualitylabpro.dtos.authentication.LoginUserDTO;
+import leonardo.labutilities.qualitylabpro.dtos.authentication.TokenJwtDTO;
+import leonardo.labutilities.qualitylabpro.dtos.users.RecoverPasswordDTO;
+import leonardo.labutilities.qualitylabpro.dtos.users.SignUpUsersDTO;
+import leonardo.labutilities.qualitylabpro.dtos.users.UpdatePasswordDTO;
+import leonardo.labutilities.qualitylabpro.dtos.users.UsersDTO;
+import leonardo.labutilities.qualitylabpro.entities.User;
+import leonardo.labutilities.qualitylabpro.enums.UserRoles;
+import leonardo.labutilities.qualitylabpro.repositories.UserRepository;
+import leonardo.labutilities.qualitylabpro.services.authentication.TokenService;
+import leonardo.labutilities.qualitylabpro.services.users.UserService;
 
 @WebMvcTest(UsersController.class)
 @Import(TestSecurityConfig.class)
@@ -68,6 +71,10 @@ class UsersControllerTest {
 	@Autowired
 	private JacksonTester<UsersDTO> usersRecordJacksonTester;
 
+	@Autowired
+	private JacksonTester<SignUpUsersDTO> signUpUsersDTOJacksonTester;
+
+
 	@Autowired
 	private JacksonTester<LoginUserDTO> loginRecordJacksonTester;
 
@@ -80,18 +87,15 @@ class UsersControllerTest {
 	@Test
 	@DisplayName("Should return 204 when signing up a new user")
 	void signUp_return_204() throws Exception {
-		UsersDTO usersDTO = new UsersDTO("testUser", "Marmota2024@", "test@example.com");
-		User user = new User("testUser", "password", "test@example.com", UserRoles.USER);
-
-		when(userService.signUp(anyString(), anyString(), anyString())).thenReturn(user);
+		SignUpUsersDTO signUpUsersDTO =
+				new SignUpUsersDTO("Leonardo Meireles", "marmotas2024@email.com", "marmotas2024@");
 
 		mockMvc.perform(post("/users/sign-up").contentType(MediaType.APPLICATION_JSON)
-				.content(usersRecordJacksonTester.write(usersDTO).getJson()))
-				.andExpect(status().isNoContent())
-				.andExpect(jsonPath("$.identifier").value("testUser"))
-				.andExpect(jsonPath("$.identifier").value("test@example.com"));
+				.content(signUpUsersDTOJacksonTester.write(signUpUsersDTO).getJson()))
+				.andExpect(status().isNoContent());
 
-		verify(userService).signUp(usersDTO.username(), usersDTO.password(), usersDTO.email());
+		verify(userService).signUp(signUpUsersDTO.identifier(), signUpUsersDTO.email(),
+				signUpUsersDTO.password());
 	}
 
 	@Test
diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java b/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java
index b343351..9b18150 100644
--- a/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java
+++ b/src/test/java/leonardo/labutilities/qualitylabpro/services/AnalyticHelperServiceTests.java
@@ -51,14 +51,15 @@ void setUp() {
 
 				@Override
 				public List<AnalyticsDTO> findAnalyticsByNameAndLevel(Pageable pageable,
-                                                                      String name, String level) {
+						String name, String level) {
 					return analyticsRepository.findByNameAndLevel(pageable, name, level).stream()
 							.map(AnalyticMapper::toRecord).toList();
 				}
 
 				@Override
 				public List<AnalyticsDTO> findAnalyticsByNameAndLevelAndDate(String name,
-                                                                             String level, LocalDateTime dateStart, LocalDateTime dateEnd) {
+						String level, LocalDateTime dateStart, LocalDateTime dateEnd,
+						Pageable pageable) {
 					return analyticsRepository
 							.findByNameAndLevelAndDateBetween(name, level, dateStart, dateEnd,
 									PageRequest.of(0, 200))
@@ -123,7 +124,8 @@ void saveNewAnalyticsRecords_WithValidRecords_ShouldSaveSuccessfully() {
 		List<AnalyticsDTO> records = createSampleRecordList();
 		when(analyticsRepository.existsByDateAndLevelAndName(any(), any(), any()))
 				.thenReturn(false);
-		when(analyticsRepository.saveAll(any())).thenReturn(null);
+		when(analyticsRepository.saveAll(any()))
+				.thenAnswer(invocation -> invocation.getArgument(0));
 
 		assertDoesNotThrow(() -> analyticHelperService.saveNewAnalyticsRecords(records));
 		verify(analyticsRepository, times(1)).saveAll(any());
@@ -191,8 +193,8 @@ void findAllAnalyticsByNameAndLevelAndDate_WithDateRange_ShouldReturnFilteredRec
 		when(analyticsRepository.findByNameAndLevelAndDateBetween(eq(name), eq(level),
 				eq(startDate), eq(endDate), any(Pageable.class))).thenReturn(expectedRecords);
 
-		List<AnalyticsDTO> result = analyticHelperService
-				.findAnalyticsByNameAndLevelAndDate(name, level, startDate, endDate);
+		List<AnalyticsDTO> result = analyticHelperService.findAnalyticsByNameAndLevelAndDate(name,
+				level, startDate, endDate, null);
 
 		assertNotNull(result);
 		assertEquals(expectedRecords.size(), result.size());
@@ -281,8 +283,8 @@ void findGroupedAnalyticsByLevel_WithValidInputs_ShouldReturnGroupedRecords() {
 		when(analyticsRepository.findByNameAndDateBetweenGroupByLevel(eq(name), eq(startDate),
 				eq(endDate), any(Pageable.class))).thenReturn(records);
 
-		List<GroupedValuesByLevelDTO> result =
-				analyticHelperService.findGroupedAnalyticsByLevel(name, startDate, endDate);
+		List<GroupedValuesByLevelDTO> result = analyticHelperService
+				.findGroupedAnalyticsByLevel(name, startDate, endDate, Pageable.unpaged());
 
 		assertNotNull(result);
 		assertFalse(result.isEmpty());
diff --git a/src/test/java/leonardo/labutilities/qualitylabpro/services/UserServiceTest.java b/src/test/java/leonardo/labutilities/qualitylabpro/services/UserServiceTest.java
index 9e309df..0f4af46 100644
--- a/src/test/java/leonardo/labutilities/qualitylabpro/services/UserServiceTest.java
+++ b/src/test/java/leonardo/labutilities/qualitylabpro/services/UserServiceTest.java
@@ -23,101 +23,102 @@
 @ExtendWith(MockitoExtension.class)
 class UserServiceTest {
 
-    @Mock
-    private UserRepository userRepository;
-
-    @Mock
-    private PasswordRecoveryTokenManager passwordRecoveryTokenManager;
-
-    @Mock
-    private EmailService emailService;
-
-    @InjectMocks
-    private UserService userService;
-
-    @Test
-    void testRecoverPassword_UserExists() {
-        when(userRepository.existsByUsernameAndEmail(anyString(), anyString())).thenReturn(true);
-        when(passwordRecoveryTokenManager.generateTemporaryPassword()).thenReturn("tempPassword");
-
-        userService.recoverPassword("identifier", "identifier@example.com");
-
-        verify(passwordRecoveryTokenManager).generateAndStoreToken("identifier@example.com",
-                                                                   "tempPassword");
-        verify(emailService).sendPlainTextEmail(any());
-    }
-
-    @Test
-    void testRecoverPassword_UserDoesNotExist() {
-        when(userRepository.existsByUsernameAndEmail(anyString(), anyString())).thenReturn(false);
-
-        assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class,
-                     () -> userService.recoverPassword("identifier", "identifier@example.com"));
-    }
-
-    @Test
-    void testChangePassword_ValidToken() {
-        User user = new User("identifier", BCryptEncoderComponent.encrypt("newPassword"),
-                             "identifier@example.com", UserRoles.USER);
-        when(passwordRecoveryTokenManager.isRecoveryTokenValid(anyString(), anyString()))
-                .thenReturn(true);
-        userService.changePassword("identifier@example.com", "tempPassword", "newPassword");
-        assertThat(passwordRecoveryTokenManager.isRecoveryTokenValid("tempPassword",
-                                                                     "identifier@example.com")).isTrue();
-    }
-
-    @Test
-    void testChangePassword_InvalidToken() {
-        when(passwordRecoveryTokenManager.isRecoveryTokenValid(anyString(), anyString()))
-                .thenReturn(false);
-
-        assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class, () -> userService
-                .changePassword("identifier@example.com", "tempPassword", "newPassword"));
-    }
-
-    @Test
-    void testSignUp_UserAlreadyExists() {
-        when(userRepository.existsByEmail(anyString())).thenReturn(true);
-
-        assertThrows(CustomGlobalErrorHandling.UserAlreadyExistException.class,
-                     () -> userService.signUp("identifier", "password", "identifier@example.com"));
-    }
-
-    @Test
-    void testSignUp_NewUser() {
-        when(userRepository.existsByEmail(anyString())).thenReturn(false);
-        when(userRepository.save(any(User.class))).thenReturn(
-                new User("identifier", "encryptedPassword", "identifier@example.com", UserRoles.USER));
-
-        User user = userService.signUp("identifier", "password", "identifier@example.com");
-
-        assertNotNull(user);
-        assertEquals("identifier", user.getUsername());
-        assertEquals("identifier@example.com", user.getEmail());
-    }
-
-    @Test
-    void should_return_error_with_testUpdateUserPassword_PasswordMatches() {
-        User user = new User("identifier", BCryptEncoderComponent.encrypt("newPassword"),
-                             "identifier@example.com", UserRoles.USER);
-
-        when(userRepository.getReferenceByUsernameAndEmail(anyString(), anyString()))
-                .thenReturn(user);
-
-        assertThrows(CustomGlobalErrorHandling.PasswordNotMatchesException.class, () -> userService
-                .updateUserPassword("identifier", "identifier@example.com", "oldPassword", "newPassword"));
-        verify(userRepository, never()).setPasswordWhereByUsername(anyString(), anyString());
-    }
-
-    @Test
-    void testUpdateUserPassword_PasswordDoesNotMatch() {
-        User user = new User("identifier", BCryptEncoderComponent.encrypt("oldPassword"),
-                             "identifier@example.com", UserRoles.USER);
-        when(userRepository.getReferenceByUsernameAndEmail(anyString(), anyString()))
-                .thenReturn(user);
-
-        assertThrows(CustomGlobalErrorHandling.PasswordNotMatchesException.class,
-                     () -> userService.updateUserPassword("identifier", "identifier@example.com",
-                                                          "wrongPassword", "newPassword"));
-    }
+	@Mock
+	private UserRepository userRepository;
+
+	@Mock
+	private PasswordRecoveryTokenManager passwordRecoveryTokenManager;
+
+	@Mock
+	private EmailService emailService;
+
+	@InjectMocks
+	private UserService userService;
+
+	@Test
+	void testRecoverPassword_UserExists() {
+		when(userRepository.existsByUsernameAndEmail(anyString(), anyString())).thenReturn(true);
+		when(passwordRecoveryTokenManager.generateTemporaryPassword()).thenReturn("tempPassword");
+
+		userService.recoverPassword("identifier", "identifier@example.com");
+
+		verify(passwordRecoveryTokenManager).generateAndStoreToken("identifier@example.com",
+				"tempPassword");
+		verify(emailService).sendPlainTextEmail(any());
+	}
+
+	@Test
+	void testRecoverPassword_UserDoesNotExist() {
+		when(userRepository.existsByUsernameAndEmail(anyString(), anyString())).thenReturn(false);
+
+		assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class,
+				() -> userService.recoverPassword("identifier", "identifier@example.com"));
+	}
+
+	@Test
+	void testChangePassword_ValidToken() {
+		User user = new User("identifier", BCryptEncoderComponent.encrypt("newPassword"),
+				"identifier@example.com", UserRoles.USER);
+		when(passwordRecoveryTokenManager.isRecoveryTokenValid(anyString(), anyString()))
+				.thenReturn(true);
+		userService.changePassword("identifier@example.com", "tempPassword", "newPassword");
+		assertThat(passwordRecoveryTokenManager.isRecoveryTokenValid("tempPassword",
+				"identifier@example.com")).isTrue();
+	}
+
+	@Test
+	void testChangePassword_InvalidToken() {
+		when(passwordRecoveryTokenManager.isRecoveryTokenValid(anyString(), anyString()))
+				.thenReturn(false);
+
+		assertThrows(CustomGlobalErrorHandling.ResourceNotFoundException.class, () -> userService
+				.changePassword("identifier@example.com", "tempPassword", "newPassword"));
+	}
+
+	@Test
+	void testSignUp_UserAlreadyExists() {
+		when(userRepository.existsByUsernameOrEmail(anyString(), anyString())).thenReturn(true);
+
+		assertThrows(CustomGlobalErrorHandling.UserAlreadyExistException.class,
+				() -> userService.signUp("identifier", "identifier@example.com", "password"));
+	}
+
+	@Test
+	void testSignUp_NewUser() {
+		when(userRepository.existsByUsernameOrEmail(anyString(), anyString())).thenReturn(false);
+		when(userRepository.save(any(User.class))).thenReturn(new User("identifier",
+				"encryptedPassword", "identifier@example.com", UserRoles.USER));
+
+		User user = userService.signUp("identifier", "password", "identifier@example.com");
+
+		assertNotNull(user);
+		assertEquals("identifier", user.getUsername());
+		assertEquals("identifier@example.com", user.getEmail());
+	}
+
+	@Test
+	void should_return_error_with_testUpdateUserPassword_PasswordMatches() {
+		User user = new User("identifier", BCryptEncoderComponent.encrypt("newPassword"),
+				"identifier@example.com", UserRoles.USER);
+
+		when(userRepository.getReferenceByUsernameAndEmail(anyString(), anyString()))
+				.thenReturn(user);
+
+		assertThrows(CustomGlobalErrorHandling.PasswordNotMatchesException.class,
+				() -> userService.updateUserPassword("identifier", "identifier@example.com",
+						"oldPassword", "newPassword"));
+		verify(userRepository, never()).setPasswordWhereByUsername(anyString(), anyString());
+	}
+
+	@Test
+	void testUpdateUserPassword_PasswordDoesNotMatch() {
+		User user = new User("identifier", BCryptEncoderComponent.encrypt("oldPassword"),
+				"identifier@example.com", UserRoles.USER);
+		when(userRepository.getReferenceByUsernameAndEmail(anyString(), anyString()))
+				.thenReturn(user);
+
+		assertThrows(CustomGlobalErrorHandling.PasswordNotMatchesException.class,
+				() -> userService.updateUserPassword("identifier", "identifier@example.com",
+						"wrongPassword", "newPassword"));
+	}
 }