Backend

바이브 코딩으로 SaaS 만들기 — 백엔드 기술 스택 선택 가이드 (Supabase 중심)

AI 에이전트와 함께 내부 관리용 SaaS 백엔드를 구성하는 방법. Supabase를 중심으로 인증, DB 설계, RLS, Edge Functions까지 실전 스택을 정리했다.

· 5분 읽기 ·

시리즈

바이브 코딩으로 SaaS 만들기

2편
  1. 1 바이브 코딩으로 SaaS 만들기 — 프론트엔드 기술 스택 선택 가이드
  2. 2 바이브 코딩으로 SaaS 만들기 — 백엔드 기술 스택 선택 가이드 (Supabase 중심) 현재
바이브 코딩으로 SaaS 만들기 — 백엔드 기술 스택 선택 가이드 (Supabase 중심)

이 글은 Supabase 최신 버전(2026년 기준), Next.js 15 App Router 연동을 기준으로 작성되었습니다.

지난 편에서 프론트엔드 스택을 정리했다. 이번에는 백엔드 영역이다. 내부 관리용 SaaS를 바이브 코딩으로 만들 때 백엔드 선택에서 가장 많이 고민하는 지점은 하나다. “직접 서버를 구축할까, BaaS를 쓸까?”

결론부터 말하면, 내부 관리 도구 규모에서는 Supabase 같은 BaaS가 압도적으로 유리하다. 이 글에서 다루는 내용:

  • BaaS vs 직접 서버 구축의 선택 기준
  • Supabase가 제공하는 레이어별 기능과 선택 이유
  • AI 에이전트와 함께 DB 스키마 및 RLS 정책 설계하는 방법
  • Next.js App Router와 Supabase 연동 패턴

BaaS vs 직접 서버 구축

바이브 코딩에서 백엔드를 직접 구축한다는 건 Spring Boot나 FastAPI로 API 서버를 만들고, 인증 시스템을 설계하고, 배포 파이프라인까지 관리한다는 뜻이다. AI가 도와주더라도 이 모든 결정을 개발자가 내려야 한다.

반면 Supabase 같은 BaaS는 이런 인프라 결정 대부분을 이미 내려놓은 플랫폼이다.

비교 항목직접 구축Supabase (BaaS)
인증 구현JWT 설계 + 구현 필요기본 제공 (OAuth, Magic Link 포함)
DB인스턴스 직접 관리Managed PostgreSQL
API엔드포인트 직접 작성스키마 기반 자동 생성
스토리지S3 연동 직접 구현기본 제공
실시간WebSocket 구현 필요Realtime 기본 제공
AI 친화성프레임워크별 상이스키마 중심, AI가 파악하기 쉬움

내부 관리 도구 규모(~수십 명 사용자, 일반적인 CRUD 중심)라면 직접 구축의 유연성보다 BaaS의 개발 속도가 훨씬 크게 작용한다.

다만 사내 보안 정책으로 외부 클라우드 DB를 쓸 수 없는 환경이라면 Supabase의 셀프 호스팅 옵션을 검토하거나, 직접 구축을 선택해야 한다.


Supabase 레이어별 역할

Supabase는 단순한 DB 서비스가 아니다. 백엔드 전체를 커버하는 플랫폼이다.

flowchart TD
    A[Next.js App Router] -->|supabase-js 클라이언트| B[Supabase]
    B --> C[PostgreSQL DB]
    B --> D[Auth]
    B --> E[Storage]
    B --> F[Realtime]
    B --> G[Edge Functions]
    C -->|자동 생성| H[REST API]
    C -->|자동 생성| I[GraphQL API]

PostgreSQL DB

Supabase의 핵심이다. Managed PostgreSQL이라 운영 부담이 없고, 테이블을 만들면 REST API가 자동으로 생성된다. AI 에이전트와 함께 스키마를 설계할 때는 Supabase의 SQL Editor나 마이그레이션 파일을 기준으로 작업하면 된다.

-- 사용자 프로필 테이블 예시
create table profiles (
  id uuid references auth.users on delete cascade,
  name text not null,
  role text not null default 'user',
  department text,
  created_at timestamptz default now(),
  primary key (id)
);

auth.users를 직접 건드리지 않고 profiles 테이블을 별도로 두는 패턴이 Supabase 공식 권장 방식이다. 인증은 Supabase Auth가 처리하고, 비즈니스 데이터는 profiles에서 관리한다.

Auth (인증)

이메일/비밀번호, OAuth(Google, GitHub 등), Magic Link를 기본 제공한다. 내부 관리 도구라면 Google OAuth 또는 이메일 방식으로 빠르게 구성할 수 있다.

Next.js App Router에서 Supabase Auth를 연동할 때는 @supabase/ssr 패키지를 쓴다.

// utils/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export async function createClient() {
  const cookieStore = await cookies()
  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll: () => cookieStore.getAll(),
        setAll: (cookiesToSet) => {
          cookiesToSet.forEach(({ name, value, options }) =>
            cookieStore.set(name, value, options)
          )
        },
      },
    }
  )
}

서버 컴포넌트, 서버 액션, API Route별로 클라이언트 생성 방식이 다르다는 점을 주의하자. AI에게 코드 생성을 요청할 때 어떤 컨텍스트인지 명시하는 것이 중요하다.

RLS (Row Level Security)

Supabase에서 가장 중요하지만 처음에 가장 헷갈리는 개념이다. RLS는 PostgreSQL의 보안 정책으로, 어떤 사용자가 어떤 행(row)을 읽고 쓸 수 있는지 DB 레벨에서 제어한다.

-- profiles 테이블 RLS 정책 예시
alter table profiles enable row level security;

-- 본인 프로필만 수정 가능
create policy "users can update own profile"
  on profiles for update
  using (auth.uid() = id);

-- admin 역할은 전체 조회 가능
create policy "admins can view all profiles"
  on profiles for select
  using (
    exists (
      select 1 from profiles
      where id = auth.uid() and role = 'admin'
    )
  );

RLS를 설정하지 않으면 anon key로 테이블 전체가 조회된다. 반드시 RLS를 활성화한 후 정책을 정의해야 한다.

AI 에이전트에게 RLS 정책 생성을 요청할 때는 역할(role) 구조를 먼저 설명하는 것이 효과적이다. “admin은 모든 레코드를 볼 수 있고, user는 자신이 속한 department 데이터만 볼 수 있다”처럼 비즈니스 규칙을 자연어로 전달하면 AI가 정책을 잘 작성한다.

Storage

파일 업로드가 필요하다면 Supabase Storage를 쓴다. S3 호환 API를 제공하고, RLS와 동일한 정책 시스템으로 파일 접근 권한을 제어할 수 있다.

// 파일 업로드 예시
const { data, error } = await supabase.storage
  .from('attachments')
  .upload(`${userId}/${fileName}`, file)

Edge Functions

서버에서 실행되어야 하는 커스텀 비즈니스 로직은 Edge Functions(Deno 런타임)으로 처리한다. 예를 들어 외부 API 호출, 이메일 발송, 웹훅 처리 등이 여기 해당한다.

// supabase/functions/send-notification/index.ts
Deno.serve(async (req) => {
  const { userId, message } = await req.json()
  // 외부 슬랙 API 호출 등
  return new Response(JSON.stringify({ ok: true }))
})

추가 백엔드 레이어

Supabase만으로 대부분의 내부 관리 도구를 커버할 수 있지만, 필요에 따라 아래 레이어를 추가한다.

역할추천 기술이유
스케줄 작업Supabase pg_cronDB 내부에서 크론 실행, 별도 인프라 불필요
복잡한 서버 로직Next.js Server Actions별도 API 서버 없이 서버 코드 실행
배치 처리Trigger.devAI 레퍼런스 많고 TypeScript 지원
이메일 발송Resendsupabase-js와 조합하기 쉬움
검색PostgreSQL Full-text SearchSupabase 내에서 바로 사용 가능

Next.js App Router 연동 패턴

실제 코드에서 서버 컴포넌트, 클라이언트 컴포넌트, 서버 액션별로 Supabase를 어떻게 쓰는지 정리했다.

서버 컴포넌트에서 데이터 조회

// app/users/page.tsx (서버 컴포넌트)
import { createClient } from '@/utils/supabase/server'

export default async function UsersPage() {
  const supabase = await createClient()
  const { data: users } = await supabase
    .from('profiles')
    .select('*')
    .order('created_at', { ascending: false })

  return <UserTable users={users ?? []} />
}

서버 액션에서 데이터 변경

// app/users/actions.ts
'use server'
import { createClient } from '@/utils/supabase/server'
import { revalidatePath } from 'next/cache'

export async function updateUserRole(userId: string, role: string) {
  const supabase = await createClient()
  const { error } = await supabase
    .from('profiles')
    .update({ role })
    .eq('id', userId)

  if (error) throw new Error(error.message)
  revalidatePath('/users')
}

클라이언트 컴포넌트에서 Realtime 구독

// components/notifications-badge.tsx
'use client'
import { createClient } from '@/utils/supabase/client'
import { useEffect, useState } from 'react'

export function NotificationsBadge() {
  const [count, setCount] = useState(0)
  const supabase = createClient()

  useEffect(() => {
    const channel = supabase
      .channel('notifications')
      .on('postgres_changes', {
        event: 'INSERT',
        schema: 'public',
        table: 'notifications',
      }, () => setCount(c => c + 1))
      .subscribe()

    return () => { supabase.removeChannel(channel) }
  }, [])

  return <span>{count}</span>
}

AI 에이전트와 함께 DB 설계하기

Supabase는 스키마 중심 플랫폼이라 AI와 협업하기 좋다. CLAUDE.md에 다음 내용을 추가해두자.

## 백엔드 스택
- BaaS: Supabase (PostgreSQL + Auth + Storage)
- 연동 패키지: @supabase/ssr (서버), @supabase/supabase-js (클라이언트)
- 인증 방식: Google OAuth + 이메일/비밀번호

## DB 설계 규칙
- 모든 테이블에 RLS 활성화 필수
- 사용자 정보는 profiles 테이블 (auth.users 참조)
- created_at, updated_at 컬럼 모든 테이블에 포함
- UUID는 gen_random_uuid() 사용

## 역할 구조
- admin: 전체 데이터 조회/수정 가능
- manager: 소속 팀 데이터 조회/수정 가능
- user: 본인 데이터만 조회/수정 가능

이 정보가 있으면 AI가 “신규 주문 테이블 만들어줘”라는 요청에 RLS 정책, 인덱스, 타입스크립트 타입까지 포함한 완성형 코드를 생성한다.


마치며

바이브 코딩 맥락에서 내부 관리 SaaS 백엔드의 핵심은 빠른 초기 구축 + AI가 파악하기 쉬운 구조다. Supabase는 스키마 → API → 인증 → 보안 정책이 하나의 플랫폼 안에서 연결되어 있어 AI와 함께 설계하기에 특히 유리하다.

프론트엔드 편(1편)과 이번 백엔드 편에서 정리한 스택을 조합하면 아래와 같은 풀스택 구성이 완성된다.

레이어기술
프레임워크Next.js 15 (App Router)
언어TypeScript 5 (strict)
UIshadcn/ui + Tailwind CSS v4
상태 관리TanStack Query + Zustand
백엔드/BaaSSupabase
DBPostgreSQL (via Supabase)
인증Supabase Auth
배포Vercel + Supabase Cloud

이 스택은 1인 개발자부터 소규모 팀까지, 바이브 코딩으로 내부 관리 도구를 빠르게 만들고 싶을 때 현재 시점에서 가장 균형 잡힌 선택이라고 생각한다.