Files
sodalive-ios/docs/20260818_팔로잉_해제_확인_팝업/prd.md

227 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 팔로잉 해제 확인 팝업 PRD
## 문서 정보
| 항목 | 내용 |
|---|---|
| 문서 상태 | 완료 |
| 작성일 | `2026-08-18` |
| 최종 수정일 | `2026-08-18` |
| 대상 제품 | SodaLive iOS 팔로잉 리스트, V2 크리에이터 채널 |
| 작성자·결정권자 | 작성자: Sisyphus / 결정권자: 제품 담당자 |
| 관련 API Contract | 해당 없음: 기존 팔로우 API 사용 |
| 관련 구현 계획 | `docs/20260818_팔로잉_해제_확인_팝업/plan-task.md` |
| 관련 review | 없음 |
### 요구사항 상태
| 상태 | 의미 | 구현 처리 |
|---|---|---|
| 확정 | 제품·기술 결정이 완료되어 구현 기준으로 사용 | `plan-task.md`의 Task와 완료 증거로 추적 |
| 미결 | 제품·UX 결정이 더 필요함 | 권고안과 결정 주체를 기록하고 임의 구현 금지 |
| 제외 | 현재 릴리스에서 구현하지 않기로 결정 | 제외 이유와 후속 조건을 Decision Log에 기록 |
## 1. Overview
팔로잉 리스트 페이지와 V2 크리에이터 채널에서 팔로잉 해제 동작을 더 안전하게 만든다. 사용자가 팔로잉 중인 크리에이터를 해제하려 할 때 `SodaV2ActionModal`로 한 번 더 확인하고, 확인한 경우에만 기존 팔로우 해제 API 흐름을 실행한다.
## 2. Problem Statement
현재 사용자는 다음 문제를 겪는다.
- 팔로잉 리스트에서 팔로잉 중 버튼을 터치하면 알림 설정 Bottom Sheet가 먼저 열려 팔로우 해제까지 추가 선택이 필요하다.
- 크리에이터 채널에서는 팔로잉 중 버튼을 터치하면 별도 확인 없이 즉시 팔로우 해제가 진행된다.
- 두 진입점의 팔로우 해제 경험이 서로 달라 destructive action의 실수 방지가 일관되지 않다.
문제를 해결했다는 판단은 두 화면 모두 팔로우 해제 전 동일한 `SodaV2ActionModal` 확인 단계를 거치고, 사용자가 취소하면 API 호출과 상태 변경이 발생하지 않는 것으로 한다.
## 3. Goals
### 3.1 제품 목표
- 팔로잉 리스트 페이지에서 팔로잉 중 버튼을 누르면 Bottom Sheet 없이 팔로우 해제 확인 Dialog를 표시한다.
- 크리에이터 채널에서 팔로잉 중 버튼을 누르면 즉시 해제하지 않고 팔로우 해제 확인 Dialog를 표시한다.
- 확인 버튼을 누른 경우에만 기존 팔로우 해제 프로세스를 실행한다.
### 3.2 UX 목표
- 팔로잉 리스트의 팔로잉 중 버튼은 `ic_new_following_white`, `Color.gray800` 배경, 원형 스타일로 표시한다.
- 팔로우 해제 확인 Dialog는 `SodaV2ActionModal`을 사용한다.
- Dialog의 취소/확인 문구와 본문은 현재 앱 언어에 맞게 한국어, 일본어, 영어로 표시한다.
## 4. Non-Goals
- 팔로우 API, 알림 설정 API, DTO, 서버 계약은 변경하지 않는다.
- 팔로우 시작 동작과 팔로우 알림 설정 변경 UX는 이 작업에서 변경하지 않는다.
- 팔로잉 리스트 외의 `FollowCreatorItemView` 재사용 화면은 제품 범위가 확인되지 않았으므로 임의로 동작을 바꾸지 않는다. 재사용 영향은 구현 전 확인하고 필요한 경우 별도 결정으로 기록한다.
- Bottom Sheet 컴포넌트 `CreatorFollowNotifyDialog` 자체는 삭제하지 않는다.
## 5. Target Users and Permissions
| 사용자 | 목표 | 주요 작업 | 사용 환경 |
|---|---|---|---|
| 로그인 사용자 | 팔로잉 중인 크리에이터를 실수 없이 해제 | 팔로잉 리스트 또는 크리에이터 채널에서 팔로우 해제 | iOS 앱 |
권한과 인증은 기존 팔로우 API 정책을 따른다. 인증 토큰 처리와 권한 오류 처리는 기존 `UserRepository` 및 각 ViewModel의 오류 표시 정책을 변경하지 않는다.
## 6. 핵심 사용자 흐름
1. 사용자가 팔로잉 리스트 페이지에 진입한다.
2. 팔로잉 중인 크리에이터 row의 원형 팔로잉 버튼을 누른다.
3. 앱은 Bottom Sheet를 표시하지 않고 팔로우 해제 확인 Dialog를 표시한다.
4. 사용자가 `취소`를 누르면 Dialog만 닫히고 팔로우 상태는 유지된다.
5. 사용자가 `해제하기`를 누르면 Dialog를 닫고 기존 팔로우 해제 프로세스를 실행한다.
6. 사용자가 V2 크리에이터 채널의 팔로잉 중 버튼을 누른 경우도 3~5와 동일하게 동작한다.
## 7. 정보 구조와 라우팅
라우팅 변경은 없다.
- 팔로잉 리스트: 기존 `FollowCreatorView` 진입 경로 유지.
- 크리에이터 채널: 기존 `CreatorChannelView(creatorId:)` 진입 경로 유지.
- Dialog는 별도 route를 만들지 않고 현재 화면 overlay로 표시한다.
## 8. 기능 요구사항
### 8.1 팔로잉 리스트 버튼과 액션
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|---|---|---|---|---|
| `UNFOLLOW-LIST-001` | 확정 | 팔로잉 리스트에서 팔로잉 중 상태의 액션 버튼은 `ic_new_following_white` 이미지를 사용한다. | 팔로잉 중 row에 기존 `btn_following_big` 또는 `btn_following_no_alarm_big` 대신 흰색 아이콘 원형 버튼이 보인다. | `P1-T1` |
| `UNFOLLOW-LIST-002` | 확정 | 팔로잉 중 버튼 배경은 `Color.gray800`을 사용한다. | 버튼 배경 색상은 `SodaLive/Sources/UI/Theme/Color.swift``gray800` 토큰을 참조한다. | `P1-T1` |
| `UNFOLLOW-LIST-003` | 확정 | 팔로잉 중 버튼 형태는 크리에이터 채널 팔로잉 중 버튼과 동일한 원형 스타일을 따른다. | 팔로잉 리스트 버튼의 touch target과 시각적 형태가 `CreatorChannelTitleBar`의 팔로잉 중 버튼과 일치한다. | `P1-T1` |
| `UNFOLLOW-LIST-004` | 확정 | 팔로잉 리스트에서 팔로잉 중 버튼을 누르면 Bottom Sheet 액션 메뉴를 표시하지 않는다. | `CreatorFollowNotifyDialog`가 팔로잉 리스트의 팔로우 해제 진입점에서 열리지 않는다. | `P1-T2` |
| `UNFOLLOW-LIST-005` | 확정 | 팔로잉 리스트에서 팔로잉 중 버튼을 누르면 팔로우 해제 확인 Dialog를 표시한다. | Dialog 확인 전에는 `creatorFollow(follow: false, notify: false)` 또는 동등한 해제 요청이 호출되지 않는다. | `P1-T2` |
### 8.2 크리에이터 채널 팔로우 해제 확인
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|---|---|---|---|---|
| `UNFOLLOW-CHANNEL-001` | 확정 | 크리에이터 채널에서 팔로잉 중 버튼을 누르면 팔로우 해제 확인 Dialog를 표시한다. | `CreatorChannelTitleBar``onTapUnfollow`가 즉시 해제를 실행하지 않고 Dialog 표시 상태를 켠다. | `P2-T1` |
| `UNFOLLOW-CHANNEL-002` | 확정 | Dialog 확인 버튼을 누른 경우에만 기존 크리에이터 채널 팔로우 해제 프로세스를 실행한다. | 확인 시 `CreatorChannelViewModel.creatorFollow(follow: false, notify: false)` 흐름이 실행되고 성공 시 `isFollow=false`, `isNotify=false`로 갱신된다. | `P2-T1` |
| `UNFOLLOW-CHANNEL-003` | 확정 | Dialog 취소 버튼을 누르면 API 호출 없이 Dialog만 닫는다. | 취소 후 기존 팔로우 상태와 알림 상태가 유지된다. | `P2-T1` |
### 8.3 Dialog 문구와 다국어
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|---|---|---|---|---|
| `UNFOLLOW-DIALOG-001` | 확정 | Dialog title은 한국어 `팔로우 해제`, 일본어 `フォロー解除`, 영어 `Unfollow`를 사용한다. | 앱 언어별 title이 정확히 표시된다. | `P1-T2`, `P2-T1` |
| `UNFOLLOW-DIALOG-002` | 확정 | Dialog 본문은 크리에이터 이름을 포함하고 줄바꿈을 유지한다. | 한국어, 일본어, 영어 모두 `\n` 줄바꿈과 크리에이터 이름 치환이 적용된다. | `P1-T2`, `P2-T1` |
| `UNFOLLOW-DIALOG-003` | 확정 | 취소 버튼은 한국어 `취소`, 일본어 `キャンセル`, 영어 `Cancel`을 사용한다. | 취소 버튼이 언어별 문구로 표시되고 API 호출 없이 닫힌다. | `P1-T2`, `P2-T1` |
| `UNFOLLOW-DIALOG-004` | 확정 | 확인 버튼은 한국어 `해제하기`, 일본어 `解除する`, 영어 `Unfollow`를 사용한다. | 확인 버튼이 언어별 문구로 표시되고 팔로우 해제 요청을 실행한다. | `P1-T2`, `P2-T1` |
Dialog 본문 문구:
| 언어 | 문구 |
|---|---|
| ko | `팔로우를 해제할까요?\n{{creatorName}}의 소식을 받을 수 없어요.` |
| ja | `{{creatorName}}からの最新情報を受け取れなくなります。\nフォローを解除しますか` |
| en | `You won't receive updates from {{creatorName}}.\nUnfollow this creator?` |
## 9. 반응형 기능 범위
| 기능 | iPhone | iPad | 비고 |
|---|---:|---:|---|
| 팔로잉 리스트 버튼 표시 | 전체 | 전체 | 기존 SwiftUI layout 유지 |
| 팔로우 해제 확인 Dialog | 전체 | 전체 | overlay 기반 표시 |
| Dynamic Type / 긴 닉네임 | 확인 필요 | 확인 필요 | Dialog 본문 줄바꿈과 clipping 수동 확인 |
## 10. UI/UX Expectations
### 10.1 디자인과 component 원칙
- 팔로잉 리스트의 팔로잉 중 버튼은 크리에이터 채널 팔로잉 중 버튼의 원형 시각 규칙을 따른다.
- 버튼 색상은 `Color.gray800`, 이미지는 `ic_new_following_white`를 사용한다.
- Dialog는 새 임의 component를 만들지 않고 기존 `SodaV2ActionModal`을 사용한다.
### 10.2 화면 상태
- Dialog 표시 중 배경 화면의 팔로우 상태는 바뀌지 않는다.
- 확인 후 API loading과 오류 toast/popup은 기존 ViewModel 정책을 따른다.
- API 실패 시 Dialog는 이미 닫힌 상태로 두고 기존 오류 표시를 사용한다.
### 10.3 접근성
- 팔로잉 중 버튼의 accessibility label은 팔로잉 상태와 팔로우 해제 의도를 알 수 있어야 한다.
- Dialog title, message, 취소, 확인 버튼이 VoiceOver에서 읽혀야 한다.
- 취소와 확인 버튼의 touch target은 기존 Dialog 기준을 유지한다.
## 11. API 계약
신규 API 계약은 없다. 기존 팔로우 상태 변경 API를 그대로 사용한다.
| 요구사항 | Method | Path | 계약 상태 | API Contract | 소유 Goal |
|---|---|---|---|---|---|
| `UNFOLLOW-LIST-005` | 기존 계약 | 기존 `UserRepository.creatorFollow` 경유 | 제공됨 | 해당 없음 | `P1-T2` |
| `UNFOLLOW-CHANNEL-002` | 기존 계약 | 기존 `UserRepository.creatorFollow` 경유 | 제공됨 | 해당 없음 | `P2-T1` |
## 12. 보안과 데이터 취급
- 인증 header와 token 저장 로직은 변경하지 않는다.
- Dialog 문구와 로그에 token, 인증 정보, 민감정보를 기록하지 않는다.
- 크리에이터 이름은 화면에 이미 표시되는 공개 프로필 이름만 사용한다.
## 13. 성능과 품질 요구사항
- Dialog 표시를 위해 새 네트워크 요청을 추가하지 않는다.
- 팔로잉 리스트 row 렌더링에서 이미지 에셋과 색상 토큰 외 추가 비동기 작업을 만들지 않는다.
- 저장소에 테스트 번들 타깃이 확인되지 않으므로 구현 검증은 focused preview/수동 확인과 `xcodebuild` 빌드 중심으로 수행한다.
## 14. 성공 기준
### 14.1 기능 수용 기준
- [x] 팔로잉 리스트에서 팔로잉 중 버튼이 `ic_new_following_white` + `Color.gray800` 원형 버튼으로 표시된다. (`UNFOLLOW-LIST-001~003`)
- [x] 팔로잉 리스트에서 팔로잉 중 버튼을 눌러도 Bottom Sheet가 뜨지 않고 확인 Dialog가 표시된다. (`UNFOLLOW-LIST-004~005`)
- [x] 크리에이터 채널에서 팔로잉 중 버튼을 누르면 확인 Dialog가 표시되고, 확인 전에는 해제 API가 호출되지 않는다. (`UNFOLLOW-CHANNEL-001`)
- [x] 두 화면 모두 취소 시 상태 변경 없이 Dialog만 닫힌다. (`UNFOLLOW-CHANNEL-003`)
- [x] 두 화면 모두 확인 시 기존 팔로우 해제 프로세스가 성공적으로 실행된다. (`UNFOLLOW-CHANNEL-002`, `UNFOLLOW-LIST-005`)
### 14.2 UI/UX 수용 기준
- [x] Dialog 문구가 한국어, 일본어, 영어에서 지정된 title/body/button으로 표시된다.
- [x] 크리에이터 이름이 Dialog 본문에 정확히 치환된다.
- [x] 긴 크리에이터 이름에서도 Dialog 본문이 잘리거나 버튼을 밀어내지 않는다.
### 14.3 추적성 완료 기준
- [x] 모든 확정 요구사항이 `plan-task.md`의 Goal로 연결된다.
- [x] 모든 미결 항목에 현재 권고와 결정 주체가 있다.
- [x] 코드 구현 전에 PRD 변경이 필요한 경우 Decision Log를 먼저 갱신한다.
## 15. Open Questions
| ID | 상태 | 결정 필요 사항 | 현재 권고 | 결정 주체 | 결정 기한/시점 | 영향 Goal |
|---|---|---|---|---|---|---|
| `OQ-001` | 해결 | 한국어 본문 `{{creatorName}}의. 소식을 받을 수 없어요.`의 마침표 위치 | 마침표를 제거해 `{{creatorName}}의 소식을 받을 수 없어요.`를 사용 | 사용자 | `2026-08-18` | `P1-T2`, `P2-T1` |
| `OQ-002` | 해결 | “V2 Dialog”의 정확한 공통 component | `SodaV2ActionModal`을 사용 | 사용자 | `2026-08-18` | `P1-T2`, `P2-T1` |
## 16. 요구사항 추적표
| 요구사항 범위 | API Contract | 계획 Phase | Goal | 자동 검증 | 수동 검증 |
|---|---|---:|---|---|---|
| `UNFOLLOW-LIST-001~003` | 해당 없음 | 1 | `P1-T1` | 빌드 | 팔로잉 리스트 버튼 시각 확인 |
| `UNFOLLOW-LIST-004~005` | 기존 팔로우 API | 1 | `P1-T2` | 빌드 | Bottom Sheet 미표시, Dialog 취소/확인 확인 |
| `UNFOLLOW-CHANNEL-001~003` | 기존 팔로우 API | 2 | `P2-T1` | 빌드 | 크리에이터 채널 Dialog 취소/확인 확인 |
| `UNFOLLOW-DIALOG-001~004` | 해당 없음 | 1, 2 | `P1-T2`, `P2-T1` | 빌드 | ko/en/ja 문구 확인 |
## 17. Decision Log
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항·계약·Goal |
|---|---|---|---|---|---|
| `2026-08-18` | `DEC-001` | 확정 | 코드 구현 없이 PRD와 구현 계획 문서만 작성한다. | 사용자 직접 지시 | 전체 |
| `2026-08-18` | `DEC-002` | 확정 | 팔로잉 리스트의 팔로잉 중 액션은 Bottom Sheet를 건너뛰고 팔로우 해제 확인 Dialog로 진입한다. | 사용자 요구사항 | `UNFOLLOW-LIST-004~005`, `P1-T2` |
| `2026-08-18` | `DEC-003` | 확정 | 영어 문구는 `Unfollow`, `You won't receive updates from {{creatorName}}.\nUnfollow this creator?`, `Cancel`, `Unfollow`로 사용한다. | 사용자 위임 | `UNFOLLOW-DIALOG-001~004` |
| `2026-08-18` | `DEC-004` | 확정 | 한국어 Dialog 본문은 `팔로우를 해제할까요?\n{{creatorName}}의 소식을 받을 수 없어요.`로 사용한다. | 사용자 결정: `OQ-001` | `UNFOLLOW-DIALOG-002`, `P1-T2`, `P2-T1` |
| `2026-08-18` | `DEC-005` | 확정 | 팔로우 해제 확인 Dialog는 `SodaV2ActionModal`을 사용한다. | 사용자 결정: `OQ-002` | `UNFOLLOW-DIALOG-001~004`, `P1-T2`, `P2-T1` |
| `2026-08-18` | `DEC-006` | 확정 | Visual QA는 에이전트가 진행하지 않고 사용자가 직접 진행한다. | 사용자 직접 지시 | `UNFOLLOW-LIST-001~005`, `UNFOLLOW-CHANNEL-001~003`, `UNFOLLOW-DIALOG-001~004` |
## 18. 변경 관리
요구사항 변경 시 다음을 확인한다.
- [x] Decision Log에 변경 이유와 날짜를 기록했다.
- [x] 관련 요구사항 상태·본문·수용 기준을 갱신했다.
- [x] `plan-task.md`의 범위·Files·체크박스·완료 증거를 코드 변경 전에 갱신했다.
- [x] 기존 Progress·검증 기록을 삭제하거나 덮어쓰지 않았다.