Step 4 프론트엔드 개발 표준 및 구조 설계서 (FE Architecture & Standards) - 100-hours-a-week/16-team-katopia-fe GitHub Wiki
본 프로젝트는 이미지 중심의 패션 SNS 서비스로, 사용자는 피드를 소비하고(스크롤/탐색), 게시물과 투표를 작성하며, 투표 하기·좋아요·댓글·북마크 등 상태 변경 인터랙션을 반복적으로 수행한다.
또한 비로그인 사용자에게는 일부 콘텐츠만 노출하고, 주요 기능은 로그인 세션 기반으로 제공하는 등 권한별 UX 차등이 존재한다.
- 성능 최적화 (Visual-First): 다량의 고화질 이미지를 처리하기 위해 Next.js의 Image Optimization과 지연 로딩 전략을 최우선으로 한다.
- 응집도 높은 설계 (Feature-Driven): 도메인(Feed, Vote, Profile) 간 결합도를 낮추어 기능 확장 시 서로 영향을 주지 않는 구조를 지향한다.
- 예측 가능한 상태 (Strict State Separation): 서버 캐시와 클라이언트 상태를 엄격히 분리하여 데이터 정합성 문제를 원천 차단한다.
이번 문서에서 범위에 포함하지 않는 것은 아래와 같다.
-
디자인 시스템 자체의 완전한 정의(토큰/모든 컴포넌트 카탈로그)
→ 최소한의 UI 규칙과 공통 컴포넌트 원칙만 정의하고, 상세 컴포넌트 목록은 별도 문서로 분리
-
백엔드 아키텍처/DB 설계/배포 인프라 상세
→ 프론트 관점에서 필요한 연동 방식(계약, 에러 규격, 인증 플로우)만 명시
-
E2E 자동화의 “완벽한 커버리지”
→ 핵심 사용자 플로우 중심으로 최소 커버리지부터 단계적 확장
-
레거시 브라우저(예: IE) 지원
→ 공식 지원 범위에서 제외하고, 현대 브라우저 기준으로 최적화
-
Framework: Next.js (App Router)
- SEO/OG, 이미지 최적화, 라우팅 구조화, 성능(스트리밍/캐싱) 활용
-
Language: TypeScript
- API 계약/도메인 모델 타입화로 협업 비용 감소
-
State/Data
- 서버 상태: TanStack Query(React Query)
- 클라이언트 상태: Zustand(또는 Context 최소화)
- 폼: React Hook Form + Zod
-
Testing
- E2E: Playwright
- Lint/Format: ESLint + Prettier
기능별 응집도를 높이기 위해 Feature-based Architecture를 채택한다.
src/
├── app/ # Next.js App Router (Routing, Layout, Server Component)
├── features/ # 도메인별 핵심 비즈니스 로직 (응집도 극대화)
│ ├── feed/
│ │ ├── api/ # 해당 도메인 전용 TanStack Query Hooks
│ │ ├── components/ # 해당 도메인 내에서만 재사용되는 컴포넌트
│ │ ├── hooks/ # 도메인 로직이 포함된 커스텀 훅
│ │ ├── types/ # API Response/Request DTO 및 도메인 모델
│ │ └── utils/ # 도메인 전용 헬퍼 함수
├── shared/ # 전역 공통 레이어 (범용성)
│ ├── components/ # UI Kit (Button, Input, Modal, Toast, Skeleton)
│ ├── hooks/ # 범용 훅 (useDebounce, useIntersectionObserver)
│ ├── lib/ # 외부 라이브러리 설정 (axiosInstance, queryClient)
│ ├── constants/ # 전역 상수 (API_ENDPOINT, STORAGE_KEY)
│ └── types/ # 전역 공통 타입
├── store/ # 전역 클라이언트 상태 (Zustand - Auth, UI State)
└── styles/ # 전역 스타일 (Tailwind Config, Tokens)
2-1. 역할 분리
- Page(라우트): 라우팅 파라미터 처리, Server Component로서 초기 데이터 패팅 수행, 여러 Feature 컴포넌트를 조합하여 레이아웃 구성
- Feature: 특정 도메인의 비즈니스 로직 소유, TanStack Query 훅을 직접 호출하여 상태 관리, Shared 컴포넌트에 데이터와 이벤트 핸들러를 주입
- Shared(Presentational): 도메인 지식이 전혀 없는 순수 UI 컴포넌트, 오직 Props에만 의존하며 재사용성이 가장 높음 , 스타일 가이드의 최소 단위
2-2. 재사용 기준
-
Shared 영역 (
shared/components):- 프로젝트 전반에서 쓰이는 공통 UI.
-
규칙 : 내부에서 특정 API를 호출하거나
features폴더의 요소를 참조해서는 안된다.
-
Feature 영역 (
features/<domain>/components):- 특정 기능에 종속된 UI.
- 규칙 : 해당 고메인의 데이터 모델을 알고 있어도 되지만, 다른 도메인의 로직을 직접 포함하지 않는다.
2-3. Props 규칙
-
Props Naming Convention:
-
Boolean :
is,has,can,should접두사를 사용한다. (예:isLoading,hasError,canEdit) -
Event Handler:
on접두사를 사용하여 이벤트임을 명시한다. (예:onClick,onClose) -
Internal Handler: 컴포넌트 내부에서 처리하는 함수는
handle접두사를 사용한다. (예:const handleClick = () => { onOpen(); };)
-
Boolean :
-
컴포넌트 합성(Composition):
-
props drilling을 피하기 위해 children을 적극 활용한다. - 복잡한 UI는 내부에서 모든 것을 처리하기 보다 작은 컴포넌트들을 조립하는 방식을 지향한다.
-
2-4. 성능 및 안정성 가이드
-
Memoization 시점:
- 모든 컴포넌트에
memo를 남용하지 않는다. 렌더링 비용이 큰 리스트 아이템이나,Context영향을 자주 받는 하위 컴포넌트에 한해 성능 측정 후 적용한다.
- 모든 컴포넌트에
-
TypeScript 적용:
- 모든 컴포넌트는
interface또는type을 통해 Props 타입을 명시한다. - Optional Props는 기본값(Default Parameters)을 지정하여
undefined로 인한 런타임 에러를 방지한다.
- 모든 컴포넌트는
3-1. 서버 상태 관리 (TanStack Query v5)
- Query Key 관리 체계 (Factory Pattern): 문자열 배열만 사용하지 않고 도메인 별 queryKeys 객체를 정의하여 오타를 방지하고 일관성을 유지한다.
-
캐싱 및 재요청 정책 (StaleTime/GcTime):
- 패션 피드와 같이 데이터 변경 빈도가 낮고 조회가 잦은 데이터는 staleTime을 5분 정도로 설정하여 불필요한 네트워크 비용을 절감한다.
- 실시간이 중요한 알림 등은 staleTime : 0으로 설정하여 항상 최신 상태를 유지한다.
-
Mutation 후처리 (Synchronization):
-
Invalidation: 게시글 작성/수정 후에는 관련
queryKey를invalidateQueries처리하여 서버 데이터를 재조회한다. - Optimistic Update: '좋아요'나 '투표'처럼 사용자 반응이 빨라야 하는 인터랙션은 낙관적 업데이트를 적용해 즉각적인 피드백을 제공한다.
-
Invalidation: 게시글 작성/수정 후에는 관련
-
데이터 패칭 최적화: 무한 스크롤은
useInfiniteQuery를 사용하며, 커서 기반 페이지네이션을 표준으로 채택한다.
3-2. 클라이언트 상태 관리(Zustand)
-
스토어 분리(Atimic Stores):
- 하나의 거대한 스토어를 지양하고 기능별로 스토어를 분리하여 불필요한 리렌더링을 방지한다.
-
서버 상태와의 경계:
-
원칙 : 서버에서 온 데이터를 Zustand에 복사하여 저장하지 않는다. 서버 데이터는
useQuery결과값을 참조한다. - 예외: 프로필 수정 시 서버 데이터를 불러와서 입력 폼의 초기값으로 세팅하는 등의 '편집용 임시 상태'는 Zustand나 로컬 상태를 활용한다.
-
원칙 : 서버에서 온 데이터를 Zustand에 복사하여 저장하지 않는다. 서버 데이터는
3-3. 전역 인증 상태 및 인가 전략 (Auth & Authorization Strategy)
-
인증 데이터 저장 및 관리
-
Access Token: 보안과 성능을 고려하여 클라이언트 메모리(
Zustand authStore)에 관리한다. API 요청 시 인터셉터를 통해Authorization헤더에 삽입합니다. -
Refresh Token: 보안 위협(XSS)을 방지하기 위해
httpOnly,Secure옵션이 적용된 쿠키에 저장하며, 토큰 재발급 로직은 백엔드와 쿠키 기반으로 자동 수행한다. -
인증 상태 SSOT:
isAuthenticated상태값은 오직authStore에서 관리하며, 이 값의 변화에 따라 UI(네비게이션 바, 기능 버튼 등)가 즉각적으로 반응하도록 설계한다.
-
Access Token: 보안과 성능을 고려하여 클라이언트 메모리(
-
인가 가드 (Authorization Guard) 및 UX 전략
-
서버 사이드 (Next.js Middleware):
- 대상: /mypage, /profile/setup 등 비로그인 유저가 절대 진입해서는 안 되는 경로
- 동작: 미들웨어에서 인증 쿠키가 없을 경우, 사용자를 메인 페이지로 리다이렉트 시키되 URL 파라미터를 전달한다.
-
클라이언트 사이드 (Global Auth Trigger):
- 동작: 루트 레이아웃에서 URL 파라미터를 감시하거나 전역 상태를 체크한다.
auth_required파라미터가 감지되면 즉시 전역 로그인 바텀시트를 노출한다. - 인터랙션 가드: ‘투표하기’ , ‘좋아요’ 등 특정 버튼 클릭 시, 페이지 이동 없이
isAuthenticated를 체크하여false일 경우 즉시 로그인 바텀시트를 호출하는 전역 유틸리티 훅을 사용한다.
- 동작: 루트 레이아웃에서 URL 파라미터를 감시하거나 전역 상태를 체크한다.
-
서버 사이드 (Next.js Middleware):
4-1. API Client 설계 (Axios Instance)
-
인스턴스 설정:
-
baseURL: 환경 변수를 기반으로 서버 엔드포인트 설정. -
timeout: 네트워크 지연 시 무한 대기를 방지하기 위해 10,000ms 설정. -
withCredentials: Refresh Token 전송을 위해 필수 활성화.
-
-
인터셉터 활용:
-
Request :
authStore에서 Access Token을 가져와Authorization: Bearer {token}헤더를 자동으로 주입한다. -
Response (Token Refresh):
- 401(Unauthorized) 에러 발생 시, 인터셉터 내에서 토큰 재발급 API를 1회 호출한다.
- 재발급 성공 시 실패했던 요청을 새로운 토큰으로 재시도(Retry)한다.
- 재발급 실패 시(세션 만료), 전역 상태를 초기화하고 로그인 유도 바텀시트를 활성화한다.
-
Request :
4-2. 에러 처리 정책
- 치명적 (Critical) : 시스템 장애, 네트워크 단절, 데이터 없음
- UI 피드백 방식 : Global/Route Error Boundary
- 처리 : 전체 화면을 에러 폴백 UI로 대체하고 '재시도' 버튼 제공
- 기능적 (Functional): 중복 투표, 권한 없음, 만료된 게시물
- UI 피드백 방식 : Toast Message
- 처리: 화면 하단에 일시적으로 알림 노출 (인터랙션 흐름 유지)
- 입력 (Form): 유효하지 않은 형식, 중복된 닉네임
- UI 피드백 방식: Field Helper Text
- 처리: 해당 입력 필드 하단에 붉은색 텍스트로 즉각 표시
4-3. 로딩 UX 전략 (Loading Experience)
-
최초 진입 (Skeleton UI):
- Next.js의
Suspense와loading.tsx를 활용하여 데이터 로딩 중 실제 콘텐츠의 구조와 유사한 스켈레톤 UI를 제공한다. - CLS(Layout Shift) 최적화: 이미지 카드나 프로필 영역의 높이값을 고정하여 로딩 후 콘텐츠가 튀는 현상을 방지한다.
- Next.js의
-
무한 스크롤 (Footer Spinner):
- 피드 하단부에서 다음 데이터를 불러올 때
IntersectionObserver를 감지하여 하단 중앙에 스피너를 노출한다.
- 피드 하단부에서 다음 데이터를 불러올 때
-
버튼 액션 (Loading State):
- 투표, 좋아요, 폼 제출 버튼은 클릭 시 Spinner로 변경하고
disabled처리하여 API 중복 호출을 방지한다.
- 투표, 좋아요, 폼 제출 버튼은 클릭 시 Spinner로 변경하고
4-4. 비동기 데이터 정합성 유지 (Sync Policy)
-
Optimistic Update (낙관적 업데이트):
- 투표나 좋아요처럼 성공 확률이 높고 즉각적인 반응이 필요한 기능은 서버 응답 전에 UI를 먼저 업데이트한다.
- API 실패 시에는
TanStack Query의onSettled를 통해 이전 상태로 롤백처리한다.
5-1. Mobile-First 및 Breakpoint 규격
패션 SNS 특성상 모바일을 기본으로 설계하고, 화면이 커짐에 따라 레이아웃을 확장하는 Mobile-First 방식을 채택한다. Tailwind CSS의 기본 규격을 준수하되 프로젝트 환경에 맞춰 커스텀한다.
| Breakpoint | Viewport Range | 주요 레이아웃 전략 |
|---|---|---|
| base (Mobile) | < 600px | 1열 피드 구성, 하단 탭 바 사용, 풀 스크린 바텀시트 |
| sm (Tablet) | 600px ~ 899px | 2~3열 그리드 구성, 모달 너비 조정 |
| md (Desktop S) | 900px ~ 1199px | 3~4열 그리드, 사이드 네비게이션 고려 |
| lg (Desktop L) | 1200px ~ 1535px | 고정 컨테이너 폭(Max-width), 여백 최적화 |
| xl (Wide) | > 1536px | 초고해상도 대응 및 와이드 스크린 레이아웃 |
5-2. 레이아웃 및 성능 최적화 원칙
-
CLS 최소화:
-
Aspect Ratio 고정: 이미지 로딩 전 화면이 덜컹거리는 현상을 막기 위해 모든 피드 카드와 이미지 컨테이너에
aspect-ratio속성을 부여한다. - Skeleton UI 매칭: 스켈레톤 UI의 높이값을 실제 콘텐츠와 1:1로 일치시켜 로딩 후 레이아웃 변화를 0에 가깝게 유지한다.
-
Aspect Ratio 고정: 이미지 로딩 전 화면이 덜컹거리는 현상을 막기 위해 모든 피드 카드와 이미지 컨테이너에
-
터치 인터페이스 최적화:
- 터치 타겟: 모든 클릭 요소(좋아요, 북마크, 투표 옵션 등)는 최소 44x44px 이상의 클릭 영역을 확보한다. (Apple/Google 가이드 준수)
-
Safe Area 대응: 하단 인디케이터 영역에서 UI가 가려지지 않도록
env(safe-area-inset-*)를 전역 레이아웃에 적용한다.
5-3. 고도화된 이미지 최적화 (next/image 전략)
- 포맷 최적화: WebP 및 AVIF 포맷을 우선적으로 지원하여 원본 대비 용량을 30~50% 절감한다.
-
Sizes 속성 필수 적용: 브라우저가 최적의 이미지 크기를 미리 알 수 있도록
sizes속성을 전략적으로 작성한다.- 예)
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 33vw"
- 예)
-
LCP(Largest Contentful Paint) 개선:
-
Priority: 피드의 상단 1~2개 게시물 이미지에는
priority속성을 부여하여 최우선 로딩한다. - Lazy Loading: 나머지 이미지는 브라우저 기본 지연 로딩을 활용하여 불필요한 네트워크 리소스 소모를 방지한다.
-
Priority: 피드의 상단 1~2개 게시물 이미지에는
-
아트 디렉션 (Art Direction): 디바이스 해상도(DPR 1.0, 2.0, 3.0)에 따라 적절한 밀도의 이미지를 서빙하도록 Next.js의
deviceSizes를 설정한다.
6-1. 네이밍 규칙 (Naming Convention)
- 파일 및 컴포넌트: PascalCase를 사용하며, 파일명과 대표 컴포넌트 명을 일치시킨다.
- 함수 및 변수: camelCase를 사용한다.
- 상수: UPPER_SNAKE_CASE를 사용하며, 전역적으로 관리되는 값에 적용한다.
-
타입 및 인터페이스: PascalCase를 사용한다.
-
접미사 활용: API 응답 모델은
DTO, 컴포넌트 Props는Props를 붙여 구분한다.
-
접미사 활용: API 응답 모델은
- 커스텀 훅: 반드시 use 접두사로 시작하며 camelCase를 따른다.
6-2. Import 규칙 (Import Order)
-
React 및 Next.js 라이브러리:
react,next/* -
외부 라이브러리 (External):
zustand,axios,lucide-react등 -
내부 절대 경로 (Alias):
@/shared,@/features,@/store등 -
상대 경로:
./components,../hooks등
7-1. ESLint 설정 (Static Analysis)
-
no-console:
production환경에서는console.log사용을 금지한다. - react-hooks/rules-of-hooks: 훅의 호출 순서와 규칙을 강제한다.
-
jsx-a11y: 이미지
alt태그 필수 등 기본적인 웹 접근성 규칙을 체크한다. - @typescript-eslint/no-unused-vars: 사용하지 않는 변수가 남아있지 않도록 엄격히 제한한다.
7-2. Prettier 설정 (Formatting)
-
semi: true(세미콜론 사용) -
singleQuote: true(홀따옴표 사용) -
tabWidth: 2(들여쓰기 2칸) -
printWidth: 100(한 줄 최대 길이 100자) -
trailingComma: 'all'(멀티라인 시 마지막 콤마 추가)
8-1. 공식 지원 대상
| 플랫폼 | 브라우저 | 지원 버전 | 비고 |
|---|---|---|---|
| Desktop | Chrome, Edge | 최신 2개 메이저 버전 | Chromium 기반 브라우저 통합 지원 |
| Safari | 최신 2개 메이저 버전 | macOS 최신/이전 버전 대응 | |
| Firefox | 최신 2개 메이저 버전 | - | |
| Mobile | iOS Safari | 최신 2개 메이저 버전 | 아이폰 사용자 필수 대응 (Webkit) |
| Android Chrome | 최신 2개 메이저 버전 | 안드로이드 표준 브라우저 | |
| Samsung Internet | 최신 2개 메이저 버전 | 국내 안드로이드 높은 점유율 고려 |
8-2. 지원 제외 및 대응 정책
- Internet Explorer (IE): 전 버전 지원 대상에서 제외한다. 접근 시 "지원하지 않는 브라우저" 안내 페이지로 리다이렉트하거나 안내 메시지를 노출한다.
9-1. 기본 폴리필(Next.js 내장)
-
SWC 기반 컴파일: Next.js의 기본 컴파일러(SWC)가 제공하는 기본 폴리필 세트를 활용합니다. 이는
Promise,Symbol,Object.assign등 ES6+의 핵심 기능을 자동으로 포함합니다.
9-2. 조건부 및 수동 폴리필 (Conditional Load)
-
IntersectionObserver: 무한 스크롤 및 이미지 지연 로딩(Lazy Loading)의 핵심 API이다. 지원하지 않는 환경(매우 구형 모바일 등)을 대비하여
polyfill.io또는 동적import()를 통해 로드한다. - ResizeObserver: 반응형 레이아웃 감지에 사용되는 API로, 필요 시 별도 폴리필을 추가한다.
-
Aspect-ratio: 구형 브라우저에서
aspect-ratioCSS가 동작하지 않을 경우를 대비해, 패딩 햌(Padding-top hack) 등을 폴백(Fallback) 스타일로 준비한다.
10-1. 크로스 브라우징 테스트
- 실기기 테스트: 주요 타겟인 iPhone(iOS Safari)과 Galaxy(Android Chrome) 환경에서 실제 터치 인터랙션과 스크롤 성능을 테스트한다.
- 가상 환경: BrowserStack이나 LambdaTest를 활용하여 지원 대상에 포함된 다양한 버전의 데스크탑 브라우저 레이아웃을 검증한다.
10-2. 배포 전 자동 검사
- Lighthouse: 성능 및 웹 표준 준수 여부를 측정하여 호환성 문제가 성능 점수에 영향을 주는지 모니터링한다.
-
CI/CD Pipeline: 빌드 시
type-check와 함께browserslist기준에 부합하는지 확인하는 단계를 거친다.
- RQ(React Query): 서버 상태 캐싱/동기화 라이브러리(TanStack Query)
- SSR: Server-Side Rendering (요청 시 서버 렌더)
- SSG: Static Site Generation (빌드 시 정적 생성)
- CSR: Client-Side Rendering (클라이언트 렌더)
- Web Vitals: 사용자 체감 성능 지표(LCP/CLS/INP 등)
- CLS: 레이아웃 이동 지표(이미지/폰트 로딩 영향)
- OG 태그: 링크 공유 시 미리보기(썸네일/제목) 메타 정보
- BrowserStack : 웹사이트나 모바일 애플리케이션을 수천 개의 실제 브라우저와 모바일 기기 환경에서 테스트할 수 있게 해주는 클라우드 기반의 크로스 브라우징 테스트 플랫폼
- LambdaTest : BrowserStack과 직접적으로 경쟁하는 클라우드 기반의 차세대 크로스 브라우징 테스트 플랫폼
- 폴백(Fallback) 스타일 : 특정 최신 CSS 속성이나 브라우저의 기능을 지원하지 않는 환경을 대비하여 대안으로 준비해두는 예비 스타일