diff --git a/apps/as/README.md b/apps/as/README.md index 46a8536a5..79d0b2e2a 100644 --- a/apps/as/README.md +++ b/apps/as/README.md @@ -13,46 +13,40 @@ Next.js 애플리케이션 with FSD(Feature Sliced Design) 아키텍처 - **HTTP 클라이언트**: Axios - **날짜 처리**: Day.js -## 프로젝트 구조 (FSD) +## 프로젝트 구조 (FSD + Next.js App Router) -이 프로젝트는 **Feature-Sliced Design v2.1**을 따르며, 계층적 아키텍처로 구성되어 있습니다. +이 프로젝트는 **Feature-Sliced Design v2.1**과 **FSD 공식 Next.js 가이드**에 맞춰 구성되어 있습니다. Next.js `app/`은 라우트만 담당하고, 실제 레이어는 `src/` 아래에 있습니다. ``` as/ -├── app/ # App 레이어 (Next.js App Router) -│ ├── (routes)/ # 라우트 구조 -│ ├── layout.tsx # 루트 레이아웃 -│ ├── page.tsx # 홈 페이지 -│ ├── globals.css # 글로벌 스타일 -│ └── providers.tsx # 전역 providers +├── 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' │ -├── widgets/ # Widgets 레이어 -│ └── [widget-name]/ # 큰 독립적 UI 블록 (여러 페이지에서 재사용) -│ ├── ui/ -│ ├── model/ -│ └── index.ts +├── pages/ # 빈 폴더 + README (Next.js가 src/pages를 Pages Router로 쓰지 않도록) +│ └── README.md │ -├── features/ # Features 레이어 -│ └── [feature-name]/ # 사용자 상호작용 기능 (여러 페이지에서 재사용) -│ ├── ui/ -│ ├── api/ -│ ├── model/ -│ └── index.ts -│ -├── entities/ # Entities 레이어 -│ └── [entity-name]/ # 비즈니스 엔티티 (User, Product 등) -│ ├── model/ -│ ├── api/ -│ ├── ui/ -│ └── index.ts -│ -└── shared/ # Shared 레이어 - ├── ui/ # UI Kit (비즈니스 로직 없는 공통 컴포넌트) - ├── api/ # API 클라이언트 설정 - ├── lib/ # 내부 라이브러리 (dates, colors 등) - ├── config/ # 환경 설정, feature flags - ├── types/ # 공통 타입 정의 - └── routes/ # 라우트 상수 +└── 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/ ``` ### 계층 구조 이해하기 @@ -86,10 +80,10 @@ shared/ ↓ 가장 낮은 책임, 의존성 없음 - **특징**: 슬라이스가 없고 세그먼트로만 구성 - **의존성**: 모든 하위 레이어 사용 가능 -### 2. Pages (app 디렉토리) +### 2. Pages (src/pages) - **목적**: 웹사이트나 애플리케이션을 구성하는 페이지/화면 - **내용**: 페이지 UI, 로딩 상태, 에러 바운더리, 데이터 fetching -- **특징**: 한 페이지당 한 슬라이스 (유사한 페이지는 그룹화 가능) +- **특징**: 한 페이지당 한 슬라이스 (유사한 페이지는 그룹화 가능). Next.js `app/`의 route 파일에서 re-export - **의존성**: `widgets`, `features`, `entities`, `shared` 사용 가능 > 💡 **FSD v2.1 권장사항**: "pages-first" 접근 방식을 따라, 재사용되지 않는 큰 UI 블록과 비즈니스 로직은 페이지 슬라이스에 유지하세요. diff --git a/apps/as/app/(with-base-layout)/layout.tsx b/apps/as/app/(with-base-layout)/layout.tsx index 1d182a0ee..24e6e7276 100644 --- a/apps/as/app/(with-base-layout)/layout.tsx +++ b/apps/as/app/(with-base-layout)/layout.tsx @@ -1,31 +1,9 @@ -"use client"; +import { BaseLayoutWrapper } from "@/app/layouts/base-layout"; -import { useCallback } from "react"; -import { usePathname, useRouter } from "next/navigation"; -import { useQueryClient } from "@tanstack/react-query"; -import { BaseLayout } from "@common/components"; -import type { MenuItem } from "@/entities/menu"; -import { PageLayout } from "@/shared/ui/page-layout"; - -export default function WithBaseLayout({ children }: { children: React.ReactNode }) { - const router = useRouter(); - const pathname = usePathname(); - const queryClient = useQueryClient(); - - const handleMenuClick = useCallback( - (item: MenuItem) => { - router.push(item.urlPath); - }, - [router], - ); - - return ( - - {children} - - ); +interface WithBaseLayoutProps { + children: React.ReactNode; +} + +export default function WithBaseLayout({ children }: WithBaseLayoutProps) { + return {children}; } diff --git a/apps/as/app/(with-base-layout)/page.tsx b/apps/as/app/(with-base-layout)/page.tsx index e118e732e..82a918b59 100644 --- a/apps/as/app/(with-base-layout)/page.tsx +++ b/apps/as/app/(with-base-layout)/page.tsx @@ -1,9 +1 @@ -"use client"; - -export default function MainPage() { - return ( -
-

Home

-
- ); -} +export { MainPage as default } from "@/pages/home"; diff --git a/apps/as/app/layout.tsx b/apps/as/app/layout.tsx index f08c67ca7..05858ffe8 100644 --- a/apps/as/app/layout.tsx +++ b/apps/as/app/layout.tsx @@ -1,10 +1,10 @@ import type { Metadata } from "next"; import { cookies } from "next/headers"; import { Noto_Sans_KR } from "next/font/google"; -import { Providers } from "./providers"; +import { Providers } from "@/app/providers"; import { setCookie } from "@/shared/lib"; import { SITE_ID } from "@/shared/config"; -import "./globals.css"; +import "@/app/styles/globals.css"; const notoSansKR = Noto_Sans_KR({ subsets: ["latin"], diff --git a/apps/as/next-env.d.ts b/apps/as/next-env.d.ts index 1b3be0840..3cd7048ed 100644 --- a/apps/as/next-env.d.ts +++ b/apps/as/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/as/pages/README.md b/apps/as/pages/README.md new file mode 100644 index 000000000..287ea7ddb --- /dev/null +++ b/apps/as/pages/README.md @@ -0,0 +1,9 @@ +# 이 폴더는 비워 둡니다 (FSD + Next.js App Router) + +Next.js가 `src/pages`를 **Pages Router**용 `pages` 디렉터리로 인식하지 않도록, +프로젝트 루트에 **빈 `pages` 폴더**를 두는 것이 FSD 공식 가이드 권장사항입니다. + +- 실제 페이지(FSD Pages 레이어)는 **`src/pages`**에 있습니다. +- Next.js 라우트는 **`app/`** 에서 `src/pages`를 re-export 하는 방식으로 연결됩니다. + +[Feature-Sliced Design - Usage with Next.js (App Router)](https://feature-sliced.design/docs/guides/tech/with-nextjs) diff --git a/apps/as/src/app/layouts/base-layout.tsx b/apps/as/src/app/layouts/base-layout.tsx new file mode 100644 index 000000000..72b95709f --- /dev/null +++ b/apps/as/src/app/layouts/base-layout.tsx @@ -0,0 +1,35 @@ +"use client"; + +import { useCallback } from "react"; +import { usePathname, useRouter } from "next/navigation"; +import { useQueryClient } from "@tanstack/react-query"; +import { BaseLayout } from "@common/components"; +import type { MenuItem } from "@/entities/menu"; +import { PageLayout } from "@/shared/ui/page-layout"; + +interface BaseLayoutWrapperProps { + children: React.ReactNode; +} + +export function BaseLayoutWrapper({ children }: BaseLayoutWrapperProps) { + const router = useRouter(); + const pathname = usePathname(); + const queryClient = useQueryClient(); + + const handleMenuClick = useCallback( + (item: MenuItem) => { + router.push(item.urlPath); + }, + [router], + ); + + return ( + + {children} + + ); +} diff --git a/apps/as/app/providers.tsx b/apps/as/src/app/providers/index.tsx similarity index 100% rename from apps/as/app/providers.tsx rename to apps/as/src/app/providers/index.tsx diff --git a/apps/as/app/globals.css b/apps/as/src/app/styles/globals.css similarity index 95% rename from apps/as/app/globals.css rename to apps/as/src/app/styles/globals.css index 60bc92fb6..2b1b139cf 100644 --- a/apps/as/app/globals.css +++ b/apps/as/src/app/styles/globals.css @@ -1,15 +1,15 @@ -@import "@common/assets/styles/base.css"; -@import "@common/assets/styles/diveicon.css"; -@import "@common/components/index.css"; - -@tailwind base; -@tailwind components; -@tailwind utilities; - -html, -body { - color: var(--foreground); - background: var(--background); - font-family: var(--font-noto-sans-kr), sans-serif; - font-size: 10px; -} +@import "@common/assets/styles/base.css"; +@import "@common/assets/styles/diveicon.css"; +@import "@common/components/index.css"; + +@tailwind base; +@tailwind components; +@tailwind utilities; + +html, +body { + color: var(--foreground); + background: var(--background); + font-family: var(--font-noto-sans-kr), sans-serif; + font-size: 10px; +} diff --git a/apps/as/entities/README.md b/apps/as/src/entities/README.md similarity index 100% rename from apps/as/entities/README.md rename to apps/as/src/entities/README.md diff --git a/apps/as/entities/instl-sncn/api/index.ts b/apps/as/src/entities/instl-sncn/api/index.ts similarity index 100% rename from apps/as/entities/instl-sncn/api/index.ts rename to apps/as/src/entities/instl-sncn/api/index.ts diff --git a/apps/as/entities/instl-sncn/api/instl-sncn-service-impl.ts b/apps/as/src/entities/instl-sncn/api/instl-sncn-service-impl.ts similarity index 100% rename from apps/as/entities/instl-sncn/api/instl-sncn-service-impl.ts rename to apps/as/src/entities/instl-sncn/api/instl-sncn-service-impl.ts diff --git a/apps/as/entities/instl-sncn/api/queries.ts b/apps/as/src/entities/instl-sncn/api/queries.ts similarity index 100% rename from apps/as/entities/instl-sncn/api/queries.ts rename to apps/as/src/entities/instl-sncn/api/queries.ts diff --git a/apps/as/entities/instl-sncn/index.ts b/apps/as/src/entities/instl-sncn/index.ts similarity index 100% rename from apps/as/entities/instl-sncn/index.ts rename to apps/as/src/entities/instl-sncn/index.ts diff --git a/apps/as/entities/instl-sncn/lib/format.ts b/apps/as/src/entities/instl-sncn/lib/format.ts similarity index 100% rename from apps/as/entities/instl-sncn/lib/format.ts rename to apps/as/src/entities/instl-sncn/lib/format.ts diff --git a/apps/as/entities/instl-sncn/lib/index.ts b/apps/as/src/entities/instl-sncn/lib/index.ts similarity index 100% rename from apps/as/entities/instl-sncn/lib/index.ts rename to apps/as/src/entities/instl-sncn/lib/index.ts diff --git a/apps/as/entities/instl-sncn/lib/validation.ts b/apps/as/src/entities/instl-sncn/lib/validation.ts similarity index 100% rename from apps/as/entities/instl-sncn/lib/validation.ts rename to apps/as/src/entities/instl-sncn/lib/validation.ts diff --git a/apps/as/entities/instl-sncn/model/constants.ts b/apps/as/src/entities/instl-sncn/model/constants.ts similarity index 100% rename from apps/as/entities/instl-sncn/model/constants.ts rename to apps/as/src/entities/instl-sncn/model/constants.ts diff --git a/apps/as/entities/instl-sncn/model/index.ts b/apps/as/src/entities/instl-sncn/model/index.ts similarity index 100% rename from apps/as/entities/instl-sncn/model/index.ts rename to apps/as/src/entities/instl-sncn/model/index.ts diff --git a/apps/as/entities/instl-sncn/model/instl-sncn-service.ts b/apps/as/src/entities/instl-sncn/model/instl-sncn-service.ts similarity index 100% rename from apps/as/entities/instl-sncn/model/instl-sncn-service.ts rename to apps/as/src/entities/instl-sncn/model/instl-sncn-service.ts diff --git a/apps/as/entities/instl-sncn/model/types.ts b/apps/as/src/entities/instl-sncn/model/types.ts similarity index 100% rename from apps/as/entities/instl-sncn/model/types.ts rename to apps/as/src/entities/instl-sncn/model/types.ts diff --git a/apps/as/entities/menu/index.ts b/apps/as/src/entities/menu/index.ts similarity index 100% rename from apps/as/entities/menu/index.ts rename to apps/as/src/entities/menu/index.ts diff --git a/apps/as/entities/menu/model/index.ts b/apps/as/src/entities/menu/model/index.ts similarity index 100% rename from apps/as/entities/menu/model/index.ts rename to apps/as/src/entities/menu/model/index.ts diff --git a/apps/as/entities/menu/model/types.ts b/apps/as/src/entities/menu/model/types.ts similarity index 100% rename from apps/as/entities/menu/model/types.ts rename to apps/as/src/entities/menu/model/types.ts diff --git a/apps/as/features/README.md b/apps/as/src/features/README.md similarity index 100% rename from apps/as/features/README.md rename to apps/as/src/features/README.md diff --git a/apps/as/src/pages/home/index.ts b/apps/as/src/pages/home/index.ts new file mode 100644 index 000000000..d11882ce5 --- /dev/null +++ b/apps/as/src/pages/home/index.ts @@ -0,0 +1 @@ +export { MainPage } from "./ui/main-page"; diff --git a/apps/as/src/pages/home/ui/main-page.tsx b/apps/as/src/pages/home/ui/main-page.tsx new file mode 100644 index 000000000..0370d5814 --- /dev/null +++ b/apps/as/src/pages/home/ui/main-page.tsx @@ -0,0 +1,9 @@ +"use client"; + +export function MainPage() { + return ( +
+

Home

+
+ ); +} diff --git a/apps/as/shared/README.md b/apps/as/src/shared/README.md similarity index 100% rename from apps/as/shared/README.md rename to apps/as/src/shared/README.md diff --git a/apps/as/shared/api/client.ts b/apps/as/src/shared/api/client.ts similarity index 100% rename from apps/as/shared/api/client.ts rename to apps/as/src/shared/api/client.ts diff --git a/apps/as/shared/api/index.ts b/apps/as/src/shared/api/index.ts similarity index 100% rename from apps/as/shared/api/index.ts rename to apps/as/src/shared/api/index.ts diff --git a/apps/as/shared/config/env.ts b/apps/as/src/shared/config/env.ts similarity index 100% rename from apps/as/shared/config/env.ts rename to apps/as/src/shared/config/env.ts diff --git a/apps/as/shared/config/index.ts b/apps/as/src/shared/config/index.ts similarity index 100% rename from apps/as/shared/config/index.ts rename to apps/as/src/shared/config/index.ts diff --git a/apps/as/shared/lib/cookie.ts b/apps/as/src/shared/lib/cookie.ts similarity index 100% rename from apps/as/shared/lib/cookie.ts rename to apps/as/src/shared/lib/cookie.ts diff --git a/apps/as/shared/lib/dayjs.ts b/apps/as/src/shared/lib/dayjs.ts similarity index 100% rename from apps/as/shared/lib/dayjs.ts rename to apps/as/src/shared/lib/dayjs.ts diff --git a/apps/as/shared/lib/index.ts b/apps/as/src/shared/lib/index.ts similarity index 100% rename from apps/as/shared/lib/index.ts rename to apps/as/src/shared/lib/index.ts diff --git a/apps/as/shared/lib/query-client.ts b/apps/as/src/shared/lib/query-client.ts similarity index 100% rename from apps/as/shared/lib/query-client.ts rename to apps/as/src/shared/lib/query-client.ts diff --git a/apps/as/shared/model/index.ts b/apps/as/src/shared/model/index.ts similarity index 100% rename from apps/as/shared/model/index.ts rename to apps/as/src/shared/model/index.ts diff --git a/apps/as/shared/ui/index.ts b/apps/as/src/shared/ui/index.ts similarity index 100% rename from apps/as/shared/ui/index.ts rename to apps/as/src/shared/ui/index.ts diff --git a/apps/as/shared/ui/page-layout.tsx b/apps/as/src/shared/ui/page-layout.tsx similarity index 100% rename from apps/as/shared/ui/page-layout.tsx rename to apps/as/src/shared/ui/page-layout.tsx diff --git a/apps/as/widgets/README.md b/apps/as/src/widgets/README.md similarity index 100% rename from apps/as/widgets/README.md rename to apps/as/src/widgets/README.md diff --git a/apps/as/tsconfig.json b/apps/as/tsconfig.json index 15b023415..8428fd5c2 100644 --- a/apps/as/tsconfig.json +++ b/apps/as/tsconfig.json @@ -13,19 +13,9 @@ "isolatedModules": true, "jsx": "preserve", "incremental": true, - "plugins": [ - { - "name": "next" - } - ], + "plugins": [{ "name": "next" }], "paths": { - "@/*": ["./*"], - "@/app/*": ["./app/*"], - "@/shared/*": ["./shared/*"], - "@/entities/*": ["./entities/*"], - "@/features/*": ["./features/*"], - "@/widgets/*": ["./widgets/*"], - "@/pages/*": ["./pages/*"], + "@/*": ["./src/*"], "@common/components": ["../../packages/common/components/dist/"], "@common/network": ["../../packages/common/network/"] }