바이브코딩 가이드 Next.js 16 Google Gemini Claude Code

PDF Evidence AI
바이브코딩 완전 가이드

PDF를 올리면 AI가 쪽수와 근거를 함께 제시하며 대화하는 앱을 Claude Code로 처음부터 직접 만드는 방법을 단계별로 설명합니다.

Next.js 16 TypeScript Gemini API NeonDB (PostgreSQL) NextAuth.js Vercel Blob pdfjs-dist react-markdown KaTeX Vercel

이 앱이 뭐야?

완성되면 이런 기능들이 있습니다

Feature 01

📄 PDF 업로드 & AI 분석

PDF를 올리면 pdfjs로 텍스트를 추출하고, Gemini API로 각 페이지 AI 요약을 자동 생성합니다. Vercel Blob에 파일이 저장됩니다.

Feature 02

💬 스트리밍 AI 채팅

질문하면 SSE 스트리밍으로 실시간 답변이 흘러오고, 마크다운·수식(KaTeX)·표가 모두 렌더링됩니다.

Feature 03

📍 쪽수 기반 근거 시스템

AI가 답변하면서 출처 쪽수와 근거 카드를 같이 제시합니다. 카드를 클릭하면 PDF 뷰어가 해당 페이지로 이동합니다.

Feature 04

🖼️ 그림 인라인 표시

AI가 그림·그래프를 설명할 때 ![설명](page:3) 태그를 출력하면, 프론트엔드가 해당 페이지 이미지를 채팅 안에 자동으로 보여줍니다.

Feature 05

🌐 웹 검색 보강

PDF 내용만으로 부족할 때 웹 검색을 병행해 더 풍부한 답변을 만들고, 출처 링크도 함께 표시합니다.

Feature 06

🔒 구글 로그인 & 채팅 저장

NextAuth.js로 구글 OAuth 로그인을 구현하고, NeonDB(PostgreSQL)에 채팅 히스토리를 영구 저장합니다.

준비물

시작 전에 설치/가입해야 할 것들

💻 로컬에 설치할 것

🟩
Node.js 20 LTS 이상 JavaScript 런타임. npm도 같이 설치됨
nodejs.org →
🐙
Git 버전 관리 + Vercel 연동에 필요
git-scm.com →
💻
VS Code (권장) Claude Code VSCode 확장 사용 가능
code.visualstudio.com →
🤖
Claude Code AI 코딩 어시스턴트 CLI
claude.ai/code →

☁️ 가입해야 할 서비스

🐱
GitHub 코드 저장소 (Vercel 연동)
github.com →
Vercel 배포 + Vercel Blob(파일 저장)
vercel.com →
🗄️
NeonDB 서버리스 PostgreSQL DB (무료)
neon.tech →
🔮
Google AI Studio Gemini API 키 발급
aistudio.google.com →
🔑
Google Cloud Console OAuth 2.0 (구글 로그인) 설정
console.cloud.google.com →

개발 환경 세팅

Node.js 설치부터 프로젝트 생성까지

1

Node.js 설치 확인

터미널에서 버전을 확인하세요. 20 이상이어야 합니다.

node -v   # v20.x.x 이상
npm -v    # 10.x.x 이상

없으면 nodejs.org에서 LTS 버전 다운로드 후 설치

2

Claude Code 설치

AI 코딩 어시스턴트를 전역으로 설치합니다.

npm install -g @anthropic-ai/claude-code
3

Next.js 프로젝트 생성

공식 CLI로 Next.js 프로젝트를 생성합니다. TypeScript, App Router를 선택하세요.

npx create-next-app@latest pdf-evidence-ai
# ✓ TypeScript → Yes
# ✓ ESLint → Yes
# ✓ App Router → Yes
# ✓ src/ directory → Yes
# ✓ Tailwind CSS → No (이 프로젝트는 순수 CSS 사용)
cd pdf-evidence-ai
4

필요한 패키지 설치

이 프로젝트에 필요한 모든 라이브러리를 한 번에 설치합니다.

npm install @google/genai @napi-rs/canvas @neondatabase/serverless @vercel/blob next-auth pdfjs-dist react-markdown remark-gfm remark-math rehype-katex lucide-react katex
각 패키지 역할
@google/genai — Gemini AI API  |  @napi-rs/canvas — 서버사이드 PDF 이미지 렌더링
@neondatabase/serverless — NeonDB 연결  |  @vercel/blob — 파일 스토리지
next-auth — 구글 OAuth  |  pdfjs-dist — PDF 파싱/렌더링
react-markdown + remark-gfm + rehype-katex — 마크다운/수식 렌더링
5

환경변수 파일 생성

루트에 .env.local 파일을 만들고 API 키를 채워넣습니다. (아래 '외부 서비스 세팅' 참고)

# .env.local
DATABASE_URL=postgres://...         # NeonDB 연결 문자열
GEMINI_API_KEY=AIza...              # Google AI Studio
BLOB_READ_WRITE_TOKEN=vercel_blob_... # Vercel Blob
GOOGLE_CLIENT_ID=...                # Google OAuth
GOOGLE_CLIENT_SECRET=...            # Google OAuth
NEXTAUTH_SECRET=...                 # openssl rand -base64 32
NEXTAUTH_URL=http://localhost:3000
6

Claude Code 실행 → 바이브코딩 시작

프로젝트 폴더에서 Claude Code를 열고 아래 프롬프트들을 순서대로 사용하세요.

claude   # 또는 VS Code에서 Claude 확장 실행

바이브코딩 프롬프트

Claude Code에 순서대로 붙여넣기 하세요 — 각 Phase마다 완성된 코드가 생성됩니다

⚠️ 사용 팁
프롬프트를 한꺼번에 다 넣지 말고 Phase 순서대로 진행하세요. 각 Phase가 완료되면 앱을 실행해보고(npm run dev) 잘 동작하는지 확인 후 다음으로 넘어가는 게 훨씬 빠릅니다.
Phase 1 프로젝트 기본 구조 & 설정 next.config, tsconfig, types

Next.js 프로젝트의 기반 설정을 잡는 단계입니다. next.config.ts에 서버 외부 패키지 설정, TypeScript 타입 파일, 기본 lib 유틸 함수들을 만듭니다.

다음 설정을 해줘. Next.js 16 App Router + TypeScript 프로젝트야. 1. next.config.ts 설정: - serverExternalPackages: ["@napi-rs/canvas"] - webpack: canvas 관련 빌드 에러 방지 (pdfjs-dist가 캔버스를 optional로 처리) - outputFileTracingIncludes: PDF 렌더링 API 라우트에 pdfjs worker 포함 2. src/lib/types.ts 에 공통 타입 정의: - PdfPage { pageNumber, text, preview, charCount, aiSummary?, pageImageUrl? } - PdfDocument { id, fileName, pageCount, totalCharacters, pages, geminiFileUri?, geminiFileName?, geminiFileMimeType?, uploadedAt } - PdfDocumentSummary (pages에 full text 없이 preview, aiSummary만 포함) - EvidenceItem { kind: "figure"|"table"|"chart"|"text", page, title, quote, why } - AskResponse { answer, confidence: "high"|"medium"|"low", pdfSufficient, usedWeb, evidence, webSources, selectedPages, model, warning? } - WebSource { url, title, snippet } 3. src/lib/errors.ts: - safeErrorMessage(error, fallback): Error면 message 반환, 아니면 fallback 4. src/components/pdf-cache.ts: - getCachedPdfDoc(url): pdfjs-dist로 PDF 로드, 같은 URL이면 캐시 재사용 - 브라우저 전용 (client component에서만 호출)
Phase 2 인증 & 데이터베이스 NextAuth + NeonDB

구글 OAuth 로그인과 NeonDB PostgreSQL 연결을 설정합니다. 먼저 NeonDB에서 아래 SQL 스키마를 직접 실행한 후 이 프롬프트를 사용하세요.

먼저 NeonDB에서 실행할 SQL 스키마:
CREATE TABLE IF NOT EXISTS users (
  id    TEXT PRIMARY KEY,
  email TEXT UNIQUE NOT NULL,
  name  TEXT,
  image TEXT
);

CREATE TABLE IF NOT EXISTS pdf_sessions (
  id                    TEXT PRIMARY KEY,
  user_id               TEXT REFERENCES users(id) ON DELETE CASCADE,
  filename              TEXT NOT NULL,
  page_count            INTEGER DEFAULT 0,
  total_characters      INTEGER DEFAULT 0,
  gemini_file_uri       TEXT,
  gemini_file_name      TEXT,
  gemini_file_mime_type TEXT,
  pdf_url               TEXT,
  created_at            TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS pdf_pages (
  session_id      TEXT REFERENCES pdf_sessions(id) ON DELETE CASCADE,
  page_number     INTEGER,
  text_content    TEXT DEFAULT '',
  preview         TEXT DEFAULT '',
  char_count      INTEGER DEFAULT 0,
  ai_summary      TEXT,
  page_image_url  TEXT,
  PRIMARY KEY (session_id, page_number)
);

CREATE TABLE IF NOT EXISTS chat_messages (
  id         TEXT PRIMARY KEY,
  session_id TEXT REFERENCES pdf_sessions(id) ON DELETE CASCADE,
  role       TEXT NOT NULL,
  content    JSONB NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);
구글 OAuth 로그인과 NeonDB 연결을 만들어줘. 1. src/auth.ts — NextAuth 설정: - Google provider 사용 - session에 user.id 포함 (callbacks.session에서 session.user.id = token.sub) - signIn 콜백에서 DB에 users upsert (upsertUser 함수 호출) - GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, NEXTAUTH_SECRET 환경변수 사용 2. src/lib/db.ts — NeonDB CRUD: - sql() helper: process.env.DATABASE_URL로 neon() 연결 - upsertUser(user): users 테이블 INSERT ON CONFLICT DO UPDATE - createSession(data): pdf_sessions INSERT - getSessionsByUser(userId): 최근 50개 세션 목록 - getSession(sessionId, userId): 세션 + 페이지 전체 조회 - getPdfUrl(sessionId, userId): pdf_url만 조회 - deleteSession(sessionId, userId): DELETE - savePdfPages(sessionId, pages[]): UNNEST batch INSERT (page_image_url 포함) - getPageImageUrl(sessionId, pageNum): page_image_url 조회 - setPageImageUrl(sessionId, pageNum, url): UPDATE - getMessages(sessionId): 채팅 메시지 목록 - saveMessage(sessionId, message): INSERT - sessionToDocument(session): FullSession → PdfDocument 변환 3. src/app/api/auth/[...nextauth]/route.ts — NextAuth API 핸들러 4. src/middleware.ts — 로그인 안 하면 /login으로 리다이렉트 (단, /login, /api/auth/* 제외) 5. src/app/login/page.tsx — 구글 로그인 버튼 페이지
Phase 3 PDF 업로드 & 처리 pdfjs + Gemini + Vercel Blob

PDF 파일을 업로드하면 텍스트를 추출하고, Gemini로 각 페이지 요약을 생성하고, 서버사이드에서 페이지별 PNG 이미지를 렌더링해서 Vercel Blob에 저장하는 API를 만듭니다.

PDF 업로드 처리 시스템을 만들어줘. 1. src/lib/pdf.ts — PDF 텍스트 추출: - pdfjs-dist legacy 빌드 사용 (Node.js 서버 호환) - extractPdfDocument(buffer, fileName): Buffer → PdfDocument - 각 페이지 text 추출, preview(100자), charCount 계산 - GlobalWorkerOptions.workerSrc 설정 (서버사이드) 2. src/lib/pdf-render.ts — 서버사이드 PDF 이미지 렌더링: - @napi-rs/canvas 동적 import 사용 - renderPdfPageToJpeg(buffer, pageNum, scale=2): Buffer → JPEG Buffer - renderAndUploadAllPages(buffer, sessionId, pageCount, scale=1.5): 4페이지씩 배치로 렌더링 → Vercel Blob에 업로드 → Map 반환 - pdfjs-dist canvasFactory 커스텀 구현 3. src/lib/ai.ts (일부): - uploadPdfToGemini(buffer, filename): @google/genai로 파일 업로드 → {uri, name, mimeType} - generatePageSummaries(pages, geminiFile?): 각 페이지 1~2문장 요약 생성 → Map 4. src/lib/pdf-store.ts: - pdfEvidenceStore: Map (서버 메모리 캐시) - summarizeDocument(doc): PdfDocumentSummary 반환 5. POST /api/analyze-pdf: - FormData로 PDF 파일 수신 (최대 200MB) - 병렬 처리: uploadPdfToGemini + extractPdfDocument + put(Vercel Blob) - 병렬 처리: generatePageSummaries + renderAndUploadAllPages - DB에 세션 + 페이지 저장 - { sessionId, document, warning? } 반환 6. GET /api/sessions — 내 세션 목록 POST /api/sessions — (미사용, 위에서 생성) GET /api/sessions/[id] — 세션 + 문서 정보 GET /api/sessions/[id]/pdf — PDF 바이너리 프록시 DELETE /api/sessions/[id] — 세션 삭제 GET /api/sessions/[id]/messages — 채팅 히스토리
Phase 4 AI 질문 답변 스트리밍 Gemini SSE + 근거 추출

사용자 질문을 받아 관련 PDF 내용을 검색하고, Gemini API로 스트리밍 답변을 생성합니다. 근거 JSON과 답변이 SSE로 실시간 전달됩니다.

AI 질문 답변 시스템을 SSE 스트리밍으로 만들어줘. 1. src/lib/ai.ts 완성: selectRelevantPages(question, pages, maxPages=6): - 키워드 매칭 + 텍스트 유사도로 관련 페이지 선택 - 최소 3페이지 보장 buildPdfPrompt(question, pages, geminiFile?): - 선택된 페이지 텍스트 포함한 프롬프트 구성 - 시스템 규칙 포함: 그림/표 설명 시 반드시 ![설명](page:N) 태그 출력 streamAnswerText(prompt, onChunk): - gemini-2.0-flash 모델로 스트리밍 생성 - systemInstruction 필수: "【필수 규칙】 너는 이미지를 직접 표시하는 것이 아니다. 그림·그래프·차트를 설명할 때는 설명 바로 위 줄에 아래 형식의 텍스트 태그를 반드시 출력하라. 이 태그는 웹 앱 프론트엔드가 해석해서 이미지를 자동 표시한다: ![짧은설명](page:N) — N은 그림이 있는 쪽 번호(정수). 이탤릭이나 텍스트로만 대체하는 것은 금지." - 각 청크를 onChunk 콜백으로 전달 extractEvidence(answer, pages): EvidenceItem[] 추출 - answer 텍스트에서 쪽수 참조 파싱 - 해당 페이지 텍스트로 근거 항목 구성 webSearch(question): WebSource[] (선택적, 구글 Custom Search API) buildWebSupplementPrompt(question, pdfAnswer, webResults): string 2. POST /api/ask: - { documentId, question, allowWeb } 수신 - pdfEvidenceStore에서 문서 로드 (없으면 DB에서 복원) - SSE 스트림 반환 (Content-Type: text/event-stream) - 스트림 이벤트: data: {"type":"chunk","text":"..."} data: {"type":"meta","evidence":[...],"confidence":"high","pdfSufficient":true} data: {"type":"done","selectedPages":[3,5],"usedWeb":false,"model":"gemini-2.0-flash"} data: {"type":"error","message":"..."} - allowWeb=true이면 웹 검색 병행 후 답변 보강 - 완료 후 DB에 질문/답변 저장
Phase 5 채팅 UI & PDF 뷰어 Next.js 클라이언트 컴포넌트

채팅 인터페이스, PDF 뷰어, 사이드바 등 프론트엔드 전체를 만듭니다. SSE 스트리밍을 실시간으로 받아 마크다운으로 렌더링합니다.

채팅 인터페이스를 만들어줘. src/app/chat/[id]/page.tsx가 메인 페이지야. 레이아웃 (그리드 3영역): - 왼쪽 사이드바: 채팅방 목록 탭 + 페이지 목록 탭, 접고 펼치기 가능 - 가운데: 채팅 패널 (질문 입력, 메시지 스트림, 근거 카드) - 오른쪽: PDF 미리보기 패널 (pdfjs 렌더링, 줌, 페이지 네비게이션) 컴포넌트: 1. PdfViewer (src/components/PdfViewer.tsx): - pdfjs-dist 브라우저 빌드 사용 - url, page, scaleMultiplier props - 페이지 렌더링 + 드래그 팬 지원 2. PdfPageThumb (src/components/PdfPageThumb.tsx): - 200px 고정 너비 썸네일 - 클릭 시 해당 페이지로 이동 3. PdfImageCrop (src/components/PdfImageCrop.tsx): - sessionId + pdfUrl props - /api/sessions/{id}/pages/{N}/image API 시도 → 실패 시 pdfjs로 직접 렌더링 - bbox [x1,y1,x2,y2] 좌표로 canvas 크롭 4. AssistantMessage 컴포넌트: - react-markdown으로 답변 렌더링 (remarkGfm, remarkMath, rehypeKatex) - img 렌더러 커스텀: src가 "page:N"이면 PdfPageThumb으로 변환 src가 "page:N,x1,y1,x2,y2"이면 PdfImageCrop으로 변환 - 근거 카드 (EvidenceCard) 그리드 표시 - figure/chart 근거는 페이지 썸네일 이미지도 함께 표시 - 웹 출처 링크 행 5. /api/sessions/[id]/pages/[pageNum]/image: - GET: DB에서 page_image_url 확인 → 있으면 redirect - 없으면: PDF 다운로드 → 서버사이드 렌더링 → Blob 업로드 → redirect 스타일: src/app/globals.css에 CSS 변수 기반 다크/라이트 테마. Tailwind 없이 순수 CSS.
Phase 6 홈 & 업로드 페이지 /chat 진입점 + 드래그앤드롭

사용자가 처음 들어오는 /chat 페이지와 PDF 업로드 UI를 만듭니다.

src/app/chat/page.tsx — PDF 업로드 홈 페이지를 만들어줘. 기능: 1. 드래그앤드롭 + 클릭으로 PDF 파일 선택 2. 파일 선택 후 /api/analyze-pdf로 POST (FormData) 3. 업로드 진행 상황 표시 (분석 중 스피너 + 상태 메시지) 4. 완료되면 /chat/{sessionId}로 자동 이동 5. 이전 채팅방 목록도 사이드바에 표시 6. 파일 크기 제한 안내 (200MB 이하) 7. PDF만 허용 (다른 형식 드롭 시 에러 메시지) 디자인: - 업로드 영역: 점선 테두리, 드래그 시 강조 효과 - lucide-react 아이콘 사용 - 로딩 중에는 업로드 비활성화
Phase 7 UI 디자인 완성 CSS 다듬기 + 반응형

기능 구현 후 UI를 다듬는 단계입니다. 아래 시스템 프롬프트를 먼저 Claude에게 주고, 그 다음 디자인 요청을 하면 훨씬 퀄리티 높은 UI가 나옵니다.

You are an elite frontend designer and developer. Your job is to create production-grade, visually stunning web interfaces that look like they were handcrafted by a top-tier design studio — NOT like generic AI output. Follow these design principles: - NEVER use Inter, Roboto, Arial as the only font. Use distinctive Google Fonts with display/body pairing. - Define cohesive CSS custom properties (--color-primary, --bg, etc.) - Use dominant color + sharp accent strategy. Never timid, evenly-distributed palettes. - Break out of boring centered-card layouts. Use asymmetry, negative space, grid-breaking elements. - Add depth: gradient meshes, subtle noise, layered transparencies. - Animation: staggered fade-ins, hover micro-interactions, smooth transitions. --- 이제 이 Next.js 앱의 globals.css를 전면 개선해줘: 목표: - 다크 테마 기준 (딥 네이비 배경, 따뜻한 오렌지 액센트) - 현재 레이아웃 구조는 유지하면서 시각적 품질만 올리기 - 채팅 메시지, 근거 카드, PDF 뷰어 패널, 사이드바 디자인 개선 - 로딩 스켈레톤 애니메이션 추가 - 모바일 반응형 (768px 이하에서 PDF 뷰어 숨김, 채팅만 표시) - 스크롤바 커스텀 스타일 CSS 변수 팔레트 예시: --bg: #080c18 --surface: #111827 --accent: #f97316 --text: #e8edf5 --border: #1e2d47

Vercel 배포

GitHub에 올린 후 Vercel에 연결하면 자동 배포됩니다

1

GitHub 레포 생성 & 푸시

git init
git add .
git commit -m "initial commit"
git remote add origin https://github.com/유저명/pdf-evidence-ai.git
git push -u origin main
2

Vercel에서 프로젝트 가져오기

vercel.comAdd New → Project

GitHub 연동 → 방금 만든 레포 선택

Framework Preset: Next.js 자동 감지됨

Environment Variables에 .env.local 내용 모두 입력

Deploy 클릭 → 2~3분 후 배포 완료

3

환경변수 업데이트

배포 후 실제 URL로 업데이트하세요.

NEXTAUTH_URL=https://your-app.vercel.app

Google Cloud Console → OAuth 클라이언트 → 승인된 리디렉션 URI에 https://your-app.vercel.app/api/auth/callback/google 추가

4

Vercel Blob 스토리지 추가

Vercel 대시보드 → Storage 탭 → Create Blob Store

프로젝트에 연결 → BLOB_READ_WRITE_TOKEN 자동 생성

이후 git push만 하면 Vercel이 자동 재배포

외부 서비스 세팅 방법

각 서비스에서 API 키를 발급받는 방법입니다

Google AI Studio
Gemini API 키
무료
  • aistudio.google.com 접속 → 구글 계정으로 로그인
  • 왼쪽 메뉴 Get API key 클릭
  • Create API key → 새 프로젝트 선택
  • 생성된 키를 GEMINI_API_KEY에 저장
aistudio.google.com/apikey
NeonDB
서버리스 PostgreSQL
무료
  • neon.tech → Sign up (GitHub으로 간편 가입)
  • New Project → 이름 입력 → 리전 선택
  • 대시보드 → Connection string 복사
  • SQL Editor에서 위의 스키마 SQL 실행
  • 연결 문자열을 DATABASE_URL에 저장
neon.tech
Google OAuth
구글 로그인 설정
무료
  • console.cloud.google.com → 새 프로젝트 생성
  • API 및 서비스 → OAuth 동의 화면 설정
  • 사용자 인증 정보 → OAuth 2.0 클라이언트 ID 생성
  • 유형: 웹 애플리케이션
  • 승인된 리디렉션 URI:
    http://localhost:3000/api/auth/callback/google
  • 클라이언트 ID/Secret → GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
console.cloud.google.com
Vercel
배포 + Blob 스토리지
무료 플랜 가능
  • vercel.com → GitHub으로 가입
  • New Project → GitHub 레포 연결
  • Storage → Blob → Create Store
  • 프로젝트에 연결 → BLOB_READ_WRITE_TOKEN 자동 추가
  • Environment Variables에 나머지 환경변수 입력
vercel.com
NextAuth Secret
세션 암호화 키
로컬 생성
  • 터미널에서 랜덤 시크릿 생성
  • 생성된 값을 NEXTAUTH_SECRET에 저장
  • 절대 공개 저장소에 올리지 마세요
openssl rand -base64 32

openssl이 없으면: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

전체 환경변수 목록

변수명 설명 어디서 얻나요
DATABASE_URL NeonDB PostgreSQL 연결 문자열 NeonDB 대시보드 → Connection string 필수
GEMINI_API_KEY Google Gemini API 키 aistudio.google.com/apikey 필수
BLOB_READ_WRITE_TOKEN Vercel Blob 스토리지 토큰 Vercel → Storage → Blob 필수
GOOGLE_CLIENT_ID Google OAuth 클라이언트 ID Google Cloud Console → OAuth 필수
GOOGLE_CLIENT_SECRET Google OAuth 클라이언트 시크릿 Google Cloud Console → OAuth 필수
NEXTAUTH_SECRET 세션 서명용 랜덤 시크릿 (32바이트) openssl rand -base64 32 필수
NEXTAUTH_URL 앱 주소 (로컬: localhost:3000) 직접 입력 필수
GOOGLE_CSE_ID Google Custom Search Engine ID (웹검색) programmablesearchengine.google.com 선택
GOOGLE_API_KEY Google Custom Search API 키 (웹검색) Google Cloud Console → API Keys 선택