Skip to content
Go back

코딩 1도 모르는 마케터, AI로 로그인/DB까지 붙이다 (Supabase 연동기)

프롤로그: “다음은 데이터베이스야”

2026년 1월 10일, 목요일 저녁 8시.

지난번 글에서 Todo 앱을 만들어 배포했던 저는, 회사 동료에게 자랑했습니다.

저: “야, 내가 앱 만들었어!”
동료: “오~ 근데 회원가입은 안 돼?”
저: ”…회원가입?”

그제야 깨달았습니다.

지금까지 만든 건 ‘로컬 스토리지’만 쓰는 장난감이었다는 것을.

진짜 앱이 되려면 필요한 것:

“데이터베이스… 엑셀 같은 건가?”

이것이 제 여정의 시작이었습니다.


Day 1: “데이터베이스가 뭔데?”

오전 10시: 개념 이해하기

Cursor Chat에 물어봤습니다:

데이터베이스가 뭐야? 초등학생도 이해할 수 있게 설명해줘.

AI 답변:

데이터베이스는 '체계적으로 정리된 엑셀'이라고 생각하면 됩니다.

차이점:
- 엑셀: 한 명만 편집 가능, 파일로 저장
- 데이터베이스: 여러 명 동시 접속, 서버에 저장

예시:
- 회원 정보 (이름, 이메일, 비밀번호)
- 게시글 (제목, 내용, 작성자)
- 주문 내역 (상품, 수량, 날짜)

“아, 그냥 온라인 엑셀이구나!”

오전 11시: Supabase 선택

Cursor Chat:

비전공자가 쓰기 쉬운 무료 데이터베이스 추천해줘

AI 추천:

  1. Supabase ⭐ (추천)

    • 무료 플랜 좋음
    • 인증 기능 내장
    • PostgreSQL 기반
  2. Firebase

    • Google 제품
    • NoSQL (좀 더 복잡)

Supabase로 결정!

오후 12시: Supabase 계정 생성

단계:

  1. supabase.com 접속
  2. GitHub 계정으로 로그인
  3. “New Project” 클릭
  4. 프로젝트 이름: my-first-app
  5. 데이터베이스 비밀번호 설정 (메모장에 저장!)
  6. 리전: Northeast Asia (Seoul)

2분 후:

✅ Your project is ready!

대시보드에 들어가니:

“와… 진짜 엑셀이네?”

오후 2시: 첫 테이블 만들기

Table Editor에서 “Create a new table” 클릭

테이블 이름: todos

컬럼 설정:

id          | uuid      | Primary Key (자동 생성)
created_at  | timestamp | 생성 시간 (자동)
user_id     | uuid      | 사용자 ID
title       | text      | 할 일 제목
completed   | boolean   | 완료 여부

“Save” 클릭 → 테이블 생성 완료!

첫 번째 깨달음:

데이터베이스 테이블 만들기 = 엑셀 시트에 열 제목 정하기


Day 2: “회원가입 기능 만들기”

오전 9시: Next.js에 Supabase 연결

Cursor Composer (Cmd+I)에 입력:

Next.js 프로젝트에 Supabase 연동해줘.

요구사항:
1. Supabase 클라이언트 설정
2. 환경 변수 설정
3. 회원가입 페이지 만들기
4. 로그인 페이지 만들기

단계별로 설명해줘.

AI가 제안한 단계:

1단계: 패키지 설치

npm install @supabase/supabase-js

2단계: 환경 변수 설정

.env.local 파일 생성:

NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

“이 값들은 어디서 가져와?”

Supabase 대시보드:

붙여넣기 완료!

3단계: Supabase 클라이언트 생성

AI가 자동으로 파일 생성:

// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!

export const supabase = createClient(supabaseUrl, supabaseAnonKey)

오전 10시: 회원가입 페이지 만들기

Cursor Composer:

회원가입 페이지 만들어줘.

기능:
- 이메일 입력
- 비밀번호 입력
- 비밀번호 확인
- 회원가입 버튼

디자인:
- 중앙 정렬
- 카드 형태
- 파스텔 그라데이션 배경

AI가 생성한 파일:

// app/signup/page.tsx
'use client'

import { useState } from 'react'
import { supabase } from '@/lib/supabase'
import { useRouter } from 'next/navigation'

export default function SignUpPage() {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [loading, setLoading] = useState(false)
  const router = useRouter()

  const handleSignUp = async (e: React.FormEvent) => {
    e.preventDefault()
    setLoading(true)

    const { data, error } = await supabase.auth.signUp({
      email,
      password,
    })

    if (error) {
      alert(error.message)
    } else {
      alert('회원가입 성공! 이메일을 확인해주세요.')
      router.push('/login')
    }

    setLoading(false)
  }

  return (
    <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-purple-100 to-pink-100">
      <div className="bg-white p-8 rounded-2xl shadow-xl w-full max-w-md">
        <h1 className="text-3xl font-bold text-center mb-8 text-gray-800">
          회원가입
        </h1>
        
        <form onSubmit={handleSignUp} className="space-y-6">
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-2">
              이메일
            </label>
            <input
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
              required
            />
          </div>

          <div>
            <label className="block text-sm font-medium text-gray-700 mb-2">
              비밀번호
            </label>
            <input
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
              required
            />
          </div>

          <button
            type="submit"
            disabled={loading}
            className="w-full bg-gradient-to-r from-purple-500 to-pink-500 text-white py-3 rounded-lg font-semibold hover:opacity-90 transition disabled:opacity-50"
          >
            {loading ? '처리 중...' : '회원가입'}
          </button>
        </form>
      </div>
    </div>
  )
}

로컬에서 테스트:

npm run dev

localhost:3000/signup 접속

“와… 진짜 회원가입 페이지다!”

오후 2시: 첫 회원가입 시도

테스트 계정:

“회원가입” 버튼 클릭

3초 후:

❌ Error: Email rate limit exceeded

“뭐야 이게!”

Cursor Chat에 에러 복붙:

AI 답변:

Supabase 무료 플랜은 시간당 이메일 전송 제한이 있습니다.

해결 방법:
1. 이메일 확인 비활성화 (개발 중에만)
2. 유료 플랜 사용
3. 다른 이메일로 재시도

개발 중에는 이메일 확인을 비활성화하는 게 편합니다.

Supabase 대시보드:

다시 시도 → 성공!

✅ 회원가입 성공!

Supabase 대시보드 → Authentication → Users 확인

제 계정이 떠 있었습니다!

두 번째 깨달음:

데이터베이스에 데이터가 들어가는 걸 직접 보면 짜릿하다.


Day 3: “로그인 & 데이터 연동”

오전 10시: 로그인 페이지 만들기

Cursor Composer:

로그인 페이지 만들어줘.
회원가입 페이지와 비슷한 디자인으로.

AI가 자동 생성:

// app/login/page.tsx
// (코드 생략 - 회원가입과 유사)

테스트:

로그인 성공!

오전 11시: 사용자별 Todo 데이터 저장

목표:

Cursor Composer:

Todo 앱을 Supabase와 연동해줘.

요구사항:
1. 로그인한 사용자만 접근 가능
2. Todo 추가 시 Supabase에 저장
3. 사용자별로 자기 Todo만 보임
4. 실시간 동기화

AI가 코드 수정:

// app/todos/page.tsx
'use client'

import { useEffect, useState } from 'react'
import { supabase } from '@/lib/supabase'
import { useRouter } from 'next/navigation'

export default function TodosPage() {
  const [todos, setTodos] = useState([])
  const [user, setUser] = useState(null)
  const router = useRouter()

  useEffect(() => {
    // 로그인 확인
    supabase.auth.getUser().then(({ data: { user } }) => {
      if (!user) {
        router.push('/login')
      } else {
        setUser(user)
        fetchTodos(user.id)
      }
    })
  }, [])

  const fetchTodos = async (userId) => {
    const { data, error } = await supabase
      .from('todos')
      .select('*')
      .eq('user_id', userId)
      .order('created_at', { ascending: false })

    if (error) {
      console.error(error)
    } else {
      setTodos(data)
    }
  }

  const addTodo = async (title) => {
    const { error } = await supabase
      .from('todos')
      .insert([
        { user_id: user.id, title, completed: false }
      ])

    if (error) {
      alert(error.message)
    } else {
      fetchTodos(user.id)
    }
  }

  // ... (나머지 UI 코드)
}

오후 2시: 첫 번째 대형 에러

Todo 추가 버튼 클릭

에러 발생:

❌ Error: new row violates row-level security policy for table "todos"

“뭐야 이게!!!”

패닉.

Cursor Chat에 에러 복붙:

AI 답변:

Supabase는 기본적으로 Row Level Security (RLS)가 활성화되어 있습니다.
이는 보안 정책으로, 누가 어떤 데이터에 접근할 수 있는지 정의해야 합니다.

해결 방법:
Supabase 대시보드에서 RLS 정책을 추가해야 합니다.

“RLS가 뭔데…”

오후 3시: RLS 정책 설정 (지옥의 시작)

Supabase 대시보드:

AI가 알려준 정책:

정책 1: 자기 Todo만 조회

CREATE POLICY "Users can view own todos"
ON todos FOR SELECT
USING (auth.uid() = user_id);

정책 2: 자기 Todo만 추가

CREATE POLICY "Users can insert own todos"
ON todos FOR INSERT
WITH CHECK (auth.uid() = user_id);

정책 3: 자기 Todo만 수정

CREATE POLICY "Users can update own todos"
ON todos FOR UPDATE
USING (auth.uid() = user_id);

정책 4: 자기 Todo만 삭제

CREATE POLICY "Users can delete own todos"
ON todos FOR DELETE
USING (auth.uid() = user_id);

SQL Editor에 복붙 → “Run” 클릭

성공!

오후 4시: 재테스트

Todo 추가:

성공!

Supabase 대시보드 → Table Editor → todos 확인

제 Todo가 저장되어 있었습니다!

세 번째 깨달음:

에러가 나도 AI에게 물어보면 90% 해결된다.

오후 5시: 친구 초대 테스트

친구에게 카톡:

“야, 내 앱에 회원가입해봐! [링크]”

친구:

“오 신기하네. 가입했어.”

Supabase 대시보드 확인:

Users: 2명

“진짜 된다…!”

친구가 Todo 추가:

제 화면에는 안 보임 (당연함)

친구 화면에는 보임

“사용자별 데이터 분리 성공!”

전율.


Day 4: “500 Server Error와의 사투”

오전 10시: Vercel 배포

Git 푸시:

git add .
git commit -m "Add Supabase authentication"
git push

Vercel 자동 배포 시작

3분 후:

✅ Deployment successful!

배포된 사이트 접속

회원가입 시도

에러:

❌ 500 Server Error

“로컬에서는 됐는데!!!”

오전 11시: 환경 변수 문제

Cursor Chat:

로컬에서는 되는데 Vercel에서 500 에러 나는 이유가 뭐야?

AI:

환경 변수가 Vercel에 설정되지 않아서 그럴 가능성이 높습니다.

확인 방법:
Vercel 대시보드 → Settings → Environment Variables

Vercel 대시보드 확인:

환경 변수: 0개

“아…”

환경 변수 추가:

NEXT_PUBLIC_SUPABASE_URL = https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

“Redeploy” 클릭

3분 후 재배포 완료

테스트:

회원가입 성공!

“드디어!!!”

오후 2시: 최종 테스트

체크리스트:

모든 테스트 통과!


배운 것들 (Lessons Learned)

1. 데이터베이스는 생각보다 쉽다

처음 생각:

“데이터베이스는 전공자나 하는 거 아냐?”

실제:

“엑셀 다룰 줄 알면 할 수 있다.”

Supabase 덕분에:

2. RLS는 필수다

Row Level Security (RLS):

핵심:

데이터베이스 만들면 무조건 RLS 정책 설정하기

3. 환경 변수 관리

로컬과 배포 환경은 다르다:

배포 전 체크리스트:

  1. 환경 변수 Vercel에 추가했나?
  2. API 키 노출 안 됐나?
  3. .env.local.gitignore에 있나?

4. 에러는 배움의 기회 (2탄)

이번에 만난 에러:

해결 방법:

성공률: 100%


비전공자를 위한 실전 팁

Tip 1: Supabase 대시보드 활용

Table Editor:

SQL Editor:

Tip 2: 인증 기능은 Supabase에 맡기기

직접 구현하면:

Supabase 쓰면:

시간 절약: 며칠 → 1시간

Tip 3: 무료 플랜으로 시작

Supabase 무료 플랜:

개인 프로젝트엔 충분합니다.

Tip 4: 보안은 기본부터

절대 하지 말 것:

꼭 할 것:


다음 프로젝트 계획

이번 성공으로 자신감이 붙었습니다.

다음 도전:

  1. 파일 업로드 기능 (Supabase Storage)
  2. 실시간 채팅 (Supabase Realtime)
  3. 이메일 알림 (Supabase Edge Functions)

목표: 2주 안에 완성


결론: “나도 백엔드 개발자?”

4일 전의 저:

4일 후의 저:

바뀐 것:

핵심 메시지:

백엔드가 어렵다고요?
Supabase + AI면 하루 만에 가능합니다.

2026년, 비전공자와 전공자의 경계가 무너지고 있습니다.

중요한 건 코딩 실력이 아니라:

여러분도 할 수 있습니다.

지금 Supabase 계정 만들고 시작하세요.

내일이면 여러분의 앱에 로그인 기능이 붙어 있을 겁니다.


자주 묻는 질문 (FAQ)

Q1. Supabase는 정말 무료인가요?

A. 네, 무료 플랜이 있습니다.

무료 플랜 제한:

개인 프로젝트나 MVP 제작엔 충분합니다.

사용자가 많아지면 유료 플랜($25/월)으로 업그레이드하면 됩니다.


Q2. SQL을 몰라도 되나요?

A. 네, 몰라도 됩니다.

Supabase Table Editor:

SQL이 필요한 경우:

하지만 AI가 SQL 코드를 다 짜줍니다.

제 SQL 지식: 0%
AI 의존도: 100%


Q3. Firebase vs Supabase, 뭐가 더 좋나요?

A. 비전공자에겐 Supabase를 추천합니다.

Supabase 장점:

Firebase 장점:

제 선택: Supabase
이유: 엑셀처럼 생겨서 이해하기 쉬움


Q4. 보안은 괜찮나요?

A. RLS 정책만 제대로 설정하면 안전합니다.

Supabase 보안 기능:

주의사항:


Q5. 에러가 나면 어떻게 하나요?

A. 에러 메시지를 Cursor Chat에 복붙하세요.

제가 만난 에러 해결률:

해결 안 되면:

  1. Supabase Discord 커뮤니티
  2. Stack Overflow
  3. 유튜브 검색

포기하지 마세요. 에러는 배움의 기회입니다.


Q6. 얼마나 걸리나요?

A. 제 경우:

Day 1 (4시간):

Day 2 (5시간):

Day 3 (4시간):

Day 4 (3시간):

총 16시간

전통적 방법이었다면:

AI 덕분에 3개월을 16시간으로 압축했습니다.


Q7. 다음엔 뭘 배워야 하나요?

A. 제 학습 로드맵:

1단계 (완료):

2단계 (완료):

3단계 (진행 중):

4단계 (계획):

한 번에 하나씩, 천천히.


Q8. 코딩을 배워야 할까요?

A. 기초는 알면 좋지만, 필수는 아닙니다.

알면 좋은 것:

몰라도 되는 것:

제 학습 방법:

“배우면서 만든다” 접근법을 추천합니다.


부록: 제가 사용한 도구들

필수 도구

선택 도구

총 비용: $0


다음 글 예고

다음 글에서는 **“파일 업로드 & 이미지 처리”**를 다룰 예정입니다.

구독하고 알림 받으세요! 🚀


질문이나 피드백은 댓글로 남겨주세요.
여러분의 Supabase 연동 성공 스토리도 기다립니다!


Share this post on:

Next Post
내 컴퓨터 파일을 AI에게 연결한다고? 초보자를 위한 Cursor MCP 설정 가이드 (Github 연결편)