diff --git a/apps/(template)/.env.example b/apps/(template)/.env.example
new file mode 100644
index 000000000..b2d706024
--- /dev/null
+++ b/apps/(template)/.env.example
@@ -0,0 +1,5 @@
+# apps/as/shared/config/env.ts 참고
+NEXT_PUBLIC_PORT=
+NEXT_PUBLIC_PROXY_HOST=
+NEXT_PUBLIC_SITE_ID=
+NEXT_PUBLIC_SERVER_API_URL=
diff --git a/apps/(template)/.eslintrc.json b/apps/(template)/.eslintrc.json
new file mode 100644
index 000000000..ea782d70a
--- /dev/null
+++ b/apps/(template)/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/apps/(template)/.gitignore b/apps/(template)/.gitignore
new file mode 100644
index 000000000..fd3dbb571
--- /dev/null
+++ b/apps/(template)/.gitignore
@@ -0,0 +1,36 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts
diff --git a/apps/(template)/.prettierrc b/apps/(template)/.prettierrc
new file mode 100644
index 000000000..059b4e33c
--- /dev/null
+++ b/apps/(template)/.prettierrc
@@ -0,0 +1,8 @@
+{
+ "semi": true,
+ "trailingComma": "all",
+ "singleQuote": false,
+ "printWidth": 100,
+ "tabWidth": 2,
+ "plugins": ["prettier-plugin-tailwindcss"]
+}
diff --git a/apps/(template)/README.md b/apps/(template)/README.md
new file mode 100644
index 000000000..7e14528f8
--- /dev/null
+++ b/apps/(template)/README.md
@@ -0,0 +1,248 @@
+# AS 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)
+
+이 프로젝트는 **Feature-Sliced Design v2.1**을 따르며, 계층적 아키텍처로 구성되어 있습니다.
+
+```
+as/
+├── app/ # App 레이어 (Next.js App Router)
+│ ├── (routes)/ # 라우트 구조
+│ ├── layout.tsx # 루트 레이아웃
+│ ├── page.tsx # 홈 페이지
+│ ├── globals.css # 글로벌 스타일
+│ └── providers.tsx # 전역 providers
+│
+├── widgets/ # Widgets 레이어
+│ └── [widget-name]/ # 큰 독립적 UI 블록 (여러 페이지에서 재사용)
+│ ├── ui/
+│ ├── model/
+│ └── index.ts
+│
+├── 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/ # 라우트 상수
+```
+
+### 계층 구조 이해하기
+
+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 (app 디렉토리)
+- **목적**: 웹사이트나 애플리케이션을 구성하는 페이지/화면
+- **내용**: 페이지 UI, 로딩 상태, 에러 바운더리, 데이터 fetching
+- **특징**: 한 페이지당 한 슬라이스 (유사한 페이지는 그룹화 가능)
+- **의존성**: `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, 유틸리티 라이브러리, 글로벌 설정
+- **특징**: 비즈니스 로직 없음, 슬라이스가 없고 세그먼트로만 구성
+- **의존성**: 외부 라이브러리만 사용 가능 (다른 레이어 불가)
+
+## 레이어 간 Import 규칙
+
+> **핵심 규칙**: 슬라이스 내의 모듈(파일)은 **오직 하위 레이어**에 있는 다른 슬라이스만 import할 수 있습니다.
+
+예시:
+- `features/auth-login/ui/form.tsx`는 `entities/user`와 `shared/ui`를 import 가능
+- 하지만 다른 `features/post-create`나 상위 레이어인 `widgets`는 import 불가
+- 같은 슬라이스 내부(`features/auth-login/`)의 다른 파일들은 자유롭게 import 가능
+
+## Public API 규칙
+
+> **슬라이스 외부의 모듈은 슬라이스의 Public API만 참조할 수 있으며, 내부 파일 구조에 직접 접근할 수 없습니다.**
+
+모든 슬라이스(및 슬라이스가 없는 레이어의 세그먼트)는 반드시 `index.ts`를 통해 Public API를 정의해야 합니다.
+
+```typescript
+// ✅ 올바른 import
+import { LoginForm } from 'features/auth-login';
+
+// ❌ 잘못된 import (내부 구조 직접 접근)
+import { LoginForm } from 'features/auth-login/ui/login-form';
+```
+
+## 시작하기
+
+```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';
+```
+
+### 3. 슬라이스 독립성
+
+- **Zero Coupling**: 같은 레이어의 슬라이스들은 서로 독립적이어야 합니다
+- **High Cohesion**: 슬라이스는 주요 목표와 관련된 대부분의 코드를 포함해야 합니다
+- 예외: Entities 레이어에서 필요한 경우 `@x` 표기법으로 cross-import 가능
+
+### 4. 세그먼트 명명 규칙
+
+세그먼트 이름은 **목적**을 설명해야 하며, **본질**을 설명하면 안 됩니다:
+
+- ❌ **나쁜 이름**: `components`, `hooks`, `types` (무엇인지만 설명)
+- ✅ **좋은 이름**: `ui`, `api`, `model`, `lib` (왜 있는지 설명)
+
+## 코드 규칙
+
+- TypeScript 사용 (strict mode)
+- 함수형 컴포넌트 사용
+- Named exports 선호
+- Tailwind CSS 사용
+- ESLint + Prettier 적용
+- Public API는 명시적으로 정의 (와일드카드 export 지양)
+
+## 아키텍처 린팅
+
+코드베이스의 FSD 규칙 준수를 자동으로 검증하려면 [Steiger](https://github.com/feature-sliced/steiger)를 사용하세요.
+
+```bash
+# Steiger 설치 및 실행
+pnpm add -D @feature-sliced/steiger
+npx steiger src
+```
diff --git a/apps/(template)/app/(with-base-layout)/layout.tsx b/apps/(template)/app/(with-base-layout)/layout.tsx
new file mode 100644
index 000000000..1d182a0ee
--- /dev/null
+++ b/apps/(template)/app/(with-base-layout)/layout.tsx
@@ -0,0 +1,31 @@
+"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";
+
+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}
+
+ );
+}
diff --git a/apps/(template)/app/(with-base-layout)/page.tsx b/apps/(template)/app/(with-base-layout)/page.tsx
new file mode 100644
index 000000000..e118e732e
--- /dev/null
+++ b/apps/(template)/app/(with-base-layout)/page.tsx
@@ -0,0 +1,9 @@
+"use client";
+
+export default function MainPage() {
+ return (
+
+
Home
+
+ );
+}
diff --git a/apps/(template)/app/README.md b/apps/(template)/app/README.md
new file mode 100644
index 000000000..5ab63ea34
--- /dev/null
+++ b/apps/(template)/app/README.md
@@ -0,0 +1,169 @@
+# 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 (
+
+
+ {children}
+
+
+ );
+}
+
+// app/layout.tsx
+import { Providers } from './providers';
+import './globals.css';
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+}
+```
+
+### 글로벌 설정
+
+```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`로 분리
+
+이 접근 방식은 과도한 추상화를 방지하고 코드를 더 쉽게 탐색할 수 있게 합니다.
diff --git a/apps/(template)/app/globals.css b/apps/(template)/app/globals.css
new file mode 100644
index 000000000..60bc92fb6
--- /dev/null
+++ b/apps/(template)/app/globals.css
@@ -0,0 +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;
+}
diff --git a/apps/(template)/app/layout.tsx b/apps/(template)/app/layout.tsx
new file mode 100644
index 000000000..d152e0da3
--- /dev/null
+++ b/apps/(template)/app/layout.tsx
@@ -0,0 +1,30 @@
+import type { Metadata } from "next";
+import { Noto_Sans_KR } from "next/font/google";
+import { Providers } from "./providers";
+import "./globals.css";
+
+const notoSansKR = Noto_Sans_KR({
+ subsets: ["latin"],
+ weight: ["100", "300", "400", "500", "700", "900"],
+ display: "swap",
+ variable: "--font-noto-sans-kr",
+});
+
+export const metadata: Metadata = {
+ title: "행정지원시스템",
+ description: "행정지원시스템",
+};
+
+interface RootLayoutProps {
+ children: React.ReactNode;
+}
+
+export default function RootLayout({ children }: RootLayoutProps) {
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/apps/(template)/app/providers.tsx b/apps/(template)/app/providers.tsx
new file mode 100644
index 000000000..bc12c443b
--- /dev/null
+++ b/apps/(template)/app/providers.tsx
@@ -0,0 +1,18 @@
+"use client";
+
+import { QueryClientProvider } from "@tanstack/react-query";
+import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
+import { queryClient } from "@/shared/lib";
+
+interface ProvidersProps {
+ children: React.ReactNode;
+}
+
+export function Providers({ children }: ProvidersProps) {
+ return (
+
+ {children}
+
+
+ );
+}
diff --git a/apps/(template)/entities/README.md b/apps/(template)/entities/README.md
new file mode 100644
index 000000000..b28c10790
--- /dev/null
+++ b/apps/(template)/entities/README.md
@@ -0,0 +1,114 @@
+# Entities Layer
+
+**Entities**는 프로젝트가 다루는 실제 비즈니스 개념을 나타내는 레이어입니다. 비즈니스에서 제품을 설명할 때 사용하는 용어들(예: User, Product, Order)이 주로 엔티티가 됩니다.
+
+## 목적
+
+- 비즈니스 엔티티의 데이터 모델 및 타입 정의
+- 엔티티 관련 API 요청 함수 관리
+- 엔티티의 시각적 표현 제공 (재사용 가능한 UI)
+- 여러 페이지에서 동일한 외관을 재사용할 수 있도록 지원
+
+## 구조
+
+각 엔티티 슬라이스는 다음 세그먼트로 구성됩니다:
+
+```
+entities/
+└── [entity-name]/
+ ├── model/ # 데이터 저장소, 검증 스키마, 상태 관리
+ ├── api/ # 엔티티 관련 API 요청 함수
+ ├── ui/ # 엔티티 시각적 표현 (선택적)
+ ├── lib/ # 엔티티 관련 유틸리티 (선택적)
+ ├── @x/ # 다른 엔티티로부터의 cross-import용 Public API (선택적)
+ └── index.ts # Public API
+```
+
+### 세그먼트 설명
+
+- **model**: 데이터 모델, 타입 정의, 상태 저장소 (Zustand 등)
+- **api**: 백엔드 API 호출 함수
+- **ui**: 엔티티를 표시하는 UI 컴포넌트 (완전한 UI 블록이 아니라 재사용 가능한 표현)
+- **lib**: 엔티티 관련 유틸리티 함수
+- **@x**: 다른 엔티티가 이 엔티티를 import할 때 사용하는 명시적 cross-import API
+- **index.ts**: 슬라이스의 Public API (외부에서 사용할 수 있는 것만 export)
+
+## 예시
+
+```typescript
+// entities/user/model/user.ts
+export interface User {
+ id: string;
+ name: string;
+ email: string;
+ role: 'admin' | 'user';
+}
+
+// entities/user/api/get-user.ts
+import type { User } from '../model/user';
+
+export async function getUser(id: string): Promise {
+ const response = await fetch(`/api/users/${id}`);
+ return response.json();
+}
+
+// entities/user/ui/user-card.tsx
+import type { User } from '../model/user';
+
+interface UserCardProps {
+ user: User;
+ onClick?: () => void;
+}
+
+export function UserCard({ user, onClick }: UserCardProps) {
+ return (
+
+
{user.name}
+
{user.email}
+
+ );
+}
+
+// entities/user/index.ts
+export { type User } from './model/user';
+export { getUser } from './api/get-user';
+export { UserCard } from './ui/user-card';
+```
+
+## 엔티티 간 관계
+
+엔티티가 서로 연결되어 있을 때는 `@x` 표기법을 사용하여 명시적으로 cross-import를 관리하는 것이 권장됩니다:
+
+```typescript
+// entities/artist/model/artist.ts
+import type { Song } from 'entities/song/@x/artist';
+
+export interface Artist {
+ name: string;
+ songs: Array;
+}
+
+// entities/song/@x/artist.ts
+export type { Song } from '../model/song';
+```
+
+> `@x` 폴더를 사용하면 엔티티 간 연결을 명확하게 만들어 함께 리팩터링이 필요한 코드를 쉽게 찾을 수 있습니다.
+
+## 레이어 의존성 규칙
+
+✅ **허용되는 의존성**:
+- `shared` 레이어의 모듈
+- 같은 엔티티 슬라이스 내의 다른 세그먼트
+- 다른 엔티티 슬라이스 (필요한 경우, `@x` 표기법 권장)
+
+❌ **금지된 의존성**:
+- `features` 레이어
+- `widgets` 레이어
+- `pages` 레이어
+- `app` 레이어
+
+## 주의사항
+
+1. **UI 컴포넌트는 완전한 비즈니스 로직을 포함하지 않음**: UI는 주로 props나 slots를 통해 다양한 비즈니스 로직을 연결할 수 있도록 설계
+2. **엔티티 간 비즈니스 로직은 상위 레이어에**: 엔티티 간 상호작용의 비즈니스 로직은 Features나 Pages 레이어에서 처리
+3. **데이터 관리에 집중**: 복잡한 비즈니스 로직보다는 데이터 모델, 검증, 저장에 집중
diff --git a/apps/(template)/entities/menu/index.ts b/apps/(template)/entities/menu/index.ts
new file mode 100644
index 000000000..cb55d9a1c
--- /dev/null
+++ b/apps/(template)/entities/menu/index.ts
@@ -0,0 +1 @@
+export { type MenuItem } from "./model/types";
diff --git a/apps/(template)/entities/menu/model/types.ts b/apps/(template)/entities/menu/model/types.ts
new file mode 100644
index 000000000..9692821e3
--- /dev/null
+++ b/apps/(template)/entities/menu/model/types.ts
@@ -0,0 +1,19 @@
+export interface MenuItem {
+ menuCd: number;
+ menuKornNm: string;
+ menuEngNm: string;
+ parentId: number | null;
+ sortSeq: number;
+ iconNm?: string;
+ children: MenuItem[] | null;
+ levelNo: number;
+ urlPath: string;
+ menuLnkgTypeCd: string;
+ menuLnkgSn: number;
+ menuPath: string;
+ qrcd: string;
+ useYn: string;
+ otptYn: string;
+ newWndwYn: string;
+ requiredUrlPath: boolean;
+}
diff --git a/apps/(template)/eslint.config.mjs b/apps/(template)/eslint.config.mjs
new file mode 100644
index 000000000..05e726d1b
--- /dev/null
+++ b/apps/(template)/eslint.config.mjs
@@ -0,0 +1,18 @@
+import { defineConfig, globalIgnores } from "eslint/config";
+import nextVitals from "eslint-config-next/core-web-vitals";
+import nextTs from "eslint-config-next/typescript";
+
+const eslintConfig = defineConfig([
+ ...nextVitals,
+ ...nextTs,
+ // Override default ignores of eslint-config-next.
+ globalIgnores([
+ // Default ignores of eslint-config-next:
+ ".next/**",
+ "out/**",
+ "build/**",
+ "next-env.d.ts",
+ ]),
+]);
+
+export default eslintConfig;
diff --git a/apps/(template)/features/README.md b/apps/(template)/features/README.md
new file mode 100644
index 000000000..2be9a3e17
--- /dev/null
+++ b/apps/(template)/features/README.md
@@ -0,0 +1,130 @@
+# Features Layer
+
+**Features**는 앱의 주요 사용자 상호작용과 기능을 구현하는 레이어입니다. 사용자가 실제로 수행하는 작업들로, 주로 비즈니스 엔티티와 관련이 있습니다.
+
+## 목적
+
+- 사용자가 중요하게 생각하는 주요 상호작용 구현
+- 재사용 가능한 비즈니스 기능 제공
+- 여러 페이지에서 사용되는 기능의 중복 제거
+
+## Feature로 만들어야 하는 경우
+
+> ⚠️ **중요**: 모든 것을 feature로 만들 필요는 없습니다.
+
+Feature로 만드는 것이 좋은 지표:
+- **여러 페이지에서 재사용됨**: 예를 들어, 여러 에디터가 있고 모두 댓글 기능이 있다면, 댓글은 재사용 가능한 feature입니다
+- **중요한 비즈니스 기능**: 신규 프로젝트 참여자가 Features 폴더를 보고 앱의 주요 기능을 빠르게 파악할 수 있어야 합니다
+
+Feature가 너무 많으면 중요한 기능이 묻히므로, 신규 참여자의 경험을 최적화하여 결정하세요.
+
+## 구조
+
+각 feature 슬라이스는 다음 세그먼트로 구성됩니다:
+
+```
+features/
+└── [feature-name]/
+ ├── ui/ # 상호작용을 수행하는 UI (폼, 버튼 등)
+ ├── api/ # 액션 수행에 필요한 API 호출 (선택적)
+ ├── model/ # 검증 및 내부 상태 관리 (선택적)
+ ├── lib/ # 유틸리티 함수 (선택적)
+ ├── config/ # feature flags (선택적)
+ └── index.ts # Public API
+```
+
+### 세그먼트 설명
+
+- **ui**: 사용자 상호작용을 위한 UI 컴포넌트 (폼, 모달, 버튼 등)
+- **api**: feature 실행에 필요한 API 요청 함수
+- **model**: 폼 검증, 내부 상태, 비즈니스 로직
+- **lib**: feature 내부에서만 사용되는 유틸리티
+- **config**: feature flags, feature별 설정값
+- **index.ts**: 슬라이스의 Public API (외부에서 사용할 수 있는 것만 export)
+
+## 예시
+
+```typescript
+// features/auth-login/ui/login-form.tsx
+import { useState } from 'react';
+import { loginUser } from '../api/login-user';
+import type { LoginCredentials } from '../model/types';
+
+export function LoginForm() {
+ const [credentials, setCredentials] = useState({
+ email: '',
+ password: ''
+ });
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ await loginUser(credentials);
+ };
+
+ return (
+
+ );
+}
+
+// features/auth-login/api/login-user.ts
+import type { LoginCredentials } from '../model/types';
+
+export async function loginUser(credentials: LoginCredentials) {
+ const response = await fetch('/api/auth/login', {
+ method: 'POST',
+ body: JSON.stringify(credentials),
+ });
+ return response.json();
+}
+
+// features/auth-login/model/types.ts
+export interface LoginCredentials {
+ email: string;
+ password: string;
+}
+
+// features/auth-login/index.ts
+export { LoginForm } from './ui/login-form';
+export { loginUser } from './api/login-user';
+export type { LoginCredentials } from './model/types';
+```
+
+## 레이어 의존성 규칙
+
+✅ **허용되는 의존성**:
+- `shared` 레이어의 모듈
+- `entities` 레이어의 모듈
+- 같은 feature 슬라이스 내의 다른 세그먼트
+
+❌ **금지된 의존성**:
+- 다른 `features` 슬라이스 (feature 간 직접 의존 금지)
+- `widgets` 레이어
+- `pages` 레이어
+- `app` 레이어
+
+> 💡 **팁**: 여러 features가 공통 기능을 필요로 한다면, 그 기능을 `shared` 레이어로 이동시키거나 `entities` 레이어에서 관리하세요.
+
+## 명명 규칙
+
+- 소문자와 대시 사용: `auth-login`, `post-create`, `comment-edit`
+- 동사 형태 권장: 사용자 액션을 나타내는 이름 사용
+- 명확하고 구체적으로: 기능의 목적이 명확하게 드러나도록
+
+## 주의사항
+
+1. **하나의 기능에만 집중**: 각 feature는 단일 사용자 시나리오를 구현해야 합니다
+2. **재사용성 고려**: 여러 페이지에서 사용될 수 있도록 설계
+3. **독립성 유지**: 다른 features에 의존하지 않고 독립적으로 작동
+4. **적절한 추상화**: 너무 많은 feature를 만들지 말고, 중요한 기능 위주로 구성
diff --git a/apps/(template)/next.config.ts b/apps/(template)/next.config.ts
new file mode 100644
index 000000000..8864de0e7
--- /dev/null
+++ b/apps/(template)/next.config.ts
@@ -0,0 +1,8 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ reactStrictMode: true,
+ transpilePackages: ["@common/assets"],
+};
+
+export default nextConfig;
diff --git a/apps/(template)/package.json b/apps/(template)/package.json
new file mode 100644
index 000000000..fb27f8af7
--- /dev/null
+++ b/apps/(template)/package.json
@@ -0,0 +1,36 @@
+{
+ "name": "as",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint",
+ "lint:fsd": "steiger ."
+ },
+ "dependencies": {
+ "@common/assets": "workspace:*",
+ "@common/components": "workspace:*",
+ "@common/network": "workspace:*",
+ "@hookform/resolvers": "^4.1.3",
+ "@tanstack/react-query": "^5.75.5",
+ "@tanstack/react-query-devtools": "^5.75.5",
+ "@tanstack/react-table": "^8.21.2",
+ "axios": "^1.8.1",
+ "dayjs": "^1.11.13",
+ "next": "15.3.8",
+ "react-hook-form": "^7.54.2",
+ "zod": "^3.24.2"
+ },
+ "devDependencies": {
+ "eslint": "^9.0.0",
+ "eslint-config-next": "15.4.0",
+ "postcss": "^8.4.49",
+ "prettier": "^3.4.2",
+ "prettier-plugin-tailwindcss": "^0.6.11",
+ "steiger": "^0.5.11",
+ "tailwindcss": "^3.4.14",
+ "typescript": "^5.7.2"
+ }
+}
\ No newline at end of file
diff --git a/apps/(template)/postcss.config.mjs b/apps/(template)/postcss.config.mjs
new file mode 100644
index 000000000..1a69fd2a4
--- /dev/null
+++ b/apps/(template)/postcss.config.mjs
@@ -0,0 +1,8 @@
+/** @type {import('postcss-load-config').Config} */
+const config = {
+ plugins: {
+ tailwindcss: {},
+ },
+};
+
+export default config;
diff --git a/apps/(template)/shared/README.md b/apps/(template)/shared/README.md
new file mode 100644
index 000000000..2b247021d
--- /dev/null
+++ b/apps/(template)/shared/README.md
@@ -0,0 +1,149 @@
+# Shared Layer
+
+**Shared**는 애플리케이션의 기반을 형성하는 레이어입니다. 외부 세계(백엔드, 서드파티 라이브러리, 환경)와의 연결을 생성하고, 높은 응집력을 가진 자체 라이브러리를 정의하는 곳입니다.
+
+## 목적
+
+- 외부 시스템 및 라이브러리와의 통합
+- 프로젝트 전체에서 사용되는 공통 코드 제공
+- 비즈니스 로직이 없는 재사용 가능한 유틸리티 및 UI 제공
+- 글로벌 설정 및 환경 변수 관리
+
+## 특징
+
+- **슬라이스 없음**: Shared 레이어는 비즈니스 도메인이 없으므로 슬라이스로 나뉘지 않습니다
+- **세그먼트 구성**: 기술적 목적에 따라 세그먼트로 직접 구성됩니다
+- **자유로운 import**: Shared 내의 모든 파일은 서로를 참조하고 import할 수 있습니다
+
+## 구조
+
+```
+shared/
+├── ui/ # 애플리케이션 UI Kit
+│ ├── button/
+│ ├── input/
+│ ├── modal/
+│ └── index.ts
+├── api/ # API 클라이언트 및 백엔드 엔드포인트 함수
+│ ├── client.ts
+│ └── index.ts
+├── lib/ # 내부 라이브러리 모음
+│ ├── dates/ # 날짜 관련 유틸리티
+│ ├── colors/ # 색상 관련 유틸리티
+│ ├── text/ # 텍스트 처리 유틸리티
+│ └── index.ts
+├── config/ # 환경 변수, 글로벌 feature flags
+│ ├── env.ts
+│ └── index.ts
+├── types/ # 공통 타입 정의
+│ └── index.ts
+├── i18n/ # 번역 설정, 글로벌 번역 문자열
+│ └── index.ts
+└── routes/ # 라우트 상수 또는 패턴
+ └── index.ts
+```
+
+## 세그먼트 설명
+
+### 📁 ui
+애플리케이션의 UI Kit로, 비즈니스 로직을 포함하지 않는 재사용 가능한 UI 컴포넌트들입니다.
+
+- Button, Input, Modal 같은 기본 컴포넌트
+- 비즈니스 로직은 없지만 UI 로직은 포함 가능 (예: Autocomplete, SearchBar)
+- 비즈니스 테마 컴포넌트도 허용 (예: 회사 로고, 페이지 레이아웃)
+
+### 📁 api
+API 클라이언트 및 특정 백엔드 엔드포인트 요청 함수입니다.
+
+- HTTP 클라이언트 설정 (Axios, Fetch 등)
+- 인증 인터셉터
+- 공통 에러 핸들링
+
+### 📁 lib
+내부 라이브러리 모음으로, 각 라이브러리는 **하나의 관심사**에 집중해야 합니다.
+
+> ⚠️ **중요**: `helpers`나 `utils` 폴더처럼 덤프 폴더로 만들지 마세요. 각 라이브러리는 명확한 초점 영역(예: dates, colors, text)을 가져야 하며, README로 문서화해야 합니다.
+
+### 📁 config
+환경 변수, 글로벌 feature flags 및 앱 전체 설정입니다.
+
+### 📁 types
+프로젝트 전체에서 사용되는 공통 타입 정의입니다.
+
+### 📁 i18n
+번역 설정 코드 및 글로벌 번역 문자열입니다.
+
+### 📁 routes
+라우트 상수 또는 라우트 매칭 패턴입니다.
+
+## 예시
+
+```typescript
+// shared/ui/button/button.tsx
+interface ButtonProps {
+ children: React.ReactNode;
+ variant?: 'primary' | 'secondary';
+ onClick?: () => void;
+}
+
+export function Button({ children, variant = 'primary', onClick }: ButtonProps) {
+ return (
+
+ );
+}
+
+// shared/api/client.ts
+import axios from 'axios';
+
+export const apiClient = axios.create({
+ baseURL: process.env.NEXT_PUBLIC_API_URL,
+ timeout: 10000,
+});
+
+// shared/lib/dates/format-date.ts
+import dayjs from 'dayjs';
+
+export function formatDate(date: Date, format: string = 'YYYY-MM-DD'): string {
+ return dayjs(date).format(format);
+}
+
+// shared/config/env.ts
+export const ENV = {
+ apiUrl: process.env.NEXT_PUBLIC_API_URL!,
+ isDev: process.env.NODE_ENV === 'development',
+} as const;
+```
+
+## 레이어 의존성 규칙
+
+✅ **허용되는 의존성**:
+- 같은 `shared` 레이어 내의 다른 세그먼트 (자유로운 cross-import)
+- 외부 라이브러리 및 패키지
+
+❌ **금지된 의존성**:
+- `entities` 레이어
+- `features` 레이어
+- `widgets` 레이어
+- `pages` 레이어
+- `app` 레이어
+
+> 💡 **원칙**: Shared는 가장 낮은 레이어이므로 상위 레이어에 의존하지 않습니다.
+
+## 세그먼트 명명 규칙
+
+세그먼트 이름은 **내용의 목적**을 설명해야 하며, **본질**을 설명하면 안 됩니다.
+
+❌ **나쁜 예시**: `components`, `hooks`, `types` (본질을 설명)
+✅ **좋은 예시**: `ui`, `api`, `lib/dates`, `config` (목적을 설명)
+
+## 주의사항
+
+1. **비즈니스 로직 없음**: Shared는 순수한 기술적 코드만 포함
+2. **높은 재사용성**: 앱 전체에서 사용될 수 있어야 함
+3. **명확한 라이브러리 구조**: `lib` 내부는 관심사별로 명확하게 분리
+4. **문서화**: 각 라이브러리는 README로 사용법과 목적을 문서화
diff --git a/apps/(template)/shared/api/client.ts b/apps/(template)/shared/api/client.ts
new file mode 100644
index 000000000..d7c4a8f1d
--- /dev/null
+++ b/apps/(template)/shared/api/client.ts
@@ -0,0 +1,9 @@
+import { Client } from "@common/network";
+import { PROXY_HOST, SITE_ID } from "@/shared/config/env";
+
+const BASE_URL = `${PROXY_HOST}/server`;
+
+export const apiClient = Client.getInstance({
+ baseURL: BASE_URL,
+ siteId: SITE_ID,
+});
diff --git a/apps/(template)/shared/api/index.ts b/apps/(template)/shared/api/index.ts
new file mode 100644
index 000000000..c5eb98066
--- /dev/null
+++ b/apps/(template)/shared/api/index.ts
@@ -0,0 +1 @@
+export { apiClient } from "./client";
diff --git a/apps/(template)/shared/config/env.ts b/apps/(template)/shared/config/env.ts
new file mode 100644
index 000000000..4f08c722a
--- /dev/null
+++ b/apps/(template)/shared/config/env.ts
@@ -0,0 +1,11 @@
+export const PORT = process.env.NEXT_PUBLIC_PORT || "3000";
+export const PROXY_HOST =
+ process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`;
+export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL;
+export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "AS";
+export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
+export const ACCESS_TOKEN =
+ process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token";
+export const REFRESH_TOKEN =
+ process.env.NEXT_PUBLIC_REFRESH_TOKEN || "refresh-token";
+export const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id";
diff --git a/apps/(template)/shared/config/index.ts b/apps/(template)/shared/config/index.ts
new file mode 100644
index 000000000..c76f8cd47
--- /dev/null
+++ b/apps/(template)/shared/config/index.ts
@@ -0,0 +1 @@
+export * from "./env";
diff --git a/apps/(template)/shared/lib/dayjs.ts b/apps/(template)/shared/lib/dayjs.ts
new file mode 100644
index 000000000..28b3f908b
--- /dev/null
+++ b/apps/(template)/shared/lib/dayjs.ts
@@ -0,0 +1,12 @@
+import dayjs from "dayjs";
+import "dayjs/locale/ko";
+import utc from "dayjs/plugin/utc";
+import timezone from "dayjs/plugin/timezone";
+import relativeTime from "dayjs/plugin/relativeTime";
+
+dayjs.extend(utc);
+dayjs.extend(timezone);
+dayjs.extend(relativeTime);
+dayjs.locale("ko");
+
+export { dayjs };
diff --git a/apps/(template)/shared/lib/index.ts b/apps/(template)/shared/lib/index.ts
new file mode 100644
index 000000000..51e9c2c5d
--- /dev/null
+++ b/apps/(template)/shared/lib/index.ts
@@ -0,0 +1,2 @@
+export { queryClient } from "./query-client";
+export { dayjs } from "./dayjs";
diff --git a/apps/(template)/shared/lib/query-client.ts b/apps/(template)/shared/lib/query-client.ts
new file mode 100644
index 000000000..0da2fb899
--- /dev/null
+++ b/apps/(template)/shared/lib/query-client.ts
@@ -0,0 +1,11 @@
+import { QueryClient } from "@tanstack/react-query";
+
+export const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: 1,
+ refetchOnWindowFocus: false,
+ staleTime: 60 * 1000,
+ },
+ },
+});
diff --git a/apps/(template)/shared/model/index.ts b/apps/(template)/shared/model/index.ts
new file mode 100644
index 000000000..15ddf4254
--- /dev/null
+++ b/apps/(template)/shared/model/index.ts
@@ -0,0 +1,29 @@
+export interface BaseEntity {
+ id: string;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface PaginationParams {
+ page: number;
+ limit: number;
+}
+
+export interface PaginationResponse {
+ data: T[];
+ total: number;
+ page: number;
+ limit: number;
+}
+
+export interface ApiResponse {
+ success: boolean;
+ data: T;
+ message?: string;
+}
+
+export interface ApiError {
+ message: string;
+ code?: string;
+ status?: number;
+}
diff --git a/apps/(template)/shared/ui/index.ts b/apps/(template)/shared/ui/index.ts
new file mode 100644
index 000000000..460542995
--- /dev/null
+++ b/apps/(template)/shared/ui/index.ts
@@ -0,0 +1 @@
+export { PageLayout } from "./page-layout";
diff --git a/apps/(template)/shared/ui/page-layout.tsx b/apps/(template)/shared/ui/page-layout.tsx
new file mode 100644
index 000000000..ecefc36bd
--- /dev/null
+++ b/apps/(template)/shared/ui/page-layout.tsx
@@ -0,0 +1,35 @@
+"use client";
+
+import { PageTitle } from "@common/components";
+
+const mockCurrentMenuInfo = {
+ menuCd: 0,
+ menuKornNm: "메인",
+ menuEngNm: "Main",
+ parentId: null,
+ sortSeq: 0,
+ children: null,
+ levelNo: 0,
+ urlPath: "/",
+ menuLnkgTypeCd: "",
+ menuLnkgSn: 0,
+ menuPath: "메인",
+ qrcd: "",
+ useYn: "Y",
+ otptYn: "Y",
+ newWndwYn: "N",
+ requiredUrlPath: false,
+};
+
+function PageLayout({ children }: { children: React.ReactNode }) {
+ const menuPaths = mockCurrentMenuInfo.menuPath.split(">").map((path) => path.trim());
+
+ return (
+
+ );
+}
+
+export { PageLayout };
diff --git a/apps/(template)/tailwind.config.ts b/apps/(template)/tailwind.config.ts
new file mode 100644
index 000000000..c02405aca
--- /dev/null
+++ b/apps/(template)/tailwind.config.ts
@@ -0,0 +1,29 @@
+import type { Config } from "tailwindcss";
+import presetConfig from "../../tailwind.config.preset";
+
+const config: Config = {
+ presets: [presetConfig],
+ content: [
+ "./pages/**/*.{js,ts,jsx,tsx,mdx}",
+ "./shared/**/*.{js,ts,jsx,tsx,mdx}",
+ "./entities/**/*.{js,ts,jsx,tsx,mdx}",
+ "./features/**/*.{js,ts,jsx,tsx,mdx}",
+ "./widgets/**/*.{js,ts,jsx,tsx,mdx}",
+ "./app/**/*.{js,ts,jsx,tsx,mdx}",
+ "../../packages/common/components/dist/**/*.{js,ts,jsx,tsx,mdx}",
+ ],
+ theme: {
+ extend: {
+ colors: {
+ background: "var(--background)",
+ foreground: "var(--foreground)",
+ },
+ fontFamily: {
+ sans: ["var(--font-noto-sans-kr)", "Noto Sans KR", "sans-serif"],
+ },
+ },
+ },
+ plugins: [],
+};
+
+export default config;
diff --git a/apps/(template)/tsconfig.json b/apps/(template)/tsconfig.json
new file mode 100644
index 000000000..15b023415
--- /dev/null
+++ b/apps/(template)/tsconfig.json
@@ -0,0 +1,35 @@
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./*"],
+ "@/app/*": ["./app/*"],
+ "@/shared/*": ["./shared/*"],
+ "@/entities/*": ["./entities/*"],
+ "@/features/*": ["./features/*"],
+ "@/widgets/*": ["./widgets/*"],
+ "@/pages/*": ["./pages/*"],
+ "@common/components": ["../../packages/common/components/dist/"],
+ "@common/network": ["../../packages/common/network/"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
+}
diff --git a/apps/(template)/widgets/README.md b/apps/(template)/widgets/README.md
new file mode 100644
index 000000000..cd160abd9
--- /dev/null
+++ b/apps/(template)/widgets/README.md
@@ -0,0 +1,135 @@
+# Widgets Layer
+
+**Widgets**는 큰 규모의 독립적인 UI 블록을 위한 레이어입니다. 여러 features와 entities를 조합하여 완전한 기능을 제공하는 복합 컴포넌트를 담습니다.
+
+## 목적
+
+- 큰 규모의 독립적인 UI 블록 구성
+- 여러 features와 entities를 하나의 응집력 있는 UI로 결합
+- 여러 페이지에서 재사용되는 복잡한 UI 제공
+- 페이지 레벨 레이아웃 및 섹션 관리
+
+## Widget으로 만들어야 하는 경우
+
+Widget은 다음 조건에 해당할 때 사용하세요:
+
+✅ **Widget으로 만들기 좋은 경우**:
+- 여러 페이지에서 재사용되는 큰 UI 블록
+- 페이지에 여러 개의 큰 독립적 블록이 있고, 이것이 그 중 하나인 경우
+- 페이지 레벨 레이아웃 컴포넌트 (nested routing 시스템 사용 시)
+
+❌ **Widget으로 만들지 말아야 하는 경우**:
+- UI 블록이 페이지의 대부분을 차지하고 재사용되지 않는 경우 → 페이지 슬라이스 내부에 직접 배치
+- 작은 재사용 컴포넌트 → `shared/ui`에 배치
+
+## 구조
+
+각 widget 슬라이스는 다음 세그먼트로 구성됩니다:
+
+```
+widgets/
+└── [widget-name]/
+ ├── ui/ # 위젯의 메인 UI 컴포넌트
+ ├── model/ # 위젯 내부 상태 관리 (선택적)
+ ├── api/ # 위젯 전용 API 호출 (선택적)
+ ├── lib/ # 위젯 내부 유틸리티 (선택적)
+ └── index.ts # Public API
+```
+
+### 세그먼트 설명
+
+- **ui**: 여러 features와 entities를 조합한 위젯 UI
+- **model**: 위젯 내부 상태 및 로직 (선택적)
+- **api**: 위젯이 필요로 하는 데이터 fetching (선택적)
+- **lib**: 위젯 내부에서만 사용되는 헬퍼 함수 (선택적)
+- **index.ts**: 슬라이스의 Public API (외부에서 사용할 수 있는 것만 export)
+
+## 예시
+
+```typescript
+// widgets/header/ui/header.tsx
+import { Logo } from 'shared/ui/logo';
+import { Navigation } from 'shared/ui/navigation';
+import { UserMenu } from 'features/user-menu';
+import { NotificationBell } from 'features/notifications';
+
+export function Header() {
+ return (
+
+ );
+}
+
+// widgets/product-list/ui/product-list.tsx
+import { useProducts } from '../api/use-products';
+import { ProductCard } from 'entities/product';
+import { AddToCartButton } from 'features/cart-add-item';
+
+export function ProductList() {
+ const { data: products, isLoading } = useProducts();
+
+ if (isLoading) return 로딩 중...
;
+
+ return (
+
+ {products.map((product) => (
+
+ ))}
+
+ );
+}
+
+// widgets/product-list/api/use-products.ts
+import { useQuery } from '@tanstack/react-query';
+import { getProducts } from 'entities/product';
+
+export function useProducts() {
+ return useQuery({
+ queryKey: ['products'],
+ queryFn: getProducts,
+ });
+}
+
+// widgets/product-list/index.ts
+export { ProductList } from './ui/product-list';
+```
+
+## 레이어 의존성 규칙
+
+✅ **허용되는 의존성**:
+- `shared` 레이어의 모듈
+- `entities` 레이어의 모듈
+- `features` 레이어의 모듈
+- 같은 widget 슬라이스 내의 다른 세그먼트
+
+❌ **금지된 의존성**:
+- 다른 `widgets` 슬라이스 (widget 간 직접 의존 금지)
+- `pages` 레이어
+- `app` 레이어
+
+## 명명 규칙
+
+- 소문자와 대시 사용: `header`, `sidebar`, `product-list`
+- 명사 형태 권장: UI 블록의 성격을 나타내는 이름 사용
+- 구체적으로: 위젯의 역할이 명확하게 드러나도록
+
+## Nested Routing 사용 시
+
+Remix 같은 nested routing 시스템을 사용한다면:
+- Widgets 레이어를 flat routing의 Pages 레이어처럼 사용 가능
+- 완전한 라우터 블록 생성 (데이터 fetching, loading states, error boundaries 포함)
+- 페이지 레이아웃을 이 레이어에 저장 가능
+
+## 주의사항
+
+1. **독립성 유지**: 각 위젯은 독립적으로 작동 가능해야 합니다
+2. **적절한 크기**: 너무 작은 컴포넌트는 `shared/ui`에, 재사용되지 않으면 `pages`에 배치
+3. **응집력**: 관련된 features와 entities를 의미 있게 조합
+4. **재사용 최적화**: 여러 페이지에서 동일한 방식으로 사용될 수 있도록 설계
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cc4dd0f6f..1a7066496 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -51,6 +51,70 @@ importers:
specifier: 2.4.2
version: 2.4.2
+ apps/(template):
+ dependencies:
+ '@common/assets':
+ specifier: workspace:*
+ version: link:../../packages/common/assets
+ '@common/components':
+ specifier: workspace:*
+ version: link:../../packages/common/components
+ '@common/network':
+ specifier: workspace:*
+ version: link:../../packages/common/network
+ '@hookform/resolvers':
+ specifier: ^4.1.3
+ version: 4.1.3(react-hook-form@7.68.0(react@19.2.3))
+ '@tanstack/react-query':
+ specifier: ^5.75.5
+ version: 5.90.12(react@19.2.3)
+ '@tanstack/react-query-devtools':
+ specifier: ^5.75.5
+ version: 5.91.1(@tanstack/react-query@5.90.12(react@19.2.3))(react@19.2.3)
+ '@tanstack/react-table':
+ specifier: ^8.21.2
+ version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ axios:
+ specifier: ^1.8.1
+ version: 1.8.1
+ dayjs:
+ specifier: ^1.11.13
+ version: 1.11.19
+ next:
+ specifier: 15.3.8
+ version: 15.3.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
+ react-hook-form:
+ specifier: ^7.54.2
+ version: 7.68.0(react@19.2.3)
+ zod:
+ specifier: ^3.24.2
+ version: 3.25.76
+ devDependencies:
+ eslint:
+ specifier: ^9.0.0
+ version: 9.39.2(jiti@1.21.7)
+ eslint-config-next:
+ specifier: 15.4.0
+ version: 15.4.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
+ postcss:
+ specifier: ^8.4.49
+ version: 8.5.6
+ prettier:
+ specifier: ^3.4.2
+ version: 3.7.4
+ prettier-plugin-tailwindcss:
+ specifier: ^0.6.11
+ version: 0.6.14(prettier@3.7.4)
+ steiger:
+ specifier: ^0.5.11
+ version: 0.5.11(typescript@5.9.3)
+ tailwindcss:
+ specifier: ^3.4.14
+ version: 3.4.19(yaml@2.8.2)
+ typescript:
+ specifier: ^5.7.2
+ version: 5.9.3
+
apps/cm:
dependencies:
'@common/assets':
@@ -705,7 +769,7 @@ importers:
version: 3.4.0
tailwindcss-animate:
specifier: ^1.0.7
- version: 1.0.7(tailwindcss@3.4.19)
+ version: 1.0.7(tailwindcss@3.4.19(yaml@2.8.2))
zod:
specifier: ^3.24.2
version: 3.25.76
@@ -727,7 +791,7 @@ importers:
version: 8.5.6
tailwindcss:
specifier: ^3.4.1
- version: 3.4.19
+ version: 3.4.19(yaml@2.8.2)
typescript:
specifier: ^5
version: 5.9.3
@@ -1612,7 +1676,7 @@ importers:
version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.7.4)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@8.6.14(prettier@3.7.4))(typescript@5.6.3)
'@storybook/react-vite':
specifier: ^8.5.3
- version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.7.4)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.3)(storybook@8.6.14(prettier@3.7.4))(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
+ version: 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.7.4)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.3)(storybook@8.6.14(prettier@3.7.4))(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
'@storybook/test':
specifier: ^8.5.3
version: 8.6.14(storybook@8.6.14(prettier@3.7.4))
@@ -1624,22 +1688,22 @@ importers:
version: 22.19.2
'@vitejs/plugin-react':
specifier: ^4.3.4
- version: 4.7.0(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
+ version: 4.7.0(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
autoprefixer:
specifier: ^10.4.20
version: 10.4.22(postcss@8.5.6)
eslint:
specifier: ^9.17.0
- version: 9.39.2(jiti@1.21.7)
+ version: 9.39.2(jiti@2.6.1)
eslint-plugin-react-hooks:
specifier: ^5.0.0
- version: 5.2.0(eslint@9.39.2(jiti@1.21.7))
+ version: 5.2.0(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react-refresh:
specifier: ^0.4.16
- version: 0.4.24(eslint@9.39.2(jiti@1.21.7))
+ version: 0.4.24(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-storybook:
specifier: ^0.11.2
- version: 0.11.6(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
+ version: 0.11.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3)
globals:
specifier: ^15.14.0
version: 15.15.0
@@ -1660,19 +1724,19 @@ importers:
version: 3.4.19(yaml@2.8.2)
tsup:
specifier: 8.3.6
- version: 8.3.6(jiti@1.21.7)(postcss@8.5.6)(typescript@5.6.3)(yaml@2.8.2)
+ version: 8.3.6(jiti@2.6.1)(postcss@8.5.6)(typescript@5.6.3)(yaml@2.8.2)
typescript:
specifier: ~5.6.2
version: 5.6.3
typescript-eslint:
specifier: ^8.18.2
- version: 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
+ version: 8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3)
vite:
specifier: ^6.0.5
- version: 6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)
+ version: 6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)
vite-tsconfig-paths:
specifier: 5.1.4
- version: 5.1.4(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
+ version: 5.1.4(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
packages/common/config:
devDependencies:
@@ -7956,15 +8020,6 @@ snapshots:
wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0
- '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
- dependencies:
- glob: 10.5.0
- magic-string: 0.27.0
- react-docgen-typescript: 2.4.0(typescript@5.6.3)
- vite: 6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)
- optionalDependencies:
- typescript: 5.6.3
-
'@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
dependencies:
glob: 10.5.0
@@ -8858,14 +8913,6 @@ snapshots:
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
- '@storybook/builder-vite@8.6.14(storybook@8.6.14(prettier@3.7.4))(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
- dependencies:
- '@storybook/csf-plugin': 8.6.14(storybook@8.6.14(prettier@3.7.4))
- browser-assert: 1.2.1
- storybook: 8.6.14(prettier@3.7.4)
- ts-dedent: 2.2.0
- vite: 6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)
-
'@storybook/builder-vite@8.6.14(storybook@8.6.14(prettier@3.7.4))(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
dependencies:
'@storybook/csf-plugin': 8.6.14(storybook@8.6.14(prettier@3.7.4))
@@ -8935,28 +8982,6 @@ snapshots:
react-dom: 19.2.3(react@19.2.3)
storybook: 8.6.14(prettier@3.7.4)
- '@storybook/react-vite@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.7.4)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.3)(storybook@8.6.14(prettier@3.7.4))(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
- dependencies:
- '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
- '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
- '@storybook/builder-vite': 8.6.14(storybook@8.6.14(prettier@3.7.4))(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
- '@storybook/react': 8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.7.4)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@8.6.14(prettier@3.7.4))(typescript@5.6.3)
- find-up: 5.0.0
- magic-string: 0.30.21
- react: 19.2.3
- react-docgen: 7.1.1
- react-dom: 19.2.3(react@19.2.3)
- resolve: 1.22.11
- storybook: 8.6.14(prettier@3.7.4)
- tsconfig-paths: 4.2.0
- vite: 6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)
- optionalDependencies:
- '@storybook/test': 8.6.14(storybook@8.6.14(prettier@3.7.4))
- transitivePeerDependencies:
- - rollup
- - supports-color
- - typescript
-
'@storybook/react-vite@8.6.14(@storybook/test@8.6.14(storybook@8.6.14(prettier@3.7.4)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(rollup@4.53.3)(storybook@8.6.14(prettier@3.7.4))(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
dependencies:
'@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
@@ -9247,19 +9272,19 @@ snapshots:
dependencies:
xlsx: 0.18.5
- '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)':
+ '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
- '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
+ '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.49.0
- '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
- '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
+ '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.49.0
eslint: 9.39.2(jiti@1.21.7)
ignore: 7.0.5
natural-compare: 1.4.0
- ts-api-utils: 2.1.0(typescript@5.6.3)
- typescript: 5.6.3
+ ts-api-utils: 2.1.0(typescript@5.9.3)
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -9295,15 +9320,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)':
+ '@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.49.0
'@typescript-eslint/types': 8.49.0
- '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.6.3)
+ '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.49.0
debug: 4.4.3
eslint: 9.39.2(jiti@1.21.7)
- typescript: 5.6.3
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -9362,15 +9387,15 @@ snapshots:
dependencies:
typescript: 5.9.3
- '@typescript-eslint/type-utils@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)':
+ '@typescript-eslint/type-utils@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.49.0
- '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.6.3)
- '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
+ '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.2(jiti@1.21.7)
- ts-api-utils: 2.1.0(typescript@5.6.3)
- typescript: 5.6.3
+ ts-api-utils: 2.1.0(typescript@5.9.3)
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -9430,14 +9455,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)':
+ '@typescript-eslint/utils@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@1.21.7))
'@typescript-eslint/scope-manager': 8.49.0
'@typescript-eslint/types': 8.49.0
- '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.6.3)
+ '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3)
eslint: 9.39.2(jiti@1.21.7)
- typescript: 5.6.3
+ typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -9527,18 +9552,6 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
- '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
- dependencies:
- '@babel/core': 7.28.5
- '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
- '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5)
- '@rolldown/pluginutils': 1.0.0-beta.27
- '@types/babel__core': 7.20.5
- react-refresh: 0.17.0
- vite: 6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)
- transitivePeerDependencies:
- - supports-color
-
'@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))':
dependencies:
'@babel/core': 7.28.5
@@ -10579,6 +10592,26 @@ snapshots:
- eslint-plugin-import-x
- supports-color
+ eslint-config-next@15.4.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3):
+ dependencies:
+ '@next/eslint-plugin-next': 15.4.0
+ '@rushstack/eslint-patch': 1.15.0
+ '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
+ '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
+ eslint: 9.39.2(jiti@1.21.7)
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@1.21.7))
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@1.21.7))
+ eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@1.21.7))
+ eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@1.21.7))
+ eslint-plugin-react-hooks: 5.2.0(eslint@9.39.2(jiti@1.21.7))
+ optionalDependencies:
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - eslint-import-resolver-webpack
+ - eslint-plugin-import-x
+ - supports-color
+
eslint-config-next@15.4.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
dependencies:
'@next/eslint-plugin-next': 15.4.0
@@ -10607,6 +10640,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@1.21.7)):
+ dependencies:
+ '@nolyfill/is-core-module': 1.0.39
+ debug: 4.4.3
+ eslint: 9.39.2(jiti@1.21.7)
+ get-tsconfig: 4.13.0
+ is-bun-module: 2.0.0
+ stable-hash: 0.0.5
+ tinyglobby: 0.2.15
+ unrs-resolver: 1.11.1
+ optionalDependencies:
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@1.21.7))
+ transitivePeerDependencies:
+ - supports-color
+
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)):
dependencies:
'@nolyfill/is-core-module': 1.0.39
@@ -10622,6 +10670,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@1.21.7)):
+ dependencies:
+ debug: 3.2.7
+ optionalDependencies:
+ '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
+ eslint: 9.39.2(jiti@1.21.7)
+ eslint-import-resolver-node: 0.3.9
+ eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@1.21.7))
+ transitivePeerDependencies:
+ - supports-color
+
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
dependencies:
debug: 3.2.7
@@ -10633,6 +10692,35 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@1.21.7)):
+ dependencies:
+ '@rtsao/scc': 1.1.0
+ array-includes: 3.1.9
+ array.prototype.findlastindex: 1.2.6
+ array.prototype.flat: 1.3.3
+ array.prototype.flatmap: 1.3.3
+ debug: 3.2.7
+ doctrine: 2.1.0
+ eslint: 9.39.2(jiti@1.21.7)
+ eslint-import-resolver-node: 0.3.9
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@1.21.7))
+ hasown: 2.0.2
+ is-core-module: 2.16.1
+ is-glob: 4.0.3
+ minimatch: 3.1.2
+ object.fromentries: 2.0.8
+ object.groupby: 1.0.3
+ object.values: 1.2.1
+ semver: 6.3.1
+ string.prototype.trimend: 1.0.9
+ tsconfig-paths: 3.15.0
+ optionalDependencies:
+ '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
+ transitivePeerDependencies:
+ - eslint-import-resolver-typescript
+ - eslint-import-resolver-webpack
+ - supports-color
+
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
dependencies:
'@rtsao/scc': 1.1.0
@@ -10662,6 +10750,25 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
+ eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.2(jiti@1.21.7)):
+ dependencies:
+ aria-query: 5.3.2
+ array-includes: 3.1.9
+ array.prototype.flatmap: 1.3.3
+ ast-types-flow: 0.0.8
+ axe-core: 4.11.0
+ axobject-query: 4.1.0
+ damerau-levenshtein: 1.0.8
+ emoji-regex: 9.2.2
+ eslint: 9.39.2(jiti@1.21.7)
+ hasown: 2.0.2
+ jsx-ast-utils: 3.3.5
+ language-tags: 1.0.9
+ minimatch: 3.1.2
+ object.fromentries: 2.0.8
+ safe-regex-test: 1.1.0
+ string.prototype.includes: 2.0.1
+
eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.2(jiti@2.6.1)):
dependencies:
aria-query: 5.3.2
@@ -10689,14 +10796,32 @@ snapshots:
dependencies:
eslint: 9.39.2(jiti@2.6.1)
- eslint-plugin-react-refresh@0.4.24(eslint@9.39.2(jiti@1.21.7)):
- dependencies:
- eslint: 9.39.2(jiti@1.21.7)
-
eslint-plugin-react-refresh@0.4.24(eslint@9.39.2(jiti@2.6.1)):
dependencies:
eslint: 9.39.2(jiti@2.6.1)
+ eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@1.21.7)):
+ dependencies:
+ array-includes: 3.1.9
+ array.prototype.findlast: 1.2.5
+ array.prototype.flatmap: 1.3.3
+ array.prototype.tosorted: 1.1.4
+ doctrine: 2.1.0
+ es-iterator-helpers: 1.2.1
+ eslint: 9.39.2(jiti@1.21.7)
+ estraverse: 5.3.0
+ hasown: 2.0.2
+ jsx-ast-utils: 3.3.5
+ minimatch: 3.1.2
+ object.entries: 1.1.9
+ object.fromentries: 2.0.8
+ object.values: 1.2.1
+ prop-types: 15.8.1
+ resolve: 2.0.0-next.5
+ semver: 6.3.1
+ string.prototype.matchall: 4.0.12
+ string.prototype.repeat: 1.0.0
+
eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)):
dependencies:
array-includes: 3.1.9
@@ -10719,16 +10844,6 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
- eslint-plugin-storybook@0.11.6(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3):
- dependencies:
- '@storybook/csf': 0.1.13
- '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
- eslint: 9.39.2(jiti@1.21.7)
- ts-dedent: 2.2.0
- transitivePeerDependencies:
- - supports-color
- - typescript
-
eslint-plugin-storybook@0.11.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3):
dependencies:
'@storybook/csf': 0.1.13
@@ -12804,33 +12919,6 @@ snapshots:
tslib@2.8.1: {}
- tsup@8.3.6(jiti@1.21.7)(postcss@8.5.6)(typescript@5.6.3)(yaml@2.8.2):
- dependencies:
- bundle-require: 5.1.0(esbuild@0.24.2)
- cac: 6.7.14
- chokidar: 4.0.3
- consola: 3.4.2
- debug: 4.4.3
- esbuild: 0.24.2
- joycon: 3.1.1
- picocolors: 1.1.1
- postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2)
- resolve-from: 5.0.0
- rollup: 4.53.3
- source-map: 0.7.6
- sucrase: 3.35.1
- tinyexec: 0.3.2
- tinyglobby: 0.2.15
- tree-kill: 1.2.2
- optionalDependencies:
- postcss: 8.5.6
- typescript: 5.6.3
- transitivePeerDependencies:
- - jiti
- - supports-color
- - tsx
- - yaml
-
tsup@8.3.6(jiti@2.6.1)(postcss@8.5.6)(typescript@5.6.3)(yaml@2.8.2):
dependencies:
bundle-require: 5.1.0(esbuild@0.24.2)
@@ -12961,17 +13049,6 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
- typescript-eslint@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3):
- dependencies:
- '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
- '@typescript-eslint/parser': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
- '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.6.3)
- '@typescript-eslint/utils': 8.49.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.6.3)
- eslint: 9.39.2(jiti@1.21.7)
- typescript: 5.6.3
- transitivePeerDependencies:
- - supports-color
-
typescript-eslint@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.6.3)
@@ -13098,17 +13175,6 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite-tsconfig-paths@5.1.4(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)):
- dependencies:
- debug: 4.4.3
- globrex: 0.1.2
- tsconfck: 3.1.6(typescript@5.6.3)
- optionalDependencies:
- vite: 6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)
- transitivePeerDependencies:
- - supports-color
- - typescript
-
vite-tsconfig-paths@5.1.4(typescript@5.6.3)(vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2)):
dependencies:
debug: 4.4.3
@@ -13131,22 +13197,6 @@ snapshots:
lightningcss: 1.30.2
terser: 5.44.1
- vite@6.4.1(@types/node@22.19.2)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2):
- dependencies:
- esbuild: 0.25.12
- fdir: 6.5.0(picomatch@4.0.3)
- picomatch: 4.0.3
- postcss: 8.5.6
- rollup: 4.53.3
- tinyglobby: 0.2.15
- optionalDependencies:
- '@types/node': 22.19.2
- fsevents: 2.3.3
- jiti: 1.21.7
- lightningcss: 1.30.2
- terser: 5.44.1
- yaml: 2.8.2
-
vite@6.4.1(@types/node@22.19.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2):
dependencies:
esbuild: 0.25.12