이 단계에서 하는 것: 앞에서 정한 Supabase/Postgres를 사용해 데이터 모델을
docs/ERD.md에 설계한다. 이어서 마이그레이션으로 테이블·행 수준 보안(RLS)·기본 데이터를 실제 DB에 적용하고, 회원가입·로그인(Auth)을 설정한다. 다음 단계로 넘길 것: 접속해 사용할 수 있는 DB와 인증 설정,.env.local의 접속 정보, RLS로 사용자별 접근을 제한한 테이블. 다음 단계에서는 이 데이터 모델을 바탕으로 API 명세서를 작성한다.
사용할 기술(Supabase·Postgres·Auth·RLS)은 앞의 아키텍처 설계에서 정했다. 이번 단계에서는 데이터 모델을 설계하고 실제 DB를 구축한다. DBA는 정해진 기술을 기준으로 작업한다.
이번 단계에서는 사람과 AI가 맡을 작업을 구분한다. 사람은 자신의 계정으로 Supabase 대시보드에 로그인해 프로젝트를 만들고 접속 정보를 준비한다. Claude Code에는 데이터 설계와 마이그레이션 작성·적용을 맡긴다.
[사람]이 하는 일 (대시보드·인증): Supabase 프로젝트 만들기 · 접속 키와 연결 문자열 복사 · 회원가입/로그인 설정 · (끝나고) DB 비밀번호 재설정. [Claude]가 하는 일 (모델링·구축·적용): ERD 설계 · 테이블·RLS·시드 마이그레이션 작성 ·
.env.local의 연결 문자열로 실제 DB에 적용. (앱에서 DB를 부르는 코드는 백엔드 몫이라 여기서 만들지 않는다.)
각 단계의 [사람] 표시는 대시보드에서 직접 할 일을, [Claude] 표시는 프롬프트로 요청할 일을 뜻한다.
http://localhost:3000에 뜬다.supabase.com에서 GitHub로 가입한다.supabase.com에 로그인하고 New project를 누른다.moneynote 를 적는다.ap-northeast-2).이렇게 나오면 성공: 프로젝트 대시보드 화면이 열린다.
.env.local에 모으기 (대시보드)Supabase 연결에 필요한 값은 세 가지다. 대시보드에서 확인해 .env.local 파일에 입력한다. 이후 Claude가 이 파일의 값을 사용한다.
① Project Settings → API 에서 URL과 키를 가져온다. 대시보드 좌측 맨 아래 ⚙ Project Settings → API(또는 API Keys).
| 무엇을 (Project Settings → API) | 설명 | .env.local 변수명 |
|---|---|---|
| Project URL | https://<프로젝트ref>.supabase.co |
NEXT_PUBLIC_SUPABASE_URL |
anon public 키 |
최근 대시보드는 publishable 이라고도 부른다(같은 값) | NEXT_PUBLIC_SUPABASE_ANON_KEY |
② 상단 초록색 Connect 버튼 → Session pooler 탭에서 연결 문자열을 가져온다. 이런 모양이다.
postgresql://postgres.<프로젝트ref>:[YOUR-PASSWORD]@aws-0-<지역>.pooler.supabase.com:5432/postgres[YOUR-PASSWORD] 자리에 단계 1에서 정한 DB 비밀번호를 넣어 문자열을 완성한다.
왜 Direct가 아니라 Session pooler인가. 같은 창의 Direct connection(
db.<ref>.supabase.co)은 IPv6 전용이라, IPv6가 안 되는 환경에서는 접속이 안 된다. Session pooler는 IPv4에서도 되니 이걸 쓴다.
③ 프로젝트 폴더의 .env.local(없으면 새로 만든다)에 아래처럼 넣고, 오른쪽 값만 자기 것으로 바꾼다.
NEXT_PUBLIC_SUPABASE_URL=https://<프로젝트ref>.supabase.coNEXT_PUBLIC_SUPABASE_ANON_KEY=<anon(publishable) 키>SUPABASE_DB_URL=postgresql://postgres.<프로젝트ref>:<비밀번호>@aws-0-<지역>.pooler.supabase.com:5432/postgresNEXT_PUBLIC_이 붙어 화면에서 써도 되는 공개 값이다. 이 두 이름은 배포 단계의 Vercel 환경변수에서 그대로 다시 쓰므로 바꾸지 않는다.SUPABASE_DB_URL에는 DB 비밀번호가 그대로 들어 있어 가장 민감하다. NEXT_PUBLIC_을 붙이지 않는다. 이건 마이그레이션 적용 전용이라 Vercel 환경변수에는 넣지 않는다..env.local은 저장소에 올라가지 않는다(앞에서 .gitignore로 이미 막아 뒀다).[service_role 키를 사용하지 않는 이유] Supabase 대시보드에는
service_role(secret) 키도 있다. 이 키는 RLS 정책을 우회하므로 이번 실습에서는 사용하지 않는다. 서버는 로그인한 사용자의 토큰으로 Supabase에 접근해 RLS가 적용되도록 한다. 그러면 서버 코드에서 사용자 조건을 빠뜨리더라도 DB가 다른 사용자의 데이터 접근을 막을 수 있다.
이렇게 나오면 성공: .env.local에 세 줄(URL·anon 키·연결 문자열)이 정확한 이름으로 들어간다.
[확인] 견본 파일(
.env.example)도 만든다..env.local은 저장소에 올리지 않으므로 필요한 환경변수 이름을 안내할 파일이 있어야 한다.docs/가이드/깃커밋컨벤션.pdf의 규칙에 따라 환경변수를 추가할 때마다.env.example도 갱신한다. 실제 값은 넣지 않고 이름만 기록한다.
.env.local에 있는 변수 이름 중 .env.example에 빠진 것을 더해줘. 값은 비우고 이름만. 이미 있으면 그대로 둬.'DBA' 서브에이전트 만들어줘. 데이터 설계와 DB·인증 구축만 담당한다 — docs/아키텍처.md·docs/PRD.md·docs/화면기획서.md를 기준으로 ERD(논리 데이터 모델)를 설계하고, 테이블·RLS·시드 마이그레이션을 만들고 실제 DB에 적용한다. 기술 스택은 앞에서 아키텍트가 정한 것을 따르고, 그 위에 스키마를 구축한다. 라이브러리는 최신 공식 문서를 확인해서 쓰고, 필요한 의존성은 알아서 추가한다. 마이그레이션은 되돌릴 수 있게 만들고, 데이터를 지우는 파괴적 작업은 먼저 확인받는다. API·화면 코드는 만들지 않는다.서브에이전트를 만든 뒤에는 Claude Code를 한 번 다시 띄운다(/exit 뒤 claude). 새 서브에이전트는 다음 세션부터 보인다.
DBA 서브에이전트로, docs/아키텍처.md·docs/화면기획서.md·docs/PRD.md를 근거로 ERD를 docs/ERD.md로 만들어줘.테이블·컬럼·제약·접근 제어는 네가 설계하고 이유를 ERD에 적어. 질문은 PRD를 바꿔야 하는 것만 남겨.테이블과 컬럼을 DBA에게 맡기는 이유: 무엇을 저장해야 하는지는 PRD와 화면기획서에, 접근 규칙(자기 데이터만, 클라이언트는 DB에 직접 접근하지 않는다)은 PRD와 CLAUDE.md에, 이름 규칙은 코딩컨벤션에 있다. DBA는 그걸 읽고 테이블·컬럼·제약·RLS를 정한다. 사람이 컬럼 이름까지 불러 주면 DB 설계를 사람이 하고 AI는 받아 적는 꼴이다. 이름이 사람마다 달라도 괜찮다 — 다음 단계의 API 명세가 "필드 이름은 ERD의 컬럼 이름 그대로"라고 ERD를 가리키므로, 각자의 프로젝트 안에서는 끝까지 같은 이름이 쓰인다. 이렇게 나오면 성공:
docs/ERD.md에 테이블 목록(사용자 프로필·카테고리·거래·결제 정도가 나온다)과 컬럼·제약, 거래·결제가 사용자에 매여 있다는 관계, 사용자별 접근 제한(RLS), 기본 카테고리 시드가 정리된다. 테이블마다 왜 그렇게 나눴는지 이유가 붙어 있다. 문서를 열어 PRD의 기능마다 저장할 자리가 있는지 본다 — 프리미엄 여부, 결제 기록, 메모가 빠졌으면 그 이름을 짚어 다시 요청한다. 질문은 비어 있거나 PRD를 고쳐야 하는 것만 남는다.
docs/ERD.md와 가이드 문서를 지정해 마이그레이션 작성과 적용을 요청한다. SQL을 파일로 남기면 어떤 변경을 적용했는지 확인할 수 있고, 실제 DB에 적용해야 설계가 동작하는지 검증할 수 있다.
Claude가 .env.local의 연결 문자열을 읽고 SQL을 실행하도록 요청한다. 연결 문자열에는 비밀번호가 들어 있으므로 프롬프트에 복사하지 않는다. 단계 2에서 설정한 SUPABASE_DB_URL을 사용한다.
[도구 설치] Claude가 DB에 접속해 SQL을 적용하려면
psql(PostgreSQL 클라이언트)이나 Supabase CLI가 필요하다. 도구가 없다면 설치 후 적용하도록 요청한다. Supabase CLI는 Mac에서brew install supabase/tap/supabase로 설치하거나 프로젝트에npm i -D supabase로 추가할 수 있다.
DBA 서브에이전트로, docs/ERD.md대로 마이그레이션 파일을 만들고 Supabase DB에 적용해줘. 연결은 .env.local을 확인해줘. 적용 후 결과를 나한테 보여줘.이렇게 나오면 성공: Claude가 "테이블 n개·정책 적용·시드 적용 완료"처럼 보고한다. ERD의 테이블 수와 같은지 센다.
[사람 검증] 적용 결과를 대시보드에서 직접 확인한다. AI의 완료 보고와 실제 DB 상태가 일치하는지 살펴본다. 1. Supabase 대시보드 좌측 Table Editor 를 누른다 →
profiles·categories·transactions·payments테이블이 보인다.categories를 누르면 시드 카테고리(카페/식비·교통·급여 등)가 행으로 들어 있다. 2. 좌측 Database → Policies를 누른다 →transactions에 조회·등록·수정·삭제 정책 4개가 활성화되어 있는지 확인한다. 빠진 정책이 있으면 해당 동작에서 접근 제한을 다시 점검한다. 3. (나중에 화면에서 두 계정으로 로그인하면, 서로의 거래가 안 보이는지 화면으로도 다시 확인한다.)막히면(연결 오류):
ENOTFOUND나 접속 실패가 나면 Direct가 아니라 Session pooler 문자열인지, 비밀번호가 맞는지 확인한다. 비밀번호가 기억 안 나면 Project Settings → Database → Reset database password로 새로 정하고 그 값으로 다시 만든다.
이렇게 나오면 성공: 이메일 회원가입/로그인이 켜졌고, 확인 메일 단계 없이 가입하면 바로 로그인된다.
이후 API·화면·배포 단계에서 반복해서 사용할 테스트 계정을 만든다. 실습에서는 아래 이메일과 비밀번호를 사용한다.
표준 테스트 계정 — 이 값을 그대로 쓴다. - 이메일:
demo@moneynote.dev- 비밀번호:moneynote1234
테스트 계정을 하나 만들어줘: 이메일 demo@moneynote.dev, 비밀번호 moneynote1234.그리고 이 계정으로 예시 거래 3건(이번 달 월급 수입 300만, 스타벅스 지출 4500, 지하철 지출 1400)을 넣어줘.이후 실습에서 이 계정으로 나도 로그인해서 확인할 거야.이렇게 나오면 성공: demo@moneynote.dev 계정과 예시 거래 3건이 만들어진다. 이후 사람이 이 계정으로 로그인해 거래가 표시되는지 확인한다. 실습이 끝날 때까지 계정과 데이터를 유지한다.
.env.local 한 곳에 접속 정보 세 줄(NEXT_PUBLIC_SUPABASE_URL·NEXT_PUBLIC_SUPABASE_ANON_KEY·SUPABASE_DB_URL)을 모았다. RLS를 우회하는 service_role 키는 쓰지 않는다..env.local의 SUPABASE_DB_URL로 실제 DB에 적용했다..env.local의 키가 Settings → API의 값과 정확히 같은지 확인한다. 가입은 되는데 로그인이 안 되면 단계 5의 "Confirm email 끄기"를 했는지 확인한다.