Supabase 데이터 저장 안됨: 바이브코딩 프로젝트 점검 순서
Cursor, Lovable, Bolt로 만든 서비스에서 Supabase 연결은 된 것 같은데 데이터가 저장되지 않을 때 테이블, RLS, 환경 변수, 요청 값을 확인하는 순서를 정리했습니다.
Supabase는 바이브코딩 프로젝트에서 정말 자주 쓰입니다. 로그인, 데이터베이스, 파일 저장까지 한 번에 붙일 수 있어서 Lovable이나 Bolt로 만든 앱에도 많이 들어갑니다.
문제는 "연결된 것처럼 보이는데 저장은 안 되는" 순간입니다. 화면에서는 저장 완료라고 나오는데 테이블에는 데이터가 없거나, 로컬에서는 되는데 배포 후에는 조용히 실패하거나, 어떤 사용자는 되고 어떤 사용자는 안 됩니다.
이럴 때 바로 AI에게 "고쳐줘"를 반복하면 코드가 더 산만해질 수 있습니다. Supabase 저장 문제는 보통 코드 한 줄보다 설정, 권한, 데이터 모양이 함께 얽혀 있습니다.
먼저 실패가 보이는 곳을 나누기
데이터 저장 문제는 크게 세 군데로 나눠서 봐야 합니다.
- 화면에서 입력값이 제대로 만들어지는가
- Supabase로 요청이 실제로 보내지는가
- Supabase가 그 요청을 허용하고 저장하는가
비개발자 입장에서는 모두 "저장이 안 된다"로 보이지만, 개발자는 이 셋을 다르게 봅니다. 입력값이 비어 있으면 화면 문제이고, 요청이 안 나가면 코드 흐름 문제이고, 요청은 갔는데 거절되면 권한이나 테이블 설정 문제입니다.
이 구분만 해도 AI에게 훨씬 정확하게 물어볼 수 있습니다.
1. 테이블 이름과 컬럼 이름 확인하기
가장 단순하지만 가장 자주 나오는 문제입니다. AI가 코드에서는 orders 테이블에 저장한다고 만들어놨는데, Supabase에는 order 테이블만 있거나, 컬럼 이름이 userName과 user_name처럼 다를 수 있습니다.
Supabase는 테이블과 컬럼 이름이 정확히 맞아야 합니다. 화면에서는 별다른 에러가 보이지 않아도 브라우저 콘솔이나 네트워크 탭에는 실패 메시지가 남아 있을 수 있습니다.
확인할 것:
- 코드의 테이블 이름과 Supabase 테이블 이름이 같은가
- 저장하려는 컬럼이 실제로 존재하는가
- 필수 컬럼에 값이 들어가는가
- 숫자, 날짜, boolean 같은 타입이 맞는가
AI가 기능을 여러 번 고치다 보면 예전 테이블 이름이 코드에 남아 있는 경우도 많습니다.
2. RLS 때문에 막히는지 보기
Supabase에서 데이터 저장이 안 될 때 자주 나오는 단어가 RLS입니다. Row Level Security, 즉 행 단위 보안 설정입니다.
RLS가 켜져 있으면, 테이블이 있어도 아무나 데이터를 읽고 쓰지 못합니다. 어떤 사용자가 어떤 조건에서 insert, select, update를 할 수 있는지 정책이 있어야 합니다.
바이브코딩 프로젝트에서는 여기서 많이 막힙니다. AI는 화면과 저장 코드를 만들었지만, Supabase 정책까지 정확히 맞춰주지 못하는 경우가 있습니다. 특히 로그인 사용자만 저장해야 하는지, 익명 사용자도 문의를 남길 수 있는지 같은 조건이 분명하지 않으면 더 그렇습니다.
증상은 보통 이렇습니다.
- 로그인하지 않으면 저장이 안 된다
- 내 데이터는 보이는데 다른 사용자의 데이터는 안 보인다
- 저장 요청이 401, 403 또는 policy 관련 에러로 실패한다
- Lovable 미리보기에서는 됐는데 운영에서는 안 된다
RLS는 보안을 위해 필요한 장치입니다. 무작정 끄기보다, 서비스 흐름에 맞게 정책을 잡는 편이 안전합니다.
3. 환경 변수가 배포에도 있는지 확인하기
로컬에서는 저장되는데 Vercel 배포 후에는 안 된다면 환경 변수를 먼저 봐야 합니다.
Supabase 프로젝트 URL과 anon key는 로컬 .env에만 있으면 배포 환경에서는 사용할 수 없습니다. Vercel, Netlify 같은 배포 서비스의 Environment Variables에 같은 값이 등록되어 있어야 합니다.
확인할 것:
- Supabase URL이 배포 서비스에 등록되어 있는가
- anon key가 빠지지 않았는가
- 변수 이름이 코드에서 읽는 이름과 정확히 같은가
- NEXT_PUBLIC_ 접두사가 필요한 값에 붙어 있는가
- 환경 변수 수정 후 다시 배포했는가
환경 변수 이름 하나가 다르면, 화면에서는 그냥 "저장 실패"처럼만 보일 수 있습니다.
4. 요청 값이 비어 있지 않은지 보기
AI가 만든 폼에서는 버튼을 눌렀을 때 입력값이 제대로 모이지 않는 경우도 있습니다. 화면에는 이름과 이메일을 쓴 것처럼 보이지만, 실제 저장 요청에는 빈 문자열이나 undefined가 들어갈 수 있습니다.
이 문제는 특히 폼 컴포넌트를 여러 번 수정했거나, 입력창 이름을 바꿨거나, 상태 관리 코드를 AI가 다시 만든 뒤에 잘 생깁니다.
비개발자도 확인할 수 있는 방법은 있습니다. 저장 버튼을 누른 뒤 브라우저 개발자 도구의 Network 탭을 보면 어떤 값이 서버나 Supabase로 보내졌는지 볼 수 있습니다. 어렵다면 AI에게 "저장 직전에 payload를 console.log로 확인하게 해줘"라고 요청해도 됩니다.
다만 운영 서비스에서는 콘솔 로그에 개인정보가 남지 않게 주의해야 합니다. 확인 후에는 제거하는 것이 좋습니다.
5. 저장은 됐는데 화면이 안 바뀌는 경우
가끔은 데이터가 실제로 저장됐는데 화면만 그대로인 경우도 있습니다. 이때는 Supabase 문제가 아니라 화면 갱신 문제입니다.
예를 들어 문의를 저장한 뒤 목록을 다시 불러오지 않거나, 캐시된 데이터를 계속 보여주거나, 저장 성공 후 이동할 페이지가 잘못되어 있을 수 있습니다.
이 경우에는 Supabase 테이블을 직접 열어보면 데이터가 들어와 있습니다. 데이터가 있다면 저장 로직이 아니라 화면 표시 로직을 봐야 합니다.
AI에게 물어볼 때도 "저장이 안 된다"가 아니라 "Supabase에는 저장되는데 화면 목록이 갱신되지 않는다"라고 말해야 합니다. 이 한 문장 차이로 수정 방향이 완전히 달라집니다.
정리
Supabase 데이터 저장이 안 될 때는 아래 순서로 확인하세요.
- 테이블 이름과 컬럼 이름이 맞는지
- 필수 값과 데이터 타입이 맞는지
- RLS 정책이 insert를 허용하는지
- 배포 환경 변수에 Supabase 값이 들어 있는지
- 저장 요청의 payload가 비어 있지 않은지
- 실제로는 저장됐지만 화면만 갱신되지 않는 것은 아닌지
Supabase는 좋은 도구지만, 데이터베이스와 권한이 들어가는 순간부터는 단순 UI 수정과 다릅니다. 같은 저장 오류를 AI가 여러 번 고치지 못한다면, 코드보다 테이블과 정책을 함께 봐야 할 가능성이 큽니다.