diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md
index 42fcde6..27f254b 100644
--- a/.github/ISSUE_TEMPLATE/issue.md
+++ b/.github/ISSUE_TEMPLATE/issue.md
@@ -1,9 +1,9 @@
---
name: Acci Issue
about: Acci 프론트엔드 이슈를 작성합니다
-labels: 'bug, enhancement, question, task'
-title: '✨ feat : 이슈 제목'
-assignees: ''
+labels: "bug, enhancement, question, task"
+title: "✨ feat : 이슈 제목"
+assignees: ""
---
## ✅ TODO
@@ -31,7 +31,7 @@ assignees: ''
## 🔗 참고
-- https://acci-ai.vercel.app
+- https://acci-ai.site
diff --git a/FSD_PATHS.md b/FSD_PATHS.md
index 3f8f09e..8c3b992 100644
--- a/FSD_PATHS.md
+++ b/FSD_PATHS.md
@@ -2,21 +2,106 @@
교통사고 영상 분석 플랫폼을 위한 FSD(Feature-Sliced Design) 아키텍처 절대경로 설정 가이드입니다.
+> ✅ **FSD 공식 권장 구조 적용 완료**
+> 이 프로젝트는 FSD 공식 문서의 권장사항을 따릅니다:
+>
+> - 루트 `app/`: NextJS App Router (라우팅만)
+> - `src/app/`: FSD app layer (providers, config만)
+> - `src/pages/`: FSD pages layer (페이지 컴포넌트)
+
+## 📁 프로젝트 구조
+
+```
+Acci-FrontEnd/
+├── app/ # NextJS App Router 폴더 (라우팅 진입점)
+│ ├── page.tsx # 라우트 페이지들
+│ ├── layout.tsx # @/app/providers를 사용
+│ ├── globals.css # 전역 스타일
+│ ├── admin/
+│ │ └── page.tsx
+│ ├── auth/
+│ │ └── page.tsx
+│ ├── analyze/
+│ │ ├── page.tsx
+│ │ ├── upload/
+│ │ ├── loading/
+│ │ └── result/
+│ ├── repair-estimate/
+│ ├── my-page/
+│ ├── policies/
+│ └── oauth2/
+├── pages/ # NextJS Pages Router 호환성 폴더 (빈 폴더)
+│ └── README.md # ⚠️ 라우팅 파일 추가 금지
+└── src/
+ ├── app/ # FSD app layer (providers, config만)
+ │ └── providers.tsx # 전역 providers (ReactQuery 등)
+ ├── pages/ # FSD pages layer (페이지 컴포넌트)
+ │ ├── home/
+ │ ├── admin/
+ │ ├── analyze/
+ │ ├── repair-estimate/
+ │ ├── my-page/
+ │ ├── policies/
+ │ └── auth/
+ ├── widgets/ # FSD widgets layer
+ │ ├── header/
+ │ ├── footer/
+ │ ├── home/
+ │ └── ...
+ ├── features/ # FSD features layer
+ │ ├── auth/
+ │ ├── analyze/
+ │ └── repair-estimate/
+ ├── entities/ # FSD entities layer
+ │ ├── user/
+ │ ├── analysis/
+ │ ├── repair-estimate/
+ │ └── vehicle/
+ └── shared/ # FSD shared layer
+ ├── api/
+ ├── ui/
+ ├── lib/
+ ├── store/
+ └── icons/
+```
+
+### ⚠️ 중요: 루트 `pages/` 폴더에 대해
+
+Next.js는 `app/`와 `pages/`가 같은 레벨에 있어야 합니다.
+루트 `pages/` 폴더는 **빈 폴더로 유지**하며, Next.js Pages Router 호환성을 위해서만 존재합니다.
+
+- **라우팅 파일은 추가하지 마세요**: 모든 라우팅은 `app/`에서 관리
+- **FSD pages layer와 혼동하지 마세요**: 실제 페이지 컴포넌트는 `src/pages/`에 작성
+
## 📁 설정된 절대경로
```typescript
// tsconfig.json
"paths": {
- "@/*": ["./src/*"], // 전체 src 폴더
- "@/app/*": ["./src/app/*"], // App Router
- "@/pages/*": ["./src/pages/*"], // 페이지 레이어
- "@/widgets/*": ["./src/widgets/*"], // 위젯 레이어
- "@/features/*": ["./src/features/*"], // 기능 레이어
- "@/entities/*": ["./src/entities/*"], // 엔티티 레이어
- "@/shared/*": ["./src/shared/*"] // 공유 레이어
+ "@/*": ["./src/*"], // 전체 src 폴더
+ "@/app/*": ["./src/app/*"], // FSD app layer (providers, global config)
+ "@/pages/*": ["./src/pages/*"], // 📌 FSD pages layer (페이지 컴포넌트)
+ "@/widgets/*": ["./src/widgets/*"], // 위젯 레이어
+ "@/features/*": ["./src/features/*"], // 기능 레이어
+ "@/entities/*": ["./src/entities/*"], // 엔티티 레이어
+ "@/shared/*": ["./src/shared/*"] // 공유 레이어
}
```
+### 📌 중요: 레이어별 역할
+
+- **루트 `app/` 폴더**: NextJS App Router (라우팅 진입점만 담당)
+ - `page.tsx`, `layout.tsx`, `loading.tsx` 등 Next.js 라우팅 규칙 파일들
+ - FSD pages layer의 컴포넌트를 import하여 사용
+- **`@/app/*` (src/app/)**: FSD app layer (providers, global config만)
+ - `providers.tsx`: 전역 providers (ReactQuery, Theme 등)
+ - 전역 설정 파일들
+ - **라우팅 파일은 포함하지 않음**
+- **`@/pages/*` (src/pages/)**: FSD pages layer
+ - 실제 페이지 컴포넌트 구현
+ - widgets, features, entities, shared import 가능
+ - **라우팅 폴더가 아님** (컴포넌트 저장소)
+
## 🎯 사용 예시
### 1. Shared 레이어에서 다른 Shared 레이어로
@@ -42,22 +127,54 @@ import { Container } from "@/shared/ui/container";
import { cn } from "@/shared/lib/utils";
```
-### 4. Pages에서 Widgets와 Features 사용
+### 4. Pages (FSD)에서 Widgets와 Features 사용
```typescript
-// src/pages/home/ui/home-page.tsx
+// src/pages/home/HomePage.tsx (FSD pages layer)
import { Header } from "@/widgets/header";
import { Footer } from "@/widgets/footer";
-import { LoginForm } from "@/features/auth";
+import { HeroSection } from "@/widgets/home";
import { Button } from "@/shared/ui/button";
```
-### 5. App에서 Pages 사용
+### 5. App Router에서 Pages 사용 ✅
```typescript
-// src/app/page.tsx
-import { HomePage } from "@/pages/home";
-import { Button } from "@/shared/ui/button";
+// app/page.tsx (NextJS App Router)
+import HomePage from "@/pages/home/HomePage";
+import { getUserInfo } from "@/entities/user/api/get-user-info";
+
+export default async function Page() {
+ const initialUserInfo = await getUserInfo();
+ return ;
+}
+```
+
+```typescript
+// app/layout.tsx (루트 레이아웃)
+import { Providers } from "@/app/providers";
+import "./globals.css";
+
+export default function RootLayout({ children }) {
+ return (
+
+
+ {children}
+
+
+ );
+}
+```
+
+```typescript
+// src/app/providers.tsx (FSD app layer)
+"use client";
+
+import { ReactQueryProvider } from "@/shared/lib/react-query";
+
+export function Providers({ children }) {
+ return {children};
+}
```
## 🚫 금지된 import 패턴
@@ -72,26 +189,57 @@ import { HomePage } from "@/pages/home"; // ❌
import { LoginForm } from "@/features/auth"; // ❌
// features에서 pages import (금지)
-import { HomePage } from "@/pages/home"; // ❌
+import { SomePage } from "@/pages/home"; // ❌
+
+// Pages에서 App Router 직접 접근 (금지)
+import { useRouter } from "next/navigation"; // ❌ (Pages 컴포넌트는 "use client"을 지양)
```
### ✅ 올바른 예시
```typescript
-// 상위 레이어에서 하위 레이어 import (허용)
+// FSD 의존성 규칙 준수 (상위 → 하위)
import { Button } from "@/shared/ui/button"; // ✅
import { User } from "@/entities/user"; // ✅
import { LoginForm } from "@/features/auth"; // ✅
+import HomePage from "@/pages/home/HomePage"; // ✅ (App Router에서만)
```
## 📋 FSD 레이어 의존성 규칙
-1. **app** → pages, widgets, features, entities, shared
-2. **pages** → widgets, features, entities, shared
-3. **widgets** → features, entities, shared
-4. **features** → entities, shared
-5. **entities** → shared
-6. **shared** → (다른 레이어 import 금지)
+```
+app/ (루트 - NextJS App Router)
+ ↓ import
+@/app (FSD app layer - providers)
+ ↓ import
+@/pages (FSD pages layer)
+ ↓ import
+@/widgets + @/features
+ ↓ import
+@/entities
+ ↓ import
+@/shared
+```
+
+### 의존성 사슬 (상위 → 하위만 가능)
+
+1. **app/** (루트 - App Router) → @/app, @/pages, @/widgets, @/features, @/entities, @/shared
+ - NextJS 라우팅 진입점
+ - Server/Client Components 구분
+2. **@/app** (FSD app layer) → @/shared만
+ - 전역 Providers (ReactQuery, Theme 등)
+ - Global configuration
+ - **다른 FSD 레이어 import 금지**
+3. **@/pages** (FSD pages layer) → @/widgets, @/features, @/entities, @/shared
+ - 페이지 컴포넌트 (화면 구성)
+4. **@/widgets** → @/features, @/entities, @/shared
+ - 기능 조합 (헤더, 푸터 등)
+5. **@/features** → @/entities, @/shared
+ - 비즈니스 로직 (인증, 분석 등)
+6. **@/entities** → @/shared
+ - 데이터 모델 (User, Analysis 등)
+7. **@/shared** → 다른 레이어 불가
+ - 기본 UI, 유틸, 상수
## 🔧 추가 설정
@@ -100,9 +248,111 @@ import { LoginForm } from "@/features/auth"; // ✅
```typescript
const nextConfig: NextConfig = {
experimental: {
- typedRoutes: true, // 타입 안전한 라우팅
+ optimizePackageImports: ["@/shared/ui", "@/shared/icons"],
+ },
+ images: {
+ formats: ["image/avif", "image/webp"],
},
};
```
+### TypeScript 경로 설정 (tsconfig.json)
+
+```json
+{
+ "compilerOptions": {
+ "paths": {
+ "@/*": ["./src/*"],
+ "@/app/*": ["./src/app/*"],
+ "@/pages/*": ["./src/pages/*"],
+ "@/widgets/*": ["./src/widgets/*"],
+ "@/features/*": ["./src/features/*"],
+ "@/entities/*": ["./src/entities/*"],
+ "@/shared/*": ["./src/shared/*"]
+ }
+ }
+}
+```
+
+## 📌 App Router + FSD 적용 시 주의사항
+
+### 1. 폴더 역할 구분
+
+- **루트 `app/`**: NextJS App Router (라우팅만)
+ - `page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx` 등
+ - FSD pages layer 컴포넌트를 import
+- **`src/app/`**: FSD app layer (providers, config만)
+ - `providers.tsx`: 전역 providers
+ - 설정 파일들
+ - **라우팅 파일 금지**
+- **`src/pages/`**: FSD pages layer (페이지 컴포넌트)
+ - 실제 페이지 UI 구현
+ - **라우팅 폴더 아님**
+
+### 2. Server/Client Components 분리
+
+```typescript
+// src/pages/home/HomePage.tsx
+// Server Component 기본
+import { getUserInfo } from "@/entities/user/api";
+
+export default function HomePage({ initialUserInfo }) {
+ return {/* ... */}
;
+}
+```
+
+```typescript
+// src/features/auth/ui/login-form.tsx
+"use client"; // Client Component 명시
+
+import { useState } from "react";
+
+export function LoginForm() {
+ const [email, setEmail] = useState("");
+ return ;
+}
+```
+
+### 3. Import 자동완성
+
+`@/pages`, `@/widgets` 등의 경로 alias를 사용하면 IDE 자동완성이 정확하게 작동합니다.
+
+### 4. FSD app layer 사용 예시
+
+```typescript
+// src/app/providers.tsx
+"use client";
+
+import { ReactQueryProvider } from "@/shared/lib/react-query";
+import { ThemeProvider } from "@/shared/ui/theme-provider";
+
+export function Providers({ children }) {
+ return (
+
+
+ {children}
+
+
+ );
+}
+```
+
+```typescript
+// app/layout.tsx
+import { Providers } from "@/app/providers";
+import "./globals.css";
+
+export default function RootLayout({ children }) {
+ return (
+
+
+ {children}
+
+
+ );
+}
+```
+
+---
+
이제 FSD 아키텍처에 맞는 절대경로를 사용하여 깔끔하고 일관된 import 구조를 유지할 수 있습니다!
diff --git a/README.md b/README.md
index c93638e..d85c1e2 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
## 🔗 Acci 바로가기
-https://acci-ai.vercel.app/
+https://acci-ai.site/
@@ -73,25 +73,57 @@
## 📁 프로젝트 구조 (FSD)
```
-src/
-├── app/ # Next.js App Router
-│ ├── layout.tsx
-│ ├── page.tsx
-│ └── globals.css
-├── pages/ # 페이지 레이어
-│ └── home/
-├── widgets/ # 위젯 레이어
-│ ├── header/
-│ └── footer/
-├── features/ # 기능 레이어
-│ └── auth/
-├── entities/ # 엔티티 레이어
-│ └── user/
-└── shared/ # 공유 레이어
- ├── ui/ # 공통 UI 컴포넌트
- ├── lib/ # 유틸리티 함수
- ├── api/ # API 클라이언트
- └── config/ # 설정 파일
+Acci-FrontEnd/
+├── app/ # NextJS App Router 폴더 (라우팅 진입점)
+│ ├── page.tsx # 라우트 페이지들
+│ ├── layout.tsx # @/app/providers를 사용
+│ ├── globals.css # 전역 스타일
+│ ├── admin/
+│ │ └── page.tsx
+│ ├── auth/
+│ │ └── page.tsx
+│ ├── analyze/
+│ │ ├── page.tsx
+│ │ ├── upload/
+│ │ ├── loading/
+│ │ └── result/
+│ ├── repair-estimate/
+│ ├── my-page/
+│ ├── policies/
+│ └── oauth2/
+├── pages/ # NextJS Pages Router 호환성 폴더 (빈 폴더)
+│ └── README.md # ⚠️ 라우팅 파일 추가 금지
+└── src/
+ ├── app/ # FSD app layer (providers, config만)
+ │ └── providers.tsx # 전역 providers (ReactQuery 등)
+ ├── pages/ # FSD pages layer (페이지 컴포넌트)
+ │ ├── home/
+ │ ├── admin/
+ │ ├── analyze/
+ │ ├── repair-estimate/
+ │ ├── my-page/
+ │ ├── policies/
+ │ └── auth/
+ ├── widgets/ # FSD widgets layer
+ │ ├── header/
+ │ ├── footer/
+ │ ├── home/
+ │ └── ...
+ ├── features/ # FSD features layer
+ │ ├── auth/
+ │ ├── analyze/
+ │ └── repair-estimate/
+ ├── entities/ # FSD entities layer
+ │ ├── user/
+ │ ├── analysis/
+ │ ├── repair-estimate/
+ │ └── vehicle/
+ └── shared/ # FSD shared layer
+ ├── api/
+ ├── ui/
+ ├── lib/
+ ├── store/
+ └── icons/
```
diff --git a/src/app/admin/page.tsx b/app/admin/page.tsx
similarity index 100%
rename from src/app/admin/page.tsx
rename to app/admin/page.tsx
diff --git a/src/app/analyze/loading/page.tsx b/app/analyze/loading/page.tsx
similarity index 100%
rename from src/app/analyze/loading/page.tsx
rename to app/analyze/loading/page.tsx
diff --git a/src/app/analyze/page.tsx b/app/analyze/page.tsx
similarity index 100%
rename from src/app/analyze/page.tsx
rename to app/analyze/page.tsx
diff --git a/src/app/analyze/result/[id]/page.tsx b/app/analyze/result/[id]/page.tsx
similarity index 100%
rename from src/app/analyze/result/[id]/page.tsx
rename to app/analyze/result/[id]/page.tsx
diff --git a/src/app/analyze/upload/page.tsx b/app/analyze/upload/page.tsx
similarity index 100%
rename from src/app/analyze/upload/page.tsx
rename to app/analyze/upload/page.tsx
diff --git a/src/app/auth/page.tsx b/app/auth/page.tsx
similarity index 100%
rename from src/app/auth/page.tsx
rename to app/auth/page.tsx
diff --git a/src/app/favicon.ico b/app/favicon.ico
similarity index 100%
rename from src/app/favicon.ico
rename to app/favicon.ico
diff --git a/src/app/globals.css b/app/globals.css
similarity index 100%
rename from src/app/globals.css
rename to app/globals.css
diff --git a/src/app/layout.tsx b/app/layout.tsx
similarity index 61%
rename from src/app/layout.tsx
rename to app/layout.tsx
index ef4afbe..ac6a00d 100644
--- a/src/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,58 +1,30 @@
-import { ReactQueryProvider } from "@/shared/lib/react-query";
+import { Providers } from "@/app/providers";
import type { Metadata, Viewport } from "next";
import localFont from "next/font/local";
import { Geist_Mono } from "next/font/google";
import "./globals.css";
+// 실제 사용하는 폰트 weight만 로드하여 초기 로딩 속도 개선
const pretendard = localFont({
variable: "--font-pretendard",
display: "swap",
+ preload: true, // 폰트 프리로드 활성화
src: [
{
- path: "../../public/fonts/pretendard/Pretendard-Thin.woff2",
- weight: "100",
- style: "normal",
- },
- {
- path: "../../public/fonts/pretendard/Pretendard-ExtraLight.woff2",
- weight: "200",
- style: "normal",
- },
- {
- path: "../../public/fonts/pretendard/Pretendard-Light.woff2",
- weight: "300",
- style: "normal",
- },
- {
- path: "../../public/fonts/pretendard/Pretendard-Regular.woff2",
+ path: "../public/fonts/pretendard/Pretendard-Regular.woff2",
weight: "400",
style: "normal",
},
{
- path: "../../public/fonts/pretendard/Pretendard-Medium.woff2",
+ path: "../public/fonts/pretendard/Pretendard-Medium.woff2",
weight: "500",
style: "normal",
},
{
- path: "../../public/fonts/pretendard/Pretendard-SemiBold.woff2",
+ path: "../public/fonts/pretendard/Pretendard-SemiBold.woff2",
weight: "600",
style: "normal",
},
- {
- path: "../../public/fonts/pretendard/Pretendard-Bold.woff2",
- weight: "700",
- style: "normal",
- },
- {
- path: "../../public/fonts/pretendard/Pretendard-ExtraBold.woff2",
- weight: "800",
- style: "normal",
- },
- {
- path: "../../public/fonts/pretendard/Pretendard-Black.woff2",
- weight: "900",
- style: "normal",
- },
],
});
@@ -95,8 +67,13 @@ export default function RootLayout({
}>) {
return (
+
+ {/* DNS Prefetch 및 Preconnect로 외부 리소스 로딩 최적화 */}
+
+
+
- {children}
+ {children}
);
diff --git a/src/app/my-page/[id]/page.tsx b/app/my-page/[id]/page.tsx
similarity index 100%
rename from src/app/my-page/[id]/page.tsx
rename to app/my-page/[id]/page.tsx
diff --git a/src/app/my-page/analysis/page.tsx b/app/my-page/analysis/page.tsx
similarity index 100%
rename from src/app/my-page/analysis/page.tsx
rename to app/my-page/analysis/page.tsx
diff --git a/src/app/my-page/page.tsx b/app/my-page/page.tsx
similarity index 100%
rename from src/app/my-page/page.tsx
rename to app/my-page/page.tsx
diff --git a/src/app/my-page/repair-estimates/page.tsx b/app/my-page/repair-estimates/page.tsx
similarity index 100%
rename from src/app/my-page/repair-estimates/page.tsx
rename to app/my-page/repair-estimates/page.tsx
diff --git a/src/app/not-found.tsx b/app/not-found.tsx
similarity index 100%
rename from src/app/not-found.tsx
rename to app/not-found.tsx
diff --git a/src/app/oauth2/redirect/page.tsx b/app/oauth2/redirect/page.tsx
similarity index 100%
rename from src/app/oauth2/redirect/page.tsx
rename to app/oauth2/redirect/page.tsx
diff --git a/src/app/page.tsx b/app/page.tsx
similarity index 100%
rename from src/app/page.tsx
rename to app/page.tsx
diff --git a/src/app/policies/cookie-policy/page.tsx b/app/policies/cookie-policy/page.tsx
similarity index 100%
rename from src/app/policies/cookie-policy/page.tsx
rename to app/policies/cookie-policy/page.tsx
diff --git a/src/app/policies/page.tsx b/app/policies/page.tsx
similarity index 100%
rename from src/app/policies/page.tsx
rename to app/policies/page.tsx
diff --git a/src/app/policies/privacy-policy/page.tsx b/app/policies/privacy-policy/page.tsx
similarity index 100%
rename from src/app/policies/privacy-policy/page.tsx
rename to app/policies/privacy-policy/page.tsx
diff --git a/src/app/policies/terms-of-service/page.tsx b/app/policies/terms-of-service/page.tsx
similarity index 100%
rename from src/app/policies/terms-of-service/page.tsx
rename to app/policies/terms-of-service/page.tsx
diff --git a/src/app/repair-estimate/page.tsx b/app/repair-estimate/page.tsx
similarity index 100%
rename from src/app/repair-estimate/page.tsx
rename to app/repair-estimate/page.tsx
diff --git a/src/app/repair-estimate/result/[id]/page.tsx b/app/repair-estimate/result/[id]/page.tsx
similarity index 100%
rename from src/app/repair-estimate/result/[id]/page.tsx
rename to app/repair-estimate/result/[id]/page.tsx
diff --git a/next.config.ts b/next.config.ts
index d972477..a9db9b6 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -4,6 +4,8 @@ const nextConfig: NextConfig = {
/* config options here */
// FSD 아키텍처를 위한 절대경로 설정
typedRoutes: true,
+
+ // 이미지 최적화 설정
images: {
remotePatterns: [
{
@@ -11,6 +13,18 @@ const nextConfig: NextConfig = {
hostname: "acci-s3.s3.ap-northeast-2.amazonaws.com",
},
],
+ formats: ["image/avif", "image/webp"], // 최신 포맷 우선 사용
+ deviceSizes: [640, 750, 828, 1080, 1200, 1920], // 반응형 이미지 크기
+ minimumCacheTTL: 60, // 이미지 캐시 시간 (초)
+ },
+
+ // 성능 최적화
+ compress: true, // gzip 압축 활성화
+ poweredByHeader: false, // X-Powered-By 헤더 제거 (보안)
+
+ // 실험적 기능 (성능 개선)
+ experimental: {
+ optimizePackageImports: ["@/shared/ui", "@/shared/icons"], // 패키지 import 최적화
},
};
diff --git a/pages/README.md b/pages/README.md
new file mode 100644
index 0000000..f0527dc
--- /dev/null
+++ b/pages/README.md
@@ -0,0 +1,15 @@
+# Pages Router Compatibility Folder
+
+⚠️ **이 폴더는 Next.js Pages Router 호환성을 위한 빈 폴더입니다.**
+
+## 용도
+
+- Next.js는 `app/`와 `pages/`가 같은 레벨에 있어야 합니다
+- 루트에 `app/` (App Router)가 있고, `src/pages/` (FSD pages layer)가 있어서
+- Next.js가 인식할 수 있도록 루트에 빈 `pages/` 폴더를 생성했습니다
+
+## 주의사항
+
+- **이 폴더에는 라우팅 파일을 추가하지 마세요**
+- 모든 라우팅은 루트 `app/` 폴더에서 관리됩니다
+- 실제 페이지 컴포넌트는 `src/pages/` (FSD pages layer)에 작성됩니다
diff --git a/public/images/balance-car.png b/public/images/balance-car.png
deleted file mode 100644
index 68f9a33..0000000
Binary files a/public/images/balance-car.png and /dev/null differ
diff --git a/public/images/balance-car.webp b/public/images/balance-car.webp
new file mode 100644
index 0000000..3051b87
Binary files /dev/null and b/public/images/balance-car.webp differ
diff --git a/src/app/providers.tsx b/src/app/providers.tsx
new file mode 100644
index 0000000..e798eb9
--- /dev/null
+++ b/src/app/providers.tsx
@@ -0,0 +1,12 @@
+"use client";
+
+import { ReactQueryProvider } from "@/shared/lib/react-query";
+import { ReactNode } from "react";
+
+/**
+ * FSD app layer - 전역 providers
+ * App Router의 layout에서 사용하는 providers 모음
+ */
+export function Providers({ children }: { children: ReactNode }) {
+ return {children};
+}
diff --git a/src/pages/home/HomePage.tsx b/src/pages/home/HomePage.tsx
index fe8298a..3681db3 100644
--- a/src/pages/home/HomePage.tsx
+++ b/src/pages/home/HomePage.tsx
@@ -1,7 +1,21 @@
import type { UserInfo } from "@/entities/user/model/user-info";
import { Header } from "@/widgets/header/Header";
import { Footer } from "@/widgets/footer/Footer";
-import { HeroSection, FeaturesSection, EstimateSection, ReviewsSection, CtaSection } from "@/widgets/home";
+import { HeroSection, FeaturesSection } from "@/widgets/home";
+import dynamic from "next/dynamic";
+
+// 스크롤 후 보이는 섹션들은 동적 로딩으로 초기 번들 크기 최적화
+const EstimateSection = dynamic(() => import("@/widgets/home").then((mod) => ({ default: mod.EstimateSection })), {
+ loading: () => , // 레이아웃 시프트 방지
+});
+
+const ReviewsSection = dynamic(() => import("@/widgets/home").then((mod) => ({ default: mod.ReviewsSection })), {
+ loading: () => ,
+});
+
+const CtaSection = dynamic(() => import("@/widgets/home").then((mod) => ({ default: mod.CtaSection })), {
+ loading: () => ,
+});
type HomePageProps = {
initialUserInfo?: UserInfo | null;
diff --git a/src/widgets/header/Header.tsx b/src/widgets/header/Header.tsx
index 582ee2a..40ce1d5 100644
--- a/src/widgets/header/Header.tsx
+++ b/src/widgets/header/Header.tsx
@@ -35,7 +35,6 @@ export function Header({ initialUserInfo = null }: HeaderProps) {
}
}, [initialUserInfo, setUser]);
-
// 모바일 메뉴가 열렸을 때 body 스크롤 방지
useEffect(() => {
if (mobileMenuOpen) {
diff --git a/src/widgets/home/HeroSection.tsx b/src/widgets/home/HeroSection.tsx
index b3cc0ae..5f52a45 100644
--- a/src/widgets/home/HeroSection.tsx
+++ b/src/widgets/home/HeroSection.tsx
@@ -23,7 +23,16 @@ export function HeroSection() {
-
+