Part 4.3 데이터베이스 기초: 이것만은 알고가자
주의! 오늘 내용은 어렵습니다. 바이브코딩을 하면서 가장 어려운 부분이지 않을까, 생각합니다. 하지만, '프로덕트'를 이루는 가장 비중있는 요소는 데이터의 영속성입니다. 그 영속성은 데이터베이스를 통해 이루어집니다. 오늘 어렵더라도 꼭 한 번은 따라 해 보시고, 추가로 모르는 게 있다면, 바이브코더 답게, LLM에 되물어보면서 개념을 더 알아가시길 바랍니다.
https://www.riilog.com/post/part-32-데이터는-어떻게-흐르는가 에서 배웠듯이, 데이터를 어디에 저장하느냐에 따라 수명이 달라집니다.
| 저장 위치 | 수명 |
|---|---|
| 변수/State | 새로고침하면 사라짐 |
| LocalStorage | 그 브라우저에서만 유지 |
| 데이터베이스 | 영구 저장 |
제가 들었던 질문 중, 아마 데이터와 관련한게 제일 많았던 거 같습니다.
"새로고침하니까 데이터가 다 사라졌습니다"
"데이터베이스가 뭐에요?"
"테이블, 스키마, 칼럼...이거 꼭 알아야 하나요?"
데이터베이스는 처음엔 어렵게 느껴지지만, 기본 개념만 알면 AI가 대부분의 코드를 만들어줍니다. 이번 챕터에서는 바이브코딩에 꼭 필요한 데이터베이스 기초를 알아보겠습니다. 절대 어려워하지 마시고 천천히 따라오세요. 여러분들은 개념만 알고 계시면 됩니다. 이 개념을 토대로 LLM한테 '잘 시켜야' 합니다.
데이터베이스란?
데이터베이스는 데이터를 체계적으로 저장하고 관리하는 시스템입니다.
엑셀을 생각하면 이해하기 쉽습니다:
| 엑셀 | 데이터베이스 |
|---|---|
| 파일 | 데이터베이스 |
| 시트 | 테이블 |
| 행(Row) | 레코드/데이터 1개 |
| 열(Column) | 필드/속성 |
예를 들어, 회원 정보를 저장한다면:
[users 테이블]
┌────┬──────────┬─────────────────┬────────────┐
│ id │ name │ email │ created_at │
├────┼──────────┼─────────────────┼────────────┤
│ 1 │ 김철수 │ kim@email.com │ 2025-11-15 │
│ 2 │ 이영희 │ lee@email.com │ 2025-11-16 │
│ 3 │ 박민수 │ park@email.com │ 2025-11-17 │
└────┴──────────┴─────────────────┴────────────┘
SQL vs NoSQL: 두 가지 종류
데이터베이스는 크게 두 종류로 나뉩니다.
SQL (관계형 데이터베이스)
-
구조: 엑셀처럼 표(테이블) 형태
-
특징: 데이터 간의 관계를 정의할 수 있음
-
종류: PostgreSQL, MySQL, SQLite 등
-- SQL 쿼리 예시 (읽을 줄만 알면 됨)
SELECT * FROM users WHERE email = 'kim@email.com';
Tip: 위 SQL 문장 그대로 AI코딩 에디터에 넣어서 해석해 달라고 하세요. 앞으로 모르는게 생기면 사용 중인 AI 코드 에디터에 바로 물어보는 습관을 기르셔야 합니다.
NoSQL (비관계형 데이터베이스)
-
구조: JSON 문서 형태
-
특징: 유연한 구조, 빠른 개발
-
종류: MongoDB, DynamoDB 등
// NoSQL 데이터 예시
{
"id": "user_001",
"name": "김철수",
"email": "kim@email.com",
"profile": {
"age": 28,
"city": "서울"
}
}
바이브코딩에서 뭘 써야 할까?
| 상황 | 추천 |
|---|---|
| 처음 시작하는 경우 | Supabase (무료 티어 넉넉, 문서 좋음) |
| 실시간 기능 중요 | Firebase (실시간 동기화 강점) |
| 복잡한 데이터 관계 | Supabase (SQL의 강점-관계형DB) |
| 빠른 프로토타입 | 둘 다 좋음 |
최근엔 Firebase의 실시간 기능도 Supabase에서 거의 높은 성능으로 구현이 되더라구요. 굳이 Supabase만 쓰겠다, Firebase만 쓰겠다라고 나누지 않으셔도 괜찮습니다. LLM한테 본인이 만드려는 프로덕트의 성격에 맞는 툴을 골라달라고 하세요.
그리고 여기서 한 가지 주의할 점은 최근 바이브코딩은 거진 Supabase로 만들어지고 있습니다. AI코딩 에디터에 특정 툴을 사용하겠다는 프롬프트를 넣지 않으면 거진 Next + Supabase기반으로 자동 세팅이 되더라구요. 이걸 말씀드리는 이유는, Supabase로 하는 것이 '시중에 자료가 많기 때문'입니다. 그 말인즉슨, 여러분이 어느 문제를 맞닥뜨리고, 이걸 해결하기 위한 솔루션이 더 많다는 뜻이죠.
이 연재글에서도 Supabase를 기준으로 설명하겠습니다.
CRUD: 데이터의 4가지 기본 동작
모든 앱의 데이터 처리는 CRUD 4가지로 귀결됩니다.
| 동작 | 의미 | SQL | 예시 |
|---|---|---|---|
| Create | 생성 | INSERT | 회원가입, 글 작성 |
| Read | 읽기 | SELECT | 목록 조회, 상세 보기 |
| Update | 수정 | UPDATE | 프로필 수정, 글 편집 |
| Delete | 삭제 | DELETE | 회원 탈퇴, 글 삭제 |
Supabase에서 CRUD 코드
AI가 이런 코드를 만들어줄 텐데, 어떤 동작인지 알아볼 수 있으면 됩니다. 다음은 Supabase 의 api를 그대로 사용했다고 가정합니다. 이 때 현재는 몰라도 되는 개념인 ORM을 쓰지 않고 있다고 하겠습니다.
Create (생성):
// 새 할 일 추가
const { data, error } = await supabase
.from('todos') // todos 테이블에
.insert({ // 새 데이터 삽입
title: '장보기',
completed: false
});
Read (읽기):
// 모든 할 일 가져오기
const { data, error } = await supabase
.from('todos') // todos 테이블에서
.select('*'); // 모든 데이터 조회
// 조건에 맞는 것만 가져오기
const { data, error } = await supabase
.from('todos')
.select('*')
.eq('completed', false); // completed가 false인 것만
Update (수정):
// 할 일 완료 처리
const { data, error } = await supabase
.from('todos') // todos 테이블에서
.update({ completed: true }) // completed를 true로 변경
.eq('id', 1); // id가 1인 항목만
Delete (삭제):
// 할 일 삭제
const { data, error } = await supabase
.from('todos') // todos 테이블에서
.delete() // 삭제
.eq('id', 1); // id가 1인 항목
패턴이 보이시나요?
supabase
.from('테이블명')
.동작(...)
.조건(...);
모든 케이스에서 꼭 패턴을 그대로 따르지는 않습니다. 하지만 대게는 큰 틀에서 벗어나지 않기 때문에, 이걸 기억해두셨다가, 여러분의 에디터와 대화하며서 만들어 나가시길 바립니다.
스키마 설계: 테이블 구조 정하기
스키마는 데이터베이스의 구조, 즉 "어떤 테이블에 어떤 필드가 있는지"를 정의한 것입니다.
기본 원칙
1. 각 테이블은 하나의 "것"을 담는다
✅ 좋은 예:
- users 테이블: 사용자 정보
- posts 테이블: 게시글 정보
- comments 테이블: 댓글 정보
❌ 나쁜 예:
- data 테이블: 사용자, 게시글, 댓글 다 섞어서
'나쁜 예' 를 좀 더 설명하자면, 처음에는 극단적으로 1개 테이블에다가 죄다 만들어두고, 나중에 디벨롭하는 과정에서 '좋은 예'처럼 쪼개는 방법도 있답니다. 이건 설명을 위해서 이렇게 말씀드렸고, 실제 AI와 함께 코딩을 하면 거진 '좋은 예'로 작성을 해 줄 거에요.
2. 각 행(레코드)은 고유한 id를 가진다
[users]
id (고유 식별자) | name | email
1 | 철수 | kim@email.com
2 | 영희 | lee@email.com
3. 필드 타입을 명확히 정한다
| 필드 타입 | 용도 | 예시 |
|---|---|---|
| text/varchar | 문자열 | 이름, 이메일, 제목 |
| integer | 정수 | 나이, 수량, 가격 |
| boolean | 참/거짓 | 완료 여부, 활성화 여부 |
| timestamp | 날짜/시간 | 생성일, 수정일 |
| uuid | 고유 ID | 기본키 |
실전 예시: 할 일 앱 스키마
[todos 테이블]
- id: uuid (기본키, 자동 생성)//uuid가 아니라 1,2,3...N처럼 할 수도 있어요
- user_id: uuid (누구의 할 일인지)
- title: text (할 일 제목)
- completed: boolean (완료 여부)
- created_at: timestamp (생성 시간)
AI에게 스키마 설계 요청하는 법:
할 일 목록 앱을 만들려고 해.
- 사용자별로 할 일 관리
- 할 일에는 제목, 마감일, 완료 여부가 있음
- 할 일에 태그를 여러 개 붙일 수 있음
Supabase 테이블 스키마를 설계해줘.
각 테이블에 어떤 필드가 필요한지, 타입은 뭔지 알려줘.
데이터 관계: 테이블 연결하기
자, 지금부터는 정말 어려운 내용이에요. 그래서 이 부분은 한 번 읽고, 그냥 넘어가셔도 좋습니다. 근데 이걸 이해하는 순간 여러분의 프로덕트에 대한 데이터를 더 잘 이해할 수 있을거에요. 당연히 처음엔 이해가 안 가실 수도 있습니다. 실제로 여러분이 한땀한땀 관계를 맺어가는 과정을 거치지 않으면 습득하기가 어렵습니다. 하지만, 우리는 바이브코딩을 하고 있잖아요? 머릿 속에 이 개념들만 잘 넣어두고, 여러분의 AI코딩 에디터한테 최대한 best practice로 설계 해 달라고 해 봅시다. 그리고, 작성된 설계, 스키마, 타입들을 계속 읽어가면서 이건 왜 이렇게 관계가 됐는지, 저건 왜 관계가 이렇게 되어있는지를 대화하면서 이해도를 높여가보세요.
저도 최대한 쉽게 작성하기 위해서 최대한 개발 용어를 배제하려고 했고, 일상 속 용어로 쓰려고 했습니다. 그럼에도 불구하고 어려울 수 있는데, 이 점은 꼭 참고하시고 읽어나가주시면 되겠습니다.
실제 앱에서는 테이블들이 서로 연결됩니다.
1:N 관계 (일대다)
"한 사용자가 여러 개의 게시글을 작성한다"
[users] [posts]
id | name id | user_id | title
1 | 철수 ──────→ 1 | 1 | 첫 번째 글
2 | 1 | 두 번째 글
2 | 영희 ──────→ 3 | 2 | 영희의 글
posts 테이블의 user_id가 users 테이블의 id를 참조합니다.
코드에서:
// 철수(id=1)의 모든 게시글 가져오기
const { data } = await supabase
.from('posts')
.select('*')
.eq('user_id', 1);
N:M 관계 (다대다)
"게시글에 여러 태그를 붙일 수 있고, 하나의 태그가 여러 게시글에 붙을 수 있다"
이 경우 중간 테이블이 필요합니다.
[posts] [post_tags] [tags]
id | title post_id | tag_id id | name
1 | React 팁 1 | 1 1 | 개발
1 | 2 2 | React
2 | 요리법 2 | 3 3 | 요리
복잡해 보이지만, AI에게 "게시글에 태그 여러 개 붙이는 기능"이라고 설명하면 이 구조를 만들어줍니다.
관계 데이터 한 번에 가져오기
Supabase에서는 관계된 데이터를 한 번에 가져올 수 있습니다. 아래 말고도 위 예시에서 파생할 수 있는 많은 케이스가 있습니다. 이걸 전부 설명드리는 것보다, 여러분이 만드려는 프로덕트의 기능명세, 스키마를 가지고 여러분의 AI와 함께 대화하면서 알아가시는 것을 더 추천드립니다.
// 게시글과 작성자 정보를 함께 가져오기
const { data } = await supabase
.from('posts')
.select(`
*,
users (name, email)
`);
// 결과:
// { id: 1, title: "첫 번째 글", users: { name: "철수", email: "..." } }
그럼 오늘은 숙제도 1개 드릴게요.
1:1 관계는 어떻게 될까요?
다음 프롬프트를 써서 직접 대화를 시도해보세요.
'데이터베이스를 배우는 중이다. 최대한 쉽고 자세하게 설명해줘. 실제 스키마, sql, supabase코드까지 함께 줘. 나는 1:1 관계를 배우고 싶다. 이에 대해 알려줘'
Supabase MCP 연결하기
https://supabase.com/docs/guides/getting-started/mcp
이 문서를 보시면 supabase mcp에 연결하는 방법이 잘 나와있습니다. 커서나 클로드코드, 윈드서프 등 많은 에디터를 지원하니, 문서 읽어보시고 연결하는 방법도 스스로 찾아보세요. ( 힌트: 위 링크 자체를 프롬프트화해서 넣어보세요 - 'link' 여기에 가서 supabase mcp연결하는 방법을 찾아 )
자주 겪는 문제와 해결법
문제 1: 데이터가 안 들어가요
// error를 확인하세요!
const { data, error } = await supabase
.from('todos')
.insert({ title: '테스트' });
if (error) {
console.log('에러:', error.message); // 원인이 여기 나옴
}
흔한 원인:
-
테이블 이름 오타
-
필수 필드 누락
-
타입 불일치 (숫자 필드에 문자열 등)
문제 2: 데이터가 안 불러와져요
const { data, error } = await supabase
.from('todos')
.select('*');
console.log('data:', data); // null이면?
console.log('error:', error); // 여기 확인
흔한 원인:
-
테이블이 비어있음
-
환경 변수 설정 안 됨
데이터베이스는 바이브코딩의 큰 산 중 하나지만, 기본 개념만 알면 AI가 대부분 처리해줍니다. AI에게 처리시키기 위해서 알아야 할 내용이 조금은 난이도가 높을 뿐입니다. 여러번 보다보면 금방 이해되실거에요.
Related Articles
Thank you for reading.