MVP 빠르게 만드는 바이브코딩 워크플로우
Claude Code + Next.js + Supabase로 48시간 안에 MVP 만드는 단계별 워크플로우.
한 줄 요약: Claude Code + Next.js + Supabase 조합으로 48시간 안에 동작하는 MVP를 만드는 것은 현실적으로 가능하다. 핵심은 Claude Code에게 무엇을 어떻게 지시하는가 — 프롬프트 전략이 개발 속도를 3배 이상 차이 나게 한다.
이 글은 이론이 아니라 실제 워크플로우다. 프로젝트 시작부터 배포까지 Claude Code를 어떻게 활용했는지, 어떤 프롬프트가 효과적이었는지, 어디서 막히는지를 단계별로 기록했다. Next.js 15 + Supabase + Vercel 스택을 기준으로 한다.
1단계 — 프로젝트 초기 설정 (2시간)
프로젝트를 시작할 때 Claude Code에게 처음부터 전체 구조를 설명하는 것이 핵심이다. 단편적으로 하나씩 지시하면 나중에 구조가 어긋난다.
CLAUDE.md 먼저 작성
코드를 한 줄도 쓰기 전에 CLAUDE.md를 작성한다. 이 파일이 Claude Code의 프로젝트 이해도를 결정한다.
CLAUDE.md 기본 템플릿 (MVP 프로젝트용)# CLAUDE.md — [프로젝트명] MVP ## 프로젝트 개요 - 서비스: [한 줄로 무엇을 하는 서비스인지] - 타겟: [누가 쓰는 서비스인지] - 스택: Next.js 15 (App Router), Supabase, Stripe, Vercel, Tailwind CSS ## 핵심 규칙 (MUST) - node --check {파일} 후 커밋 - .env 파일 절대 커밋 금지 - Supabase 쿼리는 항상 RLS 정책 확인 - 클라이언트 컴포넌트에서 직접 Supabase Admin 클라이언트 사용 금지 ## 디렉토리 구조 - app/ : App Router 페이지 - app/api/ : API Route Handlers - components/ : 재사용 UI 컴포넌트 - lib/ : 유틸리티, Supabase 클라이언트 - lib/supabase/ : server.ts, client.ts 분리 ## 환경변수 - NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY : 클라이언트 - SUPABASE_SERVICE_ROLE_KEY : 서버 전용 - STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET : 서버 전용 ## 작업 완료 기준 - 각 기능 구현 후 반드시 동작 여부를 명시 - 에러 처리 누락 없이 구현
CLAUDE.md 작성 후 초기 프로젝트 구조를 만드는 프롬프트를 입력한다.
Claude Code 초기 설정 프롬프트# 터미널에서 Claude Code 실행 claude # 첫 번째 프롬프트 (아래 내용을 붙여넣기) """ Next.js 15 App Router 기반 SaaS MVP 초기 구조를 만들어줘. 요구사항: 1. npx create-next-app@latest으로 프로젝트 생성 (TypeScript, Tailwind, App Router) 2. Supabase 클라이언트 설정 (lib/supabase/server.ts, lib/supabase/client.ts 분리) 3. Supabase Auth 미들웨어 설정 (middleware.ts) 4. 기본 레이아웃 (Header with 로그인/로그아웃 버튼) 5. 환경변수 예시 파일 (.env.example) 생성 Supa base 서버/클라이언트 분리 패턴은 공식 문서 패턴 사용. 각 파일 생성 후 의도 설명 포함. """
2단계 — 핵심 기능 구현 (12~16시간)
핵심 기능 구현 단계에서 Claude Code를 가장 효과적으로 쓰는 방법은 기능을 작은 단위로 쪼개서 순서대로 지시하는 것이다. 한 번에 너무 많이 요청하면 중간에 맥락을 잃고 코드 품질이 떨어진다.
효과적인 프롬프트 패턴
| 패턴 | 예시 | 효과 |
|---|---|---|
| 스키마 먼저 | "users, subscriptions, items 테이블 스키마 설계해줘" | DB 구조 확정 후 API 개발 |
| API 먼저, UI 나중 | "/api/items GET POST 먼저 만들고, UI는 그 다음에" | 로직과 UI 분리로 버그 감소 |
| 에러 처리 명시 | "try/catch, 사용자 친화적 에러 메시지 포함" | 빈 에러 처리 방지 |
| 완료 기준 명시 | "구현 후 curl로 테스트할 수 있는 예시 포함" | 검증 가능한 결과물 |
핵심 기능 구현 프롬프트 예시 (태스크 관리 SaaS 기준)# 단계 1: DB 스키마 """ Supabase에서 사용할 테이블 스키마를 SQL로 작성해줘: - tasks: id, user_id, title, description, status(enum: todo/in_progress/done), created_at - RLS 정책: user_id = auth.uid() 기준으로 본인 데이터만 접근 가능 마이그레이션 SQL 파일로 저장. """ # 단계 2: API Route """ app/api/tasks/route.ts 파일 생성: - GET: 로그인 사용자의 tasks 목록 반환 (Supabase 서버 클라이언트 사용) - POST: 새 task 생성 에러 처리: 미인증 시 401, DB 에러 시 500 반환. 타입 정의는 types/index.ts에 별도 파일로. """ # 단계 3: UI """ tasks API를 호출하는 TaskList 컴포넌트 만들어줘. - SWR로 데이터 패칭 (설치 포함) - 로딩 상태, 에러 상태, 빈 상태 각각 처리 - Tailwind CSS로 스타일링 - 새 task 추가 폼 포함 (모달 아니고 인라인 폼) """
3단계 — Supabase 인증 연동 (4시간)
Supabase Auth는 Google, GitHub 소셜 로그인을 5분 안에 붙일 수 있다. Claude Code에게 Next.js App Router에 맞는 인증 패턴을 명시하면 대부분 한 번에 동작하는 코드가 나온다.
Supabase 인증 미들웨어 + 보호된 라우트 설정// middleware.ts import { createServerClient } from '@supabase/ssr' import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export async function middleware(request: NextRequest) { let response = NextResponse.next({ request: { headers: request.headers }, }) const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { getAll() { return request.cookies.getAll() }, setAll(cookiesToSet) { cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value) ) response = NextResponse.next({ request }) cookiesToSet.forEach(({ name, value, options }) => response.cookies.set(name, value, options) ) }, }, } ) const { data: { user } } = await supabase.auth.getUser() // /dashboard 하위 경로는 로그인 필수 if (!user && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)) } return response } export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'], }
@supabase/ssr 패키지의 createServerClient를 반드시 사용하고, middleware.ts에서 쿠키 set/get을 위의 패턴대로 구현해야 한다. @supabase/auth-helpers-nextjs는 App Router에서 deprecated다.4단계 — Stripe 결제 연동 (6시간)
MVP에서 Stripe 연동의 핵심은 Checkout → Webhook → DB 동기화 3단계다. Claude Code에게 이 흐름 전체를 한 번에 지시하면 누락 없이 구현된다.
Stripe 연동 Claude Code 프롬프트# Claude Code에 입력할 프롬프트 """ Stripe 구독 결제 전체 흐름을 구현해줘: 1. app/api/checkout/route.ts - POST: Stripe Checkout Session 생성 - 파라미터: priceId (Stripe Price ID) - 인증된 사용자만 접근 가능 - success_url: /dashboard?success=true - cancel_url: /pricing 2. app/api/webhooks/stripe/route.ts - Stripe 웹훅 수신 (signature 검증 포함) - customer.subscription.created 이벤트: subscriptions 테이블에 삽입 - customer.subscription.updated 이벤트: status 업데이트 - customer.subscription.deleted 이벤트: status를 canceled로 업데이트 - bodyParser 비활성화 처리 (Next.js App Router 방식) 3. Supabase subscriptions 테이블 스키마 - user_id, stripe_customer_id, stripe_subscription_id, status, plan, current_period_end 웹훅 처리에 STRIPE_WEBHOOK_SECRET 환경변수 사용. 각 단계마다 에러 처리 포함. """
5단계 — Vercel 배포와 환경변수 설정 (2시간)
Vercel에 배포하기 전에 환경변수를 체크리스트로 확인한다. 빠진 환경변수 하나 때문에 배포 후 런타임 에러가 나는 경우가 많다.
STRIPE_WEBHOOK_SECRET에 등록해야 한다. 로컬 시크릿을 그대로 쓰면 웹훅 signature 검증이 실패한다.Claude Code 프롬프트 전략 — 속도를 3배 올리는 패턴
48시간 MVP 개발에서 시간을 가장 많이 절약한 프롬프트 패턴과 피해야 할 패턴을 정리했다.
효과적인 패턴
- 컨텍스트 명시: 작업 전 "현재 파일 구조를 확인하고" 또는 "lib/supabase/server.ts 패턴을 따라서"처럼 현재 코드베이스 맥락을 연결한다.
- 완료 기준 포함: "구현 후 localhost:3000에서 동작을 검증하는 방법을 알려줘"처럼 검증 가능한 완료 기준을 요청한다.
- 에러 발생 시 전체 에러 메시지 첨부: 에러 설명보다 실제 스택 트레이스를 그대로 붙여넣는다.
- 한 번에 하나: 기능 A가 완전히 동작한 것을 확인한 후 기능 B로 넘어간다.
피해야 할 패턴
- "전체 앱 만들어줘"처럼 범위가 무한한 요청
- 에러를 설명 없이 "이거 왜 안 돼?"로만 묻기
- 코드 리뷰 전에 다음 기능으로 넘어가기
- 타입 에러를
as any로 무시 요청