๐ Modern SaaS MVP Stack
4์ฃผ ์์ SaaS๋ฅผ ์ถ์ํ๊ธฐ ์ํ ๊ฒ์ฆ๋ ๊ธฐ์ ์คํ - Next.js, Supabase, Stripe๋ก ๋น ๋ฅด๊ฒ ์์ํ๊ธฐ
๐ Modern SaaS MVP Stack
4์ฃผ ์์ SaaS๋ฅผ ์ถ์ํ๊ธฐ ์ํ ๊ฒ์ฆ๋ ๊ธฐ์ ์คํ
"Ship fast, iterate faster" - ๋น ๋ฅธ ์ถ์์ ์ง์์ ์ธ ๊ฐ์ ์ ์ํ ์ต์ ์ ์กฐํฉ
๐ฏ ์ด ์คํ์ด ์ ํฉํ ๊ฒฝ์ฐ
โ ์ถ์ฒํ๋ ๊ฒฝ์ฐ
- ๋น ๋ฅธ MVP ์ถ์๊ฐ ์ต์ฐ์ ๋ชฉํ
- ์ด๊ธฐ ๋น์ฉ์ ์ต์ํํ๊ณ ์ถ์ ๋ถํธ์คํธ๋ฉ ์คํํธ์
- 1-3๋ช ์ ์๊ท๋ชจ ํ์ผ๋ก ์ด์
- B2B SaaS ๋๋ ํ๋ก์๋จธ ํ๊ฒ ์๋น์ค
- ์ฌ์ฉ๋ ๊ธฐ๋ฐ ๊ณผ๊ธ์ผ๋ก ์ฑ์ฅํ๊ณ ์ถ์ ๊ฒฝ์ฐ
โ ๋ค๋ฅธ ์คํ์ ๊ณ ๋ คํด์ผ ํ ๊ฒฝ์ฐ
- ๋ณต์กํ ๋ฐฑ์๋ ๋ก์ง์ด ํ์ํ ๊ฒฝ์ฐ โ Enterprise Stack
- ์ค์๊ฐ ํ์ ์ด ํต์ฌ์ธ ๊ฒฝ์ฐ โ Realtime Stack
- AI/ML์ด ํต์ฌ ๊ธฐ๋ฅ์ธ ๊ฒฝ์ฐ โ AI-Powered Stack
๐งฉ ํต์ฌ ๊ตฌ์ฑ์์
Frontend & UI
// ํต์ฌ ํ๋ก ํธ์๋ ์คํ const frontend = { framework: "Next.js 14 (App Router)", language: "TypeScript", styling: "Tailwind CSS + shadcn/ui", stateManagement: "Zustand", forms: "React Hook Form + Zod", animations: "Framer Motion" }; ์ฃผ์ ํน์ง:
- Next.js 14: Server Components๋ก ๋น ๋ฅธ ์ด๊ธฐ ๋ก๋ฉ
- TypeScript: ํ์ ์์ ์ฑ์ผ๋ก ๋ฒ๊ทธ ๊ฐ์
- Tailwind + shadcn/ui: ์ผ๊ด๋ ๋์์ธ ์์คํ
Backend & Database
// Supabase๋ก ๊ตฌํํ๋ ๋ฐฑ์๋ const backend = { platform: "Supabase", database: "PostgreSQL", orm: "Prisma", realtime: "Supabase Realtime", storage: "Supabase Storage", auth: "Supabase Auth" }; Supabase ์ฅ์ :
- PostgreSQL ๊ธฐ๋ฐ์ ์์ ์ ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค
- ๋ด์ฅ๋ ์ธ์ฆ ์์คํ (OAuth, Magic Link ์ง์)
- ์ค์๊ฐ ๋ฐ์ดํฐ ๋๊ธฐํ
- ํ์ผ ์คํ ๋ฆฌ์ง (S3 ํธํ)
๊ฒฐ์ & ๊ตฌ๋ ๊ด๋ฆฌ
// Stripe ํตํฉ const payments = { processor: "Stripe", subscriptions: "Stripe Billing", webhooks: "Stripe Webhooks", customerPortal: "Stripe Customer Portal", invoicing: "Stripe Invoicing" }; ์ด๋ฉ์ผ & ์ปค๋ฎค๋์ผ์ด์
- React Email: ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ด๋ฉ์ผ ํ ํ๋ฆฟ
- Resend: ํธ๋์ญ์ ๋ ์ด๋ฉ์ผ ์ ์ก
- Crisp: ๊ณ ๊ฐ ์ง์ ์ฑํ
๋ฐฐํฌ & ์ธํ๋ผ
# ์ธํ๋ผ ๊ตฌ์ฑ deployment: frontend: Vercel backend: Supabase Cloud cdn: Vercel Edge Network dns: Cloudflare monitoring: Vercel Analytics ๋ชจ๋ํฐ๋ง & ๋ถ์
- Sentry: ์๋ฌ ํธ๋ํน ๋ฐ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง
- PostHog: ์ ํ ๋ถ์ ๋ฐ ์ฌ์ฉ์ ํ๋ ์ถ์
- Vercel Analytics: ์น ์ฑ๋ฅ ์งํ
๐ฐ ์์ธ ๋น์ฉ ๋ถ์
| ์๋น์ค | ๋ฌด๋ฃ ํฐ์ด | ์ ๋ฃ ์์ | ์ 1๋ง MAU | ์ 10๋ง MAU | |--------|-----------|-----------|------------|-------------| | Vercel | ์ถฉ๋ถํจ | $20/์ | $20 | $150 | | Supabase | 500MB DB5GB ์คํ ๋ฆฌ์ง | $25/์ | $25 | $399 | | Stripe | ๊ฑฐ๋ ์์๋ฃ๋ง | 2.9% + 30ยข | ~$300* | ~$3,000* | | Resend | 100 ์ด๋ฉ์ผ/์ผ | $20/์ | $20 | $80 | | Sentry | 5K ์ด๋ฒคํธ/์ | $26/์ | $26 | $80 | | PostHog | 1M ์ด๋ฒคํธ/์ | $0/์ | $0 | $200 | | ์ด๊ณ | $0/์ | ~$91/์ | ~$391/์ | ~$3,909/์ |
*๋งค์ถ์ ์ฝ 3% ๊ธฐ์ค ๊ณ์ฐ
๐ 4์ฃผ ๊ตฌํ ๋ก๋๋งต
๐ Week 1: ๊ธฐ์ด ์ค์
# Day 1-2: ํ๋ก์ ํธ ์ด๊ธฐํ npx create-next-app@latest saas-app --typescript --tailwind --app cd saas-app npm install @supabase/supabase-js prisma @prisma/client # Day 3-4: Supabase ์ค์ npx supabase init npx prisma init # ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ์ค๊ณ # Day 5-7: ์ธ์ฆ ์์คํ
# Supabase Auth ํตํฉ # ํ์๊ฐ์
/๋ก๊ทธ์ธ ํ์ด์ง # ๋ณดํธ๋ ๋ผ์ฐํธ ์ค์ ๐ Week 2: ํต์ฌ ๊ธฐ๋ฅ
- ๋ฐ์ดํฐ ๋ชจ๋ธ๋ง: Prisma ์คํค๋ง ์ ์
- CRUD API: Server Actions๋ก ๊ตฌํ
- UI ์ปดํฌ๋ํธ: shadcn/ui ์ปดํฌ๋ํธ ์ปค์คํฐ๋ง์ด์ง
- ํผ ๊ฒ์ฆ: React Hook Form + Zod
๐ Week 3: ์์ตํ ์์คํ
// Stripe ๊ฐ๊ฒฉ ํ๋ ์์ const pricingPlans = [ { name: "Starter", price: "$9/month", features: ["1 User", "10 Projects", "Basic Support"], stripePriceId: "price_starter" }, { name: "Pro", price: "$29/month", features: ["5 Users", "Unlimited Projects", "Priority Support"], stripePriceId: "price_pro" }, { name: "Enterprise", price: "Custom", features: ["Unlimited Users", "Custom Features", "SLA"], stripePriceId: null } ]; ๐ Week 4: ์ถ์ ์ค๋น
- ์ฑ๋ฅ ์ต์ ํ: Lighthouse ์ ์ 90+ ๋ฌ์ฑ
- SEO ์ค์ : ๋ฉํ๋ฐ์ดํฐ, OG ์ด๋ฏธ์ง, sitemap
- ๋ชจ๋ํฐ๋ง ์ค์ : Sentry, PostHog ํตํฉ
- ๋ฌธ์ํ: README, API ๋ฌธ์, ์ฌ์ฉ์ ๊ฐ์ด๋
๐ ์ํคํ ์ฒ ํจํด
๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
saas-app/ โโโ app/ โ โโโ (auth)/ # ์ธ์ฆ ๊ด๋ จ ํ์ด์ง โ โโโ (dashboard)/ # ๋์๋ณด๋ (๋ณดํธ๋ ๋ผ์ฐํธ) โ โโโ api/ # API ๋ผ์ฐํธ โ โโโ (marketing)/ # ๋ง์ผํ
ํ์ด์ง โโโ components/ โ โโโ ui/ # shadcn/ui ์ปดํฌ๋ํธ โ โโโ features/ # ๊ธฐ๋ฅ๋ณ ์ปดํฌ๋ํธ โโโ lib/ โ โโโ supabase/ # Supabase ํด๋ผ์ด์ธํธ โ โโโ stripe/ # Stripe ์ ํธ๋ฆฌํฐ โ โโโ utils/ # ๊ณตํต ์ ํธ๋ฆฌํฐ โโโ prisma/ โโโ schema.prisma # ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ๋ฐ์ดํฐ ํ์นญ ํจํด
// Server Component์์ ๋ฐ์ดํฐ ํ์นญ async function DashboardPage() { const supabase = createServerComponentClient(); const { data: projects } = await supabase .from('projects') .select('*') .order('created_at', { ascending: false }); return <ProjectList projects={projects} />; } // Client Component์์ mutation function CreateProjectForm() { const createProject = async (data: ProjectData) => { const response = await fetch('/api/projects', { method: 'POST', body: JSON.stringify(data) }); // ๋ฆฌ๋ค์ด๋ ํธ ๋๋ ์ฌ๊ฒ์ฆ }; } ๐จ ๋์ ๋ฐ ๋ณํ
๐ธ ๋ ์ ๋ ดํ ๋์
| ์๋ณธ | ๋์ | ์ ๊ฐ ํจ๊ณผ | |------|------|-----------| | Supabase | PocketBase (Self-hosted) | -$25/์ | | Vercel | Coolify (Self-hosted) | -$20/์ | | Stripe | Paddle (๊ฐ๋จํ ์ธ๊ธ ์ฒ๋ฆฌ) | ๋น์ทํจ | | PostHog | Umami (Self-hosted) | -$0/์ |
๐ ๋ ๊ฐ๋ ฅํ ๋์
| ์๋ณธ | ๋์ | ์ฅ์ | |------|------|------| | Next.js | Remix | ๋ ๋์ ๋ค์คํ ๋ผ์ฐํ | | Supabase | AWS Amplify | ๋ ๋ง์ ์ปค์คํฐ๋ง์ด์ง | | Prisma | Drizzle | ๋ ๋์ ์ฑ๋ฅ | | Vercel | AWS + Terraform | ์์ ํ ์ ์ด |
๐ ์ง์ญ๋ณ ๋ณํ
- ํ๊ตญ: NHN Toast + ํ ์คํ์ด๋จผ์ธ
- ์ ๋ฝ: Hetzner + Stripe (Strong Customer Authentication)
- ์ค๊ตญ: ์๋ฆฌ๋ฐ๋ฐ ํด๋ผ์ฐ๋ + Alipay
๐ ์ฑ๊ณต ์ฌ๋ก
Cal.com
- ์คํ: Next.js + Prisma + Tailwind
- ์ฑ๊ณผ: 2๋ ๋ง์ $25M ํฌ์ ์ ์น
- ํน์ง: ์คํ์์ค๋ก ์ ๋ขฐ ๊ตฌ์ถ
Dub.co
- ์คํ: Next.js + Planetscale + Vercel
- ์ฑ๊ณผ: ์ 1์ต+ ๋งํฌ ์ฒ๋ฆฌ
- ํน์ง: ๋ฐ์ด๋ ๊ฐ๋ฐ์ ๊ฒฝํ
Papermark
- ์คํ: Next.js + Supabase + Resend
- ์ฑ๊ณผ: Product Hunt 1์
- ํน์ง: ๋น ๋ฅธ ์ถ์์ ๋ฐ๋ณต
๐ ํ์ ๋ฆฌ์์ค
์คํํฐ ํ ํ๋ฆฟ
- Next.js SaaS Starter - Vercel ๊ณต์
- Supastarter - ์ ๋ฃ ๋ถ์คํฐ
- ShipFast - Marc Lou์ ํ ํ๋ฆฟ
ํ์ต ์๋ฃ
- Supabase + Stripe ํตํฉ ๊ฐ์ด๋
- Next.js App Router ๋ง์คํฐํ๊ธฐ
- Prisma๋ก ํ์ ์์ ํ ๋ฐฑ์๋
์ปค๋ฎค๋ํฐ
๐ฌ ์ปค๋ฎค๋ํฐ ์๊ฒฌ
"Supabase๋ ์ ๋ง Firebase์ ์คํ์์ค ๋์์ด ๋ง๋ค์. ํนํ PostgreSQL ๊ธฐ๋ฐ์ด๋ผ ๋ง์ด๊ทธ๋ ์ด์ ๋ ์ฝ๊ณ , Row Level Security๋ก ๋ณด์๋ ํํํฉ๋๋ค." - @devkr
"์ฒ์์ Vercel ๋น์ฉ์ด ๋ถ๋ด์ค๋ฌ์ ๋๋ฐ, ์ค์ ๋ก๋ DevOps ์์ง๋์ด ํ ๋ช ๊ณ ์ฉํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ์ ๋ ดํ์ด์." - @saasbuilder
"shadcn/ui๋ ์ง์ง ๊ฒ์์ฒด์ธ์ . Tailwind๋ง์ผ๋ก๋ ์ถฉ๋ถํ๋ค๊ณ ์๊ฐํ๋๋ฐ, ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ์ฑ์ด ์์ ๋ค๋ฅธ ๋ ๋ฒจ์ด๋ค์." - @uimaster
๐จ ์ฃผ์์ฌํญ ๋ฐ ํ
โ ๏ธ ํํ ์ค์๋ค
- ๊ณผ๋ํ ์ต์ ํ: MVP๋ ์๋ฒฝํ์ง ์์๋ ๋จ
- ๋ณต์กํ ๊ถํ ์์คํ : ์ด๊ธฐ์ ๋จ์ํ๊ฒ ์์
- ์ปค์คํ ๊ฒฐ์ ์์คํ : Stripe Customer Portal ํ์ฉ
๐ก ํ๋ก ํ
- Supabase Edge Functions: ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ฉ
- Incremental Static Regeneration: ๋ง์ผํ ํ์ด์ง ์ฑ๋ฅ
- Database Indexes: ์ฟผ๋ฆฌ ์ฑ๋ฅ ์ต์ ํ
- Webhook ์ฌ์๋: Stripe ์นํ ์์ ์ฑ
๐ฏ ๋ค์ ๋จ๊ณ
์ด ์คํ์ผ๋ก MVP๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์ถ์ํ๋ค๋ฉด:
- ์ค์ผ์ผ๋ง: Enterprise Microservices Stack์ผ๋ก ์ ํ ๊ณ ๋ ค
- AI ๊ธฐ๋ฅ ์ถ๊ฐ: AI-Powered App Stack ์ฐธ์กฐ
- ์ค์๊ฐ ๊ธฐ๋ฅ: Realtime Collaboration Stack ํตํฉ
๋ง์ง๋ง ์ ๋ฐ์ดํธ: 2025-01-28
๊ธฐ์ฌํ๊ธฐ: GitHub์์ ํธ์ง