Skip to content

[feat/MAT-746] 학생앱 심사 onboarding/policy/push 정합#338

Merged
sterdsterd merged 7 commits into
developfrom
feat/MAT-746-onboarding-policy-push
May 19, 2026
Merged

[feat/MAT-746] 학생앱 심사 onboarding/policy/push 정합#338
sterdsterd merged 7 commits into
developfrom
feat/MAT-746-onboarding-policy-push

Conversation

@sterdsterd
Copy link
Copy Markdown
Collaborator

Summary

학생앱 App Store 심사 제출 사이클의 PR-3. 온보딩 마지막에 푸시 권한 동의 step 추가, 약관/개인정보/고객지원 메뉴 동선 연결, NotificationSettings의 QnA 토글 임시 비활성, Toast safe area 정합화. 인프라 PR(#336) 위에 사전 rebase되어 있습니다.

Linear

신규 mini task (plan §5에서 추가 결정):

  • Toast safe area inset 적용 (Toast.tsx hardcoded topOffset:30 제거)
  • NotificationSettings QnA 채팅 알림 토글 임시 주석 (정식 출시 시 QnA 비활성)

Changes

  • feat(native): connect terms, privacy, support menu linkssrc/constants/termsUrls.ts 신규 + SignupTermsScreen/TermsScreen import 통일, MenuScreen 고객센터 mailto:develop@math-pointer.com
  • feat(native): add push consent step in onboarding flowPushConsentStep 신규 (3-phase: request/tune/denied), OnboardingScreen step 등록, useFinishOnboarding register 성공 후 PushConsent로 reset, useOnboardingResume PushConsent early-return
  • fix(native): notification settings hide qna toggleNotificationSettingsScreen 12+ 위치의 QnA 처리 단일 derived constant QNA_PUSH_DISABLED로 정리 + 토글 JSX 주석. putAllowPush 호출 헬퍼 sanitizePushSettingsisAllowQnaPush:false 강제
  • fix(native): toast respect safe area insetsToastSafeAreaBridge + useToast hook + module-level latched topOffset. App.tsx SafeAreaProvider 안에 mount
  • fix(native): keep PushConsent route on resume + clarify token register intent — code-review HIGH 2건 반영. resume 시 PushConsent step 그대로 유지 (이전엔 Welcome으로 collapse되어 동의 단계 skip되는 버그). PushConsentStep inline token 등록 의도 주석

Testing

  • pnpm --filter native typecheck PASS
  • pnpm --filter native lint PASS (0 errors, 543 pre-existing warnings)
  • pnpm format:check PASS
  • OMC code-reviewer pass: REQUEST_CHANGES → HIGH 2건 반영 후 재push. MEDIUM 4건은 1.1 fast-follow
  • 실기기 회귀 권장 시나리오:
    • 신규 가입 → onboarding 진행 → PushConsent 노출 → 허용 → 토큰 등록 + Phase B 토글 → Welcome
    • PushConsent에서 "다음에 받기" → 토큰 등록 0
    • OS 권한 사전 거부 → Phase A "설정 앱으로 이동"
    • PushConsent step에서 앱 force-quit → 재시작 시 PushConsent로 복귀
    • 메뉴 → 이용약관/개인정보 → 외부 브라우저 오픈, 고객센터 → mailto
    • NotificationSettings → QnA 토글 미노출, 다른 토글 변경 시 PUT body isAllowQnaPush:false 확인
    • iPhone 14 Pro (Dynamic Island) / SE / Android에서 Toast safe-area 잘림 0

Risk / Impact

  • 영향 범위: 신규 가입 onboarding 동선 변경 + 알림 설정 UI/PUT body 변경 + Toast 시각 위치
  • 확인 필요한 부분:
    • PushConsentStep inline messaging().getToken() + StudentNavigator의 useFcmToken 두 path 모두 활성. idempotent endpoint라 race 무해하나 주석 명시
    • useOnboardingResume이 PushConsent를 sequence에 포함하지 않음 — getStepSequence도 PushConsent를 일반 step이 아닌 register 후 final step으로 취급. 의도된 설계
    • legacy 사용자 (server isAllowQnaPush:true) 처리 — hasSameSettings가 QnA 비교 안 함. 사용자가 다른 토글 변경 시까지 server에 stale 유지 (MEDIUM, fast-follow)
  • 배포 시 유의사항: PR-1([feat/MAT-746] 학생앱 심사 대응 auth/session 안정화 #337)과 함께 머지 (의존성 없으나 머지 순서: PR-1 → PR-3 → PR-2). PR-1 머지 후 본 PR rebase 필요 가능

@linear
Copy link
Copy Markdown

linear Bot commented May 19, 2026

MAT-746

@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pointer-admin Ready Ready Preview, Comment May 19, 2026 9:35pm

@sterdsterd sterdsterd requested a review from Copilot May 19, 2026 20:46
@sterdsterd sterdsterd self-assigned this May 19, 2026
@sterdsterd sterdsterd added the ✨ Feature 기능 개발 label May 19, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

학생앱(App Store 심사 대응) 제출 전 정합성을 위해 온보딩 마지막에 푸시 동의 단계를 추가하고, 약관/개인정보/고객센터 진입 경로를 실제 동작하도록 연결하며, 알림 설정(QnA 토글 임시 비활성) 및 Toast 표시 위치(safe-area) 문제를 정리하는 PR입니다.

Changes:

  • 온보딩 완료 후 PushConsent 단계로 이동하도록 플로우를 확장하고(재진입 resume 포함) 푸시 권한/수신 설정 저장 UI를 추가
  • 약관/개인정보/마케팅 동의 URL 상수화 및 메뉴 화면에서 외부 브라우저로 오픈하도록 연결
  • NotificationSettings에서 QnA 토글을 숨기고 PUT body에 isAllowQnaPush:false를 강제, Toast를 safe-area inset 기반 topOffset으로 보정

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
apps/native/tsconfig.json @constants path alias 추가로 약관 URL 상수 import 경로 통일 지원
apps/native/src/features/student/scrap/components/Notification/Toast.tsx Toast topOffset을 safe-area 기반으로 계산(bridge/hook)하여 노치 디바이스 클리핑 완화
apps/native/src/features/student/scrap/components/Notification/index.ts Notification 모듈 export 확장(showToast + safe-area bridge/hook)
apps/native/src/features/student/onboarding/screens/types.ts Onboarding stack에 PushConsent route 추가
apps/native/src/features/student/onboarding/screens/steps/PushConsentStep.tsx 신규 PushConsent 온보딩 step(권한 요청/설정/저장+토큰 등록) 추가
apps/native/src/features/student/onboarding/screens/OnboardingScreen.tsx initialRouteName에 PushConsent 포함 및 Stack.Screen 등록
apps/native/src/features/student/onboarding/hooks/useOnboardingResume.ts resume 시 PushConsent 단계 유지(조기 return)
apps/native/src/features/student/onboarding/hooks/useFinishOnboarding.ts onboarding 완료 후 Welcome 대신 PushConsent로 reset
apps/native/src/features/student/menu/screens/TermsScreen.tsx Terms 메뉴 항목을 외부 브라우저로 열도록 연결
apps/native/src/features/student/menu/screens/NotificationSettingsScreen.tsx QnA 토글 제거 및 저장 시 QnA=false 강제(로컬/PUT)
apps/native/src/features/student/menu/screens/MenuScreen.tsx 고객센터 동선을 toast 대신 mailto 링크로 연결
apps/native/src/features/auth/signup/screens/SignupTermsScreen.tsx Signup 약관 URL 상수를 @constants/termsUrls로 이동/재사용
apps/native/src/constants/termsUrls.ts 약관/개인정보/마케팅 URL 상수 신규 파일로 추출
apps/native/src/apis/controller/student/me/putAllowPush.ts PUT body에 QnA=false를 강제하는 sanitize helper 및 상수 추가
apps/native/App.tsx SafeAreaProvider 내부에 ToastSafeAreaBridge를 mount하여 showToast topOffset 동기화
Comments suppressed due to low confidence (1)

apps/native/src/features/student/onboarding/screens/steps/PushConsentStep.tsx:155

  • phase === 'denied' 화면에서 설정 앱으로 이동 후 다시 앱으로 돌아와도 OS 권한을 재확인하지 않아, 문구(“돌아오면 알림 수신 설정을 마칠 수 있어요.”)와 달리 계속 denied 상태에 머물 가능성이 큽니다. 앱이 active로 복귀했을 때 messaging().hasPermission()을 재확인해 허용되었으면 setPhase('tune')로 전환하거나, CTA를 '다시 확인' 동작으로 바꾸는 방식으로 흐름을 완결해 주세요.
  if (phase === 'denied') {
    return (
      <OnboardingLayout
        title='알림이 꺼져 있어요'
        description={
          Platform.OS === 'ios'
            ? '설정 앱에서 포인터 알림을 허용해 주세요.'
            : '설정에서 포인터 알림을 허용해 주세요.'
        }
        ctaLabel='설정 앱으로 이동'
        onPressCTA={handleOpenSettings}
        skipLabel='다음에 받기'
        onSkip={handleSkip}
        showBackButton={false}>
        <View>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/native/src/features/student/menu/screens/NotificationSettingsScreen.tsx Outdated
Comment thread apps/native/src/features/student/menu/screens/MenuScreen.tsx Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

apps/native/src/features/student/menu/screens/NotificationSettingsScreen.tsx:33

  • QnA 푸시를 비활성화하려는 변경인데, 화면 로컬 state에서 isAllowQnaPush를 항상 false로 두고 hasSameSettings 비교에서도 QnA를 제외해서, 서버에 isAllowQnaPush: true로 남아있는 기존 유저는 다른 토글을 한 번이라도 변경하기 전까지 서버 값이 그대로 유지됩니다(사용자 입장에서는 끌 방법도 없음). 최소한 최초 진입 시 pushSettingData?.isAllowQnaPush === true를 감지하면 1회 PUT로 false로 내려주거나, 초기 sync 로직에서 서버 QnA=true를 강제로 false로 reconcile하는 처리가 필요합니다.
const hasSameSettings = (a: PushSettingsPayload, b: PushSettingsPayload): boolean =>
  a.isAllowPush === b.isAllowPush &&
  a.isAllowServicePush === b.isAllowServicePush &&
  a.isAllowMarketingPush === b.isAllowMarketingPush;

const NotificationSettingsScreen = () => {
  const { data: pushSettingData } = useGetPushSetting({ enabled: true });
  const { mutate: updatePushSettings } = usePutAllowPush();

Comment on lines +121 to +133
// 사용자가 명시적으로 동의한 직후 즉시 토큰 등록.
// StudentNavigator 마운트 시 useFcmToken hook이 다시 한 번 등록을 시도하지만,
// 같은 endpoint(idempotent) + 동일 device token이라 race 무해.
try {
const token = await messaging().getToken();
if (token) {
const { error: tokenError } = await postPushToken(token);
if (tokenError) {
console.warn('[PushConsentStep] FCM token registration returned error:', tokenError);
}
}
} catch (tokenError) {
console.warn('[PushConsentStep] FCM token registration failed:', tokenError);
Comment thread apps/native/src/constants/termsUrls.ts
iPhone 14 Pro/Dynamic Island 등 notched 기기에서 토스트가 status bar에 잘리는 문제 해결.
- showToast: 모듈 레벨 latched topOffset 도입 (ToastSafeAreaBridge가 SafeAreaProvider 내부에서 inset 추적)
- useToast hook 추가 (호출 컴포넌트가 Provider 안에 있을 때 사용 가능)
- App.tsx: SafeAreaProvider 직속에 ToastSafeAreaBridge mount
학생앱 심사 정책 정합성:
- src/constants/termsUrls.ts: 약관/개인정보/마케팅 Notion URL을 단일 source로 추출
- tsconfig.json: @constants 별칭 추가
- SignupTermsScreen: TERMS_URLS을 새 상수에서 import (구 in-file 상수 제거)
- TermsScreen(메뉴): handleTermPress 활성화 — in-app WebBrowser로 Notion 문서 오픈
- MenuScreen: 고객센터 진입 시 mailto:develop@math-pointer.com 메일 컴포저 (학생앱 문의 prefilled)
QnA 채팅 알림은 정식 출시 전까지 비활성:
- putAllowPush.ts: QNA_PUSH_DISABLED 상수 + sanitizePushSettings 헬퍼 추출.
  usePutAllowPush의 mutationFn에서 자동으로 isAllowQnaPush:false 동봉
- NotificationSettingsScreen: QnA 토글 UI/state/handler 제거(주석 자리만 유지),
  자동 push-on 분기 및 모든 PUT 호출에서 isAllowQnaPush:false 강제
학생앱 심사 권한 요청 타이밍 정합 — onboarding 마지막 단계 직전에 PushConsentStep 신설:
- PushConsentStep: 3-phase UI (request → tune → denied)
  · Phase request: "알림 허용" CTA → messaging().requestPermission()
  · Phase tune: 서비스(default ON)/이벤트 마케팅(default OFF) 토글 2개,
    "완료" 시 PUT /api/student/me/push/settings + FCM 토큰 등록
  · Phase denied: OS 권한 거부 시 "설정 앱으로 이동" CTA (Linking.openSettings)
  · "다음에 받기" 선택 시 서버 호출 0, FCM 토큰 등록 0
- OnboardingStackParamList에 PushConsent route 추가, OnboardingScreen에 등록
- useFinishOnboarding: register 성공 후 Welcome 대신 PushConsent로 reset
- useOnboardingResume: PushConsent는 Welcome과 동일하게 early-return
@sterdsterd sterdsterd force-pushed the feat/MAT-746-onboarding-policy-push branch from d39714f to 9c230fd Compare May 19, 2026 21:34
@sterdsterd sterdsterd merged commit f76afe1 into develop May 19, 2026
4 checks passed
@sterdsterd sterdsterd deleted the feat/MAT-746-onboarding-policy-push branch May 19, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants