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 컴포넌트 없음.
    • 데이터 로딩 시점

      • 페이지 진입 즉시 다음 비동기 로직 실행
        1. Authorization Code 파싱
        2. 소셜 로그인 API 호출
        3. Access Token 저장
        4. 사용자 상태 분기 처리
    • 라우팅

      • 신규 사용자 (status === PENDING)
        • /profile/setup
      • 기존 사용자 (status === ACTIVE)
        • /home (로그인 바텀시트)
    • 에러 처리 / 엣지 케이스

      • Authorization Code 누락
      • 로그인 API 실패
      • 탈퇴 후 재가입 유예 상태(403)

      → 인증 상태 초기화 후 홈으로 이동 및 로그인 유도 바텀시트 노출

  • /profile/setup : 프로필 설정 페이지

    • 주요 기능
      • 프로필 이미지 업로드 및 미리보기
      • 닉네임 입력
      • 키,몸무게 입력
      • 성별 선택
      • 입력값 실시간 유효성 검증
      • 프로필 저장 API 호출
      • 저장 성공 시 사용자 상태 ACTIVE 전환
      • 저장 실패 시 입력값 유지 및 재시도 가능
    • 페이지 구성
      • Step 기반 단일 페이지
        • Step 1: 기본 프로필 정보 입력
          • 프로필 이미지
          • 닉네임 + 중복 확인
        • Step 2 : 추가 개인정보 입력
          • 성별 / 키 / 몸무게
          • 선호 스타일
          • 약관 동의
    • 사용 컴포넌트
      • ProfileSetupLayout
        • 진행 단계 표시(Progress Indicator)
      • ProfileImageUploader
      • NicknameInput
      • NicknameCheckButton
      • GenderSelector
      • BodyInfoInput (키 / 몸무게)
      • StylePreferenceSelector
      • TermsAgreement
      • ProfileSubmitButton
    • 페이지 로딩 시점
      • 페이지 진입 시
        • OAuth 로그인 직후 전달된 인증 상태(authStore) 확인
        • 사용자 상태가 PENDING 인 경우에만 접근 허용
      • 초기 데이터
        • 서버 데이터 사전 로딩 없음
        • 모든 입력 데이터는 클라이언트 입력 기반
    • API 호출 시점
      • 닉네임 중복 확인
        • GET /api/members/nickname/check
        • 호출 시점: 닉네임 입력 후 “중복 확인” 버튼 클릭
      • 프로필 저장
        • POST /api/members/profile
        • 호출 시점: Step 2에서 “회원가입” 버튼 클릭
    • 접근제어
      • 비로그인 사용자 접근 안됨.
        • /home으로 리다이렉트 후 로그인 유도
      • 로그인 상태이나 ACTIVE 사용자 접근 안됨.
        • /home으로 리다이렉트
      • PENDING 사용자만 접근가능
    • 상태 초기화 / 전환
      • 프로필 저장 성공 시
        • 사용자 상태 ACTIVE로 변경
        • authStore 인증 상태 유지
        • 서버 기준 사용자 정보 갱신
      • 실패 시
        • 입력 데이터 유지
        • 상태 초기화 안됨.
    • 에러 처리 / 엣지 케이스
      • 필수 입력값 누락: 헬퍼텍스트 표시
      • 닉네임 중복: 중복 확인 실패 메시지 노출
      • 프로필 저장 API 실패: 토스트 메시지 표시 & 재시도 가능
      • 네트워크 오류: 입력값 유지 + 재시도 유도
  • /mypage/profile : 내 프로필 조회 / 수정 진입 페이지

    • 주요 기능
      • 로그인 사용자 프로필 정보 조회
      • 현재 계정 상태 표시 (ACTIVE)
      • 프로필 수정 페이지로 이동
      • 로그아웃 트리거 제공
      • 회원탈퇴 진입 버튼 제공
    • 사용 컴포넌트
      • ProfileSummaryCard
      • EditProfileButton
      • LogoutButton
      • WithdrawAccountButton
    • 데이터 로딩 시점
      • 페이지 진입 시
      • GET /api/members/{id} 호출
      • TanStack Query 기반 사용자 정보 조회
    • 라우팅
      • /mypage/profile
        • /mypage/profile/edit (프로필 수정)
        • 로그아웃 (페이지 이동 없음)
        • /mypage/profile/withdraw (회원탈퇴 확인)
    • 접근 제어
      • 비로그인 사용자 접근 불가: /home 리다이렉트 + 로그인 바텀시트 노출
      • 로그인 상태 + ACTIVE 사용자만 접근 가능

  • /mypage/profile/edit : 프로필 수정 페이지
    • 주요 기능
      • 기존 사용자 프로필 정보 프리필(pre-fill)
      • 닉네임 수정 + 중복 확인
      • 프로필 이미지 변경
      • 신체 정보 수정
      • 스타일 선호 정보 수정
      • 수정 완료 시 서버 반영
    • 사용 컴포넌트
      • ProfileEditLayout
      • ProfileImageUploader
      • NicknameInput
      • NicknameCheckButton
      • GenderSelector
      • BodyInfoInput
      • StylePreferenceSelector
      • ProfileSaveButton
    • 데이터 로딩 시점
      • 페이지 진입 시
        • 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 진입 실패 시
        • 바텀시트 재노출
        • 토스트 메시지 표시
    • 스타일링

      • 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 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 목록을 상위 컴포넌트로 전달
    • 내부 상태 & 이벤트

      • 내부 상태
        • agreeIds : string[]
        • 현재 사용자가 동의한 약관 id 목록
      • 이벤트 흐름
        1. 체크 박스 클릭
        2. agreeIds 업데이트
        3. 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;
      }
      
    • 내부 이벤트 흐름

      1. 모달창 확인
      2. 탈퇴 확인 버튼 클릭 시 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 체크 → 저장 성공 시 캐시 무효화 및 스토어 초기화.
  • Server Cache State(Tanstack v5)
    • 대상 API : GET /api/members/{id} (사용자 프로필 상세 정보).
    • 관리 정책
      • 명시적 조회 : authStorememberId가 존재하고 인증된 경우에만 활성화(enabled).
      • 동기화 타이밍 : 프로필 설정 완료, 정보 수정, 알림 설정 변경 등 서버 데이터가 변하는 액션 직후 invalidateQueries(['member', memberId])를 실행하여 항상 최신 상태를 유지한다.
      • 데이터 검증 : Zod 스키마를 통해 API 응답 형식을 런타임에서 검증하여 신뢰할 수 있는 데이터만 UI에 전달한다.
  • 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 로 관리하며 받아온 데이터는 authStoreuser 정보를 업데이트 하는 데 사용된다.
  • 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을 관리한다.
  • 공통 네비게이션 바 연동: 하단 탭 바(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) : 입력창에 값을 미리 채워두는 기능