From b765cdd6159251fbbfd0c18be9c086cb023bd8a4 Mon Sep 17 00:00:00 2001 From: EdgarEldy Date: Mon, 9 Nov 2026 21:56:36 +0400 Subject: [PATCH 1/7] style(dto): add @JsonProperty snake_case to compound RegisterRequest fields firstName, lastName, and confirmPassword are multi-word camelCase fields. They must be serialised as first_name, last_name, and confirm_password in the JSON contract, consistent with every other compound field across the DTOs (see UserResponse, ProductResponse, CategoryResponse, etc.). Single-word fields (username, email, password) need no annotation because their Java name and the JSON key are identical. --- .../springboottutorial/dto/auth/RegisterRequest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/edgareldy/springboottutorial/dto/auth/RegisterRequest.java b/src/main/java/com/edgareldy/springboottutorial/dto/auth/RegisterRequest.java index 51670c8..593e3c3 100644 --- a/src/main/java/com/edgareldy/springboottutorial/dto/auth/RegisterRequest.java +++ b/src/main/java/com/edgareldy/springboottutorial/dto/auth/RegisterRequest.java @@ -4,6 +4,7 @@ import com.edgareldy.springboottutorial.validation.password.PasswordsMatch; import com.edgareldy.springboottutorial.validation.password.ValidPassword; import com.edgareldy.springboottutorial.validation.unique.Unique; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; @@ -24,10 +25,10 @@ public record RegisterRequest( @NotBlank(message = "First name must not be blank") - String firstName, + @JsonProperty("first_name") String firstName, @NotBlank(message = "Last name must not be blank") - String lastName, + @JsonProperty("last_name") String lastName, @NotBlank(message = "Username must not be blank") @Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters") @@ -46,7 +47,7 @@ public record RegisterRequest( String password, @NotBlank(message = "Password confirmation must not be blank") - String confirmPassword + @JsonProperty("confirm_password") String confirmPassword ) { // Overrides the compiler-generated toString(): LoggingAspect logs every From 052a49a36857ac9df4b136841e36531cf93ecf7b Mon Sep 17 00:00:00 2001 From: EdgarEldy Date: Mon, 9 Nov 2026 22:15:48 +0400 Subject: [PATCH 2/7] refactor(controller): rename /activate to /activate-account Aligns the endpoint name with the kebab-case convention used by all other multi-word paths in this project (forgot-password, reset-password). The new path /api/v1/auth/activate-account is also more self-describing for a client consuming the API. --- .../edgareldy/springboottutorial/controller/AuthController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/edgareldy/springboottutorial/controller/AuthController.java b/src/main/java/com/edgareldy/springboottutorial/controller/AuthController.java index 76fb755..6a61a5c 100644 --- a/src/main/java/com/edgareldy/springboottutorial/controller/AuthController.java +++ b/src/main/java/com/edgareldy/springboottutorial/controller/AuthController.java @@ -89,7 +89,7 @@ public ResponseEntity>> tokenInfo( return ResponseEntity.ok(ApiResponse.success(claims, "Token claims retrieved successfully")); } - @GetMapping("/activate") + @GetMapping("/activate-account") public ResponseEntity> activate(@RequestParam String token) { return ResponseEntity.ok(ApiResponse.success(userService.activate(token), "Account activated successfully")); } From 2614096b979738f6ca345e639846009df5ac76ee Mon Sep 17 00:00:00 2001 From: EdgarEldy Date: Mon, 9 Nov 2026 22:15:57 +0400 Subject: [PATCH 3/7] refactor(security): update permitAll rule for /activate-account endpoint Keeps the endpoint publicly accessible (no authentication required) under its new path /api/v1/auth/activate-account. --- .../com/edgareldy/springboottutorial/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/edgareldy/springboottutorial/config/SecurityConfig.java b/src/main/java/com/edgareldy/springboottutorial/config/SecurityConfig.java index acd7447..f09cbce 100644 --- a/src/main/java/com/edgareldy/springboottutorial/config/SecurityConfig.java +++ b/src/main/java/com/edgareldy/springboottutorial/config/SecurityConfig.java @@ -75,7 +75,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/api/v1/auth/forgot-password", "/api/v1/auth/reset-password", "/api/v1/auth/refresh-token") .permitAll() - .requestMatchers(HttpMethod.GET, "/api/v1/auth/activate") + .requestMatchers(HttpMethod.GET, "/api/v1/auth/activate-account") .permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/actuator/health") .permitAll() From 97e1dd8f14211e81d030b0571294ee06a02a1d57 Mon Sep 17 00:00:00 2001 From: EdgarEldy Date: Mon, 9 Nov 2026 22:16:08 +0400 Subject: [PATCH 4/7] refactor(service): update activation link URL to /auth/activate-account The frontend route receiving the activation token is renamed from /auth/activate to /auth/activate-account to match the backend endpoint path change. --- .../springboottutorial/service/impl/EmailServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImpl.java b/src/main/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImpl.java index 79641e1..99fb8d3 100644 --- a/src/main/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImpl.java +++ b/src/main/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImpl.java @@ -56,7 +56,7 @@ public EmailServiceImpl(JavaMailSender mailSender, @Override @Async("emailTaskExecutor") public void sendActivationEmail(AppUser user, String token) { - String link = frontendUrl + "/auth/activate?token=" + token; + String link = frontendUrl + "/auth/activate-account?token=" + token; Context context = new Context(Locale.ENGLISH); context.setVariable("username", user.getUsername()); context.setVariable("activationToken", token); From 81c03e4efb73190b4b25738e985d042cb17ea130 Mon Sep 17 00:00:00 2001 From: EdgarEldy Date: Mon, 9 Nov 2026 22:16:18 +0400 Subject: [PATCH 5/7] test(controller): update AuthControllerTest for /activate-account endpoint --- .../springboottutorial/controller/AuthControllerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java b/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java index 4785c53..3f38df4 100644 --- a/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java +++ b/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java @@ -189,7 +189,7 @@ void _10_ShouldReturn200_WhenActivateTokenValid() throws Exception { UserResponse response = new UserResponse(1L, "Ada", "Lovelace", "ada", "ada@example.com", Role.USER); when(userService.activate("valid-token")).thenReturn(response); - mockMvc.perform(get("/api/v1/auth/activate").param("token", "valid-token")) + mockMvc.perform(get("/api/v1/auth/activate-account").param("token", "valid-token")) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.username").value("ada")) .andExpect(jsonPath("$.message").value("Account activated successfully")); From d1b9055c82972ef7d827b85888f465ec5576dd4b Mon Sep 17 00:00:00 2001 From: EdgarEldy Date: Mon, 9 Nov 2026 22:16:28 +0400 Subject: [PATCH 6/7] test(service): update EmailServiceImplTest for /auth/activate-account URL --- .../springboottutorial/service/impl/EmailServiceImplTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImplTest.java b/src/test/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImplTest.java index 8747510..1853d2d 100644 --- a/src/test/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImplTest.java +++ b/src/test/java/com/edgareldy/springboottutorial/service/impl/EmailServiceImplTest.java @@ -67,7 +67,7 @@ void _01_ShouldPassFrontendActivationLink_WhenActivationEmailIsSent() { assertThat(ctx.getVariable("username")).isEqualTo("ada"); assertThat(ctx.getVariable("activationToken")).isEqualTo("raw-token"); assertThat(ctx.getVariable("activationLink")) - .isEqualTo(FRONTEND_URL + "/auth/activate?token=raw-token"); + .isEqualTo(FRONTEND_URL + "/auth/activate-account?token=raw-token"); verify(mailSender).send(any(MimeMessage.class)); } From 0cb92a2800af86caa33bd898664158301a6bd0af Mon Sep 17 00:00:00 2001 From: EdgarEldy Date: Mon, 9 Nov 2026 22:21:04 +0400 Subject: [PATCH 7/7] test(controller): fix remaining /activate path in _09_ invalid-token test --- .../springboottutorial/controller/AuthControllerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java b/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java index 6991ab2..47117f2 100644 --- a/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java +++ b/src/test/java/com/edgareldy/springboottutorial/controller/AuthControllerTest.java @@ -186,7 +186,7 @@ void _09_ShouldReturn400_WhenActivationTokenInvalid() throws Exception { when(userService.activate("bad-token")) .thenThrow(new InvalidTokenException("Invalid activation token")); - mockMvc.perform(get("/api/v1/auth/activate").param("token", "bad-token")) + mockMvc.perform(get("/api/v1/auth/activate-account").param("token", "bad-token")) .andExpect(status().isBadRequest()); }