Step 3 Auth Profile 도메인 테크 스펙(Authentication & Authorization) - 100-hours-a-week/16-team-katopia-fe GitHub Wiki
Auth + Profile 도메인 테크 스펙(Authentication & Authorization)
배경(Background)
프로젝트 목표(Objective)
- 사용자가 서비스 진입 시 로그인/회원가입(OAuth) 과정을 빠르고 안정적으로 완료할 수 있도록 하여 메인기능으로의 진입 장벽을 최소화한다.
- 인증 상태를 일관되게 관리하여 보안성, UX 안정성, 개발 생산성을 동시에 확보한다.
- OAuth 인증 이후 필수 사용자 정보를 빠르고 명확하게 수집하여 서비스의 핵심 기능 사용이 가능한 상태로 전환된다.
- 회원가입 과정에서 발생할 수 있는 이탈을 최소화하기 위해 단일 화면 기반, 명확한 유효성 검증, 실패 복구 가능한 플로우를 제공한다.
핵심 결과(Key Results)
- KR1 : 로그인 페이지 진입 → 인증 완료까지 평균 소요시간 20% 단축
- KR2: OAuth 로그인 실패율 5% 이하 유지
- KR3: 인증 관련 공통 로직 재사용률 80% 이상 확보(Hook, Store 기준)
- KR4: OAuth 로그인(PENDING) → 프로필 설정 완료까지 평균 완료율 90% 이상
- KR5: 프로필 입력 유효성 오류 발생 시 사용자 즉시 인지율 100%
문제정의(Problem)
- 인증 로직 분석 문제
- 로그인, 토큰 저장, 사용자 정보 조회 로직이 여러 컴포넌트에 흩어질 경우 유지보수 비용 증가
- 인증 상태 불명확
- 새로고침 또는 직접 URL 접근 시 로그인 여부 판별이 늦어 UX 저하 가능
- OAuth 예외 케이스 다수
- 인증 취소, 코드 만료, 서버 오류 등 다양한 실패 시나리오 존재
- 인가 처리의 복잡성
- 비로그인 사용자 접근 제한이 필요한 페이지가 다수 존재
- OAuth 인증만으로는 서비스 이용 불가
- 닉네임, 신체 정보 등 서비스 핵심 도메인에 필요한 정보가 누락됨.
- 프로필 입력 단계에서 이탈 가능성
- 입력 항목 과다
- 실패 시 어디서 잘못됐는지 인지하기 어려움.
목표가 아닌 것(Non- goals)
- ID / Password 기반 로그인 기능 : 본 프로젝트는 OAuth 기반 인증 흐름을 전제로 설계되었다. 자체 계정 생성, 비밀번호 암호화 및 재설정 플로우는 보안 정책 및 설계 범위가 커지므로 이번 범위에서는 제외한다.
- 다중 OAuth Provider(구글, 네이버 등) 지원 : 향후 확장 가능성을 고려한 구조는 설계에 반영하되, 실제 구현 범위는 단인 OAuth Provider로 제한한다.
- 계정 연동/해제 및 계정 병합 기능 : 서로 다른 인증 수단 간 계정 병합, 연동 해제 로직은 사용자 데이터 정합성과 보안이슈가 복잡하게 얽혀있어 후속 과제로 분리한다.
- 프로필 다중 수정 플로우 : 마이페이지에서의 프로필 수정은 별도 도메인으로 분리
- 소셜 프로필 자동 완성 : OAuth Provider에서 제공하는 정보 자동 매핑은 이번 범위에서 제외
- 프로필 공개 범위 설정: 공개/비공개, 차단 등은 후속 과제로 분리
설계 및 기술 자료 (Architecture and Technical Documentation)
아키텍처 개요(Architecture Overview)
- 프레임워크/라이브러리: React (v19) + Next.js (v16, App Router) - App Router Layout을 활용해 인증/비인증 영역을 분리하고 서버/클라이언트 리다이렉트 기준을 일관되게 관리한다.
- 상태 관리 (State Management): Zustand - 보일러플레이트가 적고 예측 가능한 방식으로 인증 상태 및 세션 정보를 전역에서 관리한다.
- 스타일링: Tailwind CSS - 유틸리티 클래스 기반 스타일링을 통해 인증 UI의 빠른 개발과 일관된 반응형 대응을 보장한다.
- 폼(Form) 관리: React Hook Form + Zod - 프로필 설정 등의 복합 폼 상태 관리 및 런타임 스키마 검증을 효율화한다.
- 데이터 페칭 (Data Fetching): Tanstack Query v5 - 서버 데이터를 SSOT(Single Source of Truth)로 취급하며, 인증이 유효한 경우에만 사용자 정보를 캐싱하고 관리한다.
- 인증 방식: OAuth 2.0 (Authorization Code Flow) - 프론트엔드는 Access Token 사용 및 인증 상태 제어에 집중하며, 토큰 재발급 로직은 백엔드와 연동한다.
- SSR/CSR/ISR/SSG 적용 범위
/home(로그인 바텀시트) : CSR → 로그인 유도 바텀시트 제어는 CSR에서 수행/auth/callback: CSR → 사용자 인터랙션 없이 OAuth 토큰 교환 및 전역 상태(authStore) 초기화 로직이 중심이 되는 페이지이므로 CSR 기반으로 처리/profile/setup: CSR → OAuth 인증 성공 후 진입하는 온보딩 페이지로, 여러 단계의 폼 입력과 클라이언트 측 상태 누적이 중요하므로 CSR 기반으로 설계/mypage/profile: CSR → 개인화된 데이터의 정합성이 중요하므로authStore의 인증 상태를 확인한 후 데이터를 호출하는 CSR 방식이 적합/mypage/profile/edit: CSR → 실시간 유효성 검증과dirtyFields체크 등 동적인 상호작용이 많아 CSR 위주로 동작
주요 페이지 / 컴포넌트 구조
페이지(Pages)
-
/home: 홈페이지(로그인 유도 바텀시트 포함)- 주요 기능
- 홈 피드 기본 레이아웃 및 일부 콘텐츠 렌더링
- 비로그인 사용자 접근 허용 범위내 콘텐츠 표시
- 인증이 필요한 사용자 액션 발생 시 로그인 유도 바텀시트 노출
- 로그인 완료 후 바텀시트 자동 닫힘 및 홈 UI 상태 갱신
- 사용 컴포넌트
LoginRequiredBottomSheet(로그인 필요 안내 바텀시트)OAuthLoginButton(카카오 OAuth 로그인 버튼)
- 데이터 로딩 시점
- 페이지 진입 시
- 홈 피드 프리뷰 데이터 로딩(비로그인 사용자 허용 범위)
- 로그인 유도 바텀시트 자체는 API 호출 없이 UI만 렌더링
- 페이지 진입 시
- 라우팅
- 홈페이지 유지(URL 변경 없음)
- OAuth 로그인 버튼 클릭 시에만 외부 인증 플로우 진입
- 접근 제어
- 비로그인 사용자(isAuthenticated == false)가 인증이 필요한 액션(좋아요, 댓글, 북마트 등)을 시도할 경우 → 페이지 이동 없이 로그인 유도 바텀시트 노출
- 로그인 완료 후
- 동일 페이지에서만 상태 갱신
- 주요 기능
-
/auth/callback: OAuth 콜백 처리 페이지-
주요 기능
- OAuth Provider로부터 전달된 Authorization Code 수신
- 백엔드 소셜 로그인 API 호출을 통한 인증 처리
- Access Token 발급 및 저장
- 사용자 상태(PENDING / ACTIVE)에 따른 분기 처리
-
사용 컴포넌트
- 별도의 UI 컴포넌트 없음.
-
데이터 로딩 시점
- 페이지 진입 즉시 다음 비동기 로직 실행
- Authorization Code 파싱
- 소셜 로그인 API 호출
- Access Token 저장
- 사용자 상태 분기 처리
- 페이지 진입 즉시 다음 비동기 로직 실행
-
라우팅
- 신규 사용자 (status === PENDING)
/profile/setup
- 기존 사용자 (status === ACTIVE)
/home(로그인 바텀시트)
- 신규 사용자 (status === PENDING)
-
에러 처리 / 엣지 케이스
- Authorization Code 누락
- 로그인 API 실패
- 탈퇴 후 재가입 유예 상태(403)
→ 인증 상태 초기화 후 홈으로 이동 및 로그인 유도 바텀시트 노출
-
-
/profile/setup: 프로필 설정 페이지- 주요 기능
- 프로필 이미지 업로드 및 미리보기
- 닉네임 입력
- 키,몸무게 입력
- 성별 선택
- 입력값 실시간 유효성 검증
- 프로필 저장 API 호출
- 저장 성공 시 사용자 상태 ACTIVE 전환
- 저장 실패 시 입력값 유지 및 재시도 가능
- 페이지 구성
- Step 기반 단일 페이지
- Step 1: 기본 프로필 정보 입력
- 프로필 이미지
- 닉네임 + 중복 확인
- Step 2 : 추가 개인정보 입력
- 성별 / 키 / 몸무게
- 선호 스타일
- 약관 동의
- Step 1: 기본 프로필 정보 입력
- Step 기반 단일 페이지
- 사용 컴포넌트
ProfileSetupLayout- 진행 단계 표시(Progress Indicator)
ProfileImageUploaderNicknameInputNicknameCheckButtonGenderSelectorBodyInfoInput(키 / 몸무게)StylePreferenceSelectorTermsAgreementProfileSubmitButton
- 페이지 로딩 시점
- 페이지 진입 시
- OAuth 로그인 직후 전달된 인증 상태(
authStore) 확인 - 사용자 상태가
PENDING인 경우에만 접근 허용
- OAuth 로그인 직후 전달된 인증 상태(
- 초기 데이터
- 서버 데이터 사전 로딩 없음
- 모든 입력 데이터는 클라이언트 입력 기반
- 페이지 진입 시
- API 호출 시점
- 닉네임 중복 확인
- GET /api/members/nickname/check
- 호출 시점: 닉네임 입력 후 “중복 확인” 버튼 클릭
- 프로필 저장
- POST /api/members/profile
- 호출 시점: Step 2에서 “회원가입” 버튼 클릭
- 닉네임 중복 확인
- 접근제어
- 비로그인 사용자 접근 안됨.
- /home으로 리다이렉트 후 로그인 유도
- 로그인 상태이나 ACTIVE 사용자 접근 안됨.
- /home으로 리다이렉트
- PENDING 사용자만 접근가능
- 비로그인 사용자 접근 안됨.
- 상태 초기화 / 전환
- 프로필 저장 성공 시
- 사용자 상태 ACTIVE로 변경
- authStore 인증 상태 유지
- 서버 기준 사용자 정보 갱신
- 실패 시
- 입력 데이터 유지
- 상태 초기화 안됨.
- 프로필 저장 성공 시
- 에러 처리 / 엣지 케이스
- 필수 입력값 누락: 헬퍼텍스트 표시
- 닉네임 중복: 중복 확인 실패 메시지 노출
- 프로필 저장 API 실패: 토스트 메시지 표시 & 재시도 가능
- 네트워크 오류: 입력값 유지 + 재시도 유도
- 주요 기능
-
/mypage/profile: 내 프로필 조회 / 수정 진입 페이지- 주요 기능
- 로그인 사용자 프로필 정보 조회
- 현재 계정 상태 표시 (ACTIVE)
- 프로필 수정 페이지로 이동
- 로그아웃 트리거 제공
- 회원탈퇴 진입 버튼 제공
- 사용 컴포넌트
ProfileSummaryCardEditProfileButtonLogoutButtonWithdrawAccountButton
- 데이터 로딩 시점
- 페이지 진입 시
GET /api/members/{id}호출- TanStack Query 기반 사용자 정보 조회
- 라우팅
/mypage/profile/mypage/profile/edit(프로필 수정)- 로그아웃 (페이지 이동 없음)
/mypage/profile/withdraw(회원탈퇴 확인)
- 접근 제어
- 비로그인 사용자 접근 불가:
/home리다이렉트 + 로그인 바텀시트 노출 - 로그인 상태 +
ACTIVE사용자만 접근 가능
- 비로그인 사용자 접근 불가:
- 주요 기능
/mypage/profile/edit: 프로필 수정 페이지- 주요 기능
- 기존 사용자 프로필 정보 프리필(pre-fill)
- 닉네임 수정 + 중복 확인
- 프로필 이미지 변경
- 신체 정보 수정
- 스타일 선호 정보 수정
- 수정 완료 시 서버 반영
- 사용 컴포넌트
ProfileEditLayoutProfileImageUploaderNicknameInputNicknameCheckButtonGenderSelectorBodyInfoInputStylePreferenceSelectorProfileSaveButton
- 데이터 로딩 시점
- 페이지 진입 시
GET /api/members/{id}결과를 기반으로profileEditStore초기값 세팅
- 페이지 진입 시
- API 호출 시점
- 프로필 저장
PATCH /api/members/{id}- 호출 시점: “저장” 버튼 클릭
- 프로필 저장
- 라우팅
- 저장 성공 시 :
/mypage/profile이동 - 취소 시 :
/mypage/profile이동 (상태 초기화)
- 저장 성공 시 :
- 상태 초기화
- 저장 성공 시 :
profileEditStore.reset() - 사용자 정보 Query 무효화
- 저장 성공 시 :
- 주요 기능
주요 컴포넌트
-
LoginRequiredBottomSheet: 로그인 바텀 시트 컴포넌트개요
-
역할
- 비로그인 사용자가 인증이 필요한 기능을 시도했을 때 로그인 필요 상태를 안내하는 바텀시트 컴포넌트
-
책임
- 로그인 필요 UI 제공
- OAuth 로그인 진입 트리거 제공
- 인증 로직 자체는 포함하지 않음
-
디자인 시안
- 화면 하단에서 슬라이드 업 형태로 노출
- 구성 요소
- 제목 : “로그인이 필요합니다.”
- 서브 문구 : “패션에 진심인 SNS에 참여하세요.”
OAuthLoginButton- 에러 토스트 메세지 : “로그인 실패, 잠시 후 다시 이용해주세요.”
-
Props & Interface
interface LoginRequiredBottomSheetProps { isOpen: boolean; onClose: () => void; }isOpen(required) : 바텀시트 노출 여부onClose(required) : 외부 영역 클릭 또는 제스처로 바텀시트 닫기
-
내부 상태 & 이벤트
- 상태 제어는 상위(Home 페이지 또는 UI Store)에서 관리
- 이벤트 흐름
- OAuth 버튼 클릭 → OAuth 인증 플로우 진입
- 바텀시트 외부 클릭 →
onClose호출
-
에러 처리 / 엣지 케이스
- OAuth 인증 실패 후 홈 복귀 시 & 네트워크 오류로 OAuth 진입 실패 시
- 바텀시트 재노출
- 토스트 메시지 표시
- OAuth 인증 실패 후 홈 복귀 시 & 네트워크 오류로 OAuth 진입 실패 시
-
스타일링
- Tailwind CSS 사용
- 모바일 UX 고려: Safe Area 대응, 드래그/스크롤 충돌 방지 , 슬라이드 애니메이션 적용
-
Storybook
- Closed: 기본 홈 상태
- Open: 로그인 유도 바텀시트 노출 상태
- Mobile Viewport: 모바일 환경 기준 UI 확인
-
-
OAuthLoginButton: OAuth 로그인 버튼 컴포넌트개요(Overview)
-
역할
- OAuth 인증을 시작하는 버튼 컴포넌트
-
책임
- OAuth 인증 URL로의 리다이렉트만 담당
- 인증 이후 처리 로직은 포함하지 않음
-
props & Interface
interface OAuthLoginButtonProps { provider: 'kakao'; } -
내부 상태 & 이벤트
const OAUTH_LOGIN_URL = `${process.env.NEXT_PUBLIC_API_BASE_URL}/oauth/kakao`; window.location.href =OAUTH_LOGIN_URL;- OAuth URL은 환경 변수 또는
auth.config.ts에서 관리
- OAuth URL은 환경 변수 또는
-
에러 처리 / 엣지 케이스
- 브라우저 리다이렉트 실패 시: 토스트 메시지 노출
- OAuth Provider 장애는
/auth/callback단계에서 공통 처리
-
-
ProfileSetupLayout: 프로필 설정 레이아웃개요(Overview)
-
역할
- 프로필 설정 페이지 전체 레이아웃을 담당
- 현재 진행 단계를 시각적으로 표시
- 하위 입력 컴포넌트를 공통 레이아웃 안에서 렌더링
-
디자인 시안
- 상단 Progress Bar 형태
- 프로필 설정(1/2), 추가 정보 입력(2/2) 표시
-
props & Interface
interface ProfileSetupLayoutProps { currentStep: 1 | 2; children: React.ReactNode; }currentStep(required): 현재 진행 중인 단계children(required) : 각 Step별 콘텐츠
-
스타일링
- TailwindCSS로 모바일 우선 레이아웃
- Progress Bar는 width 비율로 단계 표현
-
-
ProfileImageUploader: 프로필 이미지 업로드 컴포넌트개요(Overview)
-
역할: 사용자 프로필 이미지를 업로드하고 미리보기를 제공, 이미지 파일 유효성 검증 수행
-
디자인 시안
- 원형 이미지 영역 “+” 버튼
- 최대 용량 안내 텍스트 표시
-
props & Interface
interface ProfileImageUploaderProps { value?: File | null; onChange: (file: File | null) => void; } -
내부 상태 & 이벤트
- 이미지 미리보기 URL
- 파일 선택 → onChange(file) 호출
-
에러 처리 / 엣지 케이스
- 파일 용량 초과 (예) 5MB 초과)
- 이미지 타입이 아닌 파일 업로드
- 에러 시 하단 인라인 메시지 표시
-
스타일링 : 원형 이미지 Crop UI
-
NicknameInput: 닉네임 입력 컴포넌트NicknameCheckButton: 닉네임 중복 확인 버튼 컴포넌트GenderSelector: 성별 선택(단일 선택)BodyInfoInput: 키, 몸무게 입력( 숫자 입력만 허용, 단위 고정 표시(cm, kg) )StylePreferenceSelector: 선호 스타일 다중 선택(최대 2개)
-
TermsAgreement: 약관동의 컴포넌트개요(Overview)
-
역할
- 회원가입 및 프로필 설정 과정에서 이용약관, 개인정보 수집/이용 동의 등 약관 종의 항목을 체크박스 형태로 제공
- 필수 약관 동의 여부를 상위 페이지에서 판단할 수 있도록 상태를 전달
-
디자인 시안
- 약관 항목 리스트 + 체크 박스 UI
- 약관 제목 클릭 시 전문 확인 가능 (모달 또는 새 화면)
- 필수 항목은 * 또는 강조 스타일로 구분
-
props & Interface
interface TermsAgreementProps { terms: { id: string; title: string; contentUrl: string; // 약관 전문 링크 required: boolean; }[]; onAgreeChange: (agreedIds: string[]) => void; }- terms(required)
- 화면에 표시할 약관 목록
- 각 약관은 고유 id를 가지며, 필수/선택 여부를 포함
- onAgreeChange(required)
- 사용자가 체크 박스를 변경할 때 마다 호출
- 현재 동의된 약간 id 목록을 상위 컴포넌트로 전달
- terms(required)
-
내부 상태 & 이벤트
- 내부 상태
- agreeIds : string[]
- 현재 사용자가 동의한 약관 id 목록
- 이벤트 흐름
- 체크 박스 클릭
- agreeIds 업데이트
- onAgreeChange(agreeIds) 호출
- 약관 제목 클릭 시
- contentUrl을 기준으로 약관 전문 UI 노출
- 내부 상태
-
에러처리/엣지 케이스
- 필수 약관 미동의 상태: 버튼 비활성화 또는 제출 시 상위 페이지에서 에러 메시지 표시
- 약관 목록이 비어 있는 경우 : 컴포넌트 렌더링 생략 또는 경고 로그 출력
- 약관 전문 로딩 실패: 토스트 또는 인라인 에러 메시지 표시
-
스타일링
- tailwind CSS 사용
- 체크박스 영역 터치 영역 확대(모바일 UX 고려)
- 약관 전문은 Lazy Loading 적용 가능
-
StoryBook
- Only Required Terms : 필수 약관만 존재하는 경우
- Required + Optional Mixed : 필수 + 선택 약관 혼합
- Unchecked Required : 필수 미동의 상태
- All checked : 모든 약관 동의 완료 상태
-
ProfileSubmitButton: 프로필 설정 버튼 컴포넌트LogoutButton: 로그아웃 버튼 컴포넌트
-
WithdrawAccountButton: 회원탈퇴 버튼 컴포넌트개요(Overview)
-
역할
- 회원탈퇴 최종 실행 트리거
-
책임
- 사용자 의도 명확화 이후 API 호출
-
Props & Interface
interface WithdrawAccountButtonProps { disabled: boolean; isLoading?: boolean; onWithdraw: () => void; } -
내부 이벤트 흐름
- 모달창 확인
- 탈퇴 확인 버튼 클릭 시
DELETE /api/members호출
-
에러 처리 / 엣지 케이스
- API 실패: 인증 상태 유지, 재시도 가능
- 탈퇴 성공: 모든 상태 초기화, Query Cache clear
-
컴포넌트 간 관계
- HomePage: 인증 상태 확인, 인증 필요 액션 발생 시
LoginRequiredBottomSheet노출 LoginRequiredBottomSheet:OAuthLoginButton포함- 로그인 성공 후
- 인증 상태 업데이트
- 바텀 시트 닫힘
- 홈 UI 정상 상태로 전환
상태 관리 전략 (State Management Strategy)
- Global UI State(Zustand)
authStore: 인증 및 세션 제어- 관리 대상 : 로그인 여부, Access Token, 사용자 식별자.
- 상태 전이 흐름
- 로그인 성공 : OAuth 콜백 완료 시 setAuth() 호출 → 인증 상태 활성화
- 보호된 요청 : API 호출 시 메모리 내 토큰 참조.
- 인증 만료 / 로그아웃 :
clearAuth()호출 → 모든 전역 스토어 초기화 및/login리다이렉트.
profileSetupStore&profileEditStore: 데이터 누적 및 편집- 관리 대상 : 닉네임, 성별, 신체 정보, 스타일 선호도, 약관 동의
- 상태 전이 흐름
- Setup :
/profile/setup진입 시 초기화 → 각 단계(Step) 입력마다 액션(setNickname등)으로 상태 누적 → 최종 제출 성공 시reset()호출. - Edit : 기존 멤버 정보 조회(Server Cache) →
hydrateFromMember()를 통해 스토어에 복사 → 수정 중dirtyFields체크 → 저장 성공 시 캐시 무효화 및 스토어 초기화.
- Setup :
- Server Cache State(Tanstack v5)
- 대상 API :
GET /api/members/{id}(사용자 프로필 상세 정보). - 관리 정책
- 명시적 조회 :
authStore의memberId가 존재하고 인증된 경우에만 활성화(enabled). - 동기화 타이밍 : 프로필 설정 완료, 정보 수정, 알림 설정 변경 등 서버 데이터가 변하는 액션 직후
invalidateQueries(['member', memberId])를 실행하여 항상 최신 상태를 유지한다. - 데이터 검증 : Zod 스키마를 통해 API 응답 형식을 런타임에서 검증하여 신뢰할 수 있는 데이터만 UI에 전달한다.
- 명시적 조회 :
- 대상 API :
- Local State(React
useState/useReducer)useState활용(단순 토글 및 독립 상태)CommonModal: 모달의 열림/닫힘 애니메이션 상태.PasswordVisibillity: 비밀번호 표시/숨김 토글.
useReducer활용(복합 로직 및 연관 상태)ProfileImageUploader: 이미지 업로드 흐름 관리- 상태 :
status(LOADING, SUCCESS, ERROR),previewUrl,errorMsg - 이점 : ‘업로드 시작’ 액션 하나로 status를 LOADING으로 바꾸고 기존
errorMsg를 초기화하는 로직 처리가 가능하다.
- 상태 :
NicknameInput: 복합 유효성 검사 및 포커스 관리.- 상태 :
inputValue,isFocused,validationStatus(NONE, PENDING, VALID, INVALID) - 이점 : 사용자가 입력을 시작하면 즉시 validationStatus를 PENDING으로 돌리는 등 복잡한 UI 피드백 로직을 reducer 한 곳에서 통제한다.
- 상태 :
API 연동 (API Integration)
호출할 백엔드 API 목록
- Auth Domain
GET /api/members/{id}: 로그인 사용자 정보 조회POST /api/auth/tokens: Access Token 재발급(OAuth Redirect) 소셜 로그인 제공 경로: OAuth 인증 수행POST /api/auth/logout: 로그아웃
- Profile Domain
POST /api/members: 프로필 설정PATCH /api/members/{id}: 사용자 프로필 수정DELETE /api/members/{id}: 회원 탈퇴GET /api/members/nickname/check: 닉네임 중복확인
API 호출 처리 방식
GET /api/members/{id}- 호출 시점 : 앱 초기 진입 시 또는 로그인 성공 직후 사용자 정보를 확인할 때
- 상태 및 캐시 반영 :
useQuery로 관리하며 받아온 데이터는authStore의user정보를 업데이트 하는 데 사용된다.
POST /api/auth/tokens- 호출 시점 : Axios 인터셉터에서 401 에러 감지 시 또는 토큰 만료 전 자동 갱신 시
- 상태 및 캐시 반영 : 새롭게 발급된 Access Token을
authStore의 메모리 상태에 저장하여 이후 요청의 Bearer 헤더에 반영한다.
POST /api/auth/logout- 호출 시점 : 프로필 페이지의 '로그아웃' 버튼 클릭 시
- 상태 및 캐시 반영 : 성공 시
authStore.clearAuth()를 호출하여 클라이언트 세션을 종료하고,queryClient.clear()로 모든 사용자 캐시를 즉시 제거한다.
POST /api/members- 호출 시점 :
/profile/setup페이지에서 모든 정보 입력 후 '완료' 버튼 클릭 시 - 상태 및 캐시 반영 : 성공 시
invalidateQueries(['member', id])를 수행하여 최신 프로필 정보를 가져오고,profileSetupStore를 초기화한다.
- 호출 시점 :
PATCH /api/members/{id}- 호출 시점 : 프로필 수정 페이지에서 정보 변경 후 '저장' 버튼 클릭 시
- 상태 및 캐시 반영 :
useMutation성공 시invalidateQueries(['member', id])를 호출하여 캐시를 동기화하고, 변경된 정보를 전역 사용자 상태에 반영한다.
DELETE /api/members/{id}- 호출 시점 : 회원 탈퇴 확인 모달에서 '탈퇴하기' 버튼을 최종 클릭할 때
- 상태 및 캐시 반영 : 성공 시 로그아웃과 동일하게 모든 인증 상태와 캐시를 제거한 뒤, 메인 화면 또는 안내 페이지로 리다이렉트한다.
GET /api/members/nickname/check- 호출 시점 : 닉네임 입력 필드 옆 '중복 확인' 버튼 클릭 시
- 상태 및 캐시 반영 : 응답 결과(사용 가능 여부)를
profileSetupStore또는 로컬 상태의isNicknameChecked값에 반영하여 폼 제출 활성화 여부를 결정한다.
- 로딩 인디케이터
- 최소 프로필 로딩 시에는 Skeleton UI를 노출하여 레이아웃 무너짐을 방지한다.
- 수정/탈퇴/중복 확인 등 버튼 액션 시에는 버튼 내 Spinner를 노출하고 중복 클릭을 차단한다.
- 에러 핸들링
- API 오류 발생 시 사용자가 이해하기 쉬운 메시지로 매핑하여 Toast 또는 필드 하단 헬퍼 텍스트로 안내한다.
- 401 에러 시에는 토큰 재발급 로직을 수행하고, 실패 시 로그인 바텀시트를 노출하는 전역 정책을 적용한다.
라우팅
- Next.js App Router (File-based Routing) 사용: 모든 인증 및 프로필 관련 경로는 App Router 구조를 따르며, 폴더 기반 라우팅을 통해 경로를 정의한다.
- 온보딩 및 단계별 이동: 프로필 설정(
/profile/setup) 등 여러 단계로 구성된 온보딩 과정 내 이동은 Client-side Navigation을 활용하여 사용자 입력 상태를 유지하며 자연스럽게 전환한다. - 보호된 경로 접근 제어 (Authorization Guard):
- Middleware/Layout 활용:
/profile/setup,/mypage/profile/edit,/vote등 인가가 필요한 페이지는 서버 사이드 미들웨어 또는 레이아웃 단계에서 인증 상태를 확인한다. - 리다이렉트 정책: 비로그인 사용자가 보호된 페이지에 접근할 경우 즉시
/login페이지로 리다이렉트하며, 로그인 성공 후 원래 목적지로 돌아올 수 있도록callbackUrl을 관리한다.
- Middleware/Layout 활용:
- 공통 네비게이션 바 연동: 하단 탭 바(Home, Search, +, Vote, Profile)를 통해 페이지 간 이동을 제어하며, 현재 경로에 맞는 활성 상태(Active State)를 시각적으로 표시한다.
폼 처리 및 유효성 검증 (Forms & Validation)
표준 폼 관리 (React Hook Form)
- 프로필 설정 및 수정 폼의 상태 관리와 유효성 검증을 위해
React Hook Form을 표준으로 채택한다. ProfileSetupPage와 같은 각 페이지 최상단에서useForm()을 선언하여 전체 폼 상태를 제어한다.- 컴포넌트 분리:
NicknameInput,BodyInfoForm등 복잡한 입력 영역은 별도 컴포넌트로 분리하고useFormContext()또는Controller를 활용하여 결합도를 낮춘다.
유효성 검증 로직 (Zod Schema)
- 클라이언트 측:
Zod를 사용하여 닉네임 형식, 키/몸무게 숫자 범위, 필수 약관 동의 여부 등을 스키마 형태로 정의하고resolver를 통해 적용한다. - 제출 시 검증:
handleSubmit호출 시 폼 전체 필드에 대해 동시 검증을 수행하며, 유효하지 않은 필드가 있을 경우 첫 번째 에러 위치로 포커스를 이동시킨다.
서버 에러 매핑 및 처리
- 백엔드 검증 연동: 서버로 전송된 데이터가 유효하지 않을 경우(예: 이미 사용 중인 닉네임, 유효하지 않은 토큰 등) 응답받은 API 에러(4xx)를 처리한다.
- 프론트엔드 반영: 서버 에러를
setError메서드를 통해 특정 폼 필드 에러로 매핑하여 "이미 사용 중인 닉네임입니다"와 같은 메시지를 노출하거나 전역 토스트 알림으로 표시한다.
실시간 유효성 검증:
- 사용 시점: 사용자 경험을 위해
onBlur또는onChange시점에 실시간 검증을 수행한다.
용어 정의 (Glossary)
- OAuth 2.0: 제3자 인증을 위한 표준 인증 프로토콜
- Access Token: API 인증에 사용되는 토큰
- Refresh Token (RT): AT 재발급을 위한 토큰 (HttpOnly Cookie)
- Authorization Code Flow: OAuth 인증 방식 중 하나
- PENDING: OAuth 인증은 완료되었으나 프로필 설정이 완료되지 않은 상태
- ACTIVE: 프로필 설정이 완료되어 서비스 이용이 가능한 상태
- 유틸리티 클래스 기반 스타일링 : 하나의 속성만 담당하는 아주 작은 단위의 클래스들을 조합하여 스타일을 완성하는 방식
- 프리필(pre-fill) : 입력창에 값을 미리 채워두는 기능