From a55873a564c5a238b48b9bf2c60845533315dd37 Mon Sep 17 00:00:00 2001 From: Seungwon-Choi Date: Thu, 19 Feb 2026 03:19:57 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor:=20AppleRestClient=20Bean=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=20=EB=B0=8F=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/infrastructure/apple/AppleAuthClientAdapter.java | 4 ++-- .../java/com/loopon/global/config/RestClientConfig.java | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/loopon/auth/infrastructure/apple/AppleAuthClientAdapter.java b/src/main/java/com/loopon/auth/infrastructure/apple/AppleAuthClientAdapter.java index 284384e8..cfdd3505 100644 --- a/src/main/java/com/loopon/auth/infrastructure/apple/AppleAuthClientAdapter.java +++ b/src/main/java/com/loopon/auth/infrastructure/apple/AppleAuthClientAdapter.java @@ -17,7 +17,7 @@ @Component @RequiredArgsConstructor public class AppleAuthClientAdapter { - private final RestClient kakaoRestClient; + private final RestClient appleRestClient; private final AppleClientSecretGenerator secretGenerator; @Value("${apple.client-id}") @@ -33,7 +33,7 @@ public AppleTokenResponse getTokens(String authorizationCode) { params.add("grant_type", "authorization_code"); try { - return kakaoRestClient.post() + return appleRestClient.post() .uri("https://appleid.apple.com/auth/token") .contentType(MediaType.APPLICATION_FORM_URLENCODED) .body(params) diff --git a/src/main/java/com/loopon/global/config/RestClientConfig.java b/src/main/java/com/loopon/global/config/RestClientConfig.java index 8070c5d5..65b4f6be 100644 --- a/src/main/java/com/loopon/global/config/RestClientConfig.java +++ b/src/main/java/com/loopon/global/config/RestClientConfig.java @@ -14,6 +14,13 @@ public RestClient kakaoRestClient() { .build(); } + @Bean("appleRestClient") + public RestClient appleRestClient() { + return RestClient.builder() + .baseUrl("https://appleid.apple.com") + .build(); + } + @Bean("geminiRestClient") public RestClient geminiRestClient() { return RestClient.builder() From dded26fffe7eb8924966345ab145599e9dbd09b1 Mon Sep 17 00:00:00 2001 From: Seungwon-Choi Date: Thu, 19 Feb 2026 03:23:42 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20DTO=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=20=EB=B0=8F=20=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../loopon/auth/application/dto/request/LoginRequest.java | 1 + .../auth/application/dto/request/PasswordResetRequest.java | 7 ++++--- .../auth/application/dto/request/SocialLoginRequest.java | 7 +++++-- .../auth/application/dto/request/VerificationRequest.java | 5 +++-- .../application/dto/request/VerificationVerifyRequest.java | 7 ++++--- .../loopon/auth/application/dto/response/AuthResult.java | 5 +++++ 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/loopon/auth/application/dto/request/LoginRequest.java b/src/main/java/com/loopon/auth/application/dto/request/LoginRequest.java index 87cb208a..75eab8f3 100644 --- a/src/main/java/com/loopon/auth/application/dto/request/LoginRequest.java +++ b/src/main/java/com/loopon/auth/application/dto/request/LoginRequest.java @@ -5,6 +5,7 @@ public record LoginRequest( @NotBlank(message = "이메일을 입력해주세요.") String email, + @NotBlank(message = "비밀번호를 입력해주세요.") String password ) { diff --git a/src/main/java/com/loopon/auth/application/dto/request/PasswordResetRequest.java b/src/main/java/com/loopon/auth/application/dto/request/PasswordResetRequest.java index 3d1ffc96..f5e4f5a3 100644 --- a/src/main/java/com/loopon/auth/application/dto/request/PasswordResetRequest.java +++ b/src/main/java/com/loopon/auth/application/dto/request/PasswordResetRequest.java @@ -5,13 +5,14 @@ import jakarta.validation.constraints.Pattern; public record PasswordResetRequest( - @NotBlank @Email + @NotBlank(message = "이메일을 입력해주세요.") + @Email(message = "유효한 이메일 주소를 입력해주세요.") String email, - @NotBlank + @NotBlank(message = "리셋 토큰을 입력해주세요.") String resetToken, - @NotBlank + @NotBlank(message = "새 비밀번호를 입력해주세요.") @Pattern(regexp = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*#?&])[A-Za-z\\d@$!%*#?&]{8,}$", message = "비밀번호는 영문, 숫자, 특수문자를 포함하여 8자 이상이어야 합니다.") String newPassword diff --git a/src/main/java/com/loopon/auth/application/dto/request/SocialLoginRequest.java b/src/main/java/com/loopon/auth/application/dto/request/SocialLoginRequest.java index e32ce776..560e470c 100644 --- a/src/main/java/com/loopon/auth/application/dto/request/SocialLoginRequest.java +++ b/src/main/java/com/loopon/auth/application/dto/request/SocialLoginRequest.java @@ -5,7 +5,10 @@ import jakarta.validation.constraints.NotNull; public record SocialLoginRequest( - @NotNull UserProvider provider, - @NotBlank String accessToken + @NotNull(message = "소셜 로그인 제공자를 선택해주세요.") + UserProvider provider, + + @NotBlank(message = "액세스 토큰을 입력해주세요.") + String accessToken ) { } diff --git a/src/main/java/com/loopon/auth/application/dto/request/VerificationRequest.java b/src/main/java/com/loopon/auth/application/dto/request/VerificationRequest.java index 96e8bc7b..2907019a 100644 --- a/src/main/java/com/loopon/auth/application/dto/request/VerificationRequest.java +++ b/src/main/java/com/loopon/auth/application/dto/request/VerificationRequest.java @@ -6,10 +6,11 @@ import jakarta.validation.constraints.NotNull; public record VerificationRequest( - @NotBlank @Email + @NotBlank(message = "이메일을 입력해주세요.") + @Email(message = "유효한 이메일 주소를 입력해주세요.") String email, - @NotNull + @NotNull(message = "검증 목적을 선택해주세요.") VerificationPurpose purpose ) { } diff --git a/src/main/java/com/loopon/auth/application/dto/request/VerificationVerifyRequest.java b/src/main/java/com/loopon/auth/application/dto/request/VerificationVerifyRequest.java index c69b0eca..cf7d352a 100644 --- a/src/main/java/com/loopon/auth/application/dto/request/VerificationVerifyRequest.java +++ b/src/main/java/com/loopon/auth/application/dto/request/VerificationVerifyRequest.java @@ -6,13 +6,14 @@ import jakarta.validation.constraints.NotNull; public record VerificationVerifyRequest( - @NotBlank @Email + @NotBlank(message = "이메일을 입력해주세요.") + @Email(message = "유효한 이메일 주소를 입력해주세요.") String email, - @NotBlank + @NotBlank(message = "검증 코드를 입력해주세요.") String code, - @NotNull + @NotNull(message = "검증 목적을 선택해주세요.") VerificationPurpose purpose ) { } diff --git a/src/main/java/com/loopon/auth/application/dto/response/AuthResult.java b/src/main/java/com/loopon/auth/application/dto/response/AuthResult.java index d7b685a1..d025129e 100644 --- a/src/main/java/com/loopon/auth/application/dto/response/AuthResult.java +++ b/src/main/java/com/loopon/auth/application/dto/response/AuthResult.java @@ -1,7 +1,12 @@ package com.loopon.auth.application.dto.response; +import io.swagger.v3.oas.annotations.media.Schema; + public record AuthResult( + @Schema(description = "액세스 토큰 (Bearer)", example = "eyJhbGciOiJIUzI1NiJ9...") String accessToken, + + @Schema(description = "리프레시 토큰", example = "d1f2e3c4b5a6...") String refreshToken ) { From 5906b43c380f3baf4f07ed0e6f1e2c227ce1a7e7 Mon Sep 17 00:00:00 2001 From: Seungwon-Choi Date: Thu, 19 Feb 2026 03:41:23 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/loopon/global/config/HttpInterfaceConfig.java | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/main/java/com/loopon/global/config/HttpInterfaceConfig.java diff --git a/src/main/java/com/loopon/global/config/HttpInterfaceConfig.java b/src/main/java/com/loopon/global/config/HttpInterfaceConfig.java deleted file mode 100644 index 6cbc49bb..00000000 --- a/src/main/java/com/loopon/global/config/HttpInterfaceConfig.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.loopon.global.config; - -import org.springframework.context.annotation.Configuration; - -@Configuration -public class HttpInterfaceConfig { -} From ddf8cc26569137354c4aac8174638c91b089f90c Mon Sep 17 00:00:00 2001 From: Seungwon-Choi Date: Thu, 19 Feb 2026 03:41:38 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20HealthCheckController=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../loopon/global/config/SecurityConfig.java | 3 +- .../global/health/HealthCheckController.java | 38 +++++++++++++++++++ .../filter/JwtAuthenticationFilter.java | 2 + 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/loopon/global/health/HealthCheckController.java diff --git a/src/main/java/com/loopon/global/config/SecurityConfig.java b/src/main/java/com/loopon/global/config/SecurityConfig.java index cfe5a927..5d418e90 100644 --- a/src/main/java/com/loopon/global/config/SecurityConfig.java +++ b/src/main/java/com/loopon/global/config/SecurityConfig.java @@ -31,6 +31,7 @@ public class SecurityConfig { private static final String[] PUBLIC_URLS = { "/", + "/health", "/favicon.ico", "/v3/api-docs/**", "/swagger-ui/**", @@ -50,7 +51,7 @@ public class SecurityConfig { private static final String[] API_URLS = { "/api/users/me", "/api/users/profile", - "/api/users/password", + "/api/users/password" }; @Bean diff --git a/src/main/java/com/loopon/global/health/HealthCheckController.java b/src/main/java/com/loopon/global/health/HealthCheckController.java new file mode 100644 index 00000000..936b674e --- /dev/null +++ b/src/main/java/com/loopon/global/health/HealthCheckController.java @@ -0,0 +1,38 @@ +package com.loopon.global.health; + +import com.loopon.global.domain.dto.CommonResponse; +import io.swagger.v3.oas.annotations.Hidden; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.Map; + +@RestController +@Hidden +@RequiredArgsConstructor +public class HealthCheckController { + + @Value("${spring.profiles.active:default}") + private String activeProfile; + + @GetMapping("/") + public ResponseEntity>> systemStatus() { + Map status = Map.of( + "status", "UP", + "profile", activeProfile, + "serverTime", LocalDateTime.now().toString(), + "message", "LoopOn API Server is running!" + ); + + return ResponseEntity.ok(CommonResponse.onSuccess(status)); + } + + @GetMapping("/health") + public String healthCheck() { + return "OK"; + } +} \ No newline at end of file diff --git a/src/main/java/com/loopon/global/security/filter/JwtAuthenticationFilter.java b/src/main/java/com/loopon/global/security/filter/JwtAuthenticationFilter.java index 051ace48..7f8b7d81 100644 --- a/src/main/java/com/loopon/global/security/filter/JwtAuthenticationFilter.java +++ b/src/main/java/com/loopon/global/security/filter/JwtAuthenticationFilter.java @@ -28,6 +28,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final List excludeUrlPatterns = List.of( "/", + "/health", "/favicon.ico", "/v3/api-docs/**", "/swagger-ui/**", @@ -40,6 +41,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { "/api/users/upload-profile-image", "/api/auth/login/**", "/api/auth/reissue", + "/api/auth/logout", "/api/auth/verification/**" );