← Lecture Note
M6실습60분 · ~18 슬라이드

Next.js 프로젝트 부트스트랩

App Router + TypeScript + Tailwind

학습 목표

App Router 구조와 Server/Client 경계, Route Handler, 미들웨어 인증을 손에 익힌다.

이 모듈은 강의 전체의 뼈대가 되는 Next.js 프로젝트를 직접 손으로 만들어 보는 시간입니다. 이후 모든 모듈(RAG, Agent, 음성, 보고서)은 여기서 잡은 구조 위에 쌓이므로, 지금 설계를 제대로 이해해 두는 것이 핵심입니다.


프로젝트 생성

터미널에서 아래 명령 한 줄로 시작합니다.

npx create-next-app@latest hans17-ai \
  --typescript \
  --tailwind \
  --eslint \
  --app \
  --src-dir \
  --import-alias "@/*"

--app 플래그가 App Router를 활성화합니다. Next.js 13 이후 기본값이지만, 명시적으로 지정하는 습관을 들이세요.


디렉터리 구조

생성 직후 src/ 아래를 아래처럼 정리합니다. 강의 전체에서 이 구조를 일관되게 유지합니다.

src/
  app/
    (auth)/
      login/
        page.tsx        ← 로그인 페이지
    (protected)/
      dashboard/
        page.tsx        ← 보호된 메인 페이지
    api/
      chat/
        route.ts        ← Route Handler
    layout.tsx
    page.tsx
  components/           ← 재사용 UI 컴포넌트
  lib/
    llm.ts              ← callLLM() 통합 래퍼
    auth.ts             ← 세션 유틸
  public/
middleware.ts           ← 인증 보호 (app/ 바깥)

(auth), (protected) 같은 괄호 폴더는 Route Group으로, URL 경로에는 포함되지 않고 레이아웃만 구분합니다.


Server vs Client Components

App Router의 가장 중요한 개념입니다. 파일 상단에 아무 선언도 없으면 Server Component가 기본값입니다.

구분선언할 수 있는 것할 수 없는 것
Server Component(없음)DB/API 직접 호출, 환경변수 사용useState, useEffect, 브라우저 API
Client Component"use client"인터랙션, 훅, 이벤트 핸들러서버 전용 모듈 import

실수 방지: process.env.ANTHROPIC_API_KEY 같은 비밀 환경변수는 Server Component나 Route Handler에서만 사용하세요. "use client" 파일에서 참조하면 브라우저에 노출됩니다. 브라우저에 공개해도 되는 값만 NEXT_PUBLIC_ 접두사를 붙입니다.


Route Handler (route.ts)

API 엔드포인트는 app/api/*/route.ts 파일로 정의합니다. Express의 라우터와 동일한 역할이지만, Edge/Node.js 런타임 선택이 가능합니다.

// src/app/api/chat/route.ts
import { NextRequest, NextResponse } from "next/server";

export const runtime = "nodejs"; // 기본값; Edge로 바꾸면 경량 실행

export async function POST(req: NextRequest) {
  const { message } = await req.json();

  // 이후 모듈에서 callLLM()을 여기에 연결합니다
  return NextResponse.json({ reply: `echo: ${message}` });
}

GET, POST, PUT, DELETE 함수를 같은 파일에 나란히 export하면 HTTP 메서드가 자동으로 라우팅됩니다.


환경변수

.env.local에 키를 선언하고, process.env로 읽습니다.

# .env.local
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
ELEVENLABS_API_KEY=...
RESEND_API_KEY=re_...
SESSION_SECRET=최소32자이상의랜덤문자열

.env.local절대 Git에 커밋하지 마세요. .gitignore에 이미 포함되어 있지만 첫 커밋 전에 반드시 확인하세요.


middleware.ts — 인증 보호

src/ 바깥, 프로젝트 루트에 위치합니다. 요청이 페이지/API에 도달하기 전에 실행됩니다.

// middleware.ts
import { NextRequest, NextResponse } from "next/server";

const PUBLIC_PATHS = ["/login", "/api/auth"];

export function middleware(req: NextRequest) {
  const { pathname } = req.nextUrl;
  const isPublic = PUBLIC_PATHS.some((p) => pathname.startsWith(p));

  const token = req.cookies.get("session")?.value;

  if (!isPublic && !token) {
    return NextResponse.redirect(new URL("/login", req.url));
  }
  return NextResponse.next();
}

export const config = {
  // _next/static 등 정적 파일은 미들웨어에서 제외
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

세션 토큰 검증 로직(auth.ts)은 M7에서 확장하지만, 미들웨어 패턴 자체는 지금 완성해 두세요.


Dev 서버 + Hot Reload

npm run dev

http://localhost:3000에서 즉시 확인 가능합니다. 파일을 저장하면 브라우저가 자동으로 갱신됩니다(Fast Refresh). Server Component를 수정해도 전체 리로드 없이 서버만 다시 렌더링됩니다.


실습 (Lab)

목표

로그인 페이지(/login)와 미들웨어로 보호된 대시보드(/dashboard)를 완성합니다.

단계별 안내

Step 1 — 프로젝트 생성create-next-app 명령을 실행하고 디렉터리 구조를 위 표대로 만드세요.

Step 2 — 로그인 페이지 구현 src/app/(auth)/login/page.tsx를 Client Component로 작성합니다. 이메일/비밀번호 폼을 만들고, 제출 시 POST /api/auth/login을 호출합니다. 성공하면 쿠키에 session 토큰을 심고 /dashboard로 이동합니다.

Step 3 — 보호된 대시보드 구현 src/app/(protected)/dashboard/page.tsx를 Server Component로 작성합니다. cookies() 유틸로 세션을 읽어 사용자 이름을 표시합니다.

Step 4 — 미들웨어 연결middleware.ts 코드를 그대로 붙여넣고, 로그인 없이 /dashboard에 접근하면 /login으로 리다이렉트되는지 확인합니다.

Step 5 — 동작 확인

  1. npm run dev 실행
  2. http://localhost:3000/dashboard 직접 접근 → /login 리다이렉트 확인
  3. 로그인 후 대시보드 진입 확인
  4. 브라우저 쿠키 삭제 후 /dashboard 재접근 → 다시 리다이렉트 확인

핵심 정리

  • App Router에서 모든 컴포넌트는 Server Component가 기본값이며, 인터랙션이 필요한 경우에만 "use client"를 선언한다.
  • API 엔드포인트는 app/api/*/route.ts에 HTTP 메서드별 함수를 export해서 정의한다.
  • 비밀 환경변수(ANTHROPIC_API_KEY 등)는 Server Component·Route Handler에서만 사용하고, NEXT_PUBLIC_ 없이는 브라우저에 노출되지 않는다.
  • middleware.ts는 요청 최전선에서 실행되므로 인증 보호·리다이렉트 로직을 집중 관리하기에 최적의 위치다.
  • (auth), (protected) Route Group으로 URL 구조를 오염시키지 않고 레이아웃과 접근 제어를 분리할 수 있다.
  • 이 모듈에서 잡은 디렉터리 구조(app/api/, lib/, components/)는 이후 RAG·Agent·음성 모듈이 의존하는 공통 뼈대다.
LAB · 실습

로그인 페이지 + 보호된 메인 페이지