From c190335f38785b11e5715f2ef69c360ea336625f Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 16:53:42 +0900 Subject: [PATCH 1/8] =?UTF-8?q?CONFETI-43=20feat:=20=EC=BA=90=EC=8B=9C?= =?UTF-8?q?=EC=9D=98=20favoriteArtist=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=EB=90=9C=20?= =?UTF-8?q?=EC=98=A8=EB=B3=B4=EB=94=A9=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../confeti/api/auth/facade/AuthFacade.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java b/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java index ddf7c941..883a6bd4 100644 --- a/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java +++ b/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.sopt.confeti.api.auth.facade.dto.request.OnboardArtistDTO; import org.sopt.confeti.api.auth.facade.dto.request.OnboardDTO; +import org.sopt.confeti.api.user.facade.dto.response.onboard.UserOnboardCacheDTO; import org.sopt.confeti.auth.LoginService; import org.sopt.confeti.auth.LogoutService; import org.sopt.confeti.auth.OnboardService; @@ -68,18 +69,30 @@ public void logout(Long userId) { logoutService.logout(userId); } + @Deprecated @Transactional public void onboard(long userId, OnboardDTO onboardDTO) { User user = userService.findById(userId); Set favoriteArtistIds = onboardDTO.favoriteArtists().stream() - .map(OnboardArtistDTO::artistId) - .collect(Collectors.toSet()); + .map(OnboardArtistDTO::artistId) + .collect(Collectors.toSet()); onboardService.validateFavoriteArtistCount(favoriteArtistIds); artistFavoriteService.addFavorites(user, favoriteArtistIds); user.setRole(Role.GENERAL); } + @Transactional + public void onboard(long userId) { + UserOnboardCacheDTO cachedArtists = userOnboardService.getCachedArtists(userId); + Set favoriteArtistIds = cachedArtists.favoriteArtistIds(); + User user = userService.findById(userId); + + artistFavoriteService.addFavorites(user, favoriteArtistIds); + user.setRole(Role.GENERAL); + } + + public void flushCachedTopArtists(long userId) { userOnboardService.flushCachedTopArtists(userId); } From 6c54fa9e73af6a3b904589f4c8ae1512adbdb4cf Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 16:55:40 +0900 Subject: [PATCH 2/8] =?UTF-8?q?CONFETI-43=20feat:=20v4=20auth=20controller?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1=20-=20onboard=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EC=9D=98=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD.=20=EA=B8=B0=EC=A1=B4=EC=97=90=20requestbody?= =?UTF-8?q?=20=EB=A5=BC=20=EB=B0=9B=EB=8D=98=20=EB=B6=80=EB=B6=84=EC=9D=B4?= =?UTF-8?q?=20=EC=82=AC=EB=9D=BC=EC=A7=90.=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/auth/controller/AuthControllerV4.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java diff --git a/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java b/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java new file mode 100644 index 00000000..dab2adf4 --- /dev/null +++ b/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java @@ -0,0 +1,78 @@ +package org.sopt.confeti.api.auth.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.sopt.confeti.api.auth.dto.request.LoginRequest; +import org.sopt.confeti.api.auth.facade.AuthFacade; +import org.sopt.confeti.auth.Token; +import org.sopt.confeti.auth.command.LoginCommand; +import org.sopt.confeti.auth.dto.LoginResult; +import org.sopt.confeti.domain.user.constant.Role; +import org.sopt.confeti.global.annotation.Permission; +import org.sopt.confeti.global.annotation.RefreshToken; +import org.sopt.confeti.global.annotation.UserId; +import org.sopt.confeti.global.common.BaseResponse; +import org.sopt.confeti.global.message.SuccessMessage; +import org.sopt.confeti.global.util.ApiResponseUtil; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequiredArgsConstructor +@RequestMapping("/auth/v4") +public class AuthControllerV4 { + + private final AuthFacade authFacade; + + @PostMapping("/login") + public ResponseEntity> login( + @Valid @RequestBody LoginRequest request + ) { + LoginResult result = authFacade.login(LoginCommand.from(request)); + return ApiResponseUtil.success(SuccessMessage.SUCCESS, result); + } + + @Permission(role = {Role.ONBOARDING, Role.GENERAL}) + @PostMapping("/reissue") + public ResponseEntity> reissue( + @RefreshToken String refreshToken + ) { + Token token = authFacade.reissue(refreshToken); + return ApiResponseUtil.success(SuccessMessage.SUCCESS, token); + } + + @Permission(role = {Role.ONBOARDING, Role.GENERAL}) + @PostMapping("/logout") + public ResponseEntity> logout(@UserId Long userId) { + authFacade.logout(userId); + return ApiResponseUtil.success(SuccessMessage.SUCCESS); + } + + /** + * 개발을 위해 임시로 Role.GENERAL 접근 허용 + */ + @Permission(role = {Role.ONBOARDING, Role.GENERAL}) + @PostMapping("/onboard") + public ResponseEntity> onboard( + @UserId Long userId + ) { + authFacade.onboard(userId); + authFacade.flushCachedTopArtists(userId); + return ApiResponseUtil.success(SuccessMessage.SUCCESS); + } + + @Permission(role = {Role.GENERAL}) + @DeleteMapping("/withdraw") + public ResponseEntity> withdraw( + @UserId Long userId + ) { + authFacade.withdraw(userId); + return ApiResponseUtil.success(SuccessMessage.SUCCESS); + } + +} From ad6245bc4677eb3f94102c4d360f37f5df7a887f Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 17:01:58 +0900 Subject: [PATCH 3/8] =?UTF-8?q?CONFETI-43=20feat:=20v4=20auth=20controller?= =?UTF-8?q?=20docs=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/auth/controller/AuthControllerV4.java | 3 +- .../controller/docs/AuthControllerV4Docs.java | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java diff --git a/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java b/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java index dab2adf4..a27b96ce 100644 --- a/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java +++ b/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.sopt.confeti.api.auth.controller.docs.AuthControllerV4Docs; import org.sopt.confeti.api.auth.dto.request.LoginRequest; import org.sopt.confeti.api.auth.facade.AuthFacade; import org.sopt.confeti.auth.Token; @@ -25,7 +26,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/auth/v4") -public class AuthControllerV4 { +public class AuthControllerV4 implements AuthControllerV4Docs { private final AuthFacade authFacade; diff --git a/src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java b/src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java new file mode 100644 index 00000000..062b0ef3 --- /dev/null +++ b/src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java @@ -0,0 +1,38 @@ +package org.sopt.confeti.api.auth.controller.docs; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.sopt.confeti.global.annotation.UserId; +import org.sopt.confeti.global.common.BaseResponse; +import org.sopt.confeti.global.common.swagger.AuthErrorResponses; +import org.sopt.confeti.global.common.swagger.CommonErrorResponses; +import org.springframework.http.ResponseEntity; + +@Tag(name = "인증") +public interface AuthControllerV4Docs { + + @Operation( + summary = "회원가입한 유저의 온보딩 완료 요청", + description = + """ + V4 변경사항 + - RequestBody 로 favoriteArtistId 목록을 받아서 처리하던 부분이 사라짐 + - 서버에서 내부적으로 온보딩 시 사용된 favoriteArtistId 를 관리하므로 해당 데이터를 사용해 온보딩 완료 로직을 진행함 + """ + ) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "성공" + ) + } + ) + @CommonErrorResponses + @AuthErrorResponses + ResponseEntity> onboard( + @UserId Long userId + ); +} From f32f2b18bf6974d55a54af1757e6b51c53e12960 Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 17:03:00 +0900 Subject: [PATCH 4/8] =?UTF-8?q?CONFETI-43=20feat:=20v4=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=82=AC=ED=95=AD=EC=9C=BC=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=B4=20=EC=82=AC=EC=9A=A9=EB=90=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=9D=84=20=EC=98=88=EC=A0=95=EC=9D=B4=EB=AF=80=EB=A1=9C=20@De?= =?UTF-8?q?precated=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/sopt/confeti/api/auth/dto/request/OnboardRequest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/sopt/confeti/api/auth/dto/request/OnboardRequest.java b/src/main/java/org/sopt/confeti/api/auth/dto/request/OnboardRequest.java index 00a32c90..5623b755 100644 --- a/src/main/java/org/sopt/confeti/api/auth/dto/request/OnboardRequest.java +++ b/src/main/java/org/sopt/confeti/api/auth/dto/request/OnboardRequest.java @@ -2,7 +2,9 @@ import java.util.List; +@Deprecated public record OnboardRequest( - List favoriteArtists + List favoriteArtists ) { + } From 220234c4c2296253c77c7ec9828acb8625a0a407 Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 20:58:30 +0900 Subject: [PATCH 5/8] =?UTF-8?q?CONFETI-43=20feat:=20=EC=98=A8=EB=B3=B4?= =?UTF-8?q?=EB=94=A9=20=EC=BA=90=EC=8B=9C=20=EC=82=AD=EC=A0=9C=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20-=20topArtists=20->=20onboardArtists?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java | 3 +-- .../confeti/domain/user/application/UserOnboardService.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java b/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java index 883a6bd4..95862304 100644 --- a/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java +++ b/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java @@ -6,7 +6,6 @@ import lombok.extern.slf4j.Slf4j; import org.sopt.confeti.api.auth.facade.dto.request.OnboardArtistDTO; import org.sopt.confeti.api.auth.facade.dto.request.OnboardDTO; -import org.sopt.confeti.api.user.facade.dto.response.onboard.UserOnboardCacheDTO; import org.sopt.confeti.auth.LoginService; import org.sopt.confeti.auth.LogoutService; import org.sopt.confeti.auth.OnboardService; @@ -94,7 +93,7 @@ public void onboard(long userId) { public void flushCachedTopArtists(long userId) { - userOnboardService.flushCachedTopArtists(userId); + userOnboardService.flushCachedOnboardArtists(userId); } @Transactional diff --git a/src/main/java/org/sopt/confeti/domain/user/application/UserOnboardService.java b/src/main/java/org/sopt/confeti/domain/user/application/UserOnboardService.java index 882a3498..7a99b172 100644 --- a/src/main/java/org/sopt/confeti/domain/user/application/UserOnboardService.java +++ b/src/main/java/org/sopt/confeti/domain/user/application/UserOnboardService.java @@ -52,7 +52,7 @@ public void cacheOnboardArtists(long userId, UserOnboardCacheDTO artistsDTO) { .set(generateRedisKey(userId), artistsDTO, REDIS_TTL_DAY, TimeUnit.DAYS); } - public void flushCachedTopArtists(long userId) { + public void flushCachedOnboardArtists(long userId) { redisTemplate.delete(generateRedisKey(userId)); } } From 40099826469e7a212dd5898e7ff902f58d2e0d93 Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 21:02:29 +0900 Subject: [PATCH 6/8] =?UTF-8?q?CONFETI-43=20feat:=20=EC=98=A8=EB=B3=B4?= =?UTF-8?q?=EB=94=A9=20=EC=99=84=EB=A3=8C=20API=20=EC=97=94=EB=93=9C?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EB=B3=80=EA=B2=BD=20-=20?= =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20auth/v4/onboard=20=EC=97=90=EC=84=9C=20use?= =?UTF-8?q?r/onboard/v4=20=EB=A1=9C=20=EB=B3=80=EA=B2=BD.=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EC=98=A8=EB=B3=B4=EB=94=A9=20API=20=EB=93=B1?= =?UTF-8?q?=EA=B3=BC=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/auth/controller/AuthControllerV4.java | 79 ------------------- .../controller/docs/AuthControllerV4Docs.java | 38 --------- .../confeti/api/auth/facade/AuthFacade.java | 11 --- .../controller/UserOnboardControllerV4.java | 13 +++ .../docs/UserOnboardControllerV4Docs.java | 24 ++++++ .../api/user/facade/UserOnboardFacade.java | 17 ++++ 6 files changed, 54 insertions(+), 128 deletions(-) delete mode 100644 src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java delete mode 100644 src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java diff --git a/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java b/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java deleted file mode 100644 index a27b96ce..00000000 --- a/src/main/java/org/sopt/confeti/api/auth/controller/AuthControllerV4.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.sopt.confeti.api.auth.controller; - -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.sopt.confeti.api.auth.controller.docs.AuthControllerV4Docs; -import org.sopt.confeti.api.auth.dto.request.LoginRequest; -import org.sopt.confeti.api.auth.facade.AuthFacade; -import org.sopt.confeti.auth.Token; -import org.sopt.confeti.auth.command.LoginCommand; -import org.sopt.confeti.auth.dto.LoginResult; -import org.sopt.confeti.domain.user.constant.Role; -import org.sopt.confeti.global.annotation.Permission; -import org.sopt.confeti.global.annotation.RefreshToken; -import org.sopt.confeti.global.annotation.UserId; -import org.sopt.confeti.global.common.BaseResponse; -import org.sopt.confeti.global.message.SuccessMessage; -import org.sopt.confeti.global.util.ApiResponseUtil; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - - -@RestController -@RequiredArgsConstructor -@RequestMapping("/auth/v4") -public class AuthControllerV4 implements AuthControllerV4Docs { - - private final AuthFacade authFacade; - - @PostMapping("/login") - public ResponseEntity> login( - @Valid @RequestBody LoginRequest request - ) { - LoginResult result = authFacade.login(LoginCommand.from(request)); - return ApiResponseUtil.success(SuccessMessage.SUCCESS, result); - } - - @Permission(role = {Role.ONBOARDING, Role.GENERAL}) - @PostMapping("/reissue") - public ResponseEntity> reissue( - @RefreshToken String refreshToken - ) { - Token token = authFacade.reissue(refreshToken); - return ApiResponseUtil.success(SuccessMessage.SUCCESS, token); - } - - @Permission(role = {Role.ONBOARDING, Role.GENERAL}) - @PostMapping("/logout") - public ResponseEntity> logout(@UserId Long userId) { - authFacade.logout(userId); - return ApiResponseUtil.success(SuccessMessage.SUCCESS); - } - - /** - * 개발을 위해 임시로 Role.GENERAL 접근 허용 - */ - @Permission(role = {Role.ONBOARDING, Role.GENERAL}) - @PostMapping("/onboard") - public ResponseEntity> onboard( - @UserId Long userId - ) { - authFacade.onboard(userId); - authFacade.flushCachedTopArtists(userId); - return ApiResponseUtil.success(SuccessMessage.SUCCESS); - } - - @Permission(role = {Role.GENERAL}) - @DeleteMapping("/withdraw") - public ResponseEntity> withdraw( - @UserId Long userId - ) { - authFacade.withdraw(userId); - return ApiResponseUtil.success(SuccessMessage.SUCCESS); - } - -} diff --git a/src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java b/src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java deleted file mode 100644 index 062b0ef3..00000000 --- a/src/main/java/org/sopt/confeti/api/auth/controller/docs/AuthControllerV4Docs.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.sopt.confeti.api.auth.controller.docs; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.sopt.confeti.global.annotation.UserId; -import org.sopt.confeti.global.common.BaseResponse; -import org.sopt.confeti.global.common.swagger.AuthErrorResponses; -import org.sopt.confeti.global.common.swagger.CommonErrorResponses; -import org.springframework.http.ResponseEntity; - -@Tag(name = "인증") -public interface AuthControllerV4Docs { - - @Operation( - summary = "회원가입한 유저의 온보딩 완료 요청", - description = - """ - V4 변경사항 - - RequestBody 로 favoriteArtistId 목록을 받아서 처리하던 부분이 사라짐 - - 서버에서 내부적으로 온보딩 시 사용된 favoriteArtistId 를 관리하므로 해당 데이터를 사용해 온보딩 완료 로직을 진행함 - """ - ) - @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "성공" - ) - } - ) - @CommonErrorResponses - @AuthErrorResponses - ResponseEntity> onboard( - @UserId Long userId - ); -} diff --git a/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java b/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java index 95862304..94b7af36 100644 --- a/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java +++ b/src/main/java/org/sopt/confeti/api/auth/facade/AuthFacade.java @@ -81,17 +81,6 @@ public void onboard(long userId, OnboardDTO onboardDTO) { user.setRole(Role.GENERAL); } - @Transactional - public void onboard(long userId) { - UserOnboardCacheDTO cachedArtists = userOnboardService.getCachedArtists(userId); - Set favoriteArtistIds = cachedArtists.favoriteArtistIds(); - User user = userService.findById(userId); - - artistFavoriteService.addFavorites(user, favoriteArtistIds); - user.setRole(Role.GENERAL); - } - - public void flushCachedTopArtists(long userId) { userOnboardService.flushCachedOnboardArtists(userId); } diff --git a/src/main/java/org/sopt/confeti/api/user/controller/UserOnboardControllerV4.java b/src/main/java/org/sopt/confeti/api/user/controller/UserOnboardControllerV4.java index b55d80da..8814720f 100644 --- a/src/main/java/org/sopt/confeti/api/user/controller/UserOnboardControllerV4.java +++ b/src/main/java/org/sopt/confeti/api/user/controller/UserOnboardControllerV4.java @@ -114,4 +114,17 @@ public ResponseEntity> getFavor UserOnboardFavoriteArtistsResponse.from(favoriteArtists)); } + /** + * 개발을 위해 임시로 Role.GENERAL 접근 허용 + */ + @Permission(role = {Role.ONBOARDING, Role.GENERAL}) + @PostMapping() + public ResponseEntity> onboard( + @UserId Long userId + ) { + userOnboardFacade.onboard(userId); + userOnboardFacade.flushCachedOnboardArtists(userId); + return ApiResponseUtil.success(SuccessMessage.SUCCESS); + } + } diff --git a/src/main/java/org/sopt/confeti/api/user/controller/docs/UserOnboardControllerV4Docs.java b/src/main/java/org/sopt/confeti/api/user/controller/docs/UserOnboardControllerV4Docs.java index 3f30d991..d9368326 100644 --- a/src/main/java/org/sopt/confeti/api/user/controller/docs/UserOnboardControllerV4Docs.java +++ b/src/main/java/org/sopt/confeti/api/user/controller/docs/UserOnboardControllerV4Docs.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import org.sopt.confeti.api.user.dto.response.onboard.UserOnboardFavoriteArtistsResponse; +import org.sopt.confeti.global.annotation.UserId; import org.sopt.confeti.global.common.BaseResponse; import org.sopt.confeti.global.common.swagger.AuthErrorResponses; import org.sopt.confeti.global.common.swagger.CommonErrorResponses; @@ -28,4 +29,27 @@ ResponseEntity> getFavoriteArti Long userId ); + @Operation( + summary = "회원가입한 유저의 온보딩 완료 요청", + description = + """ + V4 변경사항 + - RequestBody 로 favoriteArtistId 목록을 받아서 처리하던 부분이 사라짐 + - 서버에서 내부적으로 온보딩 시 사용된 favoriteArtistId 를 관리하므로 해당 데이터를 사용해 온보딩 완료 로직을 진행함 + """ + ) + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "성공" + ) + } + ) + @CommonErrorResponses + @AuthErrorResponses + ResponseEntity> onboard( + @UserId Long userId + ); + } diff --git a/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java b/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java index 7803bf49..2721bac2 100644 --- a/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java +++ b/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java @@ -15,6 +15,8 @@ import org.sopt.confeti.api.user.facade.dto.response.onboard.UserOnboardCacheDTO; import org.sopt.confeti.api.user.facade.dto.response.onboard.UserOnboardFavoriteArtistsDTO; import org.sopt.confeti.api.user.facade.dto.response.onboard.UserOnboardRelatedArtistsDTO; +import org.sopt.confeti.domain.artist_favorite.application.ArtistFavoriteService; +import org.sopt.confeti.domain.user.User; import org.sopt.confeti.domain.user.application.UserOnboardService; import org.sopt.confeti.domain.user.application.UserService; import org.sopt.confeti.domain.user.constant.Role; @@ -44,6 +46,7 @@ public class UserOnboardFacade { private final UserOnboardService userOnboardService; private final RedisTemplate redisTemplate; private final ObjectMapper objectMapper; + private final ArtistFavoriteService artistFavoriteService; public UserOnboardRelatedArtistsDTO getArtistsRelatedTerm(long userId, String term, int limit) { Set topArtistIds = userOnboardService.getCachedExposedArtistIds(userId); @@ -149,6 +152,20 @@ public UserOnboardFavoriteArtistsDTO getFavoriteArtists(long userId) { return UserOnboardFavoriteArtistsDTO.from(favoriteArtists); } + @Transactional + public void onboard(long userId) { + UserOnboardCacheDTO cachedArtists = userOnboardService.getCachedArtists(userId); + Set favoriteArtistIds = cachedArtists.favoriteArtistIds(); + User user = userService.findById(userId); + + artistFavoriteService.addFavorites(user, favoriteArtistIds); + user.setRole(Role.GENERAL); + } + + public void flushCachedOnboardArtists(long userId) { + userOnboardService.flushCachedOnboardArtists(userId); + } + public void cacheTopArtists(List topArtists) { redisTemplate.opsForValue().set(RedisKey.MUSIC_TOP_ARTISTS.get(), topArtists); } From 1f53cd67a5f148d605d3878dfc508d5875d6ba29 Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 21:46:17 +0900 Subject: [PATCH 7/8] =?UTF-8?q?CONFETI-43=20feat:=20BadRequestException=20?= =?UTF-8?q?=EB=B0=8F=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../confeti/global/exception/BadRequestException.java | 10 ++++++++++ .../global/exception/GlobalExceptionHandler.java | 7 +++++++ 2 files changed, 17 insertions(+) create mode 100644 src/main/java/org/sopt/confeti/global/exception/BadRequestException.java diff --git a/src/main/java/org/sopt/confeti/global/exception/BadRequestException.java b/src/main/java/org/sopt/confeti/global/exception/BadRequestException.java new file mode 100644 index 00000000..9bbb9f31 --- /dev/null +++ b/src/main/java/org/sopt/confeti/global/exception/BadRequestException.java @@ -0,0 +1,10 @@ +package org.sopt.confeti.global.exception; + +import org.sopt.confeti.global.message.ErrorMessage; + +public class BadRequestException extends ConfetiException { + + public BadRequestException(ErrorMessage message) { + super(message); + } +} diff --git a/src/main/java/org/sopt/confeti/global/exception/GlobalExceptionHandler.java b/src/main/java/org/sopt/confeti/global/exception/GlobalExceptionHandler.java index ce3778b2..23d951b3 100644 --- a/src/main/java/org/sopt/confeti/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/org/sopt/confeti/global/exception/GlobalExceptionHandler.java @@ -12,6 +12,13 @@ @RestControllerAdvice public class GlobalExceptionHandler { + @ExceptionHandler(BadRequestException.class) + public ResponseEntity> handleIllegalArgumentException( + BadRequestException e, HttpServletRequest request) { + request.setAttribute("exception", e); + return ApiResponseUtil.failure(ErrorMessage.BAD_REQUEST); + } + @ExceptionHandler(IllegalArgumentException.class) public ResponseEntity> handleIllegalArgumentException( IllegalArgumentException e, HttpServletRequest request) { From a33a891e91b52662bd381414f94f5c9289bcb517 Mon Sep 17 00:00:00 2001 From: jher235 Date: Wed, 22 Oct 2025 21:46:59 +0900 Subject: [PATCH 8/8] =?UTF-8?q?CONFETI-43=20feat:=20=EC=98=A8=EB=B3=B4?= =?UTF-8?q?=EB=94=A9=20=EC=95=84=ED=8B=B0=EC=8A=A4=ED=8A=B8=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../confeti/api/user/facade/UserOnboardFacade.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java b/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java index 2721bac2..af42103a 100644 --- a/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java +++ b/src/main/java/org/sopt/confeti/api/user/facade/UserOnboardFacade.java @@ -21,6 +21,7 @@ import org.sopt.confeti.domain.user.application.UserService; import org.sopt.confeti.domain.user.constant.Role; import org.sopt.confeti.global.annotation.Facade; +import org.sopt.confeti.global.exception.BadRequestException; import org.sopt.confeti.global.exception.NotFoundException; import org.sopt.confeti.global.message.ErrorMessage; import org.sopt.confeti.global.resolver.music_api.artist.vo.ConfetiArtist; @@ -155,6 +156,8 @@ public UserOnboardFavoriteArtistsDTO getFavoriteArtists(long userId) { @Transactional public void onboard(long userId) { UserOnboardCacheDTO cachedArtists = userOnboardService.getCachedArtists(userId); + validOnboardArtists(cachedArtists); + Set favoriteArtistIds = cachedArtists.favoriteArtistIds(); User user = userService.findById(userId); @@ -224,4 +227,12 @@ private void cacheRelatedArtists( UserOnboardCacheDTO.of(newFavoriteArtistIds, newExposedArtistIds)); } + private void validOnboardArtists(UserOnboardCacheDTO userOnboardCacheDTO) { + Set favoriteArtistIds = userOnboardCacheDTO.favoriteArtistIds(); + + if (favoriteArtistIds == null || favoriteArtistIds.isEmpty()) { + throw new BadRequestException(ErrorMessage.BAD_REQUEST); + } + } + }