프롤로그: “다음은 데이터베이스야”
2026년 1월 10일, 목요일 저녁 8시.
지난번 글에서 Todo 앱을 만들어 배포했던 저는, 회사 동료에게 자랑했습니다.
저: “야, 내가 앱 만들었어!”
동료: “오~ 근데 회원가입은 안 돼?”
저: ”…회원가입?”
그제야 깨달았습니다.
지금까지 만든 건 ‘로컬 스토리지’만 쓰는 장난감이었다는 것을.
진짜 앱이 되려면 필요한 것:
- 회원가입/로그인
- 데이터베이스
- 사용자별 데이터 관리
“데이터베이스… 엑셀 같은 건가?”
이것이 제 여정의 시작이었습니다.
Day 1: “데이터베이스가 뭔데?”
오전 10시: 개념 이해하기
Cursor Chat에 물어봤습니다:
데이터베이스가 뭐야? 초등학생도 이해할 수 있게 설명해줘.
AI 답변:
데이터베이스는 '체계적으로 정리된 엑셀'이라고 생각하면 됩니다.
차이점:
- 엑셀: 한 명만 편집 가능, 파일로 저장
- 데이터베이스: 여러 명 동시 접속, 서버에 저장
예시:
- 회원 정보 (이름, 이메일, 비밀번호)
- 게시글 (제목, 내용, 작성자)
- 주문 내역 (상품, 수량, 날짜)
“아, 그냥 온라인 엑셀이구나!”
오전 11시: Supabase 선택
Cursor Chat:
비전공자가 쓰기 쉬운 무료 데이터베이스 추천해줘
AI 추천:
-
Supabase ⭐ (추천)
- 무료 플랜 좋음
- 인증 기능 내장
- PostgreSQL 기반
-
Firebase
- Google 제품
- NoSQL (좀 더 복잡)
Supabase로 결정!
오후 12시: Supabase 계정 생성
단계:
- supabase.com 접속
- GitHub 계정으로 로그인
- “New Project” 클릭
- 프로젝트 이름:
my-first-app - 데이터베이스 비밀번호 설정 (메모장에 저장!)
- 리전: Northeast Asia (Seoul)
2분 후:
✅ Your project is ready!
대시보드에 들어가니:
- Table Editor (표 편집기)
- SQL Editor (SQL 편집기)
- Authentication (인증)
- Storage (파일 저장소)
“와… 진짜 엑셀이네?”
오후 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 대시보드:
- Settings → API → Project URL 복사
- Settings → API → anon public 키 복사
붙여넣기 완료!
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시: 첫 회원가입 시도
테스트 계정:
- 이메일: test@example.com
- 비밀번호: test1234
“회원가입” 버튼 클릭
3초 후:
❌ Error: Email rate limit exceeded
“뭐야 이게!”
Cursor Chat에 에러 복붙:
AI 답변:
Supabase 무료 플랜은 시간당 이메일 전송 제한이 있습니다.
해결 방법:
1. 이메일 확인 비활성화 (개발 중에만)
2. 유료 플랜 사용
3. 다른 이메일로 재시도
개발 중에는 이메일 확인을 비활성화하는 게 편합니다.
Supabase 대시보드:
- Authentication → Settings
- “Enable email confirmations” 끄기
다시 시도 → 성공!
✅ 회원가입 성공!
Supabase 대시보드 → Authentication → Users 확인
제 계정이 떠 있었습니다!
두 번째 깨달음:
데이터베이스에 데이터가 들어가는 걸 직접 보면 짜릿하다.
Day 3: “로그인 & 데이터 연동”
오전 10시: 로그인 페이지 만들기
Cursor Composer:
로그인 페이지 만들어줘.
회원가입 페이지와 비슷한 디자인으로.
AI가 자동 생성:
// app/login/page.tsx
// (코드 생략 - 회원가입과 유사)
테스트:
- 이메일: test@example.com
- 비밀번호: test1234
로그인 성공!
오전 11시: 사용자별 Todo 데이터 저장
목표:
- 로그인한 사용자만 Todo 추가 가능
- 자기 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 대시보드:
- Table Editor → todos 테이블 선택
- “Add RLS policy” 클릭
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 연동 성공!” 입력
- 추가 버튼 클릭
성공!
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시: 최종 테스트
체크리스트:
- ✅ 회원가입 작동
- ✅ 로그인 작동
- ✅ Todo 추가 작동
- ✅ 사용자별 데이터 분리
- ✅ 모바일 반응형
- ✅ 다크모드
모든 테스트 통과!
배운 것들 (Lessons Learned)
1. 데이터베이스는 생각보다 쉽다
처음 생각:
“데이터베이스는 전공자나 하는 거 아냐?”
실제:
“엑셀 다룰 줄 알면 할 수 있다.”
Supabase 덕분에:
- SQL 몰라도 Table Editor로 테이블 생성
- 복잡한 설정 없이 클릭 몇 번으로 완료
- 무료 플랜으로 충분
2. RLS는 필수다
Row Level Security (RLS):
- 사용자별 데이터 접근 제어
- 보안의 기본
- 처음엔 어렵지만 AI가 정책 코드 다 짜줌
핵심:
데이터베이스 만들면 무조건 RLS 정책 설정하기
3. 환경 변수 관리
로컬과 배포 환경은 다르다:
- 로컬:
.env.local - Vercel: Environment Variables 설정
배포 전 체크리스트:
- 환경 변수 Vercel에 추가했나?
- API 키 노출 안 됐나?
.env.local은.gitignore에 있나?
4. 에러는 배움의 기회 (2탄)
이번에 만난 에러:
- Email rate limit exceeded
- Row-level security policy violation
- 500 Server Error (환경 변수)
해결 방법:
- 100% AI에게 물어봄
- 에러 메시지 복붙
- AI 답변 따라하기
성공률: 100%
비전공자를 위한 실전 팁
Tip 1: Supabase 대시보드 활용
Table Editor:
- 데이터 직접 확인 가능
- 테스트 데이터 수동 추가/삭제
- 디버깅에 필수
SQL Editor:
- AI가 준 SQL 코드 복붙
- RLS 정책 설정
- 복잡한 쿼리 테스트
Tip 2: 인증 기능은 Supabase에 맡기기
직접 구현하면:
- 비밀번호 암호화
- 세션 관리
- 이메일 인증
- 비밀번호 재설정
Supabase 쓰면:
supabase.auth.signUp()한 줄- 나머지는 Supabase가 다 해줌
시간 절약: 며칠 → 1시간
Tip 3: 무료 플랜으로 시작
Supabase 무료 플랜:
- 데이터베이스: 500MB
- 스토리지: 1GB
- 월간 대역폭: 5GB
- 사용자: 무제한
개인 프로젝트엔 충분합니다.
Tip 4: 보안은 기본부터
절대 하지 말 것:
- ❌ API 키를 코드에 직접 입력
- ❌
.env파일을 Git에 커밋 - ❌ RLS 정책 없이 테이블 공개
꼭 할 것:
- ✅ 환경 변수 사용
- ✅
.gitignore에.env.local추가 - ✅ RLS 정책 설정
다음 프로젝트 계획
이번 성공으로 자신감이 붙었습니다.
다음 도전:
- 파일 업로드 기능 (Supabase Storage)
- 실시간 채팅 (Supabase Realtime)
- 이메일 알림 (Supabase Edge Functions)
목표: 2주 안에 완성
결론: “나도 백엔드 개발자?”
4일 전의 저:
- 데이터베이스가 엑셀인 줄 알았음
- SQL이 뭔지 몰랐음
- 인증이 뭔지 몰랐음
4일 후의 저:
- Supabase로 데이터베이스 구축
- RLS 정책 설정
- 회원가입/로그인 구현
- 사용자별 데이터 관리
바뀐 것:
- 백엔드 지식? 조금 (개념은 이해함)
- AI 활용 능력? 많이 (복잡한 기능도 구현 가능)
- 자신감? 폭발 (이제 뭐든 만들 수 있을 것 같음)
핵심 메시지:
백엔드가 어렵다고요?
Supabase + AI면 하루 만에 가능합니다.
2026년, 비전공자와 전공자의 경계가 무너지고 있습니다.
중요한 건 코딩 실력이 아니라:
- 문제 해결 능력
- AI 활용 능력
- 포기하지 않는 끈기
여러분도 할 수 있습니다.
지금 Supabase 계정 만들고 시작하세요.
내일이면 여러분의 앱에 로그인 기능이 붙어 있을 겁니다.
자주 묻는 질문 (FAQ)
Q1. Supabase는 정말 무료인가요?
A. 네, 무료 플랜이 있습니다.
무료 플랜 제한:
- 데이터베이스: 500MB
- 스토리지: 1GB
- 월간 대역폭: 5GB
- 프로젝트: 2개
개인 프로젝트나 MVP 제작엔 충분합니다.
사용자가 많아지면 유료 플랜($25/월)으로 업그레이드하면 됩니다.
Q2. SQL을 몰라도 되나요?
A. 네, 몰라도 됩니다.
Supabase Table Editor:
- 클릭으로 테이블 생성
- GUI로 데이터 관리
- SQL 없이 CRUD 가능
SQL이 필요한 경우:
- RLS 정책 설정
- 복잡한 쿼리
하지만 AI가 SQL 코드를 다 짜줍니다.
제 SQL 지식: 0%
AI 의존도: 100%
Q3. Firebase vs Supabase, 뭐가 더 좋나요?
A. 비전공자에겐 Supabase를 추천합니다.
Supabase 장점:
- PostgreSQL (관계형 DB, 엑셀과 유사)
- Table Editor (직관적)
- SQL 쿼리 (강력함)
- 오픈소스
Firebase 장점:
- Google 제품 (안정성)
- NoSQL (유연함)
- 레퍼런스 많음
제 선택: Supabase
이유: 엑셀처럼 생겨서 이해하기 쉬움
Q4. 보안은 괜찮나요?
A. RLS 정책만 제대로 설정하면 안전합니다.
Supabase 보안 기능:
- Row Level Security (사용자별 접근 제어)
- JWT 토큰 인증
- HTTPS 암호화
- 비밀번호 자동 암호화
주의사항:
- API 키를 코드에 직접 입력하지 말 것
- RLS 정책 꼭 설정할 것
.env파일을 Git에 올리지 말 것
Q5. 에러가 나면 어떻게 하나요?
A. 에러 메시지를 Cursor Chat에 복붙하세요.
제가 만난 에러 해결률:
- Cursor AI: 90%
- ChatGPT: 85%
- Google 검색: 70%
해결 안 되면:
- Supabase Discord 커뮤니티
- Stack Overflow
- 유튜브 검색
포기하지 마세요. 에러는 배움의 기회입니다.
Q6. 얼마나 걸리나요?
A. 제 경우:
Day 1 (4시간):
- Supabase 계정 생성
- 테이블 생성
- Next.js 연동
Day 2 (5시간):
- 회원가입/로그인 페이지
- 인증 기능 구현
Day 3 (4시간):
- Todo 데이터 연동
- RLS 정책 설정
Day 4 (3시간):
- Vercel 배포
- 환경 변수 설정
- 최종 테스트
총 16시간
전통적 방법이었다면:
- 백엔드 학습: 2개월
- 데이터베이스 학습: 1개월
- 인증 구현: 1주일
- 총 3개월
AI 덕분에 3개월을 16시간으로 압축했습니다.
Q7. 다음엔 뭘 배워야 하나요?
A. 제 학습 로드맵:
1단계 (완료):
- ✅ 정적 웹사이트 (HTML/CSS)
- ✅ Next.js 기본
- ✅ Vercel 배포
2단계 (완료):
- ✅ Supabase 데이터베이스
- ✅ 회원가입/로그인
- ✅ CRUD 기능
3단계 (진행 중):
- 🔄 파일 업로드 (Supabase Storage)
- 🔄 실시간 기능 (Supabase Realtime)
- 🔄 이메일 알림 (Edge Functions)
4단계 (계획):
- 📝 결제 연동 (Stripe)
- 📝 관리자 대시보드
- 📝 모바일 앱 (React Native)
한 번에 하나씩, 천천히.
Q8. 코딩을 배워야 할까요?
A. 기초는 알면 좋지만, 필수는 아닙니다.
알면 좋은 것:
- JavaScript 기초 (변수, 함수, 조건문)
- React 개념 (컴포넌트, Props, State)
- Git 기본 (add, commit, push)
몰라도 되는 것:
- 알고리즘
- 자료구조
- 디자인 패턴
- 복잡한 SQL
제 학습 방법:
- 유튜브 10분 영상
- 필요할 때만 검색
- AI에게 물어보기
“배우면서 만든다” 접근법을 추천합니다.
부록: 제가 사용한 도구들
필수 도구
- Cursor: AI 코드 에디터 (무료 플랜)
- Supabase: 데이터베이스 + 인증 (무료 플랜)
- Vercel: 배포 플랫폼 (무료)
- GitHub: 코드 저장소 (무료)
선택 도구
- ChatGPT: 개념 이해용 (무료)
- Excalidraw: 데이터베이스 설계 (무료)
총 비용: $0
다음 글 예고
다음 글에서는 **“파일 업로드 & 이미지 처리”**를 다룰 예정입니다.
- Supabase Storage로 이미지 업로드
- 썸네일 자동 생성
- 프로필 사진 기능 구현
구독하고 알림 받으세요! 🚀
질문이나 피드백은 댓글로 남겨주세요.
여러분의 Supabase 연동 성공 스토리도 기다립니다!