From d36e71723b1f8f8d419c94c45c57e4e64ab25d80 Mon Sep 17 00:00:00 2001 From: Develop-KIM Date: Tue, 30 Jun 2026 14:59:41 +0900 Subject: [PATCH] =?UTF-8?q?fix(mission):=20/missions/current=20=EB=A0=88?= =?UTF-8?q?=EB=B2=A8=20=EB=AF=B8=EC=B4=88=EA=B8=B0=ED=99=94=20=EC=8B=9C=20?= =?UTF-8?q?500=20=EB=8C=80=EC=8B=A0=20Lv.1=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 회고 전(레벨 행 없는) 유저가 /api/v1/missions/current 호출 시 UserLevelNotFound로 500 나던 문제 수정. ensureInitialized로 UserLevel(Lv.1)+ Lv.1 미션을 자가 생성 후 조회하도록 변경(소급/마이그레이션 불필요). Co-Authored-By: Claude Opus 4.8 --- .../adapter/webapi/achievement/MissionApi.kt | 5 +++- .../achievement/UserMissionService.kt | 16 +++++++++++ .../provided/UserMissionRegister.kt | 2 ++ .../achievement/UserMissionServiceTest.kt | 28 ++++++++++++++++++- 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/didit/adapter/webapi/achievement/MissionApi.kt b/src/main/kotlin/com/didit/adapter/webapi/achievement/MissionApi.kt index 2cb37674..926ccbc2 100644 --- a/src/main/kotlin/com/didit/adapter/webapi/achievement/MissionApi.kt +++ b/src/main/kotlin/com/didit/adapter/webapi/achievement/MissionApi.kt @@ -24,7 +24,10 @@ class MissionApi( @GetMapping("/current") fun getCurrentMission( @CurrentUserId userId: UUID, - ): SuccessResponse = SuccessResponse.of(missionFinder.getCurrentMission(userId)) + ): SuccessResponse { + userMissionRegister.ensureInitialized(userId) + return SuccessResponse.of(missionFinder.getCurrentMission(userId)) + } @RequireAuth @ResponseStatus(HttpStatus.NO_CONTENT) diff --git a/src/main/kotlin/com/didit/application/achievement/UserMissionService.kt b/src/main/kotlin/com/didit/application/achievement/UserMissionService.kt index 4986fa2e..a5b433f8 100644 --- a/src/main/kotlin/com/didit/application/achievement/UserMissionService.kt +++ b/src/main/kotlin/com/didit/application/achievement/UserMissionService.kt @@ -3,8 +3,11 @@ package com.didit.application.achievement import com.didit.application.achievement.exception.CurrentMissionNotFoundException import com.didit.application.achievement.provided.UserMissionRegister import com.didit.application.achievement.required.MissionRepository +import com.didit.application.achievement.required.UserLevelRepository import com.didit.application.achievement.required.UserMissionRepository import com.didit.domain.achievement.MissionType +import com.didit.domain.achievement.UserLevel +import com.didit.domain.achievement.UserMission import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.time.LocalDateTime @@ -15,7 +18,20 @@ import java.util.UUID class UserMissionService( private val userMissionRepository: UserMissionRepository, private val missionRepository: MissionRepository, + private val userLevelRepository: UserLevelRepository, ) : UserMissionRegister { + override fun ensureInitialized(userId: UUID) { + if (userLevelRepository.existsByUserId(userId)) { + return + } + userLevelRepository.save(UserLevel.create(userId)) + + val lv1Mission = missionRepository.findByLevel(1) ?: return + val userMission = UserMission.create(userId, lv1Mission.id) + userMission.levelUpPopupShown = true + userMissionRepository.save(userMission) + } + override fun confirmLevelUp(userId: UUID) { val userMission = userMissionRepository.findCurrentMissionByUserId(userId) diff --git a/src/main/kotlin/com/didit/application/achievement/provided/UserMissionRegister.kt b/src/main/kotlin/com/didit/application/achievement/provided/UserMissionRegister.kt index 01fddb9c..92a15a90 100644 --- a/src/main/kotlin/com/didit/application/achievement/provided/UserMissionRegister.kt +++ b/src/main/kotlin/com/didit/application/achievement/provided/UserMissionRegister.kt @@ -3,6 +3,8 @@ package com.didit.application.achievement.provided import java.util.UUID interface UserMissionRegister { + fun ensureInitialized(userId: UUID) + fun confirmLevelUp(userId: UUID) fun retryMission(userId: UUID) diff --git a/src/test/kotlin/com/didit/application/achievement/UserMissionServiceTest.kt b/src/test/kotlin/com/didit/application/achievement/UserMissionServiceTest.kt index 7b8f1333..6e24826f 100644 --- a/src/test/kotlin/com/didit/application/achievement/UserMissionServiceTest.kt +++ b/src/test/kotlin/com/didit/application/achievement/UserMissionServiceTest.kt @@ -2,6 +2,7 @@ package com.didit.application.achievement import com.didit.application.achievement.exception.CurrentMissionNotFoundException import com.didit.application.achievement.required.MissionRepository +import com.didit.application.achievement.required.UserLevelRepository import com.didit.application.achievement.required.UserMissionRepository import com.didit.domain.achievement.Mission import com.didit.domain.achievement.MissionStatus @@ -15,6 +16,7 @@ import org.junit.jupiter.api.extension.ExtendWith import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension import org.mockito.kotlin.any +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.time.LocalDateTime @@ -28,6 +30,9 @@ class UserMissionServiceTest { @Mock lateinit var missionRepository: MissionRepository + @Mock + lateinit var userLevelRepository: UserLevelRepository + private lateinit var userMissionService: UserMissionService private val userId = UUID.randomUUID() @@ -35,7 +40,28 @@ class UserMissionServiceTest { @BeforeEach fun setUp() { - userMissionService = UserMissionService(userMissionRepository, missionRepository) + userMissionService = UserMissionService(userMissionRepository, missionRepository, userLevelRepository) + } + + @Test + fun `레벨 정보가 없으면 UserLevel과 Lv1 미션을 생성한다`() { + whenever(userLevelRepository.existsByUserId(userId)).thenReturn(false) + whenever(missionRepository.findByLevel(1)).thenReturn(Mission.firstRetro()) + + userMissionService.ensureInitialized(userId) + + verify(userLevelRepository).save(any()) + verify(userMissionRepository).save(any()) + } + + @Test + fun `이미 레벨 정보가 있으면 아무것도 생성하지 않는다`() { + whenever(userLevelRepository.existsByUserId(userId)).thenReturn(true) + + userMissionService.ensureInitialized(userId) + + verify(userLevelRepository, never()).save(any()) + verify(userMissionRepository, never()).save(any()) } @Test