From 0efdfbeed8e29787f4221548cb9547d7d11d3ec2 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 28 Mar 2026 19:06:04 +0900 Subject: [PATCH] =?UTF-8?q?fix(channel-donation):=20=ED=9B=84=EC=9B=90=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=ED=83=88=ED=87=B4=20=EB=8B=89=EB=84=A4?= =?UTF-8?q?=EC=9E=84=20=EC=A0=91=EB=91=90=EC=82=AC=EB=A5=BC=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/20260328_채널후원탈퇴닉네임접두사제거.md | 24 ++++++++++ .../channelDonation/ChannelDonationService.kt | 3 +- .../ChannelDonationServiceTest.kt | 48 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 docs/20260328_채널후원탈퇴닉네임접두사제거.md diff --git a/docs/20260328_채널후원탈퇴닉네임접두사제거.md b/docs/20260328_채널후원탈퇴닉네임접두사제거.md new file mode 100644 index 00000000..ce9b60a4 --- /dev/null +++ b/docs/20260328_채널후원탈퇴닉네임접두사제거.md @@ -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)** diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationService.kt index b6727496..b0ccc1f6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationService.kt @@ -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 { diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationServiceTest.kt index 6e98ced2..625ded9a 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationServiceTest.kt @@ -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() {