Files
sodalive-ios/docs/20261012_본인인증_후_콘텐츠_보기_설정/prd.md
T

31 KiB

PRD: 본인인증 후 콘텐츠 보기 설정

문서 정보

항목 내용
문서 상태 Phase 7·R1 구현·로컬 기능/시각 검증 완료 / 실제 인증 통합 QA는 기존 대기 유지
작성일 2026-10-12
최종 수정일 2026-10-14
대상 제품 SodaLive iOS 본인인증 완료 흐름
작성자·결정권자 사용자 승인 완료 (2026-10-12)
API Contract 본 문서 §11
구현 계획 docs/20261012_본인인증_후_콘텐츠_보기_설정/plan-task.md
구현 승인 2026-10-12 사용자 “승인”으로 구현 허가. 현재 main 브랜치, worktree 미사용.

요구사항 상태

상태 의미 구현 처리
사용자 확정 사용자에게 직접 확인된 제품 흐름 별도 문서 승인 후 계획 Task의 기준으로 사용
채택 관례 기존 코드 동작을 기본값으로 채택 명시된 한정 내 적용, 사용자 결정으로 표기하지 않음
구현 근거 저장소 소스에서 확인한 현재 동작 설계 근거이며 런타임 성공 증거는 아님
위험/검증 추가 제품 결정을 요구하지 않는 미검증 런타임 조건 구현 후 실제 앱 QA로 판정

1. Overview

Bootpay 본인인증 완료 직후 인증 요청을 보내는 현재 흐름을, 사용자가 콘텐츠 보기 설정을 확인한 뒤 제출하는 흐름으로 바꾼다. 모든 인증 진입점에서 동일한 확인 sheet와 인증·설정 제출·회원정보 동기화 순서를 사용하며, 사용자의 선호가 인증 성별 값에 의해 덮어써지지 않게 한다.

2. Problem Statement

  • 현재 MyPageViewModel.authVerify는 인증 완료 직후 POST /auth를 보내고, 응답 gender로 콘텐츠 선호를 저장한다.
  • callback 진입점에서는 성공 callback으로 이어지는 동작이 있지만, MyPage 단독 진입은 앱 재시작 경로를 사용한다.
  • 기존 ContentSettingsViewModel은 설정 변경 즉시 로컬 저장과 debounce PATCH를 수행하고 재시작 상태도 설정한다. 미확정 draft에 재사용할 수 없다.
  • AppViewModel 및 HomeViewModel의 회원정보 조회는 완료 결과를 반환하지 않고 알림·분석 부수효과도 수행한다. 요청 직후 pending action을 실행하면 동기화 순서가 보장되지 않는다.

3. Goals

3.1 제품 목표

  • 인증 완료 7개 진입점 모두에서 사용자가 설정을 확인하기 전까지 POST /auth를 보내지 않는다.
  • 사용자가 확인한 인증 영수증과 성인 콘텐츠 설정을 한 요청으로 제출한다.
  • callback 진입점은 인증 성공 후 회원정보를 받아 로컬 인증·콘텐츠 상태를 갱신한 뒤 기존 pending action을 한 번만 실행한다. 마이페이지는 기존 재시작 경로를 유지한다.

3.2 UX 목표

  • 인증 직후 ON 상태와 전체 콘텐츠를 기본 선택한 설정 sheet를 표시한다.
  • 바깥 탭, drag, 뒤로/닫기로 확인 단계를 우회해 dismiss하지 못하게 한다.
  • 실패한 단계별 복구를 구분하고 재요청 또는 action 실행을 잘못 반복하지 않는다.

4. Non-Goals

  • 독립 콘텐츠 설정 화면의 기존 자동 저장/debounce PATCH 동작 변경.
  • 일반 회원정보 조회 helper 전체의 추상화·리팩터링.
  • Bootpay 자체 동작, 인증 서버 response schema, 외부 인증 계약의 변경.
  • 승인 전 앱 코드, UI, 스크립트 또는 프로젝트 설정 변경.
  • 재시도 idempotency 또는 영수증 만료 정책 보장.

5. Target Users and Permissions

  • 사용자: Bootpay 본인인증을 완료한 로그인 사용자.
  • 인증 receipt와 앱 token은 외부 입력/민감정보로 취급한다. 원문을 로그나 문서에 남기지 않는다.

6. 핵심 사용자 흐름

  1. 사용자 또는 기존 기능이 Bootpay 본인인증을 시작한다.
  2. Bootpay onDone에서 receipt를 보존하고 Bootpay full-screen cover를 닫는다.
  3. cover dismiss가 완료된 뒤 사용자 확인을 위한 콘텐츠 설정 sheet를 연다. callback과 pending action도 이 전환 중 보존한다.
  4. sheet에서 ON/OFF와 ON일 때 선호를 선택한다. 이 단계에서는 네트워크 요청과 설정 영속화를 하지 않는다.
  5. 사용자가 설정 완료를 누르면 sheet를 먼저 닫고, 이어 POST /auth를 한 번 보낸다.
  6. 인증·설정 제출 성공 후 마이페이지는 확인한 콘텐츠 설정을 로컬에 반영하고 기존 앱 재시작 경로로 이동한다. callback 진입점만 UserRepository.getMemberInfo() 응답을 기다려 기존 member response를 decode하고 로컬 상태를 갱신한다.
  7. callback 진입점은 동기화 성공 뒤 보존된 성공 callback으로 pending action을 한 번 소비한다. 동기화 실패 시 callback을 실행하지 않고 마이페이지와 동일한 앱 재시작 경로로 이동한다.

7. 정보 구조와 라우팅

  • 앱 route를 추가하지 않는다. 인증 callback 상태를 보존하는 화면 위 modal sheet로 제공한다.
  • 시작 전에 다른 full-screen cover가 열려 있으면 이를 먼저 dismiss 완료한 뒤 sheet를 표시한다.
  • sheet는 바깥 탭, swipe/drag, back 또는 close 제스처로 닫히지 않는다. 명시적 확인만 다음 단계로 진행한다.

8. 기능 요구사항

8.1 진입점과 확인 순서

ID 상태 요구사항 수용 기준
AUTH-001 사용자 확정 모든 7개 Bootpay 인증 완료 진입점은 확인 전 auth POST를 미룬다. MyPageView.swift, Main/Home/HomeView.swift, Home/HomeTabView.swift, Chat/ChatTabView.swift, Live/Now/All/LiveNowAllView.swift, V2/Main/MainView.swift, V2/CreatorChannel/CreatorChannelView.swift에서 같은 순서를 확인한다. 확인 전 request·설정 저장 모두 0회다.
AUTH-002 사용자 확정 receipt, draft, action/callback을 cover-dismiss-sheet 표시 순서 동안 보존한다. onDone이 sheet 또는 callback을 잃지 않으며 cover dismiss 완료 전에 sheet가 겹쳐 뜨지 않는다. onClose 기존 닫기 동작을 유지한다.
AUTH-003 사용자 확정 sheet는 확인 외 경로로 dismiss되지 않는다. 배경 탭, drag, back 및 close 시트 dismiss 0회, 요청 0회다.
AUTH-004 사용자 확정 초기 draft는 isAdultContentVisible=true, contentType=ALL이다. 초기 렌더 상태와 확인 request가 이를 따른다.
AUTH-005 채택 관례 OFF 선택 시 contentType=ALL로 normalize한다. 비활성 선호 값은 제출되지 않는다. ALL normalize는 기존 코드의 채택 관례이며 별도 사용자 결정은 아니다.

8.2 제출, 동기화, 실패

ID 상태 요구사항 수용 기준
AUTH-006 사용자 확정 확인 시 sheet를 닫은 뒤 combined JSON payload로 POST /auth한다. §11 필드와 enum만 포함하고 중복 탭으로 동시 요청이 발생하지 않는다.
AUTH-007 사용자 확정 인증 및 설정 제출 실패 시 오류를 보이고 같은 draft로 sheet를 다시 연다. receipt와 pending action을 보존하고 사용자가 다시 누를 때만 재전송한다. 자동 제출은 없다.
AUTH-008 사용자 확정 인증 성공 후 회원정보 동기화 실패 시 인증을 재전송하지 않는다. sheet를 다시 열지 않고 pending action도 실행하지 않는다. My Page와 동일하게 isRestartApp=true, setAppStep(.splash)로 앱 재시작 경로에 보낸다. sync-only retry UI/정책은 추가하지 않는다.
AUTH-009 사용자 확정 여섯 callback route는 auth 성공 후 GET /member/info?container=ios와 로컬 상태 갱신을 완료하고 callback action을 한 번 소비한다. 동기화보다 callback이 앞서지 않는다. 일반 fire-and-forget member helper를 부른 직후 진행하지 않는다.
AUTH-010 사용자 확정 기존 My Page 재시작 route를 유지하고 auth 응답 gender가 사용자의 content choice를 다시 덮어쓰지 않는다. gender 기반 선호 저장 제거, callback 없음은 기존 재시작 흐름을 유지한다.
AUTH-011 구현 근거 shared auth flow에서 기존 UserRepository.getMemberInfo() 및 GetMemberInfoResponse를 재사용한다. 성공 response의 기존 필드와 로컬 키를 사용하며 별도 response schema를 만들지 않는다.

9. 반응형 기능 범위

  • iPhone SwiftUI sheet만 포함한다. 웹/tablet 반응형 범위는 해당 없음.
  • bottom safe area 포함 Figma frame: ON 402x372, OFF 402x287.

10. UI/UX Expectations

10.0 표시 방식 변경 승인 (2026-10-12)

  • 사용자가 투명 fullScreenCover를 표시 컨테이너로 사용하는 커스텀 BottomSheet 전환을 승인했다. 아래 내용은 이전 native .sheet/고정 높이 기록보다 우선한다.
  • 화면 전체에는 기존 UI가 비치는 반투명 검정 배경을 두고 터치를 차단한다. 실제 패널은 좌우·하단에 붙으며 위쪽 모서리만 둥글고, 내용과 safe area에 필요한 높이만 차지한다.
  • ON/OFF 338/253 고정 높이 및 접근성 크기에서 .large로 전환하는 규칙을 제거한다. 텍스트 줄바꿈과 선호 영역 유무에 따른 자연 높이를 사용한다.
  • 내용이 화면의 사용 가능한 높이를 초과할 때에만 본문을 스크롤하고 확인 버튼은 접근 가능하게 유지한다.
  • 확인으로 컨테이너가 닫힌 뒤 기존 onDismiss 전송을 실행한다. API·ViewModel·7개 진입점·오류 복구 정책은 변경하지 않는다.
  • 구현·검증 후속: 커스텀 패널 전환 완료. iOS26 실제 측정은 한국어 ON372pt/OFF287pt, 영어 ON383.67pt이며 고정값이 아닌 내용 높이다. 화면 초과 시 본문 스크롤, 뒤 화면 노출/입력 차단, 두 앱 빌드와 P4 독립 검토를 통과했다. 기존 실제 인증 통합 미검증은 유지한다.
  • Phase6 승인: 사용자가 배경의 올라오는 애니메이션 제거 방안을 확인하고 적용을 승인했다. fullScreenCover 기본 전환은 끄고 dim 배경은 제자리에 즉시 표시하며, 콘텐츠 패널에만 진입/퇴장 모션을 적용한다.
  • 패널 퇴장 완료 후 컨테이너를 닫고 기존 onDismiss 제출을 유지한다. ViewModel/API/개발용 mock 정책은 바꾸지 않는다. 동작 줄이기 환경에서는 수직 이동을 줄이고, 같은 닫힘 완료/1회 제출 계약을 유지한다.
  • 2026-10-13 Phase6 후속: 배경 고정·패널 단독 0.25초 진입/퇴장을 구현했다. 실제 native 중간 프레임, 빠른 확인/재표시/Reduce Motion 검사, 두 앱 빌드와 독립 기능·시각 검토가 통과했다. 제출은 host onDismiss에 유지된다.

10.1 시안과 문구

  • Figma file HmN1yNdJ3EIpqknFL0Hkab, ON 2489:32150, OFF 2489:32163을 기준으로 한다.
  • 시안 링크: ON, OFF.
  • 고정 dark background #202020, accent #00bdf7, 흰색 제목, muted copy #b5b5b5, 좌우 padding 14pt.
  • 제목 18pt medium, 본문 16pt, 안내 caption 12pt. 기존 앱 font/assets와 I18n.swift 규칙을 따른다.
  • 화면 문구는 다음과 같이 고정한다.
    • 콘텐츠 보기 설정
    • 민감한 콘텐츠 보기
    • ON 설명: 성인인증 완료 후 성인 콘텐츠를 볼 수 있어요
    • OFF 설명: 성인 콘텐츠가 목록과 검색에 노출되지 않아요
    • ON일 때만 선호 콘텐츠 및 전체 / 남성향 / 여성향 radio row 표시
    • 마이 > 설정 > 콘텐츠 보기 설정에서 언제든 바꿀 수 있어요
    • 확인 버튼 설정 완료

10.2 화면 상태

  • sheet는 제출 전 draft만 보유한다. 확인 전 기존 설정 값을 변경하거나 PATCH하지 않는다.
  • auth+settings POST 실패는 sheet 재개, member info sync 실패는 sheet 재개 없이 restart fallback으로 분리한다.

11. API 계약

11.0 개발 타깃 성공 시뮬레이션 승인 (Phase 5)

  • 사용자가 앱 흐름 테스트 목적의 모의 인증을 승인했다. 실제 서버 인증 검사 API가 거절될 수 있다는 한계를 수용했다.
  • SodaLive-dev Debug/Release에만 AUTH_VERIFICATION_MOCK 컴파일 조건을 적용한다. 일반 SodaLive는 두 구성 모두 실제 Bootpay/인증 API를 유지하며 모의 실행 코드가 제외된다.
  • 7개 본인인증 UI에서 개발 모드는 Bootpay를 열지 않고 약 0.5초 로딩 후 기존 ON/ALL 설정 패널로 진행한다. 설정 완료 후 닫힘 완료를 기다리는 기존 순서를 유지한다.
  • 모의 인증 전송은 실제 POST 없이 정상 성공 응답을 제공해 기존 공통 성공 흐름을 재사용한다. 가짜 receipt를 서버로 보내거나 서버 인증 상태를 바꾸지 않는다.
  • 후속 회원정보·마이페이지 조회는 정상 서버 응답에서 isAuth, isAdultContentVisible, contentType만 모의 상태로 보정한다. 잔액·역할·개인정보·알림 등 다른 필드는 원본을 유지하고, 실제 조회의 HTTP/API/디코딩 실패를 성공으로 바꾸지 않는다.
  • 모의 상태는 현재 로그인 세션에 한정한다. 앱 내부 Splash 재시작에는 유지하고, 로그아웃/401 초기화 및 로그인 세션 변경 때 해제한다. 실제 앱 프로세스 종료 후 모의 인증을 영구 유지하는 기능은 만들지 않는다.
  • 일반 콘텐츠 설정에서 이후 변경한 값을 오래된 모의 선택값으로 덮어쓰지 않도록 상태를 맞춘다. 새 설정 UI/모의 제어 메뉴/서버 권한 우회는 범위 밖이다.
  • 구현 후속: Phase5 완료. dev Debug/Release만 모의 flag 적용, 표준 Debug 바이너리 mock 심볼 제외, native 로딩/패널 4개 검사, 실제 helper/repository/VM 격리 검사와 두 Debug 앱 빌드 통과. 같은 로그인 세션의 인증 전 GET 지연 응답 회귀를 수정했다. 실제 회원 GET·일반 설정 PATCH는 서버 연결을 유지하며 서버 권한 부여는 하지 않는다.

별도 api-contract.md는 만들지 않는다. 아래 계약은 사용자 확인 사항이며 backend 실행/응답은 독립 검증하지 않았다.

11.1 인증과 설정 제출

항목 계약
요청 POST /auth
JSON receipt_id: String, isAdultContentVisible: Bool, contentType: ALL | MALE | FEMALE
의미 Bootpay receipt와 확인된 콘텐츠 설정을 한 번에 제출
성공 decode 기존 ApiResponse<AuthResponse> 사용, gender 외 새 response field/schema를 가정하지 않음
실패 transport/API/decode/비성공 envelope를 auth+settings 제출 실패로 처리, 오류 표시와 보존 draft로 사용자 재시도
기존 재시작 진입점 성공 시 확인된 설정을 로컬 반영하고 기존 isRestartApp=true, .splash 전환. 재시작 전에 회원정보 GET을 추가하지 않음

11.2 callback 진입점의 회원정보 동기화

항목 계약
요청 GET /member/info?container=ios
response 기존 ApiResponse<GetMemberInfoResponse>
성공 처리 can, point, auth, role, isAuditionNotification, countryCode, isAdultContentVisible, contentPreference 로컬 값 갱신 후 pending action 소비
실패 처리 sheet 재개 및 auth 재전송 금지. pending action 미실행. isRestartApp=true 설정 후 .splash 전환
재시작 조회 근거 ContentView가 isRestartApp=true일 때 MainView를 제거하고, SplashView가 해당 플래그를 해제하면 새 MainView의 hasLoadedMainData=false 초기화 경로가 member GET을 호출한다. 실제 조회/로컬 반영은 앱 QA로 확인한다.
범위 제약 Splash 자체에는 member GET이 없다. 앱 active 조회도 alreadyUpdatedMarketingInfo 조건에 묶여 있어 단독 동기화 근거로 삼지 않는다. 이번 실패 처리에서 자동 재시작 루프를 추가하지 않는다.

12. 보안과 데이터 취급

  • receipt와 token 원문을 문서, 로그, analytics에 기록하지 않는다.
  • 본 auth flow의 onDone에서 receipt payload를 dump하는 기존 DEBUG_LOG를 제거한다. 무관한 전체 repo 로그 정리는 하지 않는다.
  • draft는 확인 전 네트워크와 영속화로 보내지 않는다.

13. 성능과 품질 요구사항

  • 인증 완료 7 entrypoint, dismiss 차단, sheet 닫힘 후 POST, 중복 확인 방지와 실패 단계별 복구는 수동 앱 QA로 검증한다.
  • XCTest bundle이 없으므로 test target/framework를 추가하지 않는다.
  • Foundation 기반 assert self-check는 실제 AuthVerifyRequest와 ContentType 소스를 compile/run해 serializer payload를 확인한다. 흐름 테스트를 대체하지 않는다.
  • SodaLive 및 SodaLive-dev 양쪽 Debug build를 검증한다.
  • 재시도 idempotency, receipt 유효기간/만료 동작은 미검증 위험으로 기록하며 보장하지 않는다.

14. 성공 기준

14.1 기능 수용 기준

  • 일곱 진입점 모두 확인 전 auth POST와 설정 영속화가 0회다. (AUTH-001~AUTH-005)
  • 확인 시 sheet가 먼저 닫히고 정확한 combined payload POST는 한 번만 발생한다. (AUTH-006)
  • POST 실패 뒤 receipt/draft/action을 보존한 sheet를 재개하고 자동 제출이 없다. (AUTH-007)
  • member info 실패 시 auth 재전송 0회, sheet 재개 0회, pending action 실행 0회이며 restart fallback이 동작한다. (AUTH-008~AUTH-010)
  • restart fallback이 실제 member refresh를 발생시키고 auth/content 설정을 반영함을 QA에서 확인한다. 소스상 refresh trigger는 런타임 성공 증거가 아니다.

14.2 UI/UX 수용 기준

  • Figma ON/OFF, 고정 문구, font scale, radio 표시, safe area가 실제 화면과 일치한다.
  • 외부 탭·drag·back·close가 confirmation을 우회하지 않는다.

14.3 승인 및 추적성

  • PRD와 plan-task 별도 문서 승인을 받기 전 구현을 시작하지 않는다.
  • 승인 후 요구사항이 Task와 수동/자동 검증 증거에 연결된다.

15. Open Questions

  • 제품 결정 미결 항목 없음. 요구사항은 사용자 확인 사항이다.
  • backend combined payload 지원은 사용자 확인에 근거하며 직접 호출하거나 독립 검증한 사실이 아니다.
  • retry idempotency, receipt 만료, restart 통한 member refresh 실동작은 제품 결정이 아닌 구현/운영 검증 위험이다.

16. 요구사항 추적표

범위 계획 Phase Goal 자동 검증 수동 검증
AUTH-001~AUTH-005 2 P2-T1 실제 request serializer assert, 정적 caller 대조 일곱 entrypoint, dismiss, 미확인 network/persistence 0회
AUTH-006~AUTH-008 2 P2-T1 combined payload serializer assert duplicate confirm, POST 실패 뒤 값 보존·수동 retry
AUTH-009~AUTH-011 2 P2-T1 source review, response decode 경로 GET 실패 때 restart, auth 재전송 0회, action 0회; restart member refresh 성공 확인
전체 3 P3-GATE serializer, 두 Debug builds 최종 흐름 및 두 시안 QA

17. Decision Log

날짜 ID 상태 결정 근거 영향
2026-10-12 DEC-001 사용자 확정 모든 일곱 auth completion을 confirm sheet 뒤로 이동하고 최초 ON/ALL로 시작 사용자 확인 AUTH-001~AUTH-005, P2-T1
2026-10-12 DEC-002 사용자 확정 확인으로 닫은 뒤 combined auth/settings 제출, 여섯 callback은 회원정보 동기화 후 action 1회 소비 사용자 확인 §11, AUTH-006, AUTH-009
2026-10-12 DEC-003 사용자 확정 POST 실패는 sheet/draft 재개, 회원정보 실패는 재전송 없이 restart fallback 최신 사용자 확인 AUTH-007~AUTH-008
2026-10-12 DEC-004 채택 관례 OFF일 때 contentType=ALL 기존 ContentSettingsViewModel normalize AUTH-005

18. 변경 관리

  • 요구사항 변경은 Decision Log와 요구사항 표, §11 계약, plan-task를 함께 갱신한다.
  • 승인 전 앱 코드는 변경하지 않는다. 사용자가 이 PRD와 계획 문서를 명시적으로 승인하면 구현 시작 허가로 처리하고, 승인 기록만 갱신한 뒤 현재 브랜치에서 계획을 실행한다. 별도 추가 승인을 요구하지 않는다.

인터뷰 요약

  • 사용자 확정 흐름 및 제약을 기준으로 정리했다. 승인되지 않은 제안은 없다.
  • 범위/목표/제약/성공 기준 명확도 1.0, 기존 코드 문맥 0.9.
  • 모호도는 휴리스틱 추정 0.015 ≈ 0.02 (1 - (목표×0.30 + 범위×0.20 + 제약×0.15 + 성공×0.20 + 문맥×0.15))이며 측정값이 아니다. 문서/구현 승인은 아직 부여되지 않았다.

문서 작성 검증

  • 2026-10-12: PRD와 계획 샘플, 정책 및 지정 소스 경로를 읽고 요구사항/구현 근거를 분리해 기록했다. backend 호출, 빌드, 앱 실행은 하지 않았다.
  • 2026-10-12: 마이페이지의 기존 재시작과 callback 경로의 GET 동기화를 분리하고, 문서 승인 한 번을 구현 시작 허가로 처리하도록 사용자 지시와 대조했다. 변경 범위와 공백 오류를 확인했으며 구현 승인은 여전히 대기 중이다.
  • 2026-10-12 후속: 사용자가 문서를 승인했다. 이전 승인 대기 기록은 이력으로 보존하며, 승인된 범위의 구현·검증을 시작한다.
  • 2026-10-12 구현 후속: 7개 인증 진입점과 결합 전송·단계별 복구를 구현했다. 실제 DTO/VM 격리 실행, 네이티브 sheet UI 검사, 두 앱 Debug 시뮬레이터 빌드가 통과했다. 실제 인증 7개 경로와 실패 재시작 후 실서버 회원정보 갱신은 QA 환경이 없어 미검증이며 최종 수용 기준을 일괄 완료 처리하지 않는다. 상세 증거와 한계는 plan-task의 Progress 및 reviews/phase2-auth-content-settings.md에 기록한다.

Phase 7 후속 요구사항: 인증 중 설정 패널 종료

상태와 우선순위

  • 2026-10-13 사용자 인터뷰로 범위와 문구를 확정했다. 현재 허용 범위는 문서·계획 작성까지이며, Phase 7 구현은 이 계획에 대한 별도 승인 후 시작한다. 이전 Phase의 승인이나 문구에 대한 “그대로 진행”은 이번 구현 승인으로 처리하지 않는다.
  • 아래 요구사항은 기존 AUTH-003, §3.2·§7의 닫기 금지, §10.1 문구 및 §14.2 관련 수용 기준을 이번 범위에서 정정한다. 과거 결정·검증 기록은 이력으로 보존한다.
  • 목표: 최초 설정 및 저장 실패 후 재표시된 패널에서 사용자가 명시적으로 본인인증 과정을 중단할 수 있게 한다.
  • 범위: 인증 중 AuthContentSettingsSheet와 종료 팝업만 변경한다. 일반 콘텐츠 설정 화면, 다른 인증 안내, API·Bootpay·개발 mock 정책은 변경하지 않는다.

요구사항과 수용 기준

ID 상태 요구사항 수용 기준 Goal
AUTH-012 사용자 확정 패널 우측 상단 X는 종료 확인 팝업을 연다. 최초 패널과 POST 실패 후 패널 모두에서 동작한다. X 자체는 제출하거나 패널을 닫지 않는다. P7-T1
AUTH-013 사용자 확정 V2 내부 기존 팝업을 재사용한다. V2/Component/Modal/SodaV2ActionModal.swift를 그대로 사용하며 구형 SodaDialog나 새 팝업 컴포넌트를 만들지 않는다. P7-T1
AUTH-014 사용자 확정 confirm은 패널까지 닫고 인증 과정을 중단한다. 영수증·요청·성공 callback과 caller의 대기 action을 폐기한다. 종료에 따른 추가 POST/GET·설정 저장·성공 동작·재시작은 0회다. 새 인증으로 다시 진입할 수 있다. P7-T1
AUTH-015 사용자 확정 cancel과 팝업 바깥 터치는 팝업만 닫는다. 선택한 ON/OFF·선호와 인증 대기 상태를 유지한다. 팝업 표시 중 뒤 패널의 저장·토글은 조작되지 않는다. P7-T1
AUTH-016 사용자 확정 인증 패널과 종료 팝업에서 인증·콘텐츠 용어를 통일한다. ‘본인인증’과 ‘민감한 콘텐츠’를 사용한다. 일반 설정과 다른 인증 안내 문구는 그대로다. 팝업 본문의 두 문장 사이에 명시적인 줄바꿈이 있다. P7-T1
AUTH-017 설계 제안 X는 SwiftUI 접근성·터치·레이아웃 기준을 따른다. SF Symbol xmark, 44×44pt 터치 영역, 의미 있는 VoiceOver 레이블, 제목 가운데 정렬, 큰 글자·가로 화면에서도 닫기 접근 가능. P7-T1, P7-QA

확정 문구

위치 한국어 문구
패널 제목 / 토글 제목 기존 콘텐츠 보기 설정 / 민감한 콘텐츠 보기 유지
ON 설명 본인인증 완료 후 민감한 콘텐츠를 볼 수 있어요
OFF 설명 민감한 콘텐츠가 목록과 검색에 노출되지 않아요
X 접근성 레이블 / 팝업 제목 본인인증 종료
팝업 본문 본인인증을 종료하시겠어요?\n종료하면 다시 본인인증을 진행해야 해요.
confirm / cancel 종료하기 / 계속하기
저장 CTA 기존 설정 완료 유지
  • 본문에서 \n은 실제 줄바꿈으로 표시한다. 화면 폭에 따른 추가 자연 줄바꿈은 허용한다.
  • 기존 I18n.pick의 한국어·영어·일본어 방식을 유지하고 번역도 같은 의미와 두 문장 사이 줄바꿈을 따른다. 공용 sensitiveContentTitle은 수정하지 않는다.

UI와 상태 설계 제안

  • ui-ux-pro-max의 SwiftUI 레이블·네이티브 Button 및 iOS 44pt 터치 영역 지침을 적용한다. 기존 dark 패널·색상·간격·모션을 유지한다.
  • 헤더는 최소 54pt 높이, 기존 상단 26pt·좌우 14pt 간격을 유지한다. 좌우 동일한 44pt 영역 사이에 제목을 가운데 배치한다. 우측 16pt medium xmark는 .gray400을 사용하고 별도 원형 배경은 추가하지 않는다. 눌림 피드백을 제공한다.
  • 헤더와 저장 CTA는 스크롤 밖에 두고 내용만 필요할 때 스크롤한다. 큰 글자에서는 제목 줄바꿈과 헤더 높이 증가를 허용한다. X 식별자는 authContentSettings.close로 한다.
  • 종료 팝업은 패널이 아닌 전체 화면 host 위에 표시한다. 기존 V2 순서대로 왼쪽 ‘계속하기’, 오른쪽 ‘종료하기’를 배치한다. 팝업 동안 뒤 패널 터치와 접근성 탐색을 차단한다.
  • 배경 탭·drag로 패널을 바로 닫는 동작은 계속 금지한다. 종료는 X → 팝업 → ‘종료하기’로만 수행한다. 제출 중 취소는 허용하지 않는다.
  • 패널 단독 퇴장 및 host onDismiss 제출 연결을 유지한다. 종료로 대기 상태를 먼저 비우므로 submitPendingAuthVerification()의 기존 guard가 추가 제출을 차단한다.

제외와 검증 위험

  • 서버에 이미 도달했을 수 있는 실패 요청의 인증 결과를 취소하거나 되돌리는 기능은 없다. 종료는 앱의 로컬 진행 중단이며 서버 rollback을 보장하지 않는다.
  • V2 팝업의 기존 340pt 폭·64pt 제목 높이는 공용 컴포넌트 제약이다. 좁은 화면·큰 글자에서 문제가 확인되면 보고하고, 이번 작업에 공용 팝업 리팩터링을 임의로 포함하지 않는다.
  • 기능·native UI·두 앱 빌드는 구현 승인 후 검증한다. 기존 실서버 통합 QA 미검증은 별도로 유지한다.

후속 결정과 인터뷰 종료

날짜 ID 상태 결정 근거 영향
2026-10-13 DEC-007 정정·사용자 확정 명시적 종료 확인을 허용하고 변경 범위를 인증 패널·종료 팝업에 제한한다. V2 팝업을 재사용한다. 사용자 요청과 인터뷰 AUTH-012~AUTH-016, P7-T1
2026-10-13 DEC-008 사용자 확정 종료 문구를 채택하고 본문 두 문장 사이를 줄바꿈한다. 계획까지만 작성한 뒤 구현 승인을 기다린다. 최신 사용자 지시 확정 문구·Phase 7 승인 gate
  • 최종 모호성 0.02: 목표 1.0, 범위 1.0, 제약 1.0, 성공 기준 1.0, 코드 문맥 0.9의 휴리스틱 평가. 제품 미결 질문 없음. UI 세부 수치는 승인 대상 설계 제안이다.
  • 2026-10-13 문서 작성: 현재 패널·VM·V2 팝업·호출부·I18n·일반 설정·기존 검증 스크립트를 대조했다. 앱 코드 변경, 빌드, 앱 실행, 서버 요청은 수행하지 않았다.
  • 2026-10-13 후속 승인: 사용자가 **“구현 승인”**으로 Phase 7 PRD·계획 구현을 허가했다. 위 승인 대기 기록은 이력으로 보존하며 현재 작업 디렉터리에서 승인된 최소 변경과 검증을 진행한다.
  • 2026-10-13 구현 후속: X·V2 종료 팝업·줄바꿈·scoped 용어·VM/caller 정리를 구현했다. 실제 VM 검사, 전체 기존 shell suite, 두 앱 빌드, native 기능 matrix 20개와 추가 반복 1개 및 coordinator 핵심 시나리오 재실행 1개가 통과했다. Oracle은 코드·VM 로직 범위 APPROVE이며 전체 시각 승인은 아니다.
  • [blocked] 추가 범위 결정 필요: 가로 화면 + 최대 Dynamic Type에서 변경 없는 SodaV2ActionModal의 본문과 버튼이 잘려 경고 두 번째 문장과 동작명이 보이지 않는다(REV-P7-001). 공용 컴포넌트 수정은 승인 범위 밖이므로 수정하지 않았다. 이 제한 수용 또는 공용 팝업의 큰 글자 대응 수정 승인 전까지 최종 완료로 표시하지 않는다. 상세 증거는 reviews/phase7-auth-settings-exit.md 참조.
  • 2026-10-13 P7-R1 승인: 사용자 **“최소한 수정”**으로 공용 SodaV2ActionModal의 큰 글자 레이아웃 최소 보정을 승인했다. 공용 modal 무변경 제약은 이번 결함 보정에 한해 해제한다. 기본 크기 디자인·문구·버튼 순서·색상·callback은 보존하고, 글자 크기 제한으로 우회하지 않는다. 화면 공간에 맞춘 크기와 줄바꿈·필요한 overflow 처리만 허용한다.
  • 2026-10-14 P7-R1 완료: 공용 modal 한 파일(+46/-22, 순증24줄)을 수정해 접근성 글자에서 가용 폭·자연 높이를 사용하고 넘치는 제목/본문만 스크롤한다. 버튼은 고정되며 기본340pt 디자인·동작은 보존한다. 최대 글자 가로/375pt세로와 기본 크기·단일/두 버튼 native 검증, 현재 소스의 두 앱 빌드·전체 shell suite 및 독립 기능 APPROVE/집중 시각 PASS를 확인했다. REV-P7-001은 해결됐으며 이전 보류 기록은 이력이다.
  • 검증 한계: 실제 VoiceOver 제스처와 실서버7경로 통합은 미실행이다. native 접근성 노드와 VM doubles를 그 증거로 확대하지 않는다. 기존 일본어 단어 중간 줄바꿈은 의미 생략이 없는 경미 사항으로 유지했다. QA 앱·runner·기기·설정은 정리했다.