170 lines
5.3 KiB
Markdown
170 lines
5.3 KiB
Markdown
# App Layer
|
|
|
|
**App**은 애플리케이션 전체에 영향을 미치는 기술적, 비즈니스적 사항을 다루는 최상위 레이어입니다.
|
|
|
|
## 목적
|
|
|
|
- 애플리케이션의 진입점(entrypoint) 제공
|
|
- 전역 Context Providers 설정
|
|
- 라우터 구성
|
|
- 글로벌 스타일 정의
|
|
- 전역 상태 저장소 설정
|
|
- 애널리틱스 및 모니터링 설정
|
|
|
|
## 특징
|
|
|
|
- **슬라이스 없음**: App 레이어는 Shared처럼 슬라이스가 없고 세그먼트로만 구성됩니다
|
|
- **전체 앱 관심사**: 특정 비즈니스 도메인이 아닌 앱 전체와 관련된 코드만 포함
|
|
- **최상위 레이어**: 모든 하위 레이어의 모듈을 자유롭게 import 가능
|
|
|
|
## 구조 (Next.js App Router)
|
|
|
|
Next.js를 사용하는 경우, App 레이어는 주로 `app/` 디렉토리로 표현됩니다:
|
|
|
|
```
|
|
app/
|
|
├── (routes)/ # 라우트 그룹 및 페이지
|
|
│ ├── (auth)/
|
|
│ │ ├── login/
|
|
│ │ │ └── page.tsx
|
|
│ │ └── register/
|
|
│ │ └── page.tsx
|
|
│ └── (main)/
|
|
│ ├── dashboard/
|
|
│ │ └── page.tsx
|
|
│ └── settings/
|
|
│ └── page.tsx
|
|
├── layout.tsx # 루트 레이아웃
|
|
├── page.tsx # 홈 페이지
|
|
├── globals.css # 글로벌 스타일
|
|
├── providers.tsx # 전역 Providers 설정
|
|
└── error.tsx # 글로벌 에러 핸들러
|
|
```
|
|
|
|
### 일반적인 FSD 세그먼트 구조
|
|
|
|
FSD 표준 세그먼트를 사용하는 경우:
|
|
|
|
```
|
|
app/
|
|
├── entrypoint/ # 애플리케이션 진입점 (프레임워크별)
|
|
│ └── index.tsx
|
|
├── providers/ # Context Providers
|
|
│ ├── query-provider.tsx
|
|
│ ├── theme-provider.tsx
|
|
│ └── index.tsx
|
|
├── styles/ # 글로벌 스타일
|
|
│ ├── globals.css
|
|
│ └── theme.css
|
|
├── store/ # 글로벌 상태 저장소 설정
|
|
│ └── index.ts
|
|
└── routes/ # 라우터 설정
|
|
└── index.tsx
|
|
```
|
|
|
|
## 예시
|
|
|
|
### Next.js Providers 설정
|
|
|
|
```typescript
|
|
// app/providers.tsx
|
|
'use client';
|
|
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { ThemeProvider } from 'next-themes';
|
|
import { useState } from 'react';
|
|
|
|
export function Providers({ children }: { children: React.ReactNode }) {
|
|
const [queryClient] = useState(() => new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 60 * 1000,
|
|
},
|
|
},
|
|
}));
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
|
{children}
|
|
</ThemeProvider>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|
|
|
|
// app/layout.tsx
|
|
import { Providers } from './providers';
|
|
import './globals.css';
|
|
|
|
export default function RootLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
return (
|
|
<html lang="ko">
|
|
<body>
|
|
<Providers>
|
|
{children}
|
|
</Providers>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
```
|
|
|
|
### 글로벌 설정
|
|
|
|
```typescript
|
|
// app/config/analytics.ts
|
|
export function initAnalytics() {
|
|
if (typeof window !== 'undefined') {
|
|
// 애널리틱스 초기화
|
|
}
|
|
}
|
|
|
|
// app/config/monitoring.ts
|
|
export function initMonitoring() {
|
|
// 에러 모니터링 설정
|
|
}
|
|
```
|
|
|
|
## Next.js App Router와 FSD
|
|
|
|
Next.js의 `app/` 디렉토리는 FSD의 **App 레이어**와 **Pages 레이어**를 동시에 담당합니다:
|
|
|
|
- **루트 레벨 파일들** (`layout.tsx`, `providers.tsx`, `globals.css`): App 레이어
|
|
- **라우트 폴더들** (`dashboard/`, `login/` 등): Pages 레이어
|
|
|
|
각 페이지별 비즈니스 로직은:
|
|
- 재사용되지 않는 UI는 페이지 슬라이스(`app/dashboard/` 등) 안에 유지
|
|
- 재사용되는 기능은 `features/` 레이어로 분리
|
|
- 여러 페이지에서 재사용되는 큰 UI 블록은 `widgets/` 레이어로 분리
|
|
|
|
## 레이어 의존성 규칙
|
|
|
|
✅ **허용되는 의존성**:
|
|
- 모든 하위 레이어 (`pages`, `widgets`, `features`, `entities`, `shared`)
|
|
- 같은 `app` 레이어 내의 다른 세그먼트
|
|
- 외부 라이브러리
|
|
|
|
❌ **금지된 의존성**:
|
|
- 없음 (App은 최상위 레이어)
|
|
|
|
## 주의사항
|
|
|
|
1. **비대화 방지**: App 레이어가 너무 커지면 관리가 어려워집니다. 대부분의 로직은 하위 레이어에 배치하세요
|
|
2. **전역 관심사만**: 특정 페이지나 기능에만 관련된 코드는 해당 레이어로 이동
|
|
3. **라우터 레벨 로직**: 라우터 및 서버 레벨 로직은 이 레이어에 유지
|
|
4. **Processes 레이어 사용 지양**: Processes 레이어는 deprecated되었으므로 해당 로직은 `app`이나 `features`에 배치
|
|
|
|
## FSD v2.1 권장사항
|
|
|
|
최신 FSD 버전(v2.1)은 **"pages-first"** 접근 방식을 권장합니다:
|
|
|
|
- 더 많은 코드를 페이지 슬라이스에 유지
|
|
- 큰 UI 블록과 재사용되지 않는 비즈니스 로직은 즉시 추출하지 말고 페이지에 보관
|
|
- 실제로 재사용이 필요할 때만 `features`나 `widgets`로 분리
|
|
|
|
이 접근 방식은 과도한 추상화를 방지하고 코드를 더 쉽게 탐색할 수 있게 합니다.
|