# Template Application Next.js 애플리케이션 with FSD(Feature Sliced Design) 아키텍처 ## 기술 스택 - **프레임워크**: Next.js 15 + TypeScript - **스타일링**: Tailwind CSS - **상태관리**: Zustand - **데이터 페칭**: TanStack Query (React Query) - **폼 관리**: React Hook Form + Zod - **테이블**: TanStack Table - **HTTP 클라이언트**: Axios - **날짜 처리**: Day.js ## 프로젝트 구조 (FSD + Next.js App Router) 이 프로젝트는 **Feature-Sliced Design v2.1**과 **FSD 공식 Next.js 가이드**에 맞춰 구성되어 있습니다. Next.js `app/`은 라우트만 담당하고, 실제 레이어는 `src/` 아래에 있습니다. ``` _template/ ├── app/ # Next.js App Router (루트) — 라우트·레이아웃 진입점만 │ ├── layout.tsx # 루트 레이아웃 (src/app에서 providers, styles import) │ └── (with-base-layout)/ │ ├── layout.tsx # BaseLayout 래퍼 (src/app/layouts에서 import) │ └── page.tsx # re-export: export { MainPage as default } from '@/pages/home' │ ├── pages/ # 빈 폴더 + README (Next.js가 src/pages를 Pages Router로 쓰지 않도록) │ └── README.md │ └── src/ # FSD 레이어 (실제 코드) ├── app/ # App 레이어 (슬라이스 없음, 세그먼트만) │ ├── providers/ # 전역 Providers (QueryClient 등) │ ├── styles/ # 글로벌 스타일 (globals.css) │ └── layouts/ # 공통 레이아웃 컴포넌트 (BaseLayoutWrapper) │ ├── pages/ # Pages 레이어 (페이지 슬라이스) │ └── home/ │ ├── ui/ │ └── index.ts # Public API │ ├── widgets/ # Widgets 레이어 ├── features/ # Features 레이어 ├── entities/ # Entities 레이어 └── shared/ # Shared 레이어 ├── ui/ ├── api/ ├── lib/ └── config/ ``` ### 계층 구조 이해하기 FSD는 **3단계 계층**으로 구성됩니다: 1. **Layers (레이어)**: 책임과 의존성에 따른 수평적 분리 (app, pages, widgets, features, entities, shared) 2. **Slices (슬라이스)**: 비즈니스 도메인에 따른 수직적 분리 (user, product, auth-login 등) 3. **Segments (세그먼트)**: 기술적 목적에 따른 분리 (ui, api, model, lib 등) > 📚 각 레이어의 자세한 설명은 해당 폴더의 README.md를 참고하세요. ## FSD 레이어 설명 FSD는 계층적 아키텍처로, 각 레이어는 책임의 범위와 의존성의 정도에 따라 구분됩니다. 7개의 표준화된 레이어가 있으며, 프로젝트에 필요한 레이어만 사용하면 됩니다. ### 레이어 계층 구조 (위에서 아래로) ``` app/ ↑ 가장 높은 책임, 가장 많은 의존성 pages/ | widgets/ | features/ | entities/ | shared/ ↓ 가장 낮은 책임, 의존성 없음 ``` ### 1. App - **목적**: 앱 전체에 영향을 주는 기술적/비즈니스적 사항 - **내용**: Context providers, 글로벌 스타일, 스토어 설정, 라우터 설정, 애널리틱스 - **특징**: 슬라이스가 없고 세그먼트로만 구성 - **의존성**: 모든 하위 레이어 사용 가능 ### 2. Pages (src/pages) - **목적**: 웹사이트나 애플리케이션을 구성하는 페이지/화면 - **내용**: 페이지 UI, 로딩 상태, 에러 바운더리, 데이터 fetching - **특징**: 한 페이지당 한 슬라이스 (유사한 페이지는 그룹화 가능). Next.js `app/`의 route 파일에서 re-export - **의존성**: `widgets`, `features`, `entities`, `shared` 사용 가능 > 💡 **FSD v2.1 권장사항**: "pages-first" 접근 방식을 따라, 재사용되지 않는 큰 UI 블록과 비즈니스 로직은 페이지 슬라이스에 유지하세요. ### 3. Widgets - **목적**: 큰 규모의 독립적인 UI 블록 - **내용**: 여러 features와 entities를 조합한 복합 UI - **사용 시기**: 여러 페이지에서 재사용되거나, 페이지에 여러 개의 큰 독립적 블록이 있을 때 - **의존성**: `features`, `entities`, `shared` 사용 가능 (다른 `widgets` 불가) ### 4. Features - **목적**: 사용자가 수행하는 주요 상호작용과 비즈니스 기능 - **내용**: 사용자 시나리오 (예: 로그인, 상품 검색, 댓글 작성) - **사용 시기**: 여러 페이지에서 재사용되는 기능 - **의존성**: `entities`, `shared` 사용 가능 (다른 `features` 불가) ### 5. Entities - **목적**: 비즈니스가 다루는 실제 개념 (User, Product, Order 등) - **내용**: 데이터 모델, 타입, API 요청, 엔티티의 시각적 표현 - **특징**: 비즈니스 용어로 명명 - **의존성**: 다른 `entities`, `shared` 사용 가능 ### 6. Shared - **목적**: 애플리케이션의 기반 제공 - **내용**: API 클라이언트, UI Kit, 유틸리티 라이브러리, 글로벌 설정 - **특징**: 비즈니스 로직 없음, 슬라이스가 없고 세그먼트로만 구성 - **의존성**: 외부 라이브러리만 사용 가능 (다른 레이어 불가) ## 시작하기 ```bash # 의존성 설치 pnpm install # 개발 서버 실행 pnpm run dev # 프로덕션 빌드 pnpm run build # 프로덕션 서버 실행 pnpm start ``` ## 환경 변수 `.env.local` 파일 생성: ```env NEXT_PUBLIC_API_URL=http://localhost:3000/api ``` ## FSD 핵심 규칙 ### 1. Import 규칙 > **슬라이스 내의 모듈(파일)은 오직 하위 레이어에 있는 슬라이스만 import할 수 있습니다.** ```typescript // ✅ 올바른 import (하위 레이어) // features/auth-login/ui/form.tsx import { User } from "entities/user"; import { Button } from "shared/ui/button"; // ❌ 잘못된 import (같은 레이어) // features/auth-login/ui/form.tsx import { PostForm } from "features/post-create"; // 금지! // ❌ 잘못된 import (상위 레이어) // features/auth-login/ui/form.tsx import { Header } from "widgets/header"; // 금지! ``` ### 2. Public API 규칙 > **슬라이스 외부에서는 Public API(index.ts)를 통해서만 접근해야 합니다.** ```typescript // ✅ 올바른 import (Public API 사용) import { LoginForm } from "features/auth-login"; // ❌ 잘못된 import (내부 구조 직접 접근) import { LoginForm } from "features/auth-login/ui/login-form"; ``` **Public API 작성 시 주의사항**: - 와일드카드 re-export(`export * from`) 사용 지양 - 필요한 것만 명시적으로 export - 슬라이스의 인터페이스를 명확하게 표현 ```typescript // ❌ 나쁜 예시 export * from "./ui/Comment"; export * from "./model/comments"; // ✅ 좋은 예시 export { Comment } from "./ui/comment"; export { CommentForm } from "./ui/comment-form"; export { useComments } from "./model/use-comments"; export type { Comment, CommentFormData } from "./model/types"; ```