# User API 연동 가이드 ## 개요 FSD(Feature-Sliced Design) 아키텍처를 기반으로 User Service API 연동을 구현했습니다. ## 디렉토리 구조 ``` src/ ├── shared/ │ └── api/ │ ├── client.ts # Axios 클라이언트 설정 │ ├── types.ts # 공통 API 타입 │ └── index.ts ├── entities/ │ └── user/ │ ├── model/ │ │ └── types.ts # User 엔티티 타입 │ ├── api/ │ │ └── userApi.ts # User API 함수 │ └── index.ts └── features/ ├── auth/ │ ├── model/ │ │ ├── useAuth.ts # 인증 훅 │ │ └── AuthProvider.tsx # 인증 Context │ └── index.ts └── profile/ ├── model/ │ └── useProfile.ts # 프로필 훅 └── index.ts ``` ## API 명세 - **Base URL**: `http://20.196.65.160:8081` - **Endpoints**: - `POST /api/v1/users/login` - 로그인 - `POST /api/v1/users/register` - 회원가입 - `POST /api/v1/users/logout` - 로그아웃 - `GET /api/v1/users/profile` - 프로필 조회 - `PUT /api/v1/users/profile` - 프로필 수정 - `PUT /api/v1/users/password` - 비밀번호 변경 ## 사용 방법 ### 1. AuthProvider 설정 루트 레이아웃에 AuthProvider를 추가합니다: ```tsx // app/layout.tsx import { AuthProvider } from '@/features/auth'; export default function RootLayout({ children }) { return ( {children} ); } ``` ### 2. 로그인 구현 예제 ```tsx 'use client'; import { useAuthContext } from '@/features/auth'; import { useState } from 'react'; export default function LoginPage() { const { login, isLoading } = useAuthContext(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); const result = await login({ email, password }); if (result.success) { // 로그인 성공 console.log('로그인 성공:', result.user); // 페이지 이동 등 } else { // 로그인 실패 console.error('로그인 실패:', result.error); } }; return (
setEmail(e.target.value)} placeholder="이메일" /> setPassword(e.target.value)} placeholder="비밀번호" />
); } ``` ### 3. 회원가입 구현 예제 ```tsx 'use client'; import { useAuthContext } from '@/features/auth'; import { useState } from 'react'; import type { RegisterRequest } from '@/entities/user'; export default function RegisterPage() { const { register, isLoading } = useAuthContext(); const [formData, setFormData] = useState({ name: '', phoneNumber: '', email: '', password: '', storeName: '', industry: '', address: '', businessHours: '', }); const handleRegister = async (e: React.FormEvent) => { e.preventDefault(); const result = await register(formData); if (result.success) { console.log('회원가입 성공:', result.user); } else { console.error('회원가입 실패:', result.error); } }; return (
{/* 폼 필드들... */}
); } ``` ### 4. 프로필 조회 및 수정 예제 ```tsx 'use client'; import { useProfile } from '@/features/profile'; import { useEffect } from 'react'; export default function ProfilePage() { const { profile, isLoading, error, fetchProfile, updateProfile } = useProfile(); useEffect(() => { fetchProfile(); }, [fetchProfile]); const handleUpdate = async () => { const result = await updateProfile({ name: '새로운 이름', storeName: '새로운 가게명', }); if (result.success) { console.log('프로필 수정 성공:', result.data); } }; if (isLoading) return
로딩 중...
; if (error) return
에러: {error}
; if (!profile) return
프로필 없음
; return (

{profile.userName}

이메일: {profile.email}

가게명: {profile.storeName}

); } ``` ### 5. 인증 상태 확인 예제 ```tsx 'use client'; import { useAuthContext } from '@/features/auth'; import { useRouter } from 'next/navigation'; import { useEffect } from 'react'; export default function ProtectedPage() { const { user, isAuthenticated, isLoading } = useAuthContext(); const router = useRouter(); useEffect(() => { if (!isLoading && !isAuthenticated) { router.push('/login'); } }, [isAuthenticated, isLoading, router]); if (isLoading) return
로딩 중...
; if (!isAuthenticated) return null; return (

환영합니다, {user?.userName}님!

); } ``` ### 6. 로그아웃 구현 예제 ```tsx 'use client'; import { useAuthContext } from '@/features/auth'; import { useRouter } from 'next/navigation'; export default function Header() { const { user, isAuthenticated, logout } = useAuthContext(); const router = useRouter(); const handleLogout = async () => { await logout(); router.push('/login'); }; if (!isAuthenticated) return null; return (
{user?.userName}
); } ``` ## 타입 정의 ### User 타입 ```typescript interface User { userId: number; userName: string; email: string; role: string; phoneNumber?: string; storeId?: number; storeName?: string; industry?: string; address?: string; businessHours?: string; } ``` ### LoginRequest 타입 ```typescript interface LoginRequest { email: string; password: string; } ``` ### RegisterRequest 타입 ```typescript interface RegisterRequest { name: string; phoneNumber: string; // 패턴: ^010\d{8}$ email: string; password: string; // 최소 8자 storeName: string; industry?: string; address: string; businessHours?: string; } ``` ## API Client 설정 API 클라이언트는 다음 기능을 자동으로 처리합니다: 1. **JWT 토큰 자동 추가**: localStorage의 `accessToken`을 자동으로 헤더에 포함 2. **401 인증 오류 처리**: 인증 실패 시 자동으로 토큰 삭제 및 로그인 페이지로 리다이렉트 3. **Base URL 설정**: 환경 변수로 API 서버 URL 관리 ## 환경 변수 `.env.local` 파일에 다음 환경 변수를 설정하세요: ```env NEXT_PUBLIC_API_BASE_URL=http://20.196.65.160:8081 ``` ## 주의사항 1. **토큰 관리**: 토큰은 localStorage에 저장되며, 로그아웃 시 자동으로 삭제됩니다. 2. **인증 상태**: AuthProvider로 감싼 컴포넌트에서만 useAuthContext 사용 가능합니다. 3. **에러 처리**: 모든 API 함수는 try-catch로 에러를 처리하며, 결과 객체에 success와 error를 포함합니다. 4. **비밀번호 검증**: 회원가입 시 비밀번호는 최소 8자 이상이어야 합니다. 5. **전화번호 형식**: 010으로 시작하는 11자리 숫자만 허용됩니다. ## 빌드 및 실행 ```bash # 빌드 npm run build # 개발 서버 실행 (사용자가 직접 수행) npm run dev ```