Skip to content

Screen: Paywall (PRO / MAX)

구독 2티어(PRO/MAX) 선택·결제App 전용 하단 시트(showAppBottomSheet, 아래에서 위로). 풀페이지가 아니라 진입 맥락(공시 상세·관심종목 등) 위에 시트로 떠서, 구독 후 닫으면 하던 작업으로 복귀. 구매는 로그인 필수(엔타이틀먼트가 userID 에 귀속 — 비로그인 구매 플로우 없음). 도메인 룰: domain-subscription, API: api/subscription.

💡 시각 미리보기: design site / paywall-app

플랫폼별 차이

항목App (Flutter)Web (Next.js)
화면 존재❌ (웹 구매 플로우 없음 — 스토어 결제 기반)
제시하단 시트 showAppBottomSheet (dim 배경 + grabber, 스와이프/배경 탭 dismiss)

진입점

세 곳 모두 같은 시트를 띄운다(단일 전환 surface). source 로 어느 맥락이 전환을 만드는지 측정.

진입점트리거source 파라미터
더보기 "PRO 구독" 메뉴메뉴 탭settings
주간 분석 한도 소진분석 시도/인디케이터의 "구독하고 더 보기" 버튼 (domain-quota / quota-indicator)quota_soldout
관심종목 상한 초과 추가 시도capacity 초과 add 시 토스트/모달 대신 이 시트 노출 (domain-watchlist 409)watchlist_full
  • 진입 맥락에 맞춰 기본 선택 티어를 제안할 수 있음(예: 관심종목 초과 시 MAX 강조). v1 은 기본 PRO 선택.

  • 비로그인 진입 시 CTA 탭 → requireAuth(AuthGateAction.subscribe) 게이트 → 로그인 후 결제 진행.

시트 구성 (위→아래)

영역내용조건
grabber상단 핸들(드래그/스와이프 dismiss)항상
Hero"구독" 타이틀 + 한 줄 가치 "새 공시는 알림으로, 분석은 더 넉넉하게" (아이콘 없음)항상
플랜 선택PRO / MAX 2개 카드 (세그먼트/카드 토글). 선택 카드에 가격·한도 강조S1
혜택 비교선택 플랜의 한도 2행 (분석/종목, 아래)항상
Primary CTAAppButton.primary 풀너비S1="{플랜} 구독" / S2(PRO)="MAX 로 업그레이드"(+보조 "구독 관리") / S2(MAX)="구독 관리"
푸터자동갱신 고지 문구 + 이용약관 · 개인정보처리방침 링크 (심사 필수)항상

구매 복원은 페이월이 아니라 더보기 > 구독 그룹에 배치 — 사용 빈도 낮고 verify-on-launch 가 평소 자동 동기화하므로 페이월 전환 동선에서 제외. Apple 필수 메커니즘은 설정에서 충족.

플랜 카드 (S1)

플랜가격/월주간 분석공시 알림
PRO₩1,0006030종목
MAX₩2,000200100종목
  • 선택된 카드만 강조(브랜드 보더/배경), CTA 라벨이 선택 플랜 반영("PRO 구독" / "MAX 구독").
  • 혜택 행 아이콘: sparkle(분석), bell(공시 알림). 관심종목 혜택은 "몇 개 담는다"가 아니라 "고른 종목의 새 공시를 알림으로 받는다" 로 강조 — 라벨 "공시 알림 N종목".

상태 분기

  • S1. 비구독 (tier=none) — PRO/MAX 카드 선택 + 선택 플랜으로 "구독" CTA. 탭 → 스토어 결제 → POST /api/v1/subscription/verify.
  • S2. 구독 중 (tier=pro|max) — Hero 하단 "{PRO|MAX} 이용 중 · {premium_until} 까지".
    • PRO: Primary CTA "MAX 로 업그레이드"(탭 → MAX 구매로 업그레이드 플로우, 스토어 proration) + 보조 텍스트 "구독 관리"(스토어 deep link). MAX 혜택 안내 동반.
    • MAX: Primary CTA "구독 관리"만(이미 최상위).
  • S3. 처리 중 — 구매/복원 진행 동안 CTA 로딩(disabled). 완료 후 verify 응답(tier)으로 갱신.

액션 (API)

액션동작
구독 시작in_app_purchase 결제 → 거래 토큰 → POST /api/v1/subscription/verify → 활성이면 닫고 진입 화면 갱신
구독 관리스토어 구독 관리 화면 deep link (앱 내 해지 불가 — 스토어 정책)

구매 복원 액션은 더보기 > 구독 그룹에서 수행(스토어 복원 → verify 재호출).

상세 요청/응답: api/subscription (POST /api/v1/subscription/verify).

Analytics

domain-analytics 구독/페이월 이벤트:

  • paywall_view (source) — 페이월 진입
  • subscribe_attempt (plan: pro|max) — CTA 탭
  • subscribe_result (plan, outcome: success|cancelled|error) — 결제+verify 종결

restore_attempt / restore_result더보기의 구매 복원에서 송출.

Edge cases

  • 결제 취소: subscribe_result outcome=cancelled, 화면 유지(S1).
  • verify 실패(위조/미존재): 토스트 "구매를 확인하지 못했습니다. 잠시 후 다시 시도해주세요." (ToastType.error), 권한 부여 안 함.
  • 이미 구독 중 페이월 진입: S2 로 노출(중복 결제 방지). PRO 면 MAX 업그레이드 제시, MAX 면 관리만.

심사 요구

  • 페이월에 가격 · 기간 · "자동갱신" 명시 + 이용약관/개인정보 링크.
  • "구매 복원" 메커니즘 필수 — 더보기 > 구독 그룹에 배치(페이월 아님, Apple 은 위치 무관 존재만 요구).

관련 docs