Step 3 공통 도메인 테크 스펙 - 100-hours-a-week/16-team-katopia-fe GitHub Wiki
공통 도메인은 Auth + profile / Post / Search 등 모든 기능 도메인이 공통으로 사용하는 UI/상태/네트워크/에러/접근제어/비동기 규칙을 제공하는 시스템 레이어다.
본 서비스는 비로그인 사용자에게 일부 콘텐츠를 노출하면서도 좋아요/댓글/북마크/투표/글쓰기 등 주요 액션은 로그인 이후에만 가능한 SNS 구조를 가진다.
따라서 도메인별로 인증 유도, 로딩, 에러 UX가 다르게 구현되면, 사용자 경험이 도메인마다 제각각이 되고, 팀 개발 생산성이 떨어지며 추후 Post/Search 확장 시 중복 코드가 폭팔한다.
공통 도메인은 이를 해결하기 위해, “일관된 사용자 경험 + 재사용 가능한 공통 로직 + 예측 가능한 상태 기준”을 제공한다.
- KR1: 공통 UX 정책(로그인 유도/로딩/에러/토스트) 적용률 90% 이상
- KR2: API 호출 실패 시 사용자 피드백(토스트/리트라이/리다이렉트) 정책 1가지로 통일
- KR3: 다른 도메인 구현 시 공통 모듈만 사용하여 신규 페이지 개발 시간 20% 단축
- KR4: 인증 필요 액션의 “로그인 유도” 처리 코드 중복 0
-
로그인 유도 로직이 도메인마다 흩어짐
- HomeFeed에서는 바텀시트
- Search에서는 그냥 막힘
→ 같은 상황에서 UX가 다르면 사용자 혼란 + QA 비용 증가
-
서버 에러 처리 UX가 제각각
- 어떤 페이지는 toast
- 어떤 페이지는 빈화면
→ 서비스가 불안정하다는 인식 발생
-
상태 관리 경계가 모호함
- 서버에서 받은 데이터까지 Zustand로 저장하면 정합성 깨짐
- 반대로 UI 상태까지 Query로 하면 복잡도 증가
→ 기준이 필요
-
API Client / Retry / Token 만료 처리 분산
- axios 설정이 페이지마다 있으면 유지보수 지옥
- 인증 오류 처리 정책이 통일되지 않음.
- Post/Search/Auth의 비즈니스 로직 자체 구현(API payload 규칙, 도메인 정책)은 포함하지 않음.
- 디자인 시스템 자체 리뉴얼은 포함하지 않음.
기술스택 (전 도메인 공통)
-
프레임 워크/ 라우팅
- Next.js 16(App Router)
- App Router 기반의 File-based Routing을 사용한다.
- Layout 계층을 활용하여 공통 Provider, 전역 UI(Toast, BottomSheet 등)를 한 번만 구성한다.
- 서버/클라이언트 렌더링 경계를 명확히 분리하여 예측 가능한 렌더링 구조를 유지한다.
- Next.js 16(App Router)
-
언어(Language)
- TypeScript 5.x
- 전역 상태, API 응답, 공통 컴포넌트 Props에 대해 명시적인 타입을 명시한다.
- 도메인 간 인터페이스 불일치로 인한 런타임 오류를 사전에 방지한다.
- TypeScript 5.x
-
상태 관리(State Management)
- Zustand
- 인증 상태, 공통 UI 상태를 전역으로 관리한다.
- Redux 대비 Boilerplate가 적고, Context API 대비 불필요한 리렌더링을 줄일 수 있어 공통 상태 관리에 적합하다.
- 서버에서 내려오는 데이터는 관리하지 않고, UI/클라이언트 상태에만 한정하여 사용한다.
- Zustand
-
서버 상태 관리(Server Cache)
- TanStack Query v5
- 서버에서 내려오는 데이터는 Single Source of Truth로 간주하고 Query Cache로 관리한다.
- 인증 상태를 기준으로 Query 활성화 여부를 제어한다.
- 전 도메인에서 동일한 캐싱/재시도/에러 처리 정책을 적용할 수 있도록 공통 규칙을 제공
- TanStack Query v5
-
네트워크 계층
- Axios
- 공통 Axios Instance를 생성하여 모든 API 요청을 일관된 방식으로 처리한다.
- Axios
-
데이터 검증
- Zod
- 백엔드 API Response에 대해 런타임 스키마 검증을 수행한다.
- 외부 시스템으로부터 전달받은 데이터의 신뢰성을 확보한다.
- 잘못된 응답 구조로 인한 UI 오류 전파를 사전에 차단한다.
- Zod
-
스타일링
- Tailwind CSS
- 유틸리티 클래스 기반으로 공통 UI 스타일 규칙을 정의한다.
- 모바일 기준으로 반응형 UI를 일관되게 유지한다.
- Tailwind CSS
-
/error: 공통 에러 페이지- 주요 기능
- 네트워크 장애/ 서버 오류/ 예상치 못한 오류에 대한 사용자 안내
- “다시 시도/ 홈으로/ 로그인”등 복구 액션 제공
- 사용 컴포넌트
ErrorLayout-
ErrorView(상태 코드/메시지/CTA 렌더링) -
RetryButton,GoHomeButton
- 라우팅
- 전역 에러 핸들러에서
/error이동시키거나 현재 페이지에서ErrorView를 인라인 렌더링
- 전역 에러 핸들러에서
- 주요 기능
-
/not-found: 404(Not Found) 페이지- 주요 기능
- 잘못된 경로/ 존재하지 않는 리소스 접근에 대한 안내
- 사용 컴포넌트
NotFoundView-
GoBackButton,GoHomeButton
- 라우팅
- Next.js App Router의
not-found.tsx로 처리
- Next.js App Router의
- 주요 기능
-
AppProviders: 전역 Provider 집합 컴포넌트개요(Overview)
-
역할 : 앱 전역에서 필요한 Provider를 단일 진입점으로 구성한다.
-
책임
- Provider 중첩 순서를 고정하여 “환경 차이로 인한 버그”를 줄인다.
- 전 도메인 동일한 방식으로 Query/Toast/Auth 상태를 사용하도록 보장한다.
-
props & Interface
interface AppProvidersProps { children: React.ReactNode; }
-
내부 상태 & 이벤트
- 포함 Provider 예시
QueryClientProviderToastProviderBottomSheetProvider
- 포함 Provider 예시
-
사용 예시 (Usage)
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html> <body> <AppProviders>{children}</AppProviders> </body> </html> ); }
-
에러 처리 / 엣지 케이스
- Provider 초기화 실패 시
GlobalErrorBoundary로 fallback UI 제공
- Provider 초기화 실패 시
-
-
GlobalErrorBoundary: 전역 에러 경계개요 (Overview)
-
역할: 렌더링/런타임 오류를 UI 레벨에서 포착하여 앱 전체 크래시를 방지한다.
-
책임
- 에러 발생 시 공통 에러 UI 제공
- 에러 로그(개발 환경 console, 운영 환경 로깅 도구) 표준화
-
Props & Interface
interface GlobalErrorBoundaryProps { children: React.ReactNode; fallback?: React.ReactNode; }
-
내부 상태 & 이벤트
- 내부적으로
error상태를 잡고 fallback 렌더링 - “다시 시도” 클릭 시 boundary reset
- 내부적으로
-
사용 예시 (Usage)
<GlobalErrorBoundary fallback={<ErrorView />}> <AppProviders>{children}</AppProviders> </GlobalErrorBoundary>
-
에러 처리 / 엣지 케이스
- 네트워크 에러는 Query 레벨에서 처리하고, “렌더링 크래시”만 여기서 담당하도록 책임 분리
-
-
Toast 시스템: ToastProvider + useToast개요
-
역할 : 전 도메인 동일한 방식으로 성공/실패/경고 메시지를 노출한다.
-
책임
- 중복 토스트 방지
- 네트워크/인증 오류 등 공통 에러 메시지 표준 제공
-
props & Interface
type ToastVariant = 'success' | 'error' | 'info'; interface ToastPayload { title?: string; message: string; variant: ToastVariant; durationMs?: number; } interface ToastContextValue { push: (payload: ToastPayload) => void; clear: () => void; }
-
사용 예시 (Usage)
const { push } = useToast(); push({variant:'error',message:'네트워크 오류가 발생했습니다.' });
-
에러 처리 / 엣지 케이스
- “서버 메시지 그대로 노출”이 아니라 사용자 친화 메시지로 매핑하는 레이어 제공
-
스타일링
- Tailwind 기반 공통 토스트 UI
-
-
AppBootLoader: 앱 초기 로딩 컴포넌트개요(Overview)
-
역할
앱 최초 진입 시 아직 아래 정보들이 확정되지 않은 상태에서 사용자에게 보여주는 초기 로딩 UI
- Access Token이 유효한지?
-
/home으로 갈지/profile/setup으로 갈지?
→ 흰 화면(White Screen)을 방지하고 “앱이 멈춘 것 같은 느낌”을 제거하는 것이 핵심 목적이다.
-
책임
- 앱 초기 진입 시 임시 UI 제공
- 인증/세션/초기 라우팅 판단이 끝날 때 까지 사용자 대기 UX 개선
-
Props & Interface
interface AppBootLoaderProps { label?: string; // "불러오는 중..." 등 }
-
내부 상태 & 이벤트
-
AppBootLoader는 자기 판단을 하지 않는다. 보여줄지 말지는 상위에서 결정한다.
-
-
표시/제거 방식
{isBooting && <AppBootLoader />}
- isBooting === true
- AppBootLoader 표시
- isBooting === false
- 자동으로 사라짐
- isBooting === true
-
에러 처리 / 엣지 케이스
- 복구 가능한 경우 → 로그인 유도 / 홈 이동
- 치명적 오류가 발생한 경우 →
/error라우팅 또는ErrorView노출
-
-
Global UI & System State (Zustand)
앱 전역에서 공유되어야 하는 비-서버 데이터를 관리한다.
- 관리 대상 : 인증 상테, 전역 UI, 시스템 설정
- 초기화 시점 : 앱 최초 진입시 또는 로그아웃 시
-
authStore: 인증 및 세션 관리interface AuthState { isLoggedIn: boolean; accessToken: string | null; user: UserProfile | null; // 프로필 이미지, 닉네임 등 최소 정보 isBooting: boolean; // 앱 초기 로딩 여부 // Actions setAuth: (token: string, user: UserProfile) => void; clearAuth: () => void; // 로그아웃 시 모든 전역 상태 초기화 트리거 updateUser: (user: UserProfile) => void; }
- 상태 전이 흐름
- AppBootRouter 실행 → 토큰 유효성 검사
- 성공 시
setAuth→ 메인 피드 진입 - 실패 / 만료 시
clearAuth→ 로그인 유도 바텀시트 노출.
- 상태 전이 흐름
-
uiStore: 전역 인터랙션 관리interface UIState { globalBottomSheet: { isOpen: boolean; type: 'LOGIN_GUIDE' | 'PROFILE_EDIT' | null; }; // Actions openBottomSheet: (type: UIState['globalBottomSheet']['type']) => void; closeBottomSheet: () => void; }
-
Server Cache State (TanStack Query v5)
서버가 진실의 근원(SSOT)인 데이터를 관리하며, 도메인 간 데이터 공유 및 동기화를 담당한다.
-
관리 전략:
- Zod Integration: API 응답이 캐시에 저장되기 전, Zod 스키마를 통해 런타임 검증을 수행합니다. 잘못된 데이터는 캐시에 진입하기 전 에러를 발생시켜 UI 크래시를 원천 차단합니다.
-
Stale-While-Revalidate: 공통 정책에 따라
staleTime(기본 0~5분)과gcTime을 설정하여 네트워크 비용을 최적화합니다.
-
상태 전이 흐름:
- Fetch: Axios 인스턴스가 요청 → Zod 스키마 검증 → Query Cache 저장.
-
Mutation: 좋아요/수정 액션 발생 →
Optimistic Update로 UI 우선 반영 → 서버 성공 시invalidateQueries로 최신 데이터 동기화. -
Error: 401(인증 만료) 발생 시
authStore의clearAuth호출 및 로그인 바텀시트 팝업.
-
관리 전략:
-
Local State (React
useState/useReducer)특정 컴포넌트 내부에서만 유효하며, 외부 공유가 불필요한 휘발성 상태를 관리합니다.
- 관리 대상: 입력 필드(Input) 값, 로컬 토글(Accordion), 컴포넌트 내부 애니메이션 상태.
-
전략:
- Zustand나 Query로 올리지 않고 컴포넌트 생명주기에 맞춥니다.
-
Props Drilling 방지: 로컬 상태가 3단계 이상 하위로 전달될 경우에만
Context API또는Local Zustand Store사용을 검토합니다.
-
Next.js App Router 기반 표준 구조:
- 모든 도메인은 App Router의 File-based Routing 규칙을 준수하여 URL 구조와 파일 구조를 일치시킨다.
-
공통 레이아웃 활용 :
RootLayout에서 전역 Provider와 전역 UI를 관리하여 페이지 전환 시에도 공통 요소가 유지되도록 한다.
-
접근 제어 및 미들웨어(Authorization Guards)
- Next.js Middleware : 서버 사이드에서 세션 쿠키를 검증하여 인가가 필요한 페이지에 비로그인 사용자가 접근할 경우, 즉시 로그인 페이지로 리다이렉트하거나 메인으로 튕겨내는 전역 가이드 로직을 수행한다.
-
Client-side Guard: 클라이언트 네비게이션 중 인증이 필요한 액션 발생 시,
authStore상태를 확인하여 전역 로그인 유도 바텀시트를 호출하는 표준 프로세스를 제공한다.
-
공통 네비게이션 및 레이아웃 구조
- Persistent Bottom Navigation: 이미지에서 확인된 5개의 메뉴는 RootLayout 하위에 상주하며, 페이지 전환 시에도 초기화되지 않고 유지된다.
- Active State 관리 : 현재 URL 경로와 네비게이션 아이템을 매핑하여 활성 탭에 시각적 강조를 적용하는 로직을 공통화한다.
-
폼 관리 표준 (React Hook Form)
-
최상단 정의 원칙: 각 페이지 컴포넌트 최상단에서
useForm을 선언하고, 복잡한 폼은FormProvider를 통해 하위 컴포넌트에 상태를 전파한다. -
입력 보존(Preservation): 작성 플로우(예: 게시글 작성) 중 실수로 네비게이션 바를 눌러 이탈하려는 경우,
isDirty상태를 체크하여 작성 취소 확인 모달을 띄우는 이탈 방지 로직을 공통화한다.
-
최상단 정의 원칙: 각 페이지 컴포넌트 최상단에서
-
유효성 검증 표준 (Zod)
-
Schema-based Validation: 모든 폼은
Zod스키마를 통해 정의됩니다. 이는 클라이언트 측 유효성 검사뿐만 아니라 API 응답 데이터 검증(Runtime Validation)에도 동일하게 사용된다. -
공통 규칙 제공:
-
공통 필드: 닉네임 규칙, 내용 글자 수 제한, 이미지 파일 확장자 제한 등은
common/schemas에 정의하여 도메인 간 일관성을 유지한다. -
검증 시점: 사용자 피드백의 즉각성을 위해
mode: 'onChange'또는onBlur를 기본값으로 설정한다.
-
공통 필드: 닉네임 규칙, 내용 글자 수 제한, 이미지 파일 확장자 제한 등은
-
Schema-based Validation: 모든 폼은
-
에러 처리 및 피드백 UX
- 인라인 에러 메시지 : 각 입력 필드 하단에 유효성 검사 실패 메시지를 일관된 스타일로 노출한다.
-
서버 에러 연동
- API 호출 결과가 400일 경우, 백엔드에서 내려주는 에러 코드를
React Hook Form의setError와 매핑하여 특정 필드에 에러를 표시한다.
- API 호출 결과가 400일 경우, 백엔드에서 내려주는 에러 코드를
-
제출 중 상태 제어:
isSubmitting상태 동안 네비게이션 바를 포함한 모든 액션 버튼을 비활성화(Disabled) 처리하여 데이터 중복 제출을 원천 차단한다.
-
SSOT(Single Source of Truth) : 서버 데이터를 단일 진실의 근원으로 두고 클라이언트는 캐시된 뷰만을 관리하는 설계 원칙
-
Global UI State : 페이지를 넘나들며 유지되는 UI 상태