-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: 인증 도메인 리팩토링 #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
90271b7
e9cb5b4
29e6270
81d9a01
37c54f6
f01cab4
baf7c6c
7b93e32
be67880
8499053
fc5114c
d7017d4
5a4f5ab
8db150f
92fcf50
d5d0046
becef68
c7ece94
4d4ad7b
dc25553
d42517b
0313411
873ecb3
0b5f8a4
f9c38e3
7c8eb79
491594d
0e27462
4842ba6
6ae0a6e
b876e9d
0250e3a
be84076
681db36
563117d
b300a52
914d72b
7c2c699
187496f
eeec87e
0da7e95
0126cbf
902106e
c8421a8
6660280
0d428b4
332e7a1
1a2844f
ffe911e
75d80e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package org.yapp.apis.auth.dto.request | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema | ||
| import jakarta.validation.constraints.NotBlank | ||
| import org.yapp.apis.auth.dto.response.RefreshTokenResponse | ||
|
|
||
| @Schema( | ||
| name = "DeleteTokenRequest", | ||
| description = "Request DTO for deleting a refresh token" | ||
| ) | ||
| data class DeleteTokenRequest( | ||
| @field:NotBlank(message = "Refresh token must not be blank.") | ||
| @Schema(description = "Refresh token to be deleted", example = "eyJhbGciOiJIUz...") | ||
| val refreshToken: String? = null | ||
| ) { | ||
| fun validRefreshToken() = refreshToken!! | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 강제 언래핑으로 인한 잠재적 런타임 예외 위험이 있습니다.
다음과 같이 안전한 방식으로 개선할 수 있습니다: - fun validRefreshToken() = refreshToken!!
+ fun validRefreshToken(): String {
+ return refreshToken ?: throw IllegalStateException("Refresh token must not be null after validation")
+ }또는 검증된 상태에서만 호출되는 것이 보장된다면 주석으로 명시하는 것도 좋은 방법입니다. 🤖 Prompt for AI Agents |
||
|
|
||
| companion object { | ||
| fun from(refreshTokenResponse: RefreshTokenResponse): DeleteTokenRequest { | ||
| return DeleteTokenRequest(refreshToken = refreshTokenResponse.refreshToken) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| package org.yapp.apis.auth.dto.request | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema | ||
| import jakarta.validation.constraints.NotBlank | ||
| import org.yapp.apis.auth.dto.response.UserCreateInfoResponse | ||
| import org.yapp.apis.util.NicknameGenerator | ||
| import org.yapp.domain.user.ProviderType | ||
|
|
||
| @Schema( | ||
| name = "FindOrCreateUserRequest", | ||
| description = "Request DTO for finding an existing user or creating a new one during social login" | ||
| ) | ||
| data class FindOrCreateUserRequest private constructor( | ||
| @Schema( | ||
| description = "사용자 이메일", | ||
| example = "[email protected]", nullable = true) | ||
| val email: String? = null, | ||
|
|
||
| @Schema( | ||
| description = "사용자 닉네임", | ||
| example = "코딩하는곰", | ||
| nullable = true | ||
| ) | ||
| val nickname: String? = null, | ||
|
|
||
| @Schema( | ||
| description = "사용자 프로필 이미지 URL", | ||
| example = "https://example.com/image.jpg", | ||
| nullable = true | ||
| ) | ||
| val profileImageUrl: String? = null, | ||
|
|
||
| @Schema( | ||
| description = "소셜 로그인 제공자", | ||
| example = "KAKAO" | ||
| ) | ||
| @field:NotBlank(message = "providerType은 필수입니다.") | ||
| val providerType: ProviderType? = null, | ||
|
|
||
| @Schema( | ||
| description = "소셜 제공자에서 발급한 식별자", | ||
| example = "12345678901234567890" | ||
| ) | ||
| @field:NotBlank(message = "providerId는 필수입니다.") | ||
| val providerId: String? = null | ||
| ) { | ||
| fun getOrDefaultEmail(): String { | ||
| return email?.takeIf { it.isNotBlank() } ?: "${validProviderId()}@${validProviderType().name.lowercase()}.local" | ||
| } | ||
|
|
||
| fun getOrDefaultNickname(): String { | ||
| return nickname?.takeIf { it.isNotBlank() } ?: NicknameGenerator.generate() | ||
| } | ||
|
|
||
| fun validProviderType(): ProviderType = providerType!! | ||
| fun validProviderId(): String = providerId!! | ||
|
|
||
| companion object { | ||
| fun from( | ||
| userCreateInfoResponse: UserCreateInfoResponse | ||
| ): FindOrCreateUserRequest { | ||
| return FindOrCreateUserRequest( | ||
| email = userCreateInfoResponse.email, | ||
| nickname = userCreateInfoResponse.nickname, | ||
| profileImageUrl = userCreateInfoResponse.profileImageUrl, | ||
| providerType = userCreateInfoResponse.providerType, | ||
| providerId = userCreateInfoResponse.providerId | ||
| ) | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,27 @@ | ||||||||||
| package org.yapp.apis.auth.dto.request | ||||||||||
|
|
||||||||||
| import io.swagger.v3.oas.annotations.media.Schema | ||||||||||
| import jakarta.validation.constraints.NotNull | ||||||||||
| import org.yapp.apis.auth.dto.response.UserIdResponse | ||||||||||
| import java.util.* | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기 수정 부탁드릴게요! |
||||||||||
|
|
||||||||||
| @Schema( | ||||||||||
| name = "FindUserIdentityRequest", | ||||||||||
| description = "Request DTO to retrieve user identity information using userId" | ||||||||||
| ) | ||||||||||
| data class FindUserIdentityRequest( | ||||||||||
| @Schema( | ||||||||||
| description = "User ID (UUID format)", | ||||||||||
| example = "a1b2c3d4-e5f6-7890-1234-56789abcdef0" | ||||||||||
| ) | ||||||||||
| @field:NotNull(message = "userId must not be null") | ||||||||||
| val userId: UUID? = null | ||||||||||
move-hoon marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
| ) { | ||||||||||
| fun validUserId(): UUID = userId!! | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion !! 연산자 사용 시 NPE 위험이 있습니다.
다음과 같이 개선할 수 있습니다: - fun validUserId(): UUID = userId!!
+ fun validUserId(): UUID = userId ?: throw IllegalArgumentException("userId must not be null")또는 validation이 이미 적용되어 있다면 requireNotNull을 사용하는 것도 좋습니다: - fun validUserId(): UUID = userId!!
+ fun validUserId(): UUID = requireNotNull(userId) { "userId must not be null" }📝 Committable suggestion
Suggested change
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| companion object { | ||||||||||
| fun from(userIdResponse: UserIdResponse): FindUserIdentityRequest { | ||||||||||
| return FindUserIdentityRequest(userIdResponse.userId) | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||
| package org.yapp.apis.auth.dto.request | ||||||
|
|
||||||
| import io.swagger.v3.oas.annotations.media.Schema | ||||||
| import jakarta.validation.constraints.NotBlank | ||||||
| import org.yapp.apis.auth.dto.response.CreateUserResponse | ||||||
| import org.yapp.apis.auth.dto.response.UserAuthInfoResponse | ||||||
| import org.yapp.globalutils.auth.Role | ||||||
| import java.util.UUID | ||||||
|
|
||||||
| @Schema( | ||||||
| name = "GenerateTokenPairRequest", | ||||||
| description = "Request DTO to generate a new pair of access and refresh tokens" | ||||||
| ) | ||||||
| data class GenerateTokenPairRequest private constructor( | ||||||
| @Schema( | ||||||
| description = "User ID", | ||||||
| example = "a1b2c3d4-e5f6-7890-1234-56789abcdef0" | ||||||
| ) | ||||||
| @field:NotBlank(message = "userId must not be null") | ||||||
| val userId: UUID? = null, | ||||||
|
|
||||||
| @Schema( | ||||||
| description = "User role", | ||||||
| example = "USER" | ||||||
| ) | ||||||
| @field:NotBlank(message = "role must not be null") | ||||||
| val role: Role? = null | ||||||
| ) { | ||||||
|
|
||||||
| fun validUserId(): UUID = userId!! | ||||||
| fun validRole(): Role = role!! | ||||||
|
|
||||||
|
Comment on lines
+30
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. !! 연산자 사용으로 인한 런타임 예외 위험 nullable 필드를 non-null로 강제 변환하는 !! 연산자는 런타임 KotlinNullPointerException을 발생시킬 수 있습니다. 위의 필드를 non-null로 변경하면 이 메소드들도 불필요해집니다: - fun validUserId(): UUID = userId!!
- fun validRole(): Role = role!!📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| companion object { | ||||||
| fun from(response: CreateUserResponse): GenerateTokenPairRequest { | ||||||
| return GenerateTokenPairRequest( | ||||||
| userId = response.id, | ||||||
| role = response.role | ||||||
| ) | ||||||
| } | ||||||
|
|
||||||
| fun from(response: UserAuthInfoResponse): GenerateTokenPairRequest { | ||||||
| return GenerateTokenPairRequest( | ||||||
| userId = response.id, | ||||||
| role = response.role | ||||||
| ) | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,41 @@ | ||||||||||||||
| package org.yapp.apis.auth.dto.request | ||||||||||||||
|
|
||||||||||||||
| import io.swagger.v3.oas.annotations.media.Schema | ||||||||||||||
| import jakarta.validation.constraints.NotBlank | ||||||||||||||
| import jakarta.validation.constraints.NotNull | ||||||||||||||
| import java.util.* | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기 수정 부탁드릴게요! |
||||||||||||||
|
|
||||||||||||||
| @Schema( | ||||||||||||||
| name = "TokenGenerateRequest", | ||||||||||||||
| description = "DTO containing information required to save the generated refresh token" | ||||||||||||||
| ) | ||||||||||||||
| data class TokenGenerateRequest( | ||||||||||||||
| @field:NotNull(message = "userId must not be null") | ||||||||||||||
| @Schema(description = "User ID", example = "f6b7d490-1b1a-4b9f-8e8e-27f8e3a5dafa") | ||||||||||||||
| val userId: UUID? = null, | ||||||||||||||
|
|
||||||||||||||
| @field:NotBlank(message = "refreshToken must not be blank") | ||||||||||||||
| @Schema(description = "Generated refresh token", example = "eyJhbGciOiJIUzI1NiIsInR...") | ||||||||||||||
| val refreshToken: String? = null, | ||||||||||||||
|
|
||||||||||||||
| @field:NotNull(message = "expiration must not be null") | ||||||||||||||
| @Schema(description = "Refresh token expiration time (in seconds)", example = "2592000") | ||||||||||||||
| val expiration: Long? = null | ||||||||||||||
| ) { | ||||||||||||||
| fun validUserId() = userId!! | ||||||||||||||
| fun validRefreshToken() = refreshToken!! | ||||||||||||||
| fun validExpiration() = expiration!! | ||||||||||||||
|
Comment on lines
+25
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion !! 연산자 사용으로 인한 NPE 위험이 있습니다.
다음과 같이 개선할 수 있습니다: - fun validUserId() = userId!!
- fun validRefreshToken() = refreshToken!!
- fun validExpiration() = expiration!!
+ fun validUserId() = requireNotNull(userId) { "userId must not be null" }
+ fun validRefreshToken() = requireNotNull(refreshToken) { "refreshToken must not be blank" }
+ fun validExpiration() = requireNotNull(expiration) { "expiration must not be null" }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
|
|
||||||||||||||
| companion object { | ||||||||||||||
| fun of(userId: UUID, refreshToken: String, expiration: Long): TokenGenerateRequest { | ||||||||||||||
| require(refreshToken.isNotBlank()) { "Refresh token must not be blank." } | ||||||||||||||
| require(expiration > 0) { "Expiration must be greater than 0." } | ||||||||||||||
|
|
||||||||||||||
| return TokenGenerateRequest( | ||||||||||||||
| userId = userId, | ||||||||||||||
| refreshToken = refreshToken, | ||||||||||||||
| expiration = expiration | ||||||||||||||
| ) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,13 +8,12 @@ import jakarta.validation.constraints.NotBlank | |||||||||
| description = "DTO for requesting an access token using a refresh token" | ||||||||||
| ) | ||||||||||
| data class TokenRefreshRequest private constructor( | ||||||||||
|
|
||||||||||
| @field:NotBlank(message = "Refresh token is required") | ||||||||||
| @Schema( | ||||||||||
| description = "Valid refresh token issued during previous authentication", | ||||||||||
| example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", | ||||||||||
| required = true | ||||||||||
| ) | ||||||||||
| @field:NotBlank(message = "Refresh token is required") | ||||||||||
| val refreshToken: String? = null | ||||||||||
|
Comment on lines
+16
to
17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
- @field:NotBlank(message = "Refresh token is required")
- val refreshToken: String? = null
+ @field:NotBlank(message = "Refresh token is required")
+ val refreshToken: String이렇게 변경하면
📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| ) { | ||||||||||
| fun validRefreshToken(): String = refreshToken!! | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 불필요한 위 필드가 non-null 로 변경되면 아래 메서드는 단순 반환으로 충분합니다. -fun validRefreshToken(): String = refreshToken!!
+fun validRefreshToken(): String = refreshToken
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,33 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| package org.yapp.apis.auth.dto.response | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| import io.swagger.v3.oas.annotations.media.Schema | ||||||||||||||||||||||||||||||||||||||||||||
| import org.yapp.domain.user.vo.UserIdentityVO | ||||||||||||||||||||||||||||||||||||||||||||
| import org.yapp.globalutils.auth.Role | ||||||||||||||||||||||||||||||||||||||||||||
| import java.util.UUID | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| @Schema( | ||||||||||||||||||||||||||||||||||||||||||||
| name = "CreateUserResponse", | ||||||||||||||||||||||||||||||||||||||||||||
| description = "Response DTO returned after successful user registration" | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| data class CreateUserResponse private constructor( | ||||||||||||||||||||||||||||||||||||||||||||
| @Schema( | ||||||||||||||||||||||||||||||||||||||||||||
| description = "사용자 ID", | ||||||||||||||||||||||||||||||||||||||||||||
| example = "a1b2c3d4-e5f6-7890-1234-56789abcdef0" | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| val id: UUID, | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| @Schema( | ||||||||||||||||||||||||||||||||||||||||||||
| description = "사용자 역할", | ||||||||||||||||||||||||||||||||||||||||||||
| example = "USER" | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| val role: Role | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+14
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Schema description의 언어 일관성을 맞춰주세요. Swagger 어노테이션의 description에서 한국어와 영어가 혼재되어 있습니다. API 문서의 일관성을 위해 영어로 통일하는 것을 권장합니다. @Schema(
- description = "사용자 ID",
+ description = "User ID",
example = "a1b2c3d4-e5f6-7890-1234-56789abcdef0"
)
val id: UUID,
@Schema(
- description = "사용자 역할",
+ description = "User role",
example = "USER"
)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||||
| fun from(identity: UserIdentityVO): CreateUserResponse { | ||||||||||||||||||||||||||||||||||||||||||||
| return CreateUserResponse( | ||||||||||||||||||||||||||||||||||||||||||||
| id = identity.id.value, | ||||||||||||||||||||||||||||||||||||||||||||
| role = identity.role | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package org.yapp.apis.auth.dto.response | ||
|
|
||
| import io.swagger.v3.oas.annotations.media.Schema | ||
| import org.yapp.domain.token.RefreshToken.Token | ||
|
|
||
| @Schema( | ||
| name = "RefreshTokenResponse", | ||
| description = "Response DTO containing the issued refresh token" | ||
| ) | ||
| data class RefreshTokenResponse( | ||
| @Schema(description = "The refresh token string", example = "eyJhbGciOiJIUz...") | ||
| val refreshToken: String | ||
| ) { | ||
| companion object { | ||
| fun from(token: Token): RefreshTokenResponse { | ||
| return RefreshTokenResponse(refreshToken = token.value) | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
wildcard import 사용을 재고해보세요.
java.util.*wildcard import 대신java.util.UUID를 명시적으로 import하는 것이 더 명확하고 예측 가능합니다.다음과 같이 수정하는 것을 권장합니다:
🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이부분 반영되면 좋을 것 같아요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@minwoo1999 네, 맞습니다! 명시적인 import가 코드 가독성과 유지보수성에 더 좋겠네요.
이전에 학습한 내용에 따르면, IntelliJ IDEA에서도 와일드카드 임포트를 방지하는 설정을 통해 이런 상황을 미연에 방지할 수 있습니다. File > Settings > Editor > Code Style > Java > Imports 탭에서 "Class count to use import with '*'" 값을 높게 설정하시면 도움이 될 것 같습니다.
해당 변경사항을 적용해드리겠습니다.
Task: Replace wildcard import with explicit import
java.util.*withjava.util.UUIDin AuthControllerApi.kt🧠 Learnings used
⏳ Preparing changes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A summary of the changes CodeRabbit can apply: