Back
ESSAY비개발자를 위한 바이브코딩 안내서
DEC 18, 2025

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_idusers 테이블의 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에게 처리시키기 위해서 알아야 할 내용이 조금은 난이도가 높을 뿐입니다. 여러번 보다보면 금방 이해되실거에요.

Thank you for reading.

Based in Seoul
Since 2024