Files

16 KiB

채널 후원 메시지 항목 숨김 PRD

문서 정보

항목 내용
문서 상태 서버 구현·기능 범위 검증·최종 리뷰 완료. 운영 DDL/프론트엔드 연동 미수행
작성일 2026-11-05
최종 수정일 2026-11-05
대상 제품 크리에이터 채널 후원 메시지 숨김
작성자·결정권자 요구사항은 사용자 인터뷰로 확정, 기술안은 문서 작성자 제안
관련 API Contract 이 문서 §8, DEC-006으로 구현 승인
관련 구현 계획 plan-task.md
관련 review 없음

1. 개요

크리에이터는 자신의 채널에 표시되는 단일 후원 항목을 숨길 수 있다. 숨김은 원본 후원 기록을 보존하는 표시 조정이며, 채널 홈의 channelDonations와 후원 탭의 donations에서만 항목을 제외한다. 최초에는 문서만 작성했으며, 이후 사용자의 "문서대로 진행" 승인(DEC-006)에 따라 구현했다. 현재 실행 상태와 검증 결과는 plan-task.md를 기준으로 한다.

2. 문제와 목표

채널에 표시된 후원 메시지가 부적절하거나 더 이상 게시하기 적절하지 않을 수 있지만, 이를 제거하면서 후원 및 정산 이력을 변경해서는 안 된다. 크리에이터가 해당 후원 항목을 숨기면 모든 조회자에게 두 V2 채널 표시 위치에서 보이지 않고 원본 기록과 재무 효과는 그대로 남아야 한다.

3. 목표와 범위 밖

목표

  • 채널의 소유 CREATOR만 해당 채널의 후원 항목 하나를 숨길 수 있다.
  • 숨긴 항목은 채널 소유자와 후원자를 포함한 모든 조회자에게 두 V2 표시 목록에서 제외된다.
  • donationCount는 숨기지 않은 후원 항목만 센다.
  • 데이터베이스 원본 값, 기여도 랭킹, 정산 및 사용한 can은 그대로 보존된다.

범위 밖

  • 복원, 물리 삭제, 후원 취소, 환불, can 사용 취소 또는 정산 역분개.
  • legacy 프로필/후원 목록 API의 숨김 처리. 해당 경로는 같은 원본 기록을 계속 노출할 수 있다. 이 기능은 전역 삭제나 전체 서비스 비노출을 약속하지 않는다.
  • 관리자 추가 권한, 후원자 권한, 다른 크리에이터 권한, 일반 회원 권한.
  • 숨김 사유, 수행자/시각 이력, UI 이력, 일괄 API, 실시간 push.
  • 프론트엔드 구현 및 화면 디자인. 별도 프론트엔드 작업은 소유자 전용 ID로 숨김 API를 호출하고 두 표시 경로를 다시 조회해야 한다.

4. 사용자와 권한

주체 숨김 가능 여부 두 V2 목록의 숨긴 항목
해당 채널의 소유 CREATOR 가능 제외
후원자 본인 불가 제외
다른 CREATOR 불가 제외
일반 회원 불가 제외
관리자 이 요청으로 추가 권한 없음 제외

서버는 인증 회원, CREATOR role, 요청 경로의 creatorId와 인증 회원의 채널 소유권, 후원 항목과 동일 채널 소속을 검증한다. 존재하지 않는 항목 또는 다른 채널의 ID를 안전하게 거부하고 어떠한 기록도 변경하지 않는다. 현재 SodaException 및 공통 오류 handler를 따른다. 프로젝트 관례상 도메인 실패는 HTTP 200 응답의 success=false envelope일 수 있으며, 별도의 REST 403/404 계약을 만들지 않는다.

5. 핵심 흐름 (기술 제안 포함)

  1. 소유 CREATOR가 채널 홈 또는 후원 탭에서 항목을 선택한다.
  2. 프론트엔드는 소유자에게만 응답되는 안정적인 donationId로 숨김 요청을 보낸다.
  3. 서버가 인증, role, 채널 소유권 및 후원 소속을 확인한 뒤 해당 항목의 숨김 상태만 기록한다.
  4. 같은 소유자가 이미 숨긴 항목을 다시 요청해도 성공하는 멱등 동작을 제공한다.
  5. 프론트엔드는 홈과 후원 탭을 다시 조회한다. 숨긴 항목은 양쪽에서 보이지 않으며 count도 감소한다.

6. 제품 요구사항

ID 상태 요구사항 수용 기준
CDH-001 확정 소유 CREATOR는 채널 후원 한 항목을 숨긴다. ID로 단일 항목을 지정하며 소유권과 채널 소속이 모두 일치할 때만 성공한다.
CDH-002 확정 숨김 상태는 soft-hide다. DB 행, ID, can, 메시지, donor/creator 연결, 생성 시각, isSecret이 보존된다.
CDH-003 확정 숨긴 항목은 모든 사용자에게 숨긴다. V2 홈 channelDonations 및 V2 후원 탭 donations에서 creator와 donor 본인 포함 전원에게 제외된다.
CDH-004 확정 후원 탭의 donationCount는 보이는 항목 수다. 숨김 항목은 count에서 빠지며 pagination 및 hasNext도 같은 숨김 제외 조건을 쓴다.
CDH-005 확정 랭킹과 재무 효과는 보존한다. 기존 랭킹, 정산, 원본 can 사용 및 후원 기록의 값/행이 달라지지 않는다.
CDH-006 확정 권한은 소유 CREATOR에 한정한다. donor, 타 CREATOR, USER, ADMIN 요청은 거부되며 기록 변화가 없다.
CDH-007 확정 숨김은 지정된 두 V2 표시 경로만 바꾼다. legacy 프로필/후원 목록은 변경하지 않으며 같은 행을 계속 반환할 수 있음을 명시한다.
CDH-008 확정 현재 공개/비밀 후원 표시 정책을 유지한다. 숨기지 않은 공개 및 비밀 항목은 현재 isSecret 마스킹 규칙으로 계속 표시된다.
CDH-009 작성자 기술 초안 숨김 재요청은 안전하게 성공하도록 제안한다. 같은 소유자의 중복 숨김 요청은 성공하며 금융 효과를 재적용하지 않는다.

7. 기술 상태와 근거

다음 기술 선택은 최초 AUTHOR TECHNICAL DRAFT로 작성했고 DEC-006으로 구현 승인됐다. 아래 제안 표현은 작성 당시의 결정 근거이며 현재 구현 계약으로 사용한다.

  • 변경 전 엔티티 ChannelDonationMessage는 BaseEntity의 ID/시간을 상속하며 숨김 필드가 없었다. 구현은 boolean isHidden=false를 추가하고 MySQL의 is_hidden TINYINT(1) NOT NULL DEFAULT 0 COMMENT '채널 후원 표시 숨김 여부'를 사용한다. 운영 반영용 DDL을 작성했으며 운영 DB에는 실행하지 않았다.
  • 기존 donation 탭 QueryDSL은 채널과 KST 월 조건으로 count와 page 조회를 나눠 수행하고, 홈 QueryDSL은 같은 기간의 최신 8건을 조회한다. 숨김 조건은 각 조회 경로의 offset/limit 적용 전에 둔다. 홈은 기존 limit 8을 유지해 숨긴 항목 다음의 표시 가능 항목으로 최대 8개를 채운다.
  • donation 탭의 count와 list가 동일한 숨김 제외 predicate를 사용한다. legacy query, 랭킹/정산/금융 query에는 전역 filter를 추가하지 않는다. Hibernate 전역 @Where/@SQLDelete는 사용하지 않는다.
  • 현재 홈/탭 후원 응답은 후원 항목의 ID와 donor member ID를 노출하지 않으며 기존 테스트도 ID 부재를 검증한다. 숨김 동작을 위해 안정적인 donationId를 소유 CREATOR 응답에만 nullable/생략 방식으로 추가하는 방안을 제안한다. 일반 조회자, donor 및 다른 사용자의 JSON에는 ID가 없어야 하며 donor memberId는 누구에게도 추가 노출하지 않는다. 기존 owner ID 부재 assertion은 owner-only ID 노출 검증으로 갱신하고 non-owner 부재 검증은 유지한다.
  • 제안 endpoint는 bodyless DELETE /api/v2/creator-channels/{creatorId}/donations/{donationId}이며 ApiResponse.ok envelope에 data 없이 성공을 반환한다. 기존 인증 주입, SodaException, message key/i18n 및 handler를 재사용한다. generic REST 403/404를 새로 도입하지 않는다.
  • 공개 후원 및 비밀 후원의 기존 isSecret 표시/masking은 visible row에만 그대로 적용한다. 숨긴 항목은 공개/비밀 구분 없이 전체 제외한다.

8. 제안 API 경계 (AUTHOR TECHNICAL DRAFT)

Method / path 입력 성공 실패 및 제한
DELETE /api/v2/creator-channels/{creatorId}/donations/{donationId} 인증 사용자, 경로 ID, body 없음 기존 ApiResponse.ok envelope, data 없음 현재 SodaException/handler 및 현행 HTTP-200 success=false 도메인 오류 패턴. 비소유/불일치/미존재는 상태 변경 없이 거부

제안된 application 경계는 재사용 패키지 kr.co.vividnext.sodalive.v2.creator.channel.donation의 HideCreatorChannelDonationService.hide(creatorId: Long, donationId: Long, actor: Member)다. 출력 port는 HideCreatorChannelDonationPort.hideOwnedDonation(creatorId: Long, donationId: Long): Boolean로 채널에 속하는 항목만 원자적으로 숨긴다. 소유자 role/identity 검증은 service 경계에서 수행한다. adapter 패키지 kr.co.vividnext.sodalive.v2.api.creator.channel.donation은 controller/facade와 공개 응답의 소유자 전용 donationId를 조립한다. 구체 파일과 인터페이스는 plan의 기술 초안에 적는다.

숨김 행 재요청은 이미 숨김 상태면 성공으로 끝낸다. 첫 요청과 재요청 모두 can 사용, 환불, 랭킹, 정산을 호출하거나 수정하지 않는다. 소유권·같은 채널 소속·항목 존재 여부가 일치하지 않으면 성공 처리하지 않는다.

9. 비기능, 보안과 데이터

  • 사용자 제공 ID는 신뢰하지 않는다. 인증 회원, CREATOR role, 채널 소유자 ID 및 donation의 channel ID를 서버에서 대조한다.
  • 다른 채널/존재하지 않는 donation에 대한 거부가 데이터 존재 여부를 불필요하게 노출하지 않도록 기존 도메인 오류 패턴을 검토한다.
  • isHidden 외에 hiddenAt, hiddenBy, reason, history를 추가하지 않는다.
  • 변경 범위 밖의 구형 API가 원본을 노출할 수 있다는 제한을 제품/운영 설명에서 숨기지 않는다.
  • 테스트는 repository/HTTP 통합 근거를 포함하고, 기존 테스트 관례인 JUnit 5, @SpringBootTest, 실제 H2/MockMvc 경로를 따른다.

10. 성공 기준과 추적

  • CDH-001~CDH-009의 미래 구현 테스트와 계획 Goal이 연결되어 있다. 구현 및 테스트 통과를 뜻하지 않는다.
  • 역할별 권한, 다른 채널 및 존재하지 않는 ID, 숨김 중복 요청을 HTTP 통합으로 확인했다.
  • 모든 viewer role의 홈/탭 결과에서 숨긴 공개/비밀 행이 제외된다.
  • count, page, hasNext, 홈 최신 8개 보충 결과가 숨김 predicate와 일치한다.
  • 원본 행과 값, ranking, settlement, can 사용 내역의 불변을 H2/실제 HTTP로 확인했다. MySQL 자동 수정 시각 보존은 생성 SQL 자기 대입 회귀로 확인했으며 운영 MySQL 실행은 미검증이다.
  • legacy 출력이 변경되지 않고 그 제한을 문서화했다.
  • donor member ID는 추가 노출되지 않으며 donation ID는 소유 CREATOR에만 응답된다.
요구사항 계획 Goal 주요 완료 증거
CDH-001, CDH-006 P1-T1, P1-T2, P1-GATE 소유 CREATOR 성공, 비소유/위조 ID/미존재 거부
CDH-002, CDH-005, CDH-007 P1-T1, P3-GATE DB 재조회, 실제 랭킹/정산 및 legacy 조회 전후 비교
CDH-003, CDH-004, CDH-008 P2-T1, P2-T2, P2-GATE 역할별 숨김 제외, count/page/refill, visible 비밀 후원 마스킹
CDH-009 (기술 초안) P1-T1, P1-T2 동일 소유자의 중복 요청 성공 및 추가 변경 없음
소유자 전용 ID (기술 초안) P2-T1, P2-T2 양 응답의 동일 persisted ID, 비소유자 JSON의 ID 부재

11. 인터뷰 기록과 미결 사항

사용자 인터뷰 결정: 단일 항목 soft-hide, 소유 CREATOR만 권한 보유, 모든 viewer에게 두 V2 목록에서 제외, 복원 없음, donationCount 제외, 랭킹/정산/can 사용 보존, legacy API 불변 및 전역 삭제가 아님.

점수: Goal 1.00, Scope 1.00, Constraints 0.90, Success 0.85, Context 0.85. 기존 코드베이스 가중치 .30/.20/.15/.20/.15 적용 모호성은 **0.0675 (약 0.07)**다. 제품 질문은 모두 해결되었다. 기술안은 사용자 결정으로 승격하지 않는다.

분류 상태 항목
제품 질문 없음 구현 범위·권한·보존 정책·조회 범위는 인터뷰로 확정
기술 제안 DEC-006 승인 §7~§9의 필드, predicate, ID 노출 및 endpoint 계약을 구현 기준으로 확정
외부 의존 프론트엔드 연동 필요 실제 화면의 숨김 조작과 양쪽 데이터 갱신은 별도 프론트엔드 작업. 이 계획의 backend 완료와 화면 기능 완료를 구분

12. Decision Log

날짜 ID 상태 결정 근거
2026-11-05 DEC-001 사용자 확정 단일 채널 후원 항목을 soft-hide하고 원본 기록/값을 보존한다. 사용자 인터뷰
2026-11-05 DEC-002 사용자 확정 소유 CREATOR만 숨김할 수 있고, 숨긴 항목은 두 V2 목록에서 모든 viewer에게 제외한다. 사용자 인터뷰
2026-11-05 DEC-003 사용자 확정 donationCount에서 제외하되 랭킹, 정산, can 사용은 그대로 둔다. 사용자 인터뷰
2026-11-05 DEC-004 사용자 확정 legacy 프로필/후원 목록, 복원 및 기타 global hide는 범위 밖이다. 사용자 인터뷰
2026-11-05 DEC-005 작성자 기술 초안 isHidden 필드, 로컬 query filter, owner-only ID, DELETE route, 멱등 재요청을 제안한다. 기존 코드 경계와 최소 구현 검토. 사용자 승인 아님

13. 기준 문서와 변경 관리

docs/20261104_크리에이터채널_비밀후원_익명조회/prd.md는 현재 visible row의 비밀 여부 마스킹 기준이다. 본 문서는 기존 isSecret 마스킹 정책을 변경하지 않고, 숨김 상태의 두 V2 query 제외 및 donationCount에 한해 후속 요구를 더한다. 과거 PRD의 목록 DTO ID 비노출 요구는 owner-only donationId 기술안이 승인될 경우에만 소유 CREATOR 응답 범위에서 좁게 대체한다. 현재 공개 계약을 이미 변경한 것은 아니다. donor member ID 부재 및 모든 non-owner의 ID 부재 요구는 유지한다. 과거 문서는 수정하지 않는다.

구현 착수 전 별도의 명시적 요청이 필요하다. 구현 선택을 확정하면 이 PRD의 기술 제안을 승인된 계약과 구분해 Decision Log에 반영하고 계획을 동기화한다.

구현 승인: 2026-11-05

사용자의 "문서대로 진행" 요청으로 이 문서의 기술 제안과 계획을 구현 기준으로 승인했다. 위 초안/미요청 표기는 작성 당시 이력이며 현재는 isHidden, 소유 CREATOR 전용 donationId, bodyless DELETE 및 멱등 재요청을 구현한다. 프론트엔드·운영 DDL 실행·배포는 포함하지 않는다.

날짜 ID 상태 결정 근거
2026-11-05 DEC-006 사용자 승인 DEC-005 기술 초안을 본 구현의 계약으로 사용한다. "문서대로 진행"

서버 구현 완료: 2026-11-05

  • 관련 기능 19개 클래스 208건이 실패/오류/skip 없이 통과했다. 실제 JWT socket HTTP, 원본 DB·랭킹·정산·legacy 보존과 SQL 시각 보존을 검증했고 최종 리뷰가 승인됐다.
  • ktlintCheck, bootJar 성공. 전체 suite는 미실행이며 사용자가 ./gradlew test로 검증한다. 상세 명령·실패 이력·최종 증거는 plan-task.md에 있다.
  • DDL은 작성만 했으며 배포 전에 반영해야 한다. 프론트엔드는 소유자 전용 donationId로 DELETE를 호출하고 두 조회 결과를 갱신해야 한다. 화면 클라이언트·운영 배포 완료를 의미하지 않는다.