콘텐츠로 이동

실제 백엔드 연결

03-first-run.md에서 pnpm dev 가 자리 표시 값 화면을 띄우는 모습까지 확인했다면, 이 단계에서는 같은 base 를 실제 Supabase 프로젝트에 연결해 회원가입과 로그인이 정말 동작하도록 바꿉니다. 보통 30분에서 1시간 정도 걸립니다.

지금 당장 필요하지 않다면 건너뛰어도 됩니다. 다만 phase 3 (/3-analyze-saas) 이후의 컨셉 결정 단계에서 데이터 모델을 정하려면 Supabase 가 연결돼 있어야 의미가 있습니다.

supabase.com 대시보드에서 New project 를 누릅니다. 프로젝트 이름과 비밀번호를 정합니다. 리전은 가까운 곳을 고르세요. 한국에서는 Tokyo 또는 Singapore 가 대기 시간 면에서 무난합니다.

프로젝트 준비가 끝나면 왼쪽 메뉴에서 Settings → API 로 갑니다. 이 페이지에서 세 가지를 메모해 둡니다.

  • Project URL 을 적어 둡니다.
  • anon public 키를 적어 둡니다.
  • service_role 키를 적어 둡니다. 이 키는 절대 클라이언트 코드에 넣지 마세요. 뒤에서 다시 설명합니다.

같은 페이지의 왼쪽 위에 보이는 Project Reference ID (abcdefghijklmn 같은 모양입니다) 도 함께 메모해 둡니다. 다음 단계에서 CLI 가 이 ID 로 프로젝트를 가리킵니다.

본인 my-saas 디렉터리에서 다음 명령을 실행합니다.

Terminal window
supabase login # [01-prerequisites.md] 에서 하지 않았다면 한 번 실행합니다
supabase link --project-ref <project-reference-id>

<project-reference-id> 에는 위에서 메모한 ID 를 그대로 넣습니다. 처음에는 DB 비밀번호도 한 번 물어봅니다. 위 1) 단계에서 정한 비밀번호입니다.

명령이 끝나면 .supabase/ 디렉터리가 새로 생기고 그 안에 연결 정보가 저장됩니다. .gitignore 가 이 디렉터리를 이미 제외하고 있으니 그대로 두면 됩니다.

base 루트에 .env.example 이 있습니다. 그 파일을 복사해 .env.local 을 만듭니다.

Terminal window
cp .env.example .env.local

.env.local 을 에디터로 열고 다음 네 줄을 본인 값으로 채웁니다.

VITE_SUPABASE_URL=https://<project-ref>.supabase.co
VITE_SUPABASE_ANON_KEY=<anon-public-key>
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
VITE_API_MODE=edge-functions

VITE_ 접두사가 중요합니다. Vite 는 이 접두사가 붙은 변수만 클라이언트 번들에 노출합니다. 접두사가 없는 변수는 빌드 시점에 undefined 로 처리됩니다. service_role 같은 비밀 값이 실수로 클라이언트에 노출되는 것을 이 접두사 규칙이 막아 줍니다.

VITE_API_MODE 는 API 어댑터를 어떤 모드로 실행할지 결정합니다. 기본값인 edge-functions 를 권장합니다. Cloudflare Workers 위에 Hono 어댑터로 실행할 일이 생기면 그때 hono 로 바꿉니다. 이 결정은 전문가용 아키텍처 에 더 자세히 적혀 있습니다. 비개발자라면 기본값을 유지해도 충분합니다.

.env.local 은 .gitignore 에 들어 있어야 합니다. git status 를 한 번 실행해서 이 파일이 untracked 로 보이지 않는지 확인하세요.

base 가 들고 있는 마이그레이션은 골격뿐입니다. api/migrations/ 디렉터리에 빈 골격만 들어 있고, 본인 SaaS 도메인의 테이블 (예를 들어 subscriptions, invoices, 본인 도메인 entity) 은 phase 5 (/5-customize-saas) 의 implement-data-layer 단계에서 자동으로 만들어집니다. 이 항목은 fork 할 때 채워집니다.

지금은 인증과 세션이 동작하는지만 확인하면 충분합니다. Supabase 의 Auth 는 별도 마이그레이션 없이 프로젝트가 생긴 시점부터 켜져 있습니다.

Terminal window
supabase db push

이 명령이 api/migrations/ 안의 SQL 파일을 모두 본인 Supabase 프로젝트에 순서대로 적용합니다. 기본 상태에서는 적용할 마이그레이션이 거의 없어서 명령이 짧게 끝납니다. 에러 출력이 보이지 않으면 정상입니다.

5) 행 수준 접근 정책은 어디에 두나

섹션 제목: “5) 행 수준 접근 정책은 어디에 두나”

Supabase 의 모든 테이블은 기본값이 default deny 입니다. 행 수준 접근 정책이 켜진 테이블은 정책이 한 줄이라도 정의돼 있어야 사용자가 그 행을 읽거나 쓸 수 있습니다. 정책이 없으면 anon 키를 쓰든 로그인한 사용자든 그 테이블에 접근하지 못합니다.

이 base 의 행 수준 접근 정책은 모두 api/migrations/<timestamp>_<name>.sql 안에서 정의됩니다. Supabase Studio 화면에서 정책을 만드는 방법은 쓰지 않습니다. 화면에서 만든 정책은 git 에 남지 않아 다음 환경에서 사라집니다.

본인 SaaS 의 테이블과 정책이 phase 5 에서 자동으로 만들어질 때 다음 모양의 SQL 이 마이그레이션 파일에 기록됩니다.

alter table public.subscriptions enable row level security;
create policy "subscriptions_select_own"
on public.subscriptions for select to authenticated
using (auth.uid() = user_id);

이 한 줄이 “로그인한 사용자는 자기 행만 select 할 수 있다” 는 규칙을 강제합니다. 이 항목은 fork 할 때 채워집니다. base 를 막 받은 시점에는 본인 SaaS 의 도메인 테이블이 아직 결정되지 않아서 실제 정책이 비어 있습니다.

pnpm dev 를 다시 띄우고 (Ctrl+C 로 끈 다음 pnpm dev 를 다시 실행합니다) 브라우저에서 http://localhost:5173 을 새로고침합니다. 회원가입 화면이 자리 표시 값이 아니라 실제 Supabase Auth 에 연결된 상태로 떠야 합니다.

이메일과 비밀번호로 한 번 가입을 시도합니다. Supabase 대시보드의 Authentication → Users 에서 본인 이메일로 새 행이 한 줄 들어와 있어야 정상입니다.

행이 보이지 않으면 09-troubleshooting.md 의 “Supabase 가입이 안 됩니다” 항목으로 갑니다. 가장 흔한 원인은 .env.local 의 VITE_SUPABASE_URL 또는 VITE_SUPABASE_ANON_KEY 를 잘못 적은 경우입니다.

7) Edge Function 시크릿: Stripe 와 service_role

섹션 제목: “7) Edge Function 시크릿: Stripe 와 service_role”

여기는 위 3) 단계의 .env.local 과 다릅니다. 클라이언트 번들로 나가면 안 되는 비밀 값 (Stripe Secret key, Stripe Webhook Secret, Supabase service_role) 은 Supabase 쪽 인프라에 직접 넣습니다.

Terminal window
supabase secrets set STRIPE_SECRET_KEY=sk_test_...
supabase secrets set STRIPE_WEBHOOK_SECRET=whsec_...
supabase secrets list

supabase secrets list 출력에 두 키가 보이면 정상입니다. Edge Function 안에서 Deno.env.get('STRIPE_SECRET_KEY') 로 읽습니다. .env* 파일과는 관계가 없습니다.

Stripe Webhook Secret 은 phase 5 의 implement-billing 단계에서 Stripe 대시보드에 webhook endpoint 를 등록할 때 받습니다. 그 시점까지 이 절은 비워 두어도 됩니다.

src/shared/api/server/ 디렉터리에 어댑터 인터페이스가 정의돼 있습니다. 기본값은 Supabase Edge Functions 호출 (edge-functions) 이고, 선택지는 Hono on Node 또는 Cloudflare Workers (hono) 입니다. 같은 features 코드가 어떤 어댑터를 쓰는지 모르는 채로 api.invoke('checkout-session', payload) 만 호출합니다.

비개발자라면 기본값인 edge-functions 를 유지하는 쪽이 가장 손이 덜 갑니다. Supabase 한 곳에 DB 와 Auth, Edge Functions 가 모여 있어 다른 인프라를 더 붙이지 않아도 됩니다. 나중에 트래픽이 늘거나 인프라 정책이 바뀌어 Cloudflare Workers 로 옮기고 싶어지면 VITE_API_MODE 한 줄만 바꾸고 어댑터를 교체하면 됩니다. 호출 코드는 한 줄도 건드리지 않습니다.

이 결정은 phase 4 (/4-design-saas) 의 API 어댑터 결정 단계와 같은 표를 봅니다. 결정 결과는 .claude/state/api-adapter.json 에 저장됩니다.

  • 401 또는 403 에러가 납니다. anon 키를 다시 복사합니다. 붙여 넣을 때 끝에 공백이나 줄바꿈이 같이 따라 들어가는 경우가 흔한 원인입니다.
  • Failed to connect to Supabase 가 뜹니다. .env.local 의 VITE_SUPABASE_URL 에 https:// 가 빠졌거나 끝에 / 가 붙은 상태입니다. 정확히 https://<ref>.supabase.co 형태로 적혀 있어야 합니다.
  • supabase db push 가 권한 에러로 실패합니다. supabase login 이 만료된 상태이니 다시 로그인합니다.
  • 그 밖의 증상은 09-troubleshooting.md 의 Supabase 항목에 모여 있습니다.

한 발 더 나아가서, 내가 말한 시나리오대로 동작하는지 확인하기

섹션 제목: “한 발 더 나아가서, 내가 말한 시나리오대로 동작하는지 확인하기”

여기까지 오면 회원가입과 로그인이 실제 Supabase 에 연결되는 모습을 확인한 셈입니다. 다음 질문은 보통 이렇습니다. “내가 처음에 말로 설명했던 시나리오대로 진짜 동작하나?”

이 질문은 손으로 한 번씩 클릭해서 확인할 수도 있지만, 시나리오가 두세 개로 늘어나면 매번 다 눌러 보기가 번거롭습니다. base 에는 그 확인을 자동으로 해 주는 도구가 하나 들어 있습니다. Claude Code 에서 이렇게 호출합니다.

/test-saas

이 명령은 docs/design/saas-spec.md 의 §2 “사용 시나리오” 단락을 읽습니다. 거기 적은 한 줄짜리 시나리오를 AI 가 직접 검증 코드로 변환합니다. Vitest 가 unit 테스트를, Playwright 가 e2e 테스트를, supabase test db 가 행 수준 접근 정책 테스트를 각각 맡습니다.

결과는 익숙한 테스트 출력 그대로가 아니라 시나리오 언어로 다시 적힌 보고서로 돌아옵니다.

총 시나리오: 6개 중 5개 통과, 1개 실패
✓ 회원가입: 이메일과 비밀번호로 새 행 생성, 행 수준 접근 정책 통과
✓ 로그인: 세션 발급, /app 진입 가능
✓ 가격 페이지: Pro 플랜 선택 시 Stripe Checkout 세션 시작
✗ Stripe webhook: 서명 검증 실패, secret 이 .env.local 에 있고 supabase secrets 에 없음
파일: api/functions/stripe-webhook/index.ts:14
고치는 곳: supabase secrets set STRIPE_WEBHOOK_SECRET=...

실패가 한 줄 나오면 거기서 같은 Claude 에게 “이거 고쳐줘” 라고 말하면 됩니다. 어디를 봐야 하는지가 보고서에 적혀 있어서 별도 설명을 다시 적어 줄 필요가 없습니다.

/test-saas 의 자세한 작동 원리 (시나리오를 어떻게 나누어 어디에 테스트 파일을 만드는지, 정적 검사를 맡는 review-saas 와는 어떻게 다른지) 는 전문가용 검증 페이지에 있습니다.

데이터가 의도한 곳에 도착하는 모습까지 확인했다면 본인 SaaS 의 모양을 정하는 단계로 넘어갑니다. 05-customize-design.md 에서 브랜딩과 디자인 톤을 정하고, 그 사이에 /3-analyze-saas 와 /4-design-saas phase 가 컨셉과 라우팅, 가격, 데이터 모델을 결정합니다.