Compare commits

...

2 Commits

3 changed files with 74 additions and 1 deletions

View File

@@ -0,0 +1,24 @@
# 채널 후원 내역 탈퇴 닉네임 접두사 제거
## 완료 기준 (Pass/Fail)
- [x] 채널 후원 내역 리스트 조회 응답에서 탈퇴 회원 닉네임의 `deleted_` 접두사가 제거된다.
- [x] 비탈퇴 회원 닉네임은 기존과 동일하게 노출된다.
- [x] 기존 코드베이스의 유사 처리 패턴과 동일한 방식으로 구현된다.
- [x] 변경 파일 LSP 진단 에러가 0건이다. *(Kotlin LSP 미지원 환경으로 `lsp_diagnostics` 실행 불가, `./gradlew build` 성공으로 대체 검증)*
- [x] 관련 테스트/빌드 검증 명령이 성공한다.
## 구현 체크리스트
- [x] `deleted_` 닉네임 처리 유사 구현 위치를 전수 탐색한다.
- [x] 채널 후원 내역 조회 응답 생성 경로를 확인한다.
- [x] 조회 시점에 닉네임 접두사 제거 로직을 반영한다.
- [x] 변경사항 검증 후 체크리스트를 완료 처리한다.
## 검증 기록
### 1차 구현
- 무엇을: 채널 후원 내역 조회 응답의 탈퇴 회원 닉네임에서 `deleted_` 접두사를 제거하고, 동일 동작을 검증하는 테스트를 추가했다.
- 왜: 탈퇴 회원 닉네임이 API 응답에 내부 저장 포맷(`deleted_`) 그대로 노출되는 문제를 해결하기 위해서다.
- 어떻게:
- `lsp_diagnostics` 실행 시도: `ChannelDonationService.kt` 대상 실행 → **불가(환경에 Kotlin LSP 서버 미구성)**
- 기능 집중 테스트 실행: `./gradlew test --tests "kr.co.vividnext.sodalive.explorer.profile.channelDonation.ChannelDonationServiceTest.shouldRemoveDeletedPrefixFromNicknameInDonationList"`**성공(BUILD SUCCESSFUL)**
- 관련 테스트 실행: `./gradlew test --tests "kr.co.vividnext.sodalive.explorer.profile.channelDonation.ChannelDonationServiceTest" --tests "kr.co.vividnext.sodalive.explorer.profile.channelDonation.ChannelDonationControllerTest"`**성공(BUILD SUCCESSFUL)**
- 전체 빌드 실행: `./gradlew build`**성공(BUILD SUCCESSFUL)**

View File

@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.explorer.profile.channelDonation
import kr.co.vividnext.sodalive.can.payment.CanPaymentService
import kr.co.vividnext.sodalive.can.use.CanUsage
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.extensions.removeDeletedNicknamePrefix
import kr.co.vividnext.sodalive.i18n.LangContext
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
import kr.co.vividnext.sodalive.member.Member
@@ -102,7 +103,7 @@ class ChannelDonationService(
GetChannelDonationListItem(
id = it.id!!,
memberId = it.member!!.id!!,
nickname = it.member!!.nickname,
nickname = it.member!!.nickname.removeDeletedNicknamePrefix(),
profileUrl = if (it.member!!.profileImage != null) {
"$cloudFrontHost/${it.member!!.profileImage}"
} else {

View File

@@ -149,6 +149,54 @@ class ChannelDonationServiceTest {
assertEquals(startDateTimeKst.plusMonths(1), endDateTimeKst)
}
@Test
@DisplayName("탈퇴 회원 닉네임 접두사는 목록 응답에서 제거된다")
fun shouldRemoveDeletedPrefixFromNicknameInDonationList() {
// given: 탈퇴 접두사가 포함된 후원자 닉네임 데이터를 준비한다.
val creator = createMember(id = 1L, role = MemberRole.CREATOR, nickname = "creator")
val viewer = createMember(id = 2L, role = MemberRole.USER, nickname = "viewer")
val withdrawnMember = createMember(id = 3L, role = MemberRole.USER, nickname = "deleted_withdrawn")
val message = ChannelDonationMessage(can = 3, isSecret = false, additionalMessage = null)
message.id = 1002L
message.member = withdrawnMember
message.creator = creator
message.createdAt = LocalDateTime.of(2026, 2, 20, 12, 0, 0)
// given: 목록 조회 repository 응답을 설정한다.
Mockito.`when`(memberRepository.findCreatorByIdOrNull(creator.id!!)).thenReturn(creator)
Mockito.`when`(
channelDonationMessageRepository.getChannelDonationMessageTotalCount(
Mockito.eq(creator.id!!),
Mockito.eq(viewer.id!!),
Mockito.eq(false),
anyLocalDateTime(),
anyLocalDateTime()
)
).thenReturn(1)
Mockito.`when`(
channelDonationMessageRepository.getChannelDonationMessageList(
Mockito.eq(creator.id!!),
Mockito.eq(viewer.id!!),
Mockito.eq(false),
Mockito.eq(0L),
Mockito.eq(5L),
anyLocalDateTime(),
anyLocalDateTime()
)
).thenReturn(listOf(message))
// when: 채널 후원 목록 조회를 실행한다.
val result = service.getChannelDonationList(
creatorId = creator.id!!,
member = viewer,
offset = 0,
limit = 5
)
// then: 응답 닉네임에서 deleted_ 접두사가 제거되어야 한다.
assertEquals("withdrawn", result.items[0].nickname)
}
@Test
@DisplayName("후원 캔 수는 천 단위 콤마가 포함된 메시지로 포맷된다")
fun shouldFormatCanWithCommaInDonationMessage() {