Conversation
- Create signupStore for STEP 1 data (email, identity, terms) with AsyncStorage persistence - Refactor onboardingStore to remove email/identity (moved to signupStore), add currentStep persistence - Add signup/onboarding store reset on signOut to prevent data leaks between accounts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- EmailInputScreen: email input with existence check - EmailLoginScreen: password login for existing users - SignupPasswordScreen: password setup for new email users - SignupEmailScreen: email collection for social signup - SignupTermsScreen: terms consent (fullscreen, replaces bottom sheet) - SignupIdentityScreen: SMS identity verification (moved from onboarding) - ForgotEmail/ForgotCode/ForgotResetScreen: password reset flow Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove TermsConsentSheet and EmailAuthSheet from LoginScreen - Social buttons now trigger OAuth directly without prior terms consent - Email button navigates to fullscreen EmailInput screen - Update useNativeOAuth to navigate to SignupEmail for first-time social users - Register all new auth screens in AuthNavigator with proper param types - Remove useEmailAuth exports (logic moved to individual screens) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove Email and Identity steps from onboarding (moved to auth signup) - OnboardingScreen now starts from Grade step - Update types to remove Email/Identity from OnboardingStackParamList - WelcomeStep now merges signupStore (STEP 1) + onboardingStore (STEP 2) for postRegister - Add currentStep persistence to all onboarding steps for app restart recovery - Reset signupStore after successful registration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… flow - RootNavigator: authenticated + STEP 1 incomplete → Auth stack (signup screens) - RootNavigator: authenticated + STEP 1 complete → StudentNavigator (onboarding check) - useLoadAssets: wait for Zustand persist store hydration before auth check - useLoadAssets: auto sign-out on app restart if STEP 1 was incomplete - StudentNavigator: clarify onboarding display condition comment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete EmailAuthSheet (replaced by fullscreen screens) - Delete TermsConsentSheet (replaced by SignupTermsScreen) - Delete useEmailAuth hook (logic distributed to individual screens) - Delete EmailStep, IdentityStep from onboarding (moved to auth signup) - Delete NicknameStep (was already deprecated) - Remove unused imports (ActivityIndicator) from new screens Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rify - postPasswordResetVerifyCode was using ResetPasswordRequest (requires newPassword) instead of VerifyCodeRequest (only email + code) - Remove unnecessary newPassword: '' workaround in ForgotCodeScreen Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaced hardcoded text styles with shared typography tokens to ensure consistent design across the app.
Replaced all instances of TextInput with the shared OnboardingInput component across authentication screens for consistency and improved code reuse.
Add unique keys to navigation screens in RootNavigator to ensure the stack resets when sessionStatus or onboardingStatus changes.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
학생 Auth/Onboarding 진입 구조를 “STEP 1(계정 생성/약관/본인인증) → STEP 2(프로필 온보딩)”로 재구성하고, 기존 바텀시트 기반 로그인/가입 UI를 풀스크린 네비게이션으로 전환하는 변경입니다.
Changes:
- Auth 스택에 이메일 로그인/회원가입/비밀번호 찾기 풀스크린 플로우 추가 및 기존 바텀시트 구현 제거
- signupStore / onboardingStore persist 도입 및 RootNavigator에서 session + step1Completed + onboardingStatus 기반 분기
- 온보딩 STEP 2 스텝 단순화(이메일/본인인증 제거) 및 타이포 토큰(
typo-*) 적용 확대
Reviewed changes
Copilot reviewed 37 out of 37 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/native/src/stores/authStore.ts | signOut 시 signup/onboarding 스토어 reset 연동 |
| apps/native/src/navigation/student/StudentNavigator.tsx | onboarding 표시 조건 주석/로직 보완 |
| apps/native/src/navigation/auth/AuthNavigator.tsx | Auth 스택에 이메일 로그인/가입/비번찾기 라우트 추가 |
| apps/native/src/navigation/RootNavigator.tsx | sessionStatus + step1Completed + onboardingStatus로 루트 분기 |
| apps/native/src/hooks/useLoadAssets.ts | persist hydration 대기 및 특정 조건에서 재시작 시 signOut |
| apps/native/src/features/student/onboarding/store/useOnboardingStore.ts | onboarding store를 persist로 전환, currentStep/status 구조 변경 |
| apps/native/src/features/student/onboarding/screens/types.ts | 온보딩 라우트에서 Email/Identity 제거 |
| apps/native/src/features/student/onboarding/screens/steps/WelcomeStep.tsx | register payload를 signupStore(step1Data)+onboarding payload로 구성, signup reset |
| apps/native/src/features/student/onboarding/screens/steps/ScoreStep.tsx | 다음/스킵 시 currentStep 갱신 추가, import alias 정리 |
| apps/native/src/features/student/onboarding/screens/steps/SchoolStep.tsx | 다음/스킵 시 currentStep 갱신 추가, 타이포 토큰 적용 |
| apps/native/src/features/student/onboarding/screens/steps/NicknameStep.tsx | 사용 중지된 닉네임 스텝 파일 제거 |
| apps/native/src/features/student/onboarding/screens/steps/MathSubjectStep.tsx | 다음 이동 시 currentStep 갱신 추가 |
| apps/native/src/features/student/onboarding/screens/steps/GradeStep.tsx | 다음 이동 시 currentStep 갱신 추가 |
| apps/native/src/features/student/onboarding/screens/OnboardingScreen.tsx | initialRouteName을 persist된 currentStep 기반으로 설정 |
| apps/native/src/features/student/onboarding/components/OptionButton.tsx | 타이포 토큰 적용 |
| apps/native/src/features/student/onboarding/components/OnboardingLayout.tsx | CTA/skip/back UI 타이포/스타일 토큰 정리 |
| apps/native/src/features/student/onboarding/components/OnboardingInput.tsx | 라벨/힌트/에러/성공 텍스트 타이포 토큰 적용 |
| apps/native/src/features/student/onboarding/components/MailBoxGraphic.tsx | SVG path/gradient/mask 리팩터링(에셋 업데이트) |
| apps/native/src/features/student/onboarding/components/InfoCard.tsx | 타이포 토큰 적용 |
| apps/native/src/features/auth/signup/store/useSignupStore.ts | STEP 1 데이터 영속화(persist)용 signupStore 신규 추가 |
| apps/native/src/features/auth/signup/screens/SignupTermsScreen.tsx | 약관 동의 풀스크린 화면 신규 |
| apps/native/src/features/auth/signup/screens/SignupPasswordScreen.tsx | 이메일 가입 비밀번호 설정 화면 신규 |
| apps/native/src/features/auth/signup/screens/SignupIdentityScreen.tsx | 본인인증을 Auth 플로우로 이동 및 step1Completed 처리 |
| apps/native/src/features/auth/signup/screens/SignupEmailScreen.tsx | 소셜 가입 시 이메일 수집 화면 신규 |
| apps/native/src/features/auth/signup/screens/ForgotResetScreen.tsx | 비밀번호 재설정(새 비밀번호) 화면 신규 |
| apps/native/src/features/auth/signup/screens/ForgotEmailScreen.tsx | 비밀번호 찾기(코드 전송) 화면 신규 |
| apps/native/src/features/auth/signup/screens/ForgotCodeScreen.tsx | 비밀번호 찾기(코드 검증) 화면 신규 |
| apps/native/src/features/auth/signup/screens/EmailLoginScreen.tsx | 이메일 로그인(비밀번호 입력) 화면 신규 |
| apps/native/src/features/auth/signup/screens/EmailInputScreen.tsx | 이메일 존재 여부 판단 후 로그인/가입 분기 화면 신규 |
| apps/native/src/features/auth/signup/index.ts | signup 기능 엔트리(export) 추가 |
| apps/native/src/features/auth/login/screens/LoginScreen.tsx | 바텀시트 제거 및 EmailInput으로 네비게이션 전환 |
| apps/native/src/features/auth/login/hooks/useNativeOAuth.ts | 소셜 로그인 성공 시 signup 플로우 진입 처리 추가 |
| apps/native/src/features/auth/login/hooks/useEmailAuth.ts | 바텀시트 기반 이메일 Auth hook 제거 |
| apps/native/src/features/auth/login/hooks/index.ts | useEmailAuth export 제거 |
| apps/native/src/features/auth/login/components/TermsConsentSheet.tsx | 약관 바텀시트 컴포넌트 제거 |
| apps/native/src/features/auth/login/components/EmailAuthSheet.tsx | 이메일 Auth 바텀시트 컴포넌트 제거 |
| apps/native/src/apis/controller/student/auth/postPasswordResetVerifyCode.ts | VerifyCodeRequest 타입으로 수정 |
Comments suppressed due to low confidence (3)
apps/native/src/features/auth/signup/screens/SignupEmailScreen.tsx:57
- 뒤로가기에서
useAuthStore.getState().signOut(); navigation.goBack();를 동기적으로 호출하고 있는데,signOut()은 async라 완료 전에 화면을 pop하고 곧바로 RootNavigator가 리마운트되는 등 네비게이션 레이스가 생길 수 있습니다.await signOut()후에 명시적으로 Login/EmailInput 등으로reset/replace하는 방식으로 흐름을 고정하는 편이 안전합니다.
apps/native/src/features/auth/signup/screens/SignupIdentityScreen.tsx:145 - 주석에 "RootNavigator/StudentNavigator가 step1Completed + isFirstLogin으로 분기"라고 되어 있는데, 현재 분기 로직은
step1Completed/onboardingStatus(및 grade) 기반이고isFirstLogin은 사용되지 않습니다. 실제 동작과 다른 설명이라 이후 유지보수 시 혼동을 줄 수 있으니 주석을 현재 분기 조건에 맞게 수정해주세요.
apps/native/src/features/auth/signup/screens/SignupIdentityScreen.tsx:158 - 뒤로가기 확인에서
useAuthStore.getState().signOut()을 await하지 않고 바로 호출하고 있어, 로그아웃/스토어 reset이 완료되기 전에 네비게이션 컨텍스트가 바뀌면서 레이스/미처리 Promise가 생길 수 있습니다.onPress에서 async 처리로await signOut()을 수행하고, 이후 목적 화면으로reset/replace하는 방식으로 흐름을 고정하는 편이 안전합니다.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| reset: () => set(initialState), | ||
|
|
||
| setCurrentStep: (step) => set({ currentStep: step }), | ||
|
|
||
| setGrade: (grade) => set({ grade }), |
There was a problem hiding this comment.
currentStep을 persist로 저장하지만, 현재 갱신 지점이 setCurrentStep을 호출하는 경우로만 한정되어 있습니다. OnboardingLayout 기본 뒤로가기(navigation.goBack)나 iOS 스와이프-back으로 화면이 바뀌면 currentStep이 동기화되지 않아 앱 종료/재시작 시 잘못된 step으로 복원될 수 있습니다. 화면 focus/route 변경 이벤트에서 currentStep을 업데이트하거나 뒤로가기 handler에서 이전 step을 반영하는 방식으로 동기화를 보완해주세요.
| disabled={isLoading}> | ||
| {isLoading && pendingSocial === 'APPLE' ? ( | ||
| {isLoading ? ( | ||
| <ActivityIndicator size='small' color='white' /> | ||
| ) : ( |
There was a problem hiding this comment.
isLoading이 true이면 이 버튼(그리고 아래의 다른 소셜 버튼들) 모두가 동시에 ActivityIndicator를 렌더링합니다. 실제로는 하나의 provider 로그인만 진행 중인데 여러 버튼이 동시에 로딩처럼 보여 UX 혼란을 유발할 수 있습니다. 현재 시도 중인 provider를 별도 상태로 추적해 해당 버튼에만 스피너를 표시하거나, 공통 로딩 UI로 변경해주세요.
| return ( | ||
| <Stack.Navigator screenOptions={{ headerShown: false }}> | ||
| <Stack.Navigator key={activeScreen.key} screenOptions={{ headerShown: false }}> | ||
| <Stack.Screen name={activeScreen.name} component={activeScreen.component} /> | ||
| </Stack.Navigator> |
There was a problem hiding this comment.
여기서 key={activeScreen.key}를 주고 auth-login↔auth-signup처럼 key를 바꾸면 AuthNavigator가 리마운트되어 스택이 리셋됩니다. 로그인/회원가입 성공 직후에 Auth 스택 안에서 navigation.navigate('SignupEmail'/'SignupTerms') 등을 호출하는 흐름과 충돌해, 화면이 Login으로 되돌아가거나 언마운트된 navigator로 navigate하는 레이스가 발생할 수 있습니다. key 변경은 Auth↔Student 전환에만 쓰거나, AuthNavigator 내부에서 reset/replace로 목적 화면을 명시하는 방식으로 조정해주세요.
| if (data.isFirstLogin) { | ||
| // 기존 회원이지만 STEP 1 미완료 → signup flow로 | ||
| signupStore.setEmail(email); | ||
| startOnboarding(); | ||
| } else { |
There was a problem hiding this comment.
data.isFirstLogin(STEP 1 미완료) 분기에서 signupStore.setEmail/startOnboarding만 수행하고, signup 플로우(약관/본인인증)로의 화면 전환이 없습니다. RootNavigator는 이 상태에서 Auth 스택을 유지하므로 사용자가 다음 단계로 진입하지 못할 수 있습니다. isFirstLogin인 경우 SignupTerms(또는 진행 단계에 맞는 화면)로 navigate/replace/reset을 명시적으로 수행하도록 보완해주세요.
| sessionStatus === 'authenticated' && | ||
| onboardingStatus === 'in-progress' && | ||
| !step1Completed | ||
| ) { | ||
| await useAuthStore.getState().signOut(); |
There was a problem hiding this comment.
앱 재시작 시 authenticated + onboardingStatus === 'in-progress' + !step1Completed이면 강제로 signOut()하고 signup/onboarding 스토어도 reset됩니다. PR 설명의 "앱 재시작 시 진행 단계 복원"과 상충하므로, 재시작 후 STEP 1을 이어갈지/로그아웃할지 정책을 정리한 뒤 조건 및 reset 동작(또는 주석)을 맞춰주세요.
- Replace `isLoading` with `loadingProvider` for more granular control - Use `navigation.reset` for explicit navigation resets in signup flow - Add `useFocusEffect` to onboarding steps for better state management - Simplify `RootNavigator` and `AuthNavigator` logic for route handling
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 37 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
apps/native/src/features/auth/signup/screens/SignupEmailScreen.tsx:41
getEmailExists()는 내부에서{ data }만 반환하고error를 확인하지 않아(HTTP 오류 시에도 throw되지 않음)data가undefined여도 catch로 가지 않고 회원가입 플로우가 진행될 수 있습니다.data === undefined(또는 error 존재)인 경우를 명시적으로 처리해서 사용자에게 오류를 보여주고 다음 단계로 진행하지 않도록 해 주세요.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // STEP 1 미완료 상태에서 앱 재시작 시 → 로그아웃 처리 (로그인 화면에서 시작) | ||
| const onboardingStatus = useOnboardingStore.getState().status; | ||
| const step1Completed = useSignupStore.getState().step1Completed; | ||
| const sessionStatus = useAuthStore.getState().sessionStatus; | ||
|
|
||
| if ( | ||
| sessionStatus === 'authenticated' && | ||
| onboardingStatus === 'in-progress' && | ||
| !step1Completed | ||
| ) { | ||
| await useAuthStore.getState().signOut(); | ||
| } |
There was a problem hiding this comment.
useLoadAssets에서 authenticated && onboardingStatus === 'in-progress' && !step1Completed인 경우 앱 재시작 시 강제 signOut() 처리하고 있는데, PR 설명(#3)처럼 signupStore를 영속화해 재시작 후 진행단계를 복원하려는 목적 및 RootNavigator/AuthNavigator의 'signup 진행 중이면 Auth 스택 유지' 분기와 동작이 충돌합니다. 재시작 후에도 STEP 1 플로우로 복원하려면 이 강제 로그아웃 로직을 제거하거나, 로그아웃 대신 signup 진행 화면으로 라우팅되도록 처리 방향을 정리해 주세요.
| setCurrentStep('MathSubject'); | ||
| navigation.navigate('MathSubject'); | ||
| } | ||
| }, [grade, navigation, setSelectSubject]); |
There was a problem hiding this comment.
handleNext의 useCallback dependency 배열에 setCurrentStep가 포함되어 있지 않습니다. 현재 클로저가 stale해질 수 있고 hook lint에도 걸릴 수 있으니, setCurrentStep를 dependency에 추가하거나(혹은 callback을 useCallback 없이 작성) 의도를 명확히 해 주세요.
| }, [grade, navigation, setSelectSubject]); | |
| }, [grade, navigation, setSelectSubject, setCurrentStep]); |
| setCurrentStep('School'); | ||
| navigation.navigate('School'); | ||
| } | ||
| }, [grade, selectSubject, navigation, setSchoolId]); |
There was a problem hiding this comment.
handleNext의 useCallback dependency 배열에 setCurrentStep가 포함되어 있지 않습니다. 현재는 store action이 안정적일 수 있지만, 훅 규칙/린트 관점에서 누락된 dependency이며 stale 클로저 위험이 있습니다. setCurrentStep를 dependency에 추가해 주세요.
| }, [grade, selectSubject, navigation, setSchoolId]); | |
| }, [grade, selectSubject, navigation, setSchoolId, setCurrentStep]); |
Ensure `setCurrentStep` is included in the dependency array for `useCallback` and improve formatting for `useFocusEffect` across onboarding step components.
📌 Related Issue Number
✅ Key Changes
sessionStatus+step1Completed+onboardingStatus조합으로 Auth/Onboarding/메인 화면 분기 처리VerifyCodeRequest타입 사용)typo-*)으로 통일