Files

11 KiB

PRD: 커뮤니티 게시글 좋아요 상태 응답 추가

1. Overview

v2 API에서 커뮤니티 게시글 item을 내려줄 때 인증 조회자가 해당 게시글에 좋아요를 누른 상태를 함께 제공한다.


2. Problem

  • v2 커뮤니티 게시글 응답은 likeCount는 제공하지만, 조회자 본인의 좋아요 여부는 제공하지 않는다.
  • 앱 클라이언트는 게시글 카드의 좋아요 버튼 초기 상태를 알기 위해 별도 조회를 하거나 화면 진입 후 상태를 추정해야 한다.
  • 같은 커뮤니티 게시글이 홈 추천, 크리에이터 채널 홈, 크리에이터 채널 커뮤니티 탭에서 각각 다른 DTO로 노출되므로 누락 없이 동일한 의미의 필드를 추가해야 한다.

3. Goals

  • v2에서 커뮤니티 게시글 카드로 노출되는 모든 응답 item에 조회자의 좋아요 상태를 추가한다.
  • 신규 응답 필드 이름은 isLiked로 한다.
  • Kotlin Boolean 직렬화가 liked로 바뀌지 않도록 응답 DTO에는 @JsonProperty("isLiked")를 사용한다.
  • 좋아요 상태는 CreatorCommunityLike.isActive == true인 행을 기준으로 계산한다.
  • 인증 회원 기준으로 조회되는 크리에이터 채널 홈/커뮤니티 탭에서는 로그인한 조회자의 좋아요 여부를 반영한다.
  • 비회원도 호출 가능한 홈 추천 전체 응답에서는 비회원의 isLikedfalse로 내려준다.
  • 기존 likeCount, commentCount, existOrdered, 유료 콘텐츠 마스킹, 성인 콘텐츠 필터, 차단 정책은 변경하지 않는다.

4. Non-Goals

  • 커뮤니티 게시글 좋아요 생성/취소 API 동작은 변경하지 않는다.
  • likeCount 집계 기준은 변경하지 않는다.
  • legacy 커뮤니티 API 응답 스키마는 변경하지 않는다.
  • 팔로잉 뉴스의 COMMUNITY_POST news item은 이 문서 작성 당시 게시글 카드 필드가 없어 이번 범위에서 제외했다. 이후 FollowingNewsResponse.communityPost nested DTO 계약으로 변경하며 무료 커뮤니티 게시글에 한해 likeCount, commentCount를 포함하도록 별도 후속 범위에서 다룬다.
  • DB schema, 운영 DDL, 마이그레이션은 포함하지 않는다.
  • 추천 스냅샷 산정 로직과 인기 커뮤니티 정렬 정책은 변경하지 않는다.

5. Target Users

  • 회원: 커뮤니티 게시글 카드에서 본인이 누른 좋아요 상태를 즉시 확인하려는 사용자
  • 앱 클라이언트: 게시글 카드 렌더링 시 좋아요 버튼의 초기 active 상태가 필요한 클라이언트
  • 서버 개발자: v2 커뮤니티 게시글 응답 간 좋아요 상태 필드 의미를 일관되게 유지해야 하는 개발자

6. 조사 결과

대상 응답 item

  • HomePopularCommunityPostItem

    • 파일: src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/dto/recommendation/HomeRecommendationResponse.kt
    • 노출 API: GET /api/v2/home/recommendations
    • 현재 필드: postId, creatorId, creatorNickname, creatorProfileImage, imageUrl, audioUrl, content, price, createdAt, likeCount, commentCount, existOrdered
    • 데이터 흐름: HomeRecommendationFacadeHomePopularCommunityRecommendationRecord를 변환한다.
  • CreatorChannelCommunityPostResponse in creator channel home

    • 파일: src/main/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/dto/CreatorChannelHomeResponse.kt
    • 노출 API: GET /api/v2/creator-channels/{creatorId}/home
    • 현재 필드: postId, creatorId, creatorNickname, creatorProfileUrl, imageUrl, audioUrl, content, price, dateUtc, existOrdered, likeCount, commentCount
    • 데이터 흐름: CreatorChannelHomeQueryServiceCreatorChannelCommunityQueryService.findHomeCommunityPosts(...)를 호출하고, 공지/커뮤니티 섹션이 같은 domain post를 사용한다.
  • CreatorChannelCommunityPostResponse in creator channel community tab

    • 파일: src/main/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/community/dto/CreatorChannelCommunityTabResponse.kt
    • 노출 API: GET /api/v2/creator-channels/{creatorId}/community
    • 현재 필드: postId, creatorId, creatorNickname, creatorProfileUrl, createdAtUtc, content, imageUrl, audioUrl, price, isCommentAvailable, existOrdered, likeCount, commentCount, isPinned
    • 데이터 흐름: CreatorChannelCommunityQueryService.getCommunityTab(...)CreatorChannelCommunityPost를 만들고 DTO가 이를 변환한다.

대상 하위 모델

  • CreatorChannelCommunityPost

    • 파일: src/main/kotlin/kr/co/vividnext/sodalive/v2/creator/channel/community/domain/CreatorChannelCommunityTab.kt
    • 채널 홈과 커뮤니티 탭이 함께 사용하는 domain post다.
  • CreatorChannelCommunityPostRecord

    • 파일: src/main/kotlin/kr/co/vividnext/sodalive/v2/creator/channel/community/port/out/CreatorChannelCommunityQueryPort.kt
    • repository에서 조회한 게시글 row와 부가 상태를 service로 전달한다.
  • HomePopularCommunityRecommendationRecord

    • 파일: src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt
    • 홈 인기 커뮤니티 상세 조회 결과를 facade로 전달한다.

제외 대상

  • HomeFollowingNews / FollowingNewsResponse
    • 이 문서 작성 당시에는 FollowingNewsType.COMMUNITY_POSTtargetId만 있었고 게시글 카드 DTO가 아니어서 제외했다. 이후 팔로잉 뉴스 응답 계약 변경으로 communityPost nested DTO가 무료 커뮤니티 게시글의 postId, creatorProfileImage, creatorNickname, imageUrl, content, createdAt, likeCount, commentCount를 제공하도록 별도 후속 작업에서 갱신한다.

7. User Stories

  • 사용자는 홈 추천의 인기 커뮤니티 게시글을 볼 때 내가 이미 좋아요를 눌렀는지 바로 알고 싶다.
  • 사용자는 크리에이터 채널 홈의 공지/커뮤니티 게시글 카드에서 좋아요 버튼이 현재 상태대로 표시되기를 원한다.
  • 사용자는 크리에이터 채널 커뮤니티 탭 목록에서 각 게시글의 좋아요 상태가 정확하게 표시되기를 원한다.
  • 앱 클라이언트는 게시글 목록 응답만으로 좋아요 버튼의 selected 상태를 렌더링하고 싶다.

8. Core Features

Feature A. 홈 인기 커뮤니티 게시글 좋아요 상태

Requirements

  • HomePopularCommunityPostItemisLiked: Boolean을 추가한다.
  • HomePopularCommunityRecommendationRecord에 조회자 좋아요 여부를 전달할 수 있는 Boolean 필드를 추가한다.
  • DefaultHomeRecommendationQueryRepository.findPopularCommunityRecommendationDetails(...)memberId가 null이면 isLiked=false를 반환한다.
  • memberId가 있으면 해당 회원의 활성 좋아요가 있는 게시글만 isLiked=true로 반환한다.
  • 홈 추천 전체 응답은 비회원 호출을 허용하므로 비회원 isLiked=false를 명시적으로 보장한다.

Edge Cases

  • 비활성 좋아요는 isLiked=false다.
  • 다른 회원이 좋아요한 게시글은 현재 조회자의 isLiked=true가 되면 안 된다.
  • 좋아요 수가 1 이상이어도 현재 조회자가 좋아요하지 않았으면 isLiked=false다.

Feature B. 크리에이터 채널 홈 게시글 좋아요 상태

Requirements

  • 크리에이터 채널 홈의 CreatorChannelCommunityPostResponseisLiked: Boolean을 추가한다.
  • CreatorChannelCommunityPost domain에 조회자 좋아요 여부를 추가한다.
  • CreatorChannelCommunityPostRecord에 조회자 좋아요 여부를 추가한다.
  • DefaultCreatorChannelCommunityQueryRepository.findHomeCommunityPosts(...)는 기존 id 목록 기반 부가 조회 패턴을 유지하고, 조회자 좋아요 게시글 id 목록을 bulk 조회한다.
  • 공지(notices)와 일반 커뮤니티(communities) 모두 같은 isLiked 의미를 사용한다.

Edge Cases

  • 조회자가 게시글 작성자여도 본인이 활성 좋아요를 누른 이력이 없으면 isLiked=false다.
  • 유료 미구매로 이미지/오디오/본문이 마스킹되어도 좋아요 상태는 실제 조회자의 활성 좋아요 기준으로 내려준다.

Feature C. 크리에이터 채널 커뮤니티 탭 게시글 좋아요 상태

Requirements

  • 커뮤니티 탭의 CreatorChannelCommunityPostResponseisLiked: Boolean을 추가한다.
  • DefaultCreatorChannelCommunityQueryRepository.findCommunityPosts(...)도 홈 조회와 동일한 조회자 좋아요 상태 계산을 적용한다.
  • page/size와 무관하게 응답에 포함된 각 게시글의 isLiked가 정확해야 한다.

Edge Cases

  • 현재 page에 포함되지 않은 게시글의 좋아요 상태를 조회하거나 응답에 포함하지 않는다.
  • 좋아요가 없는 게시글은 isLiked=false다.

9. Technical Constraints

  • 기존 v2 패키지 경계를 유지한다.
  • 공개 API 응답 필드 추가 외에 기존 필드명과 의미를 변경하지 않는다.
  • 커뮤니티 좋아요 상태는 CreatorCommunityLikecreatorCommunityLike.isActive.isTrue를 기준으로 한다.
  • 채널 홈/커뮤니티 탭은 이미 postIds 기반으로 likeCount, commentCount, existOrdered를 bulk 조회하므로 같은 패턴의 likedCommunityPostIds(viewerId, postIds) helper를 추가하는 방향을 우선 검토한다.
  • 홈 인기 커뮤니티는 QueryDSL projection으로 record를 생성하므로 isLiked 계산식 또는 별도 subquery를 projection에 추가하는 방향을 우선 검토한다.
  • Boolean 응답 필드는 Jackson 직렬화 이름 보존을 위해 @JsonProperty("isLiked")를 명시한다.
  • 신규 필드 추가에 따른 테스트 fixture와 controller JSON assertion을 갱신한다.

10. Success Criteria

  • GET /api/v2/home/recommendationspopularCommunityPosts[*].isLiked가 인증 회원 기준 활성 좋아요 여부를 반환한다.
  • GET /api/v2/home/recommendations를 비회원으로 호출하면 popularCommunityPosts[*].isLiked=false를 반환한다.
  • GET /api/v2/creator-channels/{creatorId}/homenotices[*].isLiked, communities[*].isLiked가 인증 조회자 기준 활성 좋아요 여부를 반환한다.
  • GET /api/v2/creator-channels/{creatorId}/communitycommunityPosts[*].isLiked가 인증 조회자 기준 활성 좋아요 여부를 반환한다.
  • 비활성 좋아요, 다른 회원의 좋아요, 좋아요 수와 조회자 좋아요 여부가 다른 케이스를 테스트로 구분한다.
  • 기존 좋아요 수, 댓글 수, 구매 여부, 유료 콘텐츠 마스킹, 성인 콘텐츠 필터 테스트가 계속 통과한다.

11. Open Questions

  • 없음. 필드명은 요청 의미와 기존 Boolean 응답 패턴을 기준으로 isLiked로 확정한다.