15 KiB
15 KiB
PRD: 크리에이터 채널 커뮤니티 탭
1. Overview
크리에이터 채널 공통 shell의 커뮤니티 탭에서 크리에이터의 커뮤니티 게시글을 리스트형 또는 썸네일형으로 제공한다. 상단 title bar, header, sticky tab-bar는 기존 크리에이터 채널 홈/라이브/오디오/시리즈/팬Talk/후원 구현을 재사용하고, tab-bar 아래 콘텐츠만 커뮤니티 탭 전용 API 응답으로 구성한다.
API는 GET /api/v2/creator-channels/{creatorId}/community를 사용한다. creatorId는 path variable이며, query parameter는 page, size를 사용한다. 기본값은 page=0, size=20이다.
Figma 참조:
- 전체 리스트형:
290:9061,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-9061&m=dev - 전체 썸네일형:
290:9073,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-9073&m=dev - 전체 리스트형 + 본인 채널:
665:19021,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=665-19021&m=dev - 전체 썸네일형 + 본인 채널: Figma 설명 기준, 썸네일 UI는
290:9073과 동일하고 하단 고정커뮤니티 글 올리기버튼을 표시한다. - 유료이고 구매하지 않은 게시글:
290:9066,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-9066&m=dev - 유료 금액 우측 상단 표시:
665:19024,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=665-19024&m=dev - Empty:
290:8994,https://www.figma.com/design/HmN1yNdJ3EIpqknFL0Hkab/-%EA%B3%B5%EC%9C%A0%EC%9A%A9-%EB%B3%B4%EC%9D%B4%EC%8A%A4%EC%98%A8-UI-UX-%EA%B8%B0%ED%9A%8D%EB%AC%B8%EC%84%9C?node-id=290-8994&m=dev
2. Problem
- 현재
CreatorChannelTab.community는 임시 화면으로 표시되어 V2 크리에이터 채널 안에서 커뮤니티 게시글 목록을 확인할 수 없다. - 기존
CreatorCommunityAllView는 구 프로필 커뮤니티 전체보기 화면이고, V2 채널 탭의 sticky header, tab-bar, sort-bar 구조와 직접 맞지 않는다. - 커뮤니티 탭은 오디오 탭의 정렬 선택과 달리 리스트형/썸네일형 보기 전환 버튼이 필요하다.
- 유료 미구매 게시글, 댓글 비활성 게시글, 본인 채널 게시글의 표시 조건이 기존 전체보기와 일부 달라 V2 탭 기준으로 명확히 분리해야 한다.
3. Goals
CreatorChannelTab.community선택 시 커뮤니티 탭 API를 호출하고 응답 데이터로 화면을 구성한다.- 기본 query는
page=0,size=20이다. - sort-bar 좌측에는
전체 {communityPostCount}를 표시한다. - sort-bar 우측은 정렬이 아니라 리스트형/썸네일형 토글 버튼으로 제공한다.
- 기본 보기 방식은 리스트형이고, 기본 아이콘은
ic_new_list를 사용한다. - 토글 후 썸네일형에서는
ic_new_grid를 사용한다. - 리스트형/썸네일형 표시 문구는
I18n에 ko/en/ja 다국어로 추가한다. - 리스트형은 기존 커뮤니티 리스트 카드의 정보 구조를 따르되 V2 채널 탭 디자인에 맞춰 작성한다.
- 썸네일형은 3열 grid로 표시하고, 이미지가 있으면 이미지 또는 GIF를 재생 가능하게 표시한다.
- 썸네일형에서
imageUrl == nil이면 유/무료 관계없이 이미지를 표시하지 않고 기존 크리에이터 커뮤니티 페이지의 fallback 규칙을 참고해 글 일부를 표시한다. - 유료 미구매 게시글은 이미지 영역에 회색
RoundedRectangle을 표시하고, 오디오 재생 버튼은 표시하지 않는다. - 본인 또는 구매한 유저는 이미지와 중앙 오디오 재생 버튼을 기존 커뮤니티 페이지와 동일한 방식으로 표시한다.
- 댓글을 사용할 수 없는 게시글은 댓글 아이콘과 댓글 개수를 숨긴다.
- 본인 채널에 본인이 쓴 커뮤니티 게시글에서만 상단 더보기와 가격 표시를 표시한다.
- 본인 채널이면 하단 고정
커뮤니티 글 올리기버튼을 표시한다. - 게시글 우측 더보기 액션은 기존 커뮤니티 전체보기의 수정/삭제/신고/고정 액션 흐름을 재사용한다.
4. Non-Goals
- 크리에이터 채널 공통 shell, header, sticky tab-bar 동작을 다시 설계하지 않는다.
- 커뮤니티 게시글 상세 화면은 이번 범위에서 구현하지 않는다.
- 커뮤니티 글쓰기/수정 화면 자체를 새로 구현하지 않고 기존
creatorCommunityWrite/creatorCommunityModifynavigation step을 재사용한다. - 커뮤니티 댓글 리스트, 댓글 작성, 신고, 삭제, 구매 mutation API를 새로 만들지 않고 기존 커뮤니티 구현의 흐름을 재사용한다.
- 오디오 탭의 정렬 popup을 커뮤니티 탭에 표시하지 않는다.
- Figma localhost asset URL을 앱 코드에 직접 사용하지 않는다.
Pods/**,generated/**,build/**는 수정하지 않는다.
5. Core Requirements
5.1 API
- Method:
GET - Path:
/api/v2/creator-channels/{creatorId}/community - Path parameter:
creatorId
- Query parameters:
page: 기본값0size: 기본값20
- 응답 래퍼는 기존 패턴대로
ApiResponse<CreatorChannelCommunityTabResponse>로 디코딩한다.
data class CreatorChannelCommunityTabResponse(
val communityPostCount: Int,
val communityPosts: List<CreatorChannelCommunityPostResponse>,
val page: Int,
val size: Int,
@JsonProperty("hasNext")
val hasNext: Boolean
)
data class CreatorChannelCommunityPostResponse(
val postId: Long,
val creatorId: Long,
val creatorNickname: String,
val creatorProfileUrl: String,
val createdAtUtc: String,
val content: String,
val imageUrl: String?,
val audioUrl: String?,
val price: Int,
@JsonProperty("isCommentAvailable")
val isCommentAvailable: Boolean,
val likeCount: Int,
val commentCount: Int,
@JsonProperty("isPinned")
val isPinned: Boolean,
val existOrdered: Boolean
)
- Kotlin
Long은 기존 V2 모델 관례대로 SwiftInt로 선언한다. creatorProfileUrl,existOrdered는 서버 응답에 추가되는 필드로 포함한다.createdAtUtc는 기존DateParser.relativeTimeText(fromUTC:fallback:now:)계열 helper를 사용해 상대 시간으로 표시한다.
5.2 View mode toggle
- 기본 보기 방식은 리스트형이다.
- sort-bar 우측 버튼을 터치할 때마다 리스트형과 썸네일형을 토글한다.
- 리스트형 상태에서는 버튼에
ic_new_list와 리스트형 문구를 표시한다. - 썸네일형 상태에서는 버튼에
ic_new_grid와 썸네일형 문구를 표시한다. - 리스트형/썸네일형 문구는
I18n.CreatorChannelCommunity또는 같은 범위의 신규 enum에 ko/en/ja로 추가한다. - 보기 방식 전환은 현재까지 로드된
communityPosts를 그대로 사용하고 API를 다시 호출하지 않는다.
5.3 List layout
- 리스트형은 Figma
290:9061과665:19021을 기준으로 표시한다. - 작성자 프로필 이미지, 닉네임, 상대 시간, 본문, 이미지/오디오 영역, 좋아요 수, 댓글 수를 표시한다.
- 반응 정보는 Figma 기준으로 댓글 아이콘/댓글 수를 먼저, 좋아요 아이콘/좋아요 수를 뒤에 표시한다.
isPinned == true이면 게시글에 고정 표시를 제공한다.price > 0 && existOrdered == false && isOwnPost == false이면 유료 미구매 상태로 표시한다.- 유료 미구매 상태에서는 이미지 URL도
nil로 내려올 수 있으므로 이미지 영역에 회색RoundedRectangle을 표시한다. - 유료 미구매 상태에서는 오디오 재생 버튼을 표시하지 않는다.
- 본인 또는 구매한 유저는 이미지가 있으면 이미지 또는 GIF를 표시하고,
audioUrl != nil이면 이미지 중앙에 재생 버튼을 표시한다. - GIF URL은 정지 이미지로 변환하지 않고 재생 가능한 이미지 컴포넌트를 사용한다.
imageUrl == nil이면 유/무료 관계없이 이미지 영역을 표시하지 않는다.isCommentAvailable == false이면 댓글 아이콘과 댓글 개수를 숨긴다.
5.4 Thumbnail layout
- 썸네일형은 Figma
290:9073기준 3열 grid로 표시한다. - 이미지 또는 GIF가 있으면 정방형 썸네일에 표시한다.
- 이미지가 없으면 유/무료 관계없이 기존
CreatorCommunityAllGridItemView의 fallback 규칙을 참고해 글 일부를 표시한다. - 유료 미구매 게시글은 회색 배경과 중앙형 가격 UI를 표시한다.
isPinned == true이면 썸네일 우측 상단에 고정 표시를 제공한다.- grid item tap은 후속 상세 화면 구현 전까지 상세 이동을 연결하지 않는다.
5.5 Paid post display
- 유료 미구매 판정은
price > 0 && existOrdered == false && isOwnPost == false이다. - 리스트형 중앙 가격 표시는 Figma
290:9066을 따른다. - 우측 상단 가격 표시는 Figma
665:19024를 따른다. - 썸네일형 유료 미구매 가격 UI는 중앙형을 사용한다.
- 상단 더보기와 가격 표시는 본인 채널에 본인이 쓴 커뮤니티 게시글에서만 표시한다.
- 유료 미구매 게시글의 구매 dialog는 기존
CommunityPostPurchaseDialog를 재사용한다. - 구매 성공 후 현재 페이지 범위를 첫 페이지부터 다시 조회하거나 해당 item을 갱신한다.
5.6 Actions
- 좋아요는 기존
CreatorCommunityRepository.communityPostLike(postId:)흐름을 재사용한다. - 댓글 목록은 기존
CreatorCommunityCommentListView를 재사용하되,isCommentAvailable == false이면 진입 UI를 표시하지 않는다. - 더보기 메뉴는 기존
CreatorCommunityMenuView또는 V2 anchored popup 패턴 중 구현 시점에 더 작은 변경으로 맞는 방식을 사용한다. - 본인 채널의 내 게시글에서 더보기 메뉴는 기존과 동일하게 고정/수정/삭제 액션을 제공한다.
- 내 게시글이 아니면 신고 액션을 기존
CreatorCommunityReportView와ReportType.COMMUNITY_POST흐름으로 처리한다. - 수정 성공, 삭제 성공, 고정 상태 변경 성공 후 커뮤니티 탭 첫 페이지를 다시 조회한다.
5.7 Own channel CTA
- 본인 채널이고
selectedTab == .community이면 하단 고정커뮤니티 글 올리기버튼을 표시한다. - 버튼 문구는 기존
I18n.CreatorChannelHome.uploadCommunityPost또는 동일 의미의 기존 다국어 문구를 우선 재사용한다. - 버튼 tap은 기존
showCommunityWrite()흐름을 재사용한다. - 글 작성 성공 후 홈 정보와 커뮤니티 탭 목록을 갱신한다.
5.8 Pagination and state
- 첫 진입 시
page=0,size=20으로 조회한다. - 다음 페이지 로딩 중 중복 호출을 막는다.
- 마지막 item이 화면에 나타났고
hasNext == true이면page + 1을 조회한다. - 다음 페이지 성공 시 기존
communityPosts뒤에 append한다. - 첫 페이지 재조회 시 기존 목록을 교체한다.
- Empty 상태는
communityPostCount == 0기준으로 판정하고 Figma290:8994를 따른다.
6. Success Criteria
- 커뮤니티 탭 진입 시
GET /api/v2/creator-channels/{creatorId}/community?page=0&size=20가 호출된다. - count bar에는
전체 {communityPostCount}가 표시된다. - 우측 버튼은 정렬이 아니라 리스트형/썸네일형 토글로 동작한다.
- 기본값은 리스트형이며
ic_new_list상태로 표시된다. - 토글 시 썸네일형으로 바뀌고
ic_new_grid상태로 표시된다. - 리스트형/썸네일형 문구는 ko/en/ja 다국어로 제공된다.
- 유료 미구매 게시글은 회색
RoundedRectangle이미지 영역과 가격 UI를 표시하고 오디오 재생 버튼은 표시하지 않는다. - 본인 또는 구매한 유저의 게시글은 이미지/GIF와 중앙 오디오 재생 버튼을 표시한다.
isCommentAvailable == false이면 댓글 아이콘과 댓글 개수가 표시되지 않는다.- 본인 채널의 내 게시글에서만 상단 더보기와 가격 표시가 노출된다.
- 본인 채널이면 리스트형/썸네일형 모두에서 하단 고정
커뮤니티 글 올리기버튼이 표시된다. - 게시글 더보기 액션은 기존 커뮤니티 페이지와 동일한 수정/삭제/신고/고정 흐름을 사용한다.
communityPostCount == 0이면 커뮤니티 empty 상태가 표시된다.- 목록 하단 도달 시
hasNext == true이면 다음 페이지가 append된다.
7. Technical Constraints
- 기능 변경은
SodaLive/Sources/V2/CreatorChannel/**하위에서 해결한다. - 커뮤니티 탭 전용 View, ViewModel, Repository, API, 모델은
SodaLive/Sources/V2/CreatorChannel/Community/**아래에 둔다. - 기존 구 커뮤니티 전체보기 파일은 필요한 재사용 지점만 참고하고, V2 탭 구현을 위해 직접 대규모 수정하지 않는다.
- 기존 커뮤니티 mutation, 댓글, 구매, 신고, 오디오 플레이어 흐름은 가능한 한 재사용한다.
- 신규 문구는
SodaLive/Sources/I18n/I18n.swift에 ko/en/ja를 추가한다. - 프로젝트 설정 변경은 신규 Swift 파일 target 등록이 필요한 경우에만 수행한다.
8. Assumptions
creatorProfileUrl과existOrdered는 커뮤니티 탭 API 응답에 포함된다.- 현재 로그인 사용자의 id는 기존 관례대로
UserDefaults.int(forKey: .userId)로 확인한다. isOwnPost는post.creatorId == UserDefaults.int(forKey: .userId)로 판정한다.- 커뮤니티 게시글 상세 화면은 후속 범위이므로 grid/list item tap 상세 이동은 이번 작업에서 연결하지 않는다.
- 본인 채널 여부는
CreatorChannelView의isOwnCreatorChannel값을 커뮤니티 탭에 주입한다.
9. Open Questions
- 해당 없음
10. Verification Notes
- 2026-07-05: 사용자 제공 API, 응답 모델, Figma URL, 본인 채널/유료/댓글/토글 요구사항을 기준으로 PRD를 작성했다.
- 2026-07-05:
docs/agent-guides/documentation-policy.md, 기존 크리에이터 채널 오디오/팬Talk 문서,CreatorChannelView, 기존CreatorCommunityAllView,CreatorCommunityAllItemView,CreatorCommunityAllViewModel을 확인해 문서 범위를 정했다. - 2026-07-05: 사용자 추가 확인으로 Empty Figma
290:8994, 썸네일형 유료 미구매 가격 UI 중앙형,imageUrl == nil일 때 유/무료 관계없이 이미지 미표시 규칙을 반영했다.