Files

197 lines
14 KiB
Markdown

# PRD: FanTalk 상세 / 답글쓰기
## 1. Overview
크리에이터 채널 `FanTalk` 탭에서 본인 채널의 FanTalk item을 터치하면 FanTalk 상세 화면으로 진입하고, 기존 FanTalk 답글 쓰기 API로 크리에이터 답글을 작성할 수 있게 한다.
---
## 2. Problem
- 현재 v2 `FanTalk` 탭은 목록 item에 표시되는 FanTalk 원문과 최신 크리에이터 답글을 보여주지만, item 터치로 상세 화면에 진입하는 흐름이 없다.
- 본인 채널의 크리에이터는 FanTalk 원문을 상세히 보고 같은 화면에서 답글을 작성해야 한다.
- FanTalk 상세 UI는 커뮤니티 답글 화면과 동일해야 하므로, 기존 구현과 Figma 기준을 문서로 고정해야 한다.
- 답글 입력값 유무에 따른 send button 활성/비활성 상태가 명확히 정의되어야 한다.
- 구현 전에 V2 패키지 하위에서 재사용 가능한 위젯/화면 요소 후보를 확인해 중복 구현을 줄여야 한다.
---
## 3. Goals
- `FanTalk` 탭의 FanTalk item 터치 시 FanTalk 상세 화면으로 진입하는 요구사항을 정의한다.
- FanTalk 상세 진입은 본인 채널(`currentHeader?.isOwner == true`)에서만 허용한다.
- FanTalk 상세 UI는 `CreatorChannelCommunityReplyActivity`와 동일한 구조를 따른다.
- Figma 답글 없음 `669:40462`, 답글 있음 `669:40468` 기준으로 FanTalk 상세/답글쓰기 UI 요구사항을 정의한다.
- FanTalk는 별도의 상세 조회 API가 없으므로 FanTalk item 터치 시 목록의 data model을 통째로 상세 화면에 전달한다.
- FanTalk 상세에서는 크리에이터 답글을 최대 1개만 표시/관리한다.
- 답글 작성은 기존 FanTalk 답글 쓰기 API를 그대로 재사용한다.
- 기존 경로: `ExplorerRepository.writeCheers(parentCheersId = fanTalkId, creatorId = creatorId, content = content, token = token)`
- v2 wrapper 추가 시 `CreatorChannelRepository.writeFanTalkReply(fanTalkId, creatorId, content, token)`처럼 레거시 API를 감싸는 최소 wrapper만 둔다.
- 기존 답글이 있는 상태에서 신규 답글을 쓰려고 하면 안내 모달을 표시하고, 확인 시 신규 작성 API가 아니라 답글 수정 API로 기존 답글을 대체한다.
- 입력값이 `trim()` 기준 비어 있으면 send button을 비활성화한다.
- 입력값이 `trim()` 기준 비어 있지 않으면 send button을 활성화한다.
- 재사용 가능한 V2 위젯/화면 요소 후보를 계획 문서에 기록한다.
---
## 4. Non-Goals
- 레거시 FanTalk 화면 파일을 직접 수정하지 않는다.
- 서버 API schema나 endpoint를 새로 정의하지 않는다.
- 별도 FanTalk 상세 조회 API를 새로 가정하지 않는다.
- FanTalk 원글 작성 화면은 이번 범위에서 수정하지 않는다.
- FanTalk 원글 수정/삭제 UX를 새로 설계하지 않는다.
- 일반 사용자가 타인 채널에서 FanTalk 상세에 진입하는 흐름은 이번 범위에서 제공하지 않는다.
- 커뮤니티 상세/답글 화면의 기존 동작을 변경하지 않는다.
- Figma에 없는 새로운 reaction row, title text, marketing성 안내 문구를 추가하지 않는다.
---
## 5. Target Users
- 본인 채널의 FanTalk에 답글을 작성하려는 크리에이터.
- `kr.co.vividnext.sodalive.v2` 하위 크리에이터 채널 FanTalk 기능을 구현/유지보수하는 Android 개발자.
---
## 6. User Stories
- 크리에이터는 내 채널의 FanTalk item을 터치해 상세 화면으로 들어가고 싶다.
- 크리에이터는 FanTalk 상세에서 팬이 남긴 원문, 작성자 프로필, 닉네임, 작성 시간을 확인하고 싶다.
- 크리에이터는 이미 작성된 답글이 있으면 FanTalk 상세에서 확인하고 싶다.
- 크리에이터는 답글이 없는 FanTalk 상세에서도 바로 답글을 입력하고 싶다.
- 크리에이터는 답글 input field에 글을 입력하면 send button이 활성화되기를 기대한다.
- 크리에이터는 답글 작성 성공 후 FanTalk 목록과 홈 요약이 최신 상태로 갱신되기를 기대한다.
- 일반 사용자는 타인 채널에서 FanTalk item을 터치해 상세 화면으로 들어가지 못해야 한다.
---
## 7. Core Features
### F1. FanTalk 상세 진입
본인 채널의 FanTalk item 터치 시 상세 화면으로 이동한다.
#### Requirements
- `CreatorChannelFanTalkAdapter`의 item root 또는 FanTalk 본문 영역 터치를 상세 진입점으로 사용한다.
- 상세 진입은 `CreatorChannelActivity``currentHeader?.isOwner == true`인 경우에만 허용한다.
- 본인 채널이 아니면 item 터치 callback을 연결하지 않거나, Activity에서 안전하게 무시한다.
- 상세 화면에는 목록에서 사용 중인 FanTalk data model을 통째로 전달한다.
- data model 전달 방식은 `Parcelable`을 우선 사용하고, 기존 model에 직접 적용하기 어렵다면 FanTalk 상세 전용 payload model을 만들어 원본 item 데이터를 한 번에 담아 전달한다.
- 개별 primitive extra로 `fanTalkId`, `writerNickname`, `content` 등을 나누어 전달하지 않는다.
- `fanTalkId <= 0L` 또는 `creatorId <= 0L`이면 상세 화면을 열지 않는다.
- 로그인 토큰이 없으면 기존 크리에이터 채널 로그인 이동 정책을 따른다.
#### Edge Cases
- 목록 refresh 중 stale item을 터치해 유효하지 않은 ID가 전달되면 아무 동작도 하지 않는다.
- 본인 채널이 아닌 상태에서 callback이 호출되더라도 상세 화면을 열지 않는다.
### F2. FanTalk 상세 UI
Figma와 커뮤니티 답글 화면 기준으로 FanTalk 상세 화면을 표시한다.
#### Requirements
- UI 구조는 `app/src/main/java/kr/co/vividnext/sodalive/v2/creator/channel/community/detail/reply/CreatorChannelCommunityReplyActivity.kt`와 동일하게 한다.
- layout 기준은 `activity_creator_channel_community_reply.xml`을 따른다.
- 상단 title-bar에는 뒤로가기 icon만 표시하고 별도 title text는 표시하지 않는다.
- 상단에는 부모 FanTalk 원문을 표시한다.
- 프로필 이미지 42dp
- 닉네임
- 작성 시간
- 본문
- 본인 채널 관리용 더보기 button
- 답글이 없으면(Figma `669:40462`) 부모 FanTalk만 표시하고 답글 card 영역은 비운다.
- 답글이 있으면(Figma `669:40468`) 부모 FanTalk 아래에 크리에이터 답글 card 1개만 표시한다.
- 답글 card는 `gray_900` 배경, round corner, profile 20dp, 닉네임, 시간, 본문, 더보기 button 구조를 따른다.
- 하단 input bar는 화면 하단에 고정하고 키보드 표시 시 키보드 위로 함께 올라오게 한다.
#### Edge Cases
- 전달받은 답글 목록이 비어 있으면 empty message를 추가하지 않는다.
- 답글은 1개만 가능하므로 별도 pagination/API를 사용하지 않는다.
- 서버 응답 data model에 답글 list가 들어 있더라도 상세에서는 첫 번째 답글만 기존 답글로 취급한다.
### F3. FanTalk 답글 작성
기존 FanTalk 답글 쓰기 API를 재사용한다.
#### Requirements
- 답글 input placeholder는 기존 커뮤니티 답글 화면과 동일한 문자열을 우선 재사용한다.
- 입력값 판단은 `trim()` 기준으로 한다.
- 입력값이 없으면 send button은 disabled 상태다.
- button bg: `gray_900`
- button icon: `ic_new_arrow_up_gray`
- 입력값이 있으면 send button은 enabled 상태다.
- button bg: `soda_400`
- button icon: `ic_new_arrow_up_white`
- 답글이 없는 상태에서 send를 누르면 기존 FanTalk 등록 API에 `parentCheersId = fanTalkId`를 전달해 호출한다.
- 답글이 있는 상태에서 send를 누르면 기존 답글 대체 안내 모달을 먼저 표시한다.
- 기존 답글 대체 안내 모달은 기존 답글이 신규 답글로 대체된다는 내용을 포함한다.
- title: `답글 수정`
- desc: `기존 답글이 신규 답글로 대체됩니다.\n수정하시겠어요?`
- cancel button: `취소`
- confirm button: `확인`
- 기존 답글 대체 안내 모달에서 확인을 누르면 신규 작성 API가 아니라 답글 수정 API를 호출한다.
- 답글 수정 API는 기존 답글의 `fanTalkId`를 대상으로 `ExplorerRepository.modifyCheers(PutModifyCheersRequest(cheersId = replyFanTalkId, content = ...), token)`를 호출하는 v2 wrapper를 사용한다.
- 전송 content는 앞뒤 공백을 제거한 값을 사용한다.
- 작성 중에는 중복 전송을 막는다.
- 작성 또는 수정 성공 시 입력값을 비우고 상세 화면/목록/홈 요약 갱신을 요청한다.
- 작성 또는 수정 성공 시 키보드를 내리고 input focus를 해제한다.
- 작성 실패 시 입력값을 유지하고 기존 toast/error 표시 정책을 따른다.
#### Edge Cases
- 공백/줄바꿈만 입력하면 API를 호출하지 않는다.
- 기존 답글이 있는 상태에서 대체 안내 모달을 취소하면 API를 호출하지 않고 입력 상태를 유지한다.
- 서버 실패 응답의 message가 있으면 해당 message를 우선 표시한다.
- 답글 작성 성공 후 목록 refresh 결과가 늦게 도착해도 현재 상세 상태를 stale 데이터로 덮지 않는다.
### F4. FanTalk 답글 수정/삭제 메뉴
본인 채널 상세에서 답글 관리 메뉴를 제공한다.
#### Requirements
- Figma `669:40468`처럼 답글 card 우측 더보기 버튼을 표시한다.
- 메뉴 문구는 `수정하기`, `삭제하기`를 사용한다.
- popup UI는 커뮤니티 답글 화면의 `CreatorChannelCommunityMorePopup` 패턴을 우선 검토한다.
- 삭제 확인은 v2 공통 모달 `V2ModalDialog`를 사용한다.
- 기존 FanTalk 수정/삭제 API wrapper가 없으면 `ExplorerRepository.modifyCheers(PutModifyCheersRequest(...))`를 감싸는 v2 wrapper를 추가한다.
- 수정 UX는 커뮤니티 답글 화면과 동일하게 하단 input field 수정 모드를 우선한다.
- 하단 input field에서 기존 답글을 대체하는 흐름도 같은 답글 수정 API를 사용한다.
#### Edge Cases
- 기존 답글이 없으면 답글 card 더보기 button을 표시하지 않는다.
---
## 8. UX / UI Expectations
- FanTalk 상세는 커뮤니티 답글 화면과 시각적으로 동일해야 한다.
- 본인 채널에서만 item 터치 affordance가 느껴져야 한다.
- 하단 input bar는 화면 하단에 안정적으로 고정되어야 한다.
- send button 상태는 입력값 변화에 즉시 반응해야 한다.
- 답글 작성 성공 후 사용자는 목록으로 돌아가지 않아도 작성된 답글 상태를 확인할 수 있어야 한다.
- Figma `669:40462`/`669:40468`의 검은 배경, gray divider, gray_900 input/card, soda_400 활성 button 색상을 유지한다.
---
## 9. Technical Constraints
- Android XML View/ViewBinding 기반으로 구현한다.
- 신규 Activity/ViewModel 및 하위 코드는 `kr.co.vividnext.sodalive.v2.creator.channel.fantalk` 하위에 작성한다.
- 레거시 FanTalk 코드는 직접 수정하지 않고 기존 repository/API 흐름만 호출한다.
- 신규 API endpoint를 추가하지 않는다.
- API 호출은 기존 RxJava3, Koin, `ApiResponse<T>` 패턴을 따른다.
- 상대 시간 표시는 기존 `UtcRelativeTimeTextFormatter`를 재사용한다.
- 삭제 확인 dialog는 v2 패키지 내부이므로 `V2ModalDialog`를 사용한다.
- 기존 답글 대체 안내도 v2 패키지 내부이므로 `V2ModalDialog`를 사용한다.
- 신규 문자열은 `values`, `values-en`, `values-ja`에 추가하거나 기존 문자열을 재사용한다.
- 커뮤니티 답글 화면 리소스를 직접 재사용할 경우 resource id/name과 ViewBinding 충돌을 피한다.
---
## 10. Metrics
- 별도 분석 이벤트 추가는 이번 범위에서 정의하지 않는다.
- 기능 성공 기준은 본인 채널에서 FanTalk item 터치로 상세에 진입하고, 답글이 없으면 기존 답글 쓰기 API로 답글 작성이 성공하며, 답글이 있으면 안내 모달 확인 후 수정 API로 기존 답글이 대체되는 것이다.
- 접근 제한 성공 기준은 본인 채널이 아닌 경우 FanTalk 상세에 진입할 수 없는 것이다.
- UI 완료 기준은 Figma `669:40462`, `669:40468``CreatorChannelCommunityReplyActivity`의 주요 layout 구조, input bar, send button 상태가 반영되는 것이다.
- 자동 검증 기준은 owner gate, data model 통째 전달, send button enabled/disabled 상태, 기존 `writeCheers(parentCheersId = fanTalkId)` 호출 계약, 기존 답글 대체 모달 및 `modifyCheers` 호출 계약, 작성/수정 성공 후 refresh event를 ViewModel/source 테스트로 확인하는 것이다.
---
## 11. Open Questions & Decisions
- 결정: 별도 FanTalk 상세 조회 API가 프롬프트에 없으므로 신규 조회 endpoint를 가정하지 않는다. 최초 상세 데이터는 목록 item의 UI model을 intent payload로 전달한다.
- 결정: FanTalk item 터치로 상세 이동 시 data model을 통째로 전달한다. 개별 primitive extra 분해 전달은 사용하지 않는다.
- 결정: 답글 작성은 기존 `writeCheers` API를 `parentCheersId = fanTalkId`로 호출하는 방식으로 정의한다.
- 결정: FanTalk 상세의 답글은 1개만 가능하므로 pagination/API가 필요 없다.
- 결정: 기존 답글이 있는 상태에서 신규 답글을 쓰려 하면 안내 모달을 표시하고, 확인 시 답글 수정 API로 기존 답글을 신규 답글 내용으로 대체한다.
- 결정: send button icon은 `ic_new_arrow_up_white`, `ic_new_arrow_up_gray`를 사용한다.
- 결정: FanTalk 상세 진입은 `currentHeader?.isOwner == true`일 때만 허용한다.
- 남은 확인: 없음.