Files
sodalive-ios/docs/20260818_메인_탭_당겨서_새로고침/prd.md

15 KiB

PRD: 메인 탭 당겨서 새로고침

문서 정보

항목 내용
문서 상태 구현 완료
작성일 2026-08-18
최종 수정일 2026-08-18
대상 제품 메인 홈, 콘텐츠, 대화 탭 당겨서 새로고침
작성자·결정권자 사용자, Sisyphus
관련 API Contract 기존 각 탭 API 계약 재사용, 신규 endpoint 없음
관련 구현 계획 docs/20260818_메인_탭_당겨서_새로고침/plan-task.md
관련 review 없음

요구사항 상태

상태 의미 구현 처리
확정 제품·기술 결정이 완료되어 구현 기준으로 사용 plan-task.md의 Task와 완료 증거로 추적
미결 제품·UX·운영 결정이 더 필요함 권고안과 결정 주체를 기록하고 임의 구현 금지
제외 현재 릴리스에서 구현하지 않기로 결정 제외 이유와 후속 조건을 Decision Log에 기록

1. Overview

메인 하단 , 콘텐츠, 대화 탭에 iOS 기본 당겨서 새로고침 동작을 추가한다. 사용자가 현재 보고 있는 내부 탭과 필터 상태를 유지한 채 해당 화면의 첫 페이지 또는 단일 조회 API를 다시 호출해 최신 데이터를 표시한다.

구현 결과와 사용자 수동 검증 대기 상태는 관련 구현 계획에서 추적한다.

2. Problem Statement

현재 V2 메인 화면의 주요 조회 탭은 최초 진입 또는 내부 필터 변경 시에만 데이터를 불러온다. 사용자가 이미 보고 있는 화면에서 최신 상태를 직접 확인하려면 탭을 이동하거나 앱 흐름을 다시 진입해야 한다.

문제를 해결했다는 판단은 , 콘텐츠, 대화 탭에서 현재 선택 상태 그대로 당겨서 새로고침을 실행하고, 성공·빈 목록·오류 상태에서도 재시도 가능한 것으로 한다.

3. Goals

3.1 제품 목표

  • , 콘텐츠, 대화 하단 탭에서 사용자가 수동으로 최신 데이터를 다시 조회할 수 있다.
  • 새로고침은 현재 선택된 내부 탭·필터·정렬 상태만 대상으로 한다.
  • 새로고침 실패 시 기존 오류 노출 패턴을 유지하고, 사용자는 같은 화면에서 다시 당겨서 재시도할 수 있다.

3.2 UX 목표

  • iOS 기본 pull-to-refresh 제스처와 표시 방식을 사용한다.
  • loading, empty, error, content 상태 어디서든 당겨서 새로고침을 시도할 수 있다.
  • 새로고침은 현재 선택된 탭을 바꾸지 않고 스크롤 가능한 화면 문맥 안에서 동작한다.

4. Non-Goals

  • 마이 탭에는 당겨서 새로고침을 추가하지 않는다.
  • 하단 탭 전체 데이터를 한 번에 새로고침하지 않는다.
  • background 자동 갱신, 주기적 polling, push 기반 갱신은 추가하지 않는다.
  • 신규 API endpoint, DTO, Repository를 만들지 않는다.
  • 새 공통 추상화나 refresh protocol을 만들지 않는다. 기존 ViewModel fetch 경로를 화면별로 연결한다.

5. Target Users and Permissions

5.1 사용자

사용자 목표 주요 작업 사용 환경
로그인 사용자 메인 화면의 최신 홈·콘텐츠·대화 데이터를 직접 갱신 당겨서 새로고침 iOS 앱
비로그인 또는 로그인 필요 상태 사용자 실패/제한 상태에서 재시도 당겨서 새로고침 iOS 앱

5.2 권한

  • 인증 주체: 기존 앱 인증 상태와 각 API의 현재 인증 정책을 그대로 사용한다.
  • 허용 역할: 기존 각 탭 접근 정책을 따른다.
  • 거부 조건: 기존 API 실패·로그인 필요 상태를 그대로 표시한다.
  • 리소스 소유권: 기존 API와 화면 모델의 소유권 검증을 변경하지 않는다.

6. 핵심 사용자 흐름

  1. 사용자가 메인 하단 , 콘텐츠, 대화 중 하나에 진입한다.
  2. 사용자는 내부 탭 또는 필터를 선택해 특정 상태를 보고 있다.
  3. 사용자가 화면을 아래로 당긴다.
  4. 앱은 현재 선택 상태를 유지하고 해당 상태의 첫 페이지 또는 단일 조회 API를 다시 호출한다.
  5. 성공하면 최신 데이터로 교체하고, 실패하면 기존 오류 메시지/토스트 정책을 유지한다.
  6. 빈 목록이나 오류 상태에서도 사용자는 다시 당겨서 새로고침할 수 있다.

7. 정보 구조와 라우팅

MainView
  MainTab.home
    MainHomeTab.recommendation
    MainHomeTab.ranking
    MainHomeTab.following
  MainTab.content
    MainContentTab.recommendation
    MainContentTab.ranking
      AudioRankingType
    MainContentTab.all
      MainContentAllType
      ContentSort
      SeriesPublishedDaysOfWeek
  MainTab.chat
    MainChatFilter.all
    MainChatFilter.ai
    MainChatFilter.dm
  • 새로고침은 라우팅을 변경하지 않는다.
  • 현재 하단 탭과 내부 선택 상태는 유지한다.
  • 목록 아이템 상세 진입, 검색, 충전, 보관함 라우팅은 변경하지 않는다.

8. 기능 요구사항

8.1 공통 새로고침 동작

ID 상태 요구사항 수용 기준 계약/Goal 연결
REFRESH-001 확정 , 콘텐츠, 대화 하단 탭에 당겨서 새로고침을 제공한다. 각 탭에서 아래로 당기면 현재 화면의 조회 API가 다시 호출된다. P1-T1, P2-T1, P3-T1
REFRESH-002 확정 현재 선택된 내부 탭·필터·정렬·요일 상태만 새로고침한다. 선택 상태가 변경되지 않고 해당 조건의 데이터만 첫 페이지부터 다시 조회된다. P1-T1, P2-T1, P3-T1
REFRESH-003 확정 loading, empty, error, content 상태 모두에서 새로고침을 시도할 수 있다. 빈/오류 화면에서도 pull-to-refresh 제스처 또는 동등한 재시도 흐름이 가능하다. P1-GATE, P2-GATE, P3-GATE
REFRESH-004 확정 새로고침은 기존 loading guard와 요청 경합 방지 정책을 깨지 않는다. 중복 요청이 화면 상태를 역전시키지 않고, 기존 최신 요청 우선 패턴을 유지한다. P2-T1, P3-T1

8.2 홈 탭

ID 상태 요구사항 수용 기준 계약/Goal 연결
HOME-REFRESH-001 확정 추천 선택 시 MainHomeRecommendationViewModel.fetchRecommendations() 경로로 다시 조회한다. 기존 추천 섹션 데이터가 최신 응답으로 교체된다. P1-T1
HOME-REFRESH-002 확정 랭킹 선택 시 MainHomeRankingViewModel.fetchRankings() 경로로 다시 조회한다. 기존 랭킹 데이터와 rank change 표시가 최신 응답으로 교체된다. P1-T1
HOME-REFRESH-003 확정 팔로잉 선택 시 MainHomeFollowingViewModel.fetchFollowing() 경로로 다시 조회한다. 로그인 필요, 빈 상태, 콘텐츠 상태가 최신 응답 기준으로 갱신된다. P1-T1

8.3 콘텐츠 탭

ID 상태 요구사항 수용 기준 계약/Goal 연결
CONTENT-REFRESH-001 확정 콘텐츠 추천 선택 시 MainContentRecommendationViewModel.fetchRecommendations() 경로로 다시 조회한다. 추천 콘텐츠 섹션 데이터가 최신 응답으로 교체된다. P2-T1
CONTENT-REFRESH-002 확정 콘텐츠 랭킹 선택 시 현재 AudioRankingType을 유지하고 MainContentRankingViewModel.fetchRankings() 경로로 다시 조회한다. 선택된 랭킹 타입이 유지되고 목록이 최신 응답으로 교체된다. P2-T1
CONTENT-REFRESH-003 확정 콘텐츠 전체 선택 시 현재 MainContentAllType, ContentSort, SeriesPublishedDaysOfWeek를 유지하고 첫 페이지를 다시 조회한다. 기존 목록이 첫 페이지 결과로 교체되고 다음 페이지 상태가 초기화된다. P2-T1

8.4 대화 탭

ID 상태 요구사항 수용 기준 계약/Goal 연결
CHAT-REFRESH-001 확정 대화 탭에서 현재 MainChatFilter를 유지하고 첫 페이지를 다시 조회한다. ALL, AI, DM 중 선택된 필터가 유지되고 rooms가 첫 페이지 결과로 교체된다. P3-T1
CHAT-REFRESH-002 확정 새로고침 후 pagination 상태를 첫 페이지 기준으로 초기화한다. hasMore, nextCursor가 최신 첫 페이지 응답 기준으로 갱신된다. P3-T1

9. 반응형 기능 범위

기능 iPhone iPad 비고
당겨서 새로고침 전체 전체 SwiftUI 기본 동작 기준
빈/오류 상태 재시도 전체 전체 상태 화면도 스크롤 가능한 컨테이너 안에서 표시

10. UI/UX Expectations

10.1 디자인과 component 원칙

  • SwiftUI .refreshable 또는 동등한 iOS 기본 refresh affordance를 사용한다.
  • 별도 커스텀 spinner, 신규 refresh button, 신규 공통 컴포넌트는 만들지 않는다.
  • 기존 Color.black, ProgressView, sodaToast, empty state 스타일을 유지한다.

10.2 화면 상태

  • 첫 로딩 상태와 수동 새로고침 상태를 구분하되, 기존 화면 레이아웃을 크게 바꾸지 않는다.
  • 빈/오류 상태에서도 새로고침 가능해야 하므로 상태 화면을 refresh 가능한 스크롤 컨테이너로 감싸는 방식을 계획한다.
  • 새로고침 실패 시 현재 탭 선택 상태는 유지한다.

10.3 접근성

  • 기본 iOS refresh control 접근성 동작을 해치지 않는다.
  • 기존 버튼, 탭, 리스트 아이템의 focus/touch target을 변경하지 않는다.

11. API 계약

11.1 공통 규칙

  • 신규 endpoint 없음.
  • 기존 Repository와 API 계약을 그대로 사용한다.
  • 콘텐츠 전체와 대화 탭은 첫 페이지 재조회 시 기존 pagination cursor/page 상태를 초기화한다.

11.2 Endpoint 추적

요구사항 Method Path 계약 상태 API Contract 소유 Goal
HOME-REFRESH-001 GET 기존 홈 추천 API 제공됨 기존 MainHomeRecommendationRepository P1-T1
HOME-REFRESH-002 GET 기존 홈 랭킹 API 제공됨 기존 MainHomeRankingRepository P1-T1
HOME-REFRESH-003 GET 기존 홈 팔로잉 API 제공됨 기존 MainHomeFollowingRepository P1-T1
CONTENT-REFRESH-001 GET 기존 콘텐츠 추천 API 제공됨 기존 MainContentRecommendationRepository P2-T1
CONTENT-REFRESH-002 GET 기존 콘텐츠 랭킹 API 제공됨 기존 MainContentRankingRepository P2-T1
CONTENT-REFRESH-003 GET 기존 콘텐츠 전체 API 제공됨 기존 MainContentAllRepository P2-T1
CHAT-REFRESH-001 GET /api/v2/chat/rooms 제공됨 docs/20260708_홈_채팅_탭/prd.md P3-T1

12. 보안과 데이터 취급

  • 인증 header, token 저장, 언어 header 흐름은 변경하지 않는다.
  • 새로고침 실패 로그에 token, 개인 메시지 본문, signed URL 등 민감정보를 기록하지 않는다.
  • 기존 AuthPlugin, UserDefaultsKey.token 처리 로직은 수정 대상이 아니다.

13. 성능과 품질 요구사항

  • 이미 로딩 중인 동일 화면에서 중복 새로고침이 과도하게 발생하지 않도록 기존 loading guard를 유지하거나 같은 수준의 guard를 둔다.
  • 콘텐츠 전체와 대화 탭은 첫 페이지 새로고침 시 기존 다음 페이지 로딩 상태를 초기화한다.
  • 새 공통 abstraction을 만들지 않고 화면별 최소 변경으로 구현한다.
  • 현재 테스트 번들 타깃이 명확하지 않으므로 구현 검증은 focused 코드 리뷰, xcodebuild 빌드, 수동 QA를 필수로 한다.

14. 성공 기준

14.1 기능 수용 기준

  • 추천, 랭킹, 팔로잉에서 각각 현재 선택된 내부 탭만 새로고침된다. (HOME-REFRESH-001~003)
  • 콘텐츠 추천, 랭킹, 전체에서 각각 현재 선택된 내부 탭과 필터 상태만 새로고침된다. (CONTENT-REFRESH-001~003)
  • 대화 전체, AI, DM에서 현재 필터만 유지해 첫 페이지를 새로고침한다. (CHAT-REFRESH-001~002)
  • 빈/오류 상태에서도 사용자가 당겨서 재시도할 수 있다. (REFRESH-003)

14.2 UI/UX 수용 기준

  • iOS 기본 refresh affordance가 보인다.
  • 새로고침 후 선택된 하단 탭과 내부 탭/필터가 변경되지 않는다.
  • 새로고침 실패 시 기존 토스트/오류 상태 정책을 유지한다.

14.3 추적성 완료 기준

  • 모든 확정 요구사항이 plan-task.md의 Task/Goal 완료 증거로 연결된다.
  • 신규 API 또는 신규 dependency가 없다는 결정이 Decision Log에 남아 있다.
  • 코드 구현 전 이 문서와 계획 문서가 먼저 작성되어 있다.

15. Open Questions

ID 상태 결정 필요 사항 현재 권고 결정 주체 결정 기한/시점 영향 Goal
없음 확정 남은 제품 결정 없음 없음 사용자 2026-08-18 전체

16. 요구사항 추적표

요구사항 범위 API Contract 계획 Phase Goal 자동 검증 수동 검증
REFRESH-001~004 기존 API 재사용 1~3 P1-T1, P2-T1, P3-T1 빌드 홈/콘텐츠/대화 새로고침
HOME-REFRESH-001~003 홈 기존 Repository 1 P1-T1, P1-GATE 빌드 홈 내부 탭별 새로고침
CONTENT-REFRESH-001~003 콘텐츠 기존 Repository 2 P2-T1, P2-GATE 빌드 콘텐츠 내부 탭/필터별 새로고침
CHAT-REFRESH-001~002 /api/v2/chat/rooms 3 P3-T1, P3-GATE 빌드 대화 필터별 새로고침

17. Decision Log

날짜 ID 상태 결정 근거 영향 요구사항·계약·Goal
2026-08-18 DEC-001 확정 당겨서 새로고침은 현재 선택된 내부 탭·필터·정렬 상태만 대상으로 한다. 사용자 인터뷰 A안 선택 REFRESH-002, 전체 Goal
2026-08-18 DEC-002 확정 빈/오류 상태에서도 당겨서 새로고침을 허용한다. 사용자 인터뷰 A안 선택 REFRESH-003, 전체 Gate
2026-08-18 DEC-003 확정 신규 API, 신규 dependency, 신규 공통 refresh abstraction은 만들지 않는다. 기존 화면별 fetch 경로 존재, 최소 변경 원칙 REFRESH-004, 전체 Goal

18. 변경 관리

요구사항 변경 시 다음을 확인한다.

  • Decision Log에 변경 이유와 날짜를 기록했다.
  • 관련 요구사항 상태·본문·수용 기준을 갱신했다.
  • plan-task.md의 범위·Files·체크박스·완료 증거를 코드 변경 전에 갱신했다.
  • 기존 Progress·review·검증 기록을 삭제하거나 덮어쓰지 않았다.