프로덕션 레디의 Next.js 15 스타터킷입니다. Tailwind CSS, shadcn/ui, 상태관리, 폼 관리 등 모든 필수 도구가 사전 구성되어 있습니다.
- Next.js 15 - React 풀스택 프레임워크
- React 19 - UI 라이브러리
- TypeScript - 정적 타입 체크
- Tailwind CSS 4 - 유틸리티 퍼스트 CSS 프레임워크
- shadcn/ui - 복사 가능한 컴포넌트 라이브러리
- Radix UI - shadcn/ui의 기반 라이브러리
- Lucide React - 아이콘 라이브러리
- next-themes - 다크 모드 테마 관리
- Zustand - 가볍고 간단한 상태관리
- React Hook Form - 성능 최적화된 폼 관리
- Zod - TypeScript 우선 스키마 검증
- ESLint - 코드 품질 검사 (jsx-a11y 포함)
- Prettier - 코드 포맷팅
- Turbopack - Next.js 개발 서버 번들러
src/
├── app/ # App Router (Next.js 15)
│ ├── layout.tsx # 루트 레이아웃 (ThemeProvider + Header/Footer)
│ ├── page.tsx # 홈페이지
│ ├── about/
│ │ └── page.tsx # 소개 페이지
│ ├── dashboard/
│ │ └── page.tsx # 대시보드 페이지
│ └── globals.css # 전역 스타일 (다크모드 CSS 변수)
├── components/
│ ├── ui/ # shadcn/ui 컴포넌트
│ │ ├── button.tsx
│ │ ├── card.tsx
│ │ ├── input.tsx
│ │ ├── label.tsx
│ │ ├── textarea.tsx
│ │ ├── select.tsx
│ │ └── checkbox.tsx
│ ├── layout/ # 레이아웃 컴포넌트
│ │ ├── theme-provider.tsx # next-themes 래퍼
│ │ ├── theme-toggle.tsx # 다크모드 토글 버튼
│ │ ├── header.tsx # 헤더 (네비게이션)
│ │ └── footer.tsx # 푸터
│ └── features/ # 기능별 컴포넌트
│ └── login-form.tsx # 로그인 폼 예제
├── lib/
│ └── utils.ts # cn() 유틸리티
├── hooks/ # 커스텀 훅
├── types/ # TypeScript 타입 정의
├── stores/ # Zustand 스토어
│ └── example.ts # 상태관리 예제
├── schemas/ # Zod 검증 스키마
│ └── example.ts # 폼 검증 예제
└── utils/ # 유틸리티 함수
└── format.ts # 포맷팅 함수 예제
public/ # 정적 자산
npm run devhttp://localhost:3000에 접속하여 앱을 확인하세요.
src/app/page.tsx메인 페이지 수정src/components/새로운 컴포넌트 추가src/stores/Zustand 스토어 추가src/schemas/폼 검증 스키마 추가
npm run build # 프로덕션 빌드
npm run start # 프로덕션 서버 시작-
홈 (
/)- 기술 스택 소개
- Zustand 상태관리 예제
- React Hook Form + Zod 폼 검증 예제
-
소개 (
/about)- 프로젝트 목표 및 특징
- 핵심 기능 목록
- 접근성 & 코드 품질 정보
-
대시보드 (
/dashboard)- 통계 카드 (수익, 사용자, 주문, 활동률)
- 최근 활동 피드
- 인기 제품 목록
- Sticky 헤더 (상단 고정)
- 반응형 네비게이션 (데스크톱 수평, 모바일 햄버거 메뉴)
- ThemeToggle 컴포넌트 (다크 모드 전환)
- 포커스 관리 및 키보드 네비게이션 지원
- 회사 정보
- 링크 섹션
- 기술 스택 정보
- 저작권 표시
이 프로젝트는 next-themes를 사용하여 다크 모드를 구현합니다:
// src/app/layout.tsx
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{/* ... */}
</ThemeProvider>다크 모드는 globals.css의 CSS 변수로 관리됩니다:
라이트 모드 (:root)
--background: 0 0% 100%;
--foreground: 0 0% 3.6%;
--primary: 0 0% 9%;
/* ... 더 많은 변수 */다크 모드 (.dark 클래스)
--background: 0 0% 3.6%;
--foreground: 0 0% 98%;
--primary: 0 0% 98%;
/* ... 더 많은 변수 */컴포넌트에서 CSS 변수를 직접 사용합니다:
// ❌ 하드코딩된 색상 (금지)
<div className="bg-slate-50 text-slate-900">내용</div>
// ✅ CSS 변수 사용 (권장)
<div className="bg-background text-foreground">내용</div>Header의 ThemeToggle 컴포넌트로 테마를 전환합니다:
- Light → Dark → System 순환
- 선택한 테마는 localStorage에 저장됨
- SSR 깜빡임 없음 (hydration 안전)
npm run dev # 개발 서버 시작 (Turbopack 활성화)
npm run build # 프로덕션 빌드
npm run start # 프로덕션 서버 시작
npm run lint # ESLint 검사
npm run format # Prettier로 코드 포맷팅
npm run format:check # 포맷팅 확인
npm run type-check # TypeScript 타입 검사| 파일 | 용도 |
|---|---|
tsconfig.json |
TypeScript 설정 (strict 모드 활성화) |
tailwind.config.ts |
Tailwind CSS 커스터마이징 |
next.config.ts |
Next.js 설정 |
postcss.config.js |
PostCSS 플러그인 설정 |
.eslintrc.json |
ESLint 규칙 (a11y 포함) |
.prettierrc.json |
Prettier 포맷팅 규칙 |
components.json |
shadcn/ui 설정 |
// src/stores/example.ts
import { create } from 'zustand';
interface ExampleState {
count: number;
increment: () => void;
}
export const useExampleStore = create<ExampleState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));// src/components/features/login-form.tsx
'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { loginSchema, type LoginFormData } from '@/schemas/example';
export function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm<LoginFormData>({
resolver: zodResolver(loginSchema),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* 폼 필드 */}
</form>
);
}import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
export default function Example() {
return (
<Card>
<CardHeader>
<CardTitle>예제</CardTitle>
</CardHeader>
<CardContent>
<Label>이름</Label>
<Input placeholder="이름을 입력하세요" />
<Button>제출</Button>
</CardContent>
</Card>
);
}이 프로젝트는 다음 TypeScript 옵션을 사용합니다:
"strict": true- 엄격한 타입 검사"noUncheckedIndexedAccess": true- 인덱스 접근 안전성"noFallthroughCasesInSwitch": true- switch 문 안전성"baseUrl": "."- 기본 경로"paths": { "@/*": ["./src/*"] }- 경로 별칭
전역 스타일은 src/app/globals.css에서 CSS 변수로 관리됩니다:
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.6%;
--primary: 0 0% 9%;
/* ... 더 많은 변수 */
}
}라이트/다크 모드를 지원합니다.
이 프로젝트는 WCAG 2.2 AA 수준의 접근성을 목표합니다:
- ESLint의
jsx-a11y플러그인 활성화 - shadcn/ui의 Radix UI 기반 내장 접근성
- 모든 상호작용 요소는 포커스 가능
- focus-visible로 키보드 네비게이션 지원
npm install -g vercel
vercelFROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]MIT
문제가 발생하면 다음을 확인하세요:
- Node.js 버전: Node.js 18 이상 필요
- 의존성:
npm install실행 - TypeScript 에러:
npm run type-check실행 - 린트 에러:
npm run lint실행
추가 지원이 필요하면 프로젝트의 이슈를 생성하세요.