데이터베이스 붙이기
“새로고침해도 사라지지 않게”
02이 차시를 마치면
- 1.구글 시트와 데이터베이스의 차이를 설명하고, 언제 DB로 넘어가야 하는지 판단할 수 있다.
- 2.내 서비스에 필요한 데이터를 테이블(표) 구조로 설계할 수 있다.
- 3.Supabase 프로젝트를 만들어 08차시에서 만든 화면에 저장·조회·수정·삭제(CRUD)를 연결할 수 있다.
- 4.회원가입과 로그인을 붙여 사용자를 구분할 수 있다.
- 5.접근 권한(RLS)의 개념을 이해하고 최소한의 보호를 적용할 수 있다.
03왜 필요한가
08차시에서 만든 입력 폼은 잘 동작한다 — 값을 넣고 제출하면 화면에 반영된다. 그런데 새로고침을 한 번 누르는 순간 방금 입력한 내용이 흔적도 없이 사라진다. 지금 화면은 데이터를 어디에도 저장하지 않고, 그저 화면 위에 잠깐 띄워 보여주고 있을 뿐이기 때문이다. 실제 서비스가 되려면 입력한 데이터가 어딘가에 남아 있어야 하고, 누가 그 데이터를 넣었는지도 구분할 수 있어야 한다.
- 입력한 데이터가 새로고침 한 번에 사라져서, 지금 상태로는 진짜 서비스라고 부를 수 없다.
- 로그인이 없어 여러 사람이 접속해도 누가 어떤 데이터를 넣었는지 구분할 수 없다.
- 구글 시트로 계속 버티면 동시 접속자나 데이터량이 늘었을 때 한계에 부딪힌다(10절 비교표 참조).
- 로그인이 없으면 '내 글만 보기', '내 예약만 수정하기' 같은 개인화된 기능을 애초에 만들 수 없다.
04개념 설명
시트와 DB의 차이, 언제 넘어가야 하나
구글 시트는 사람이 눈으로 보고 손으로 고치기 좋은 표다. 반면 데이터베이스(DB)는 여러 프로그램이 정해진 규칙으로 동시에 정확하게 읽고 쓰도록 설계된 저장소다. 시트도 데이터를 저장하지만, 여러 사람(또는 여러 화면)이 동시에 접근하거나 데이터량이 늘어나면 급격히 느려지고 꼬인다.
이 과정에서는 04차시에서 시트를 데이터베이스처럼 다루는 법을 익혔다. 이번 차시는 그 경험을 발판 삼아, 실제 서비스에는 왜 전용 데이터베이스가 필요한지로 넘어간다. 판단 기준은 단순하다 — 로그인이 필요한가, 동시에 여러 사람이 쓰는가, 데이터끼리 서로 연결(예: 사용자와 그 사용자의 글)돼야 하는가. 셋 중 하나라도 해당되면 시트를 넘어설 시점이다.
사람이 보고 고치는 표
소량 · 단일 사용자에 적합
여러 프로그램이 동시에 읽고 쓰는 저장소
로그인 · 동시 접속 · 데이터 연결이 필요할 때
- 시트 — 사람이 보고 고치는 표, 소량·단일 사용자에 적합
- DB — 여러 프로그램이 동시에 정확히 읽고 쓰는 저장소
- 로그인·동시 접속·데이터 간 연결이 필요해지면 DB로 넘어간다
테이블 설계 기초
데이터베이스의 테이블은 구글 시트와 생김새가 비슷하다 — 행(row)과 열(column)로 이뤄진 표다. 다른 점은 각 행을 고유하게 식별하는 값인 기본키(primary key)가 반드시 있고, 서로 다른 테이블끼리 값을 통해 연결(관계)될 수 있다는 것이다.
예를 들어 '신청' 테이블의 한 행마다 '누가 신청했는지'를 나타내는 사용자 식별값을 하나의 열로 갖고 있으면, '사용자' 테이블과 연결해 '이 사용자가 신청한 목록'을 뽑아낼 수 있다. 이번 차시에서는 이 관계까지 복잡하게 설계하지 않고, 08차시 화면 하나에 필요한 테이블 1~2개를 단순하게 설계하는 데 집중한다.
| 개념 | 의미 |
|---|---|
| 행(row) | 기록 하나 (시트와 동일) |
| 열(column) | 항목 하나 (시트와 동일) |
| 기본키 | 행을 고유하게 구분하는 값 |
- 행(row) = 기록 하나, 열(column) = 항목 하나(시트와 동일)
- 기본키(primary key) = 행을 고유하게 구분하는 값
- 테이블끼리는 식별값을 통해 서로 연결될 수 있다
Supabase 연동과 CRUD
Supabase는 데이터베이스, 로그인(인증), 파일 저장, 그리고 이 모든 것을 코드에서 바로 쓸 수 있는 API를 한 번에 제공하는 서비스다. PRD 18절의 결정에 따라 이 과정은 Supabase를 표준 데이터베이스로 쓴다 — 별도 서버를 직접 구축하지 않아도 웹 화면에서 곧바로 데이터를 저장하고 불러올 수 있다.
데이터를 다루는 동작은 네 가지로 요약된다 — 만들기(Create), 읽기(Read), 고치기(Update), 지우기(Delete). 이를 합쳐 CRUD라고 부른다. 08차시에서 만든 입력 폼은 Create에 해당하고, 목록 화면은 Read에 해당한다. 이번 차시에서 이 둘을 실제 저장소에 연결하고, 이어서 Update와 Delete까지 붙인다.
| 동작 | 의미 |
|---|---|
| Create | 입력 폼 제출 시 저장 |
| Read | 목록 화면에서 불러오기 |
| Update | 저장된 데이터 수정 |
| Delete | 저장된 데이터 삭제 |
- Create — 입력 폼 제출 시 저장
- Read — 목록 화면에서 저장된 데이터 불러오기
- Update / Delete — 저장된 데이터 수정·삭제
회원가입/로그인과 접근 권한
Supabase Auth를 쓰면 회원가입·로그인·비밀번호 관리를 직접 구현하지 않고도 붙일 수 있다. 로그인이 생기면 '이 데이터를 누가 넣었는지'를 시스템이 자동으로 구분하게 되고, 이는 개인화된 기능의 출발점이다.
접근 권한은 '로그인했다고 모든 데이터를 볼 수 있는 건 아니다'를 보장하는 장치다. Supabase의 RLS(Row Level Security, 행 단위 보안)는 '내가 만든 데이터만 내가 수정할 수 있다' 같은 규칙을 데이터베이스 자체에 걸어두는 기능이다. 이번 차시에서는 개념과 가장 기본적인 규칙 하나(내 데이터만 수정 가능)만 적용해보고, 더 복잡한 권한 설계는 필요해질 때 다시 다룬다.
- 로그인 = 누가 데이터를 넣었는지 구분하는 것
- RLS = 행 단위로 '누가 무엇을 볼/고칠 수 있는지'를 DB에 거는 규칙
- 지금은 '내 데이터만 내가 수정 가능' 수준으로 시작한다
05실습 가이드
1. Supabase 프로젝트 만들기
- Supabase 사이트에서 무료 계정으로 새 프로젝트를 만든다. 프로젝트 이름과 데이터베이스 비밀번호를 설정한다(비밀번호는 따로 안전하게 적어둔다).
- 프로젝트 생성이 끝나면 대시보드에서 프로젝트 URL과 anon(공개용) API 키를 확인한다. 화면 구성은 실습 직전 공식 화면과 다를 수 있으니, 메뉴 이름이 정확히 일치하지 않아도 'API' 또는 'Settings' 관련 메뉴를 찾아본다.
예상 결과 — Supabase 대시보드에 프로젝트가 생성되고, 프로젝트 URL과 anon 키를 확인할 수 있다.
안 될 때 — 프로젝트 생성이 오래 걸리거나 멈춘 것처럼 보이면 잠시 기다렸다 새로고침한다. 그래도 안 되면 다른 이름으로 새 프로젝트를 다시 만들어본다.
2. 테이블 설계하기
- 08차시에서 만든 입력 폼 화면을 기준으로, 그 데이터를 저장할 테이블 구조를 P9-1 프롬프트로 AI에게 설계받는다.
- AI가 제안한 열(컬럼) 목록과 각 열의 데이터 종류(글자, 숫자, 날짜 등)를 확인하고, 08차시 폼의 입력 항목과 하나씩 대응이 맞는지 점검한다.
예상 결과 — 테이블 이름과 열 목록(이름·데이터 종류·필수 여부)이 표로 정리된다.
안 될 때 — AI가 제안한 구조가 너무 복잡하면(예: 관계형 테이블 여러 개) '지금은 테이블 1~2개로 단순하게 시작하고 싶다'고 다시 요청한다.
3. 테이블 만들고 연결 정보 안전하게 보관하기
- Supabase 대시보드의 테이블 편집 화면(또는 SQL 편집기)에서 방금 설계한 테이블을 실제로 만든다.
- 프로젝트 URL과 anon 키를 코드에 직접 적지 않고 환경변수(.env 파일 등)로 분리해 저장한다.
- .gitignore에 .env 파일이 포함되어 있는지 확인해, 실수로 키가 저장소에 올라가지 않게 한다.
예상 결과 — Supabase에 테이블이 생성되고, 연결 정보는 .env 파일에만 있으며 .gitignore에 의해 제외된다.
안 될 때 — 테이블 편집 화면에서 열 타입 선택이 헷갈리면 AI에게 'Supabase 테이블 편집 화면에서 이 열을 어떤 타입으로 선택해야 하는지' 화면 구성 이름을 알려주며 다시 물어본다.
4. 데이터 저장·조회(Create/Read) 연동하기
- P9-2 프롬프트로 08차시의 입력 폼(Create)과 목록 화면(Read)을 Supabase 테이블에 연결하는 코드를 요청한다.
- 폼에 값을 입력해 제출한 뒤, Supabase 대시보드의 테이블 화면에서 그 데이터가 실제로 들어갔는지 확인한다.
- 목록 화면을 새로고침해 방금 저장한 데이터가 화면에 나타나는지 확인한다.
예상 결과 — 폼으로 제출한 데이터가 Supabase 테이블에 쌓이고, 새로고침해도 목록 화면에 그대로 남아 있다.
안 될 때 — 데이터가 테이블에 안 보이면 연결 정보(URL·키)가 정확한지, 테이블 이름과 코드가 참조하는 이름이 일치하는지 확인한다. 에러 메시지가 있다면 P9-5(복구 프롬프트)로 물어본다.
5. 수정·삭제(Update/Delete) 연동하기
- P9-3 프롬프트로 목록 화면에 수정·삭제 버튼과 그 동작을 추가로 요청한다.
- 등록한 항목 하나를 수정해보고, 다른 하나는 삭제해본다.
- 두 동작 모두 Supabase 테이블 화면에서 실제로 반영됐는지 확인한다.
예상 결과 — 화면에서 수정·삭제한 내용이 Supabase 테이블에도 그대로 반영된다.
안 될 때 — 삭제 버튼을 눌렀는데 화면에서만 사라지고 테이블에는 남아 있다면, 화면 상태만 바뀌고 실제 삭제 요청이 전송되지 않은 것이다. 삭제 동작이 어느 데이터를 대상으로 하는지 식별값(기본키)을 정확히 넘기고 있는지 확인해달라고 요청한다.
6. 회원가입/로그인 붙이기
- P9-4 프롬프트로 Supabase Auth를 이용한 회원가입·로그인 화면 연동을 요청한다.
- 새 계정으로 가입한 뒤 로그인해보고, Supabase 대시보드의 인증(Authentication) 관련 화면에서 가입한 계정이 보이는지 확인한다.
예상 결과 — 회원가입한 계정으로 로그인이 되고, Supabase 대시보드에서 그 사용자를 확인할 수 있다.
안 될 때 — 가입은 되는데 로그인이 안 되면 이메일 인증(확인 메일 클릭)이 필요한 설정인지 확인한다. 실습 환경에서는 이메일 인증을 끄는 옵션을 쓰는 것도 방법이라고 AI에게 물어본다.
7. 접근 권한(RLS) 최소 적용하기
- P9-6 프롬프트로 '로그인한 사용자가 자신이 만든 데이터만 수정·삭제할 수 있게' RLS 규칙 설정을 요청한다.
- 로그인 계정 A로 데이터를 하나 만들고, 계정 B로 로그인해 그 데이터를 수정·삭제해본다 — 실패해야 정상이다.
예상 결과 — 다른 사람이 만든 데이터는 수정·삭제가 거부되고, 자신이 만든 데이터만 수정·삭제된다.
안 될 때 — 아직 아무나 다 고칠 수 있다면 RLS가 켜져 있지 않거나 정책이 저장되지 않은 것이다. Supabase 대시보드에서 해당 테이블의 RLS가 활성화(Enable RLS) 상태인지 먼저 확인한다.
8. 전체 점검 — 새로고침해도 살아있는지 확인
- 로그인 → 데이터 입력 → 새로고침 → 로그아웃 → 재로그인까지 전체 흐름을 처음부터 다시 밟아본다.
- 매 단계에서 데이터와 로그인 상태가 예상대로 유지되는지 확인하고, 여기까지의 변경 사항을 커밋한다.
예상 결과 — 새로고침·재로그인을 거쳐도 데이터가 사라지지 않고, 각자의 계정으로 구분되어 보인다.
안 될 때 — 재로그인 후 데이터가 안 보이면 화면이 로그인 상태와 상관없이 모든 데이터를 보여주고 있거나, 반대로 RLS 정책이 지나치게 엄격해 자신의 데이터까지 막고 있을 수 있다. 어느 쪽인지 P9-5로 상황을 설명해 짚어본다.
06실전 프롬프트
07이것만은 주의
무슨 일이 생기나 — Supabase를 포함한 여러 무료 데이터베이스 서비스는 일정 기간 사용하지 않으면 프로젝트가 일시 정지된다. 발표나 시연 직전에 접속했다가 응답이 없어 당황하는 경우가 흔하다.
대처 — 발표·시연 전에는 미리 접속해 프로젝트가 깨어 있는지 확인한다. 정지된 상태라면 재활성화에 시간이 걸릴 수 있으니 여유를 두고 확인한다.
무슨 일이 생기나 — anon 키는 공개돼도 되도록 설계된 키지만, RLS 없이 테이블을 열어두면 이 키만으로 전체 데이터에 접근할 수 있다. service_role 키(관리자용)를 화면 코드에 넣는 것은 그보다 훨씬 위험하다.
대처 — 화면(프론트엔드) 코드에는 anon 키만 사용하고, service_role 키는 절대 넣지 않는다. anon 키를 쓰더라도 RLS로 접근 범위를 제한해야 안전하다.
무슨 일이 생기나 — 테이블을 만들고 RLS를 켜지 않으면, 로그인 여부와 상관없이 누구나 anon 키만으로 테이블의 모든 데이터를 읽고 쓸 수 있다.
대처 — 테이블을 만든 직후 RLS를 활성화하는 것을 기본 습관으로 삼는다. 정책을 아직 안 정했더라도 RLS부터 켜두면 최소한 전체 공개는 막을 수 있다.
무슨 일이 생기나 — 서비스를 운영하다 필요한 열이 새로 생기면 테이블 구조를 바꿔야 하는데, 이미 저장된 데이터와 새 구조가 안 맞아 오류가 나거나 기존 데이터가 비어 보일 수 있다.
대처 — 처음 설계할 때 앞으로 필요할 만한 항목을 한 번 더 점검한다. 구조를 바꿔야 한다면 기존 데이터를 먼저 백업하고, 변경 후 정상적으로 보이는지 확인한다.
무슨 일이 생기나 — 회원 정보 테이블을 직접 설계하면서 비밀번호 열을 만들어 평문으로 저장하려는 실수를 할 수 있다.
대처 — 비밀번호 저장·암호화는 Supabase Auth가 대신 처리한다. 직접 만든 테이블에는 비밀번호 열을 두지 않고, 사용자 식별은 Auth가 제공하는 사용자 ID를 참조한다.
08자가 점검
09과제
08차시에서 만든 화면 중 아직 데이터베이스를 연결하지 않은 화면이 있다면 하나를 골라 Supabase와 연결해본다. 이미 모두 연결했다면, 로그인한 사용자 본인의 데이터만 보이도록 목록 화면에 필터를 추가해본다.
제출 형식 — ① 저장 전/후, 새로고침 후 상태를 보여주는 스크린샷 ② 테이블 구조 캡처 화면 ③ 회원가입·로그인 동작 스크린샷 ④ 사용한 프롬프트와 AI 응답 요약을 하나의 문서로 정리해 제출한다.
10더 알아보기
- Supabase 공식 문서 — Database — 테이블 생성과 데이터 타입 참고용
- Supabase 공식 문서 — Row Level Security — RLS 정책 작성법을 더 깊이 볼 때
- Supabase 공식 문서 — Auth — 회원가입/로그인 방식(이메일, 소셜 로그인 등) 비교
- CRUD
- — 데이터를 다루는 네 가지 기본 동작 — 만들기(Create)·읽기(Read)·고치기(Update)·지우기(Delete).
- 기본키(Primary Key)
- — 테이블의 각 행을 고유하게 구분하는 값.
- RLS(Row Level Security)
- — 행 단위로 누가 무엇을 읽고 쓸 수 있는지 데이터베이스 자체에 거는 접근 권한 규칙.
- 환경변수
- — API 키처럼 코드에 직접 적으면 안 되는 값을 코드 밖의 별도 파일(.env)에 저장해 불러오는 방식.
다음 차시 예고 — 다음 차시는 지금까지 로컬(내 컴퓨터)에서만 확인해온 서비스를 실제 주소로 세상에 공개하는 시간이다. 배포 서비스 선택 기준, 환경변수와 비밀 관리, 커스텀 도메인 연결, 배포 후 점검 체크리스트까지 다루며 기본과정의 캡스톤 발표로 이어진다.