# 채널 후원 기능 추가 작업 계획 ## 메시지 저장 전략 선택 - 선택: 기본 메시지는 DB에 저장하지 않고, 후원 이력에는 `can`, `isSecret`, `additionalMessage`를 저장한 뒤 리스트 조회 시 메시지를 생성한다. - 이유: 일반/비밀 구분과 캔 수 노출 요구를 구조화 필드로 충족할 수 있고, 문구 변경/다국어 확장 시 DB 마이그레이션 없이 대응 가능하다. - 메시지 생성 규칙: - 일반 후원: `OO캔을 후원하셨습니다.` - 비밀 후원: `OO캔을 비밀후원하셨습니다.` - 추가 메시지 입력 시: 기본 메시지 + `\n` + `"사용자 추가 메시지"` - [x] 채널 후원 도메인 모델/저장소 설계 (`ChannelDonationMessage` 성격의 별도 엔티티, creator/sponsor/can/isSecret/additionalMessage/createdAt) - [x] `CanUsage`에 채널 후원 전용 값 1종 추가 및 영향 범위 정의 (`CanPaymentService`, 사용내역 타이틀 매핑) - [x] 채널 후원 API 요청/응답 스펙 확정 (필드: `creatorId`, `can`, `isSecret`, `message`, `container`) - [x] 채널 후원 API 서비스 플로우 설계 (인증/크리에이터 검증 -> 캔 차감 -> 후원 메시지 DB 저장) - [x] 채널 후원 리스트 API 스펙 확정 (최근 1개월, `createdAt` 내림차순, 페이징) - [x] 채널 후원 리스트 조회 권한 규칙 반영 - 크리에이터: 모든 후원 내역 조회 - 유저: 일반 후원 + 본인이 한 비밀 후원 내역 조회 - [x] 리스트 응답 메시지 조합 규칙 반영 (일반/비밀 기본 메시지 + 추가 메시지 쌍따옴표 처리) - [x] `explorer/profile/{id}` 응답 확장 설계 (최근 1개월 채널 후원 내역 최대 5건 포함) - [x] QueryDSL 조회 조건 확정 (`createdAt >= now().minusMonths(1)`, `orderBy(createdAt.desc(), id.desc())`, `limit 5`) - [x] 테스트 계획 수립 (서비스 단위 테스트 + 리포지토리 날짜 필터/정렬 테스트 + 컨트롤러 통합 테스트) - [x] 정산 로직 제외 범위 명시 (정산 비율 변경 작업은 미포함, 채널 후원 기능만 구현) - [x] 구현 후 검증 계획 확정 (`./gradlew test`, `./gradlew build`, 필요 시 `./gradlew ktlintCheck`) - [x] 운영 반영용 DDL 파일 추가 (`docs/20260223_channel_donation_message_ddl.sql`) - [x] 채널 후원 회귀 테스트 구현 - 서비스: `ChannelDonationServiceTest` - 리포지토리: `ChannelDonationMessageRepositoryTest` - 컨트롤러: `ChannelDonationControllerTest` ## 검증 기록 - 무엇을: - 1차 계획 수립: 채널 후원 기능의 API/도메인/조회 범위를 정의하고, 메시지 저장 전략을 선택해 계획 문서로 고정했다. - 2차 수정: 채널 후원 리스트 API의 조회 권한 규칙(크리에이터 전체 조회, 유저는 일반 후원+본인 비밀 후원 조회)을 계획 항목에 추가했다. - 3차 구현: 채널 후원 API/리스트 API/Explorer 프로필 확장, `CanUsage.CHANNEL_DONATION`, 메시지 엔티티 저장, 권한별 노출 필터를 구현했다. - 왜: - 기존 코드 패턴(Explorer/CanUsage/후원 조회)을 따르는 구현 범위를 먼저 고정해 불필요한 확장과 API 불일치를 방지하기 위해. - 리스트 조회 시 요청자 역할에 따라 비밀 후원 노출 범위가 달라지므로, 구현 전 권한 규칙을 계획 단계에서 명확히 고정하기 위해. - 채널 후원은 기존 라이브/콘텐츠 후원과 정산 분리를 위해 별도 `CanUsage`와 별도 메시지 저장소가 필요하고, 프로필 화면에 최근 내역 노출 요구가 있어 Explorer 응답 확장이 필요하기 때문에. - 어떻게: - 내부 탐색: `ExplorerController`, `ExplorerService`, `ExplorerQueryRepository`, `CanUsage`, `CanPaymentService`, `LiveRoomService`, `LiveRoomRepository`를 확인했다. - 병렬 조사: `explore` 2건(`bg_07537536`, `bg_5be8611b`)과 `librarian` 1건(`bg_bfe81033`) 결과를 수집해 근거를 보강했다. - 추가 확인: `AudioContentCommentRepository`, `CreatorCommunityCommentRepository`, `LiveRoomRepository`의 비밀/본인 공개 조건 패턴(`isSecret.isFalse.or(writerId.eq(memberId))`)을 확인해 문서 규칙에 반영했다. - 구현 파일: `explorer/profile/channelDonation/*`, `CanUsage.kt`, `CanPaymentService.kt`, `CanService.kt`, `ExplorerService.kt`, `GetCreatorProfileResponse.kt`를 수정/추가했다. - 검증 명령: - `./gradlew test` -> 성공 - `./gradlew build` -> 최초 1회 `GetCreatorProfileResponse.kt` import 정렬 실패(ktlint), 정렬 수정 후 재실행 성공 - `./gradlew ktlintCheck` -> 성공 ### 4차 보완(리뷰 지적사항 반영) - 무엇을: - 누락됐던 운영 반영용 DDL 파일 `docs/20260223_channel_donation_message_ddl.sql`을 추가했다. - 채널 후원 회귀 테스트 3종(서비스/리포지토리/컨트롤러)을 신규 추가했다. - 왜: - `ddl-auto: validate` 환경에서 신규 엔티티 스키마 누락 시 부팅 실패 위험이 있어 적용 스크립트를 분리 관리해야 했기 때문이다. - 권한별 비밀후원 노출, 1개월 필터, 정렬/페이징 규칙을 자동 검증해 회귀를 방지하기 위해서다. - 어떻게: - 추가 파일: - `docs/20260223_channel_donation_message_ddl.sql` - `src/test/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationServiceTest.kt` - `src/test/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationMessageRepositoryTest.kt` - `src/test/kotlin/kr/co/vividnext/sodalive/explorer/profile/channelDonation/ChannelDonationControllerTest.kt` - 검증 명령: - `lsp_diagnostics` -> Kotlin LSP 미설정으로 실행 불가(환경 제약 확인) - `./gradlew test --tests "*ChannelDonation*"` -> 성공 - `./gradlew test` -> 성공 - `./gradlew build` -> 성공