# Next.js App Router의 라우트 그룹(Route Groups) 구현 분석
## 개요
Next.js의 App Router에서는 괄호로 묶인 디렉토리(`(with-base-layout)`, `(without-base-layout)`)를 라우트 그룹으로 처리하여 URL 경로에 영향을 주지 않으면서 서로 다른 레이아웃을 적용할 수 있게 합니다. 이 문서에서는 프로젝트에서 라우트 그룹이 어떻게 구현되고 사용되는지 분석합니다.
## 라우트 그룹 구조 분석
### 1. 디렉토리 구조
프로젝트에서는 두 가지 주요 라우트 그룹이 사용되고 있습니다:
```
/apps/cs/app/
├── (with-base-layout)/
│ ├── banner/
│ ├── bbs/
│ ├── code/
│ ├── contents/
│ ├── dashboard/
│ ├── ...
│ ├── layout.tsx
│ └── loading.tsx
├── (without-base-layout)/
│ ├── user-survey-article/
│ └── user-survey-result/
└── layout.tsx
```
### 2. 라우트 그룹별 레이아웃 구현
#### 루트 레이아웃 (`/apps/cs/app/layout.tsx`)
```tsx
import type { Metadata } from "next";
import { App } from "@/app";
export const metadata: Metadata = {
title: "유역하수도 통합 정보플랫폼",
};
export default App;
```
#### App 컴포넌트 (`/apps/cs/src/app/index.tsx`)
```tsx
import "./styles/base.css";
import "./styles/components.css";
import "@fontsource-variable/noto-sans-kr";
import { AppProvider } from "./providers";
import { cookies } from "next/headers";
const App = async ({ children }: Readonly<{ children: React.ReactNode }>) => {
const theme = (await cookies()).get("site-theme-key");
return (
{children}
);
};
export { App };
```
#### (with-base-layout) 레이아웃 (`/apps/cs/app/(with-base-layout)/layout.tsx`)
```tsx
"use client";
import { usePathname, useRouter } from "next/navigation";
import { useQueryClient } from "@tanstack/react-query";
import { BaseLayout } from "@common/components";
import type { MenuItem } from "@/entities/menu";
import { useMenuStore } from "@/shared/lib";
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 setCurrentMenuInfo = useMenuStore((state) => state.setCurrentMenuInfo);
const handleMenuClick = (item: MenuItem) => {
setCurrentMenuInfo(item);
router.push(item.urlPath);
};
return (
{children}
);
}
```
#### PageLayout 컴포넌트 (`/apps/cs/src/shared/ui/page-layout.tsx`)
```tsx
import { PageTitle } from "@common/components";
import { useMenuStore } from "../lib/use-menu-store";
function PageLayout({ children }: { children: React.ReactNode }) {
const currentMenuInfo = useMenuStore((state) => state.currentMenuInfo);
const menuPaths = currentMenuInfo?.menuPath
?.split(">")
.map((path) => path.trim());
return (
);
}
```
## 라우트 그룹의 작동 원리
### 1. URL 경로에 영향을 주지 않는 그룹화
Next.js App Router에서 괄호로 묶인 디렉토리는 URL 경로에 포함되지 않습니다. 예를 들어:
- `/bbs/register` 경로는 `(with-base-layout)/bbs/register` 디렉토리에 매핑됩니다.
- `/user-survey-article/1` 경로는 `(without-base-layout)/user-survey-article/[srvySn]` 디렉토리에 매핑됩니다.
### 2. 레이아웃 분리 및 재사용
라우트 그룹을 사용하면 서로 다른 레이아웃을 가진 페이지들을 효율적으로 구성할 수 있습니다:
- `(with-base-layout)` 그룹: 메뉴, 헤더, 사이드바 등을 포함하는 `BaseLayout`과 `PageLayout`을 사용합니다.
- `(without-base-layout)` 그룹: 기본 레이아웃 없이 페이지 컴포넌트만 렌더링합니다.
### 3. 중첩 라우트 그룹
프로젝트에서는 중첩된 라우트 그룹도 사용되고 있습니다:
```
(with-base-layout)/bbs/(post)/bbsnormal/
```
여기서 `(post)`는 게시물 관련 페이지들을 그룹화하는 중첩된 라우트 그룹입니다.
## 라우트 그룹 사용 사례
### 1. 관리자 인터페이스 (`with-base-layout`)
관리자 인터페이스는 일관된 레이아웃과 네비게이션이 필요합니다:
```tsx
// (with-base-layout)/layout.tsx
return (
{children}
);
```
이 레이아웃은 다음과 같은 기능을 제공합니다:
- 메뉴 시스템을 통한 페이지 간 이동
- 현재 페이지 경로 표시
- 일관된 페이지 타이틀 및 구조
### 2. 독립적인 페이지 (`without-base-layout`)
설문 기사나 결과 페이지와 같은 독립적인 페이지는 기본 레이아웃 없이 콘텐츠에 집중합니다:
```tsx
// (without-base-layout)/user-survey-article/[srvySn]/page.tsx
export default async function UserSurveyArticlePage({
params,
}: {
params: Promise<{ srvySn: string }>;
}) {
const { srvySn } = await params;
return ;
}
```
이러한 페이지는:
- 외부 링크나 팝업으로 열리는 경우가 많음
- 독립적인 기능을 제공(예: 설문 제출 후 창 닫기)
- 메인 애플리케이션 UI와 분리된 경험 제공
## 두 라우트 그룹의 주요 차이점
### (with-base-layout)
- `BaseLayout` 컴포넌트를 포함하는 레이아웃을 사용합니다.
- 이 레이아웃은 메뉴, 헤더, 사이드바 등 기본 UI 요소를 포함합니다.
- `PageLayout` 컴포넌트로 감싸져 있어 일관된 페이지 구조를 제공합니다.
- 주로 관리자 페이지나 로그인 후 사용하는 내부 페이지에 사용됩니다.
- 다양한 관리 기능을 포함하는 여러 하위 디렉토리가 있습니다.
### (without-base-layout)
- 기본 레이아웃 없이 페이지 컴포넌트만 렌더링합니다.
- 메뉴, 헤더, 사이드바 등의 UI 요소가 없는 독립적인 페이지입니다.
- 주로 외부 사용자용 페이지나 팝업, 임베드 페이지에 사용됩니다.
- 현재 두 가지 특수 목적 페이지만 포함하고 있습니다.
## 기술적 이점
1. **코드 구성 개선**: 관련 페이지와 레이아웃을 논리적으로 그룹화할 수 있습니다.
2. **레이아웃 재사용**: 공통 레이아웃을 여러 페이지에서 재사용할 수 있습니다.
3. **URL 구조 단순화**: 그룹 이름이 URL에 포함되지 않아 깔끔한 URL 구조를 유지할 수 있습니다.
4. **유지보수성 향상**: 관련 기능을 함께 그룹화하여 코드 탐색과 유지보수가 용이합니다.
## 결론
Next.js App Router의 라우트 그룹 기능은 프로젝트에서 다양한 레이아웃 요구사항을 효율적으로 관리하는 데 중요한 역할을 합니다. `(with-base-layout)`과 `(without-base-layout)` 그룹을 통해 관리자 인터페이스와 독립적인 페이지를 명확하게 분리하면서도 코드 재사용성과 유지보수성을 높일 수 있습니다.
이 구조는 확장성이 뛰어나 새로운 페이지나 기능을 추가할 때 기존 패턴을 따르기 쉽고, 애플리케이션이 성장함에 따라 필요한 경우 추가 라우트 그룹을 도입할 수 있는 유연성을 제공합니다.