기술 포스트

백엔드가 무서웠는데, Supabase로 하루 만에 뭔가 만들었다


Article

고백하자면 나는 백엔드가 무서웠다. 퍼블리셔에서 프론트로 넘어올 때도 한참 걸렸는데, 서버는 아예 다른 세계 같았다. DB 스키마, 인증, API 설계 같은 단어만 들어도 "그건 백엔드 분들이…" 하고 물러섰다.

그런데 요즘 AI 에이전트랑 일하면서 혼자 커버하는 범위가 계속 넓어지다 보니, 백엔드만 계속 비워두는 게 오히려 어색해졌다. 그래서 주말에 Supabase로 간단한 방명록을 만들어봤다. 결론부터 쓰면, 하루 만에 됐다.

테이블 만들고 나니 API가 이미 있었다

Supabase 대시보드에서 테이블을 하나 만들었다.

create table guestbook (
  id uuid primary key default gen_random_uuid(),
  nickname text not null,
  message text not null,
  created_at timestamptz default now()
);

여기서 첫 번째 충격. 테이블을 만들자마자 REST API가 자동으로 생긴다. 별도의 서버 코드 없이 클라이언트에서 바로 쓴다.

import { createClient } from "@supabase/supabase-js";

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
);

// 읽기
const { data } = await supabase
  .from("guestbook")
  .select("*")
  .order("created_at", { ascending: false });

// 쓰기
await supabase.from("guestbook").insert({ nickname, message });

Express 강의를 세 번쯤 끊었던 나로서는 허무할 정도였다. "백엔드를 만든다"가 아니라 "데이터 구조를 정의한다"에 가까웠다.

RLS에서 한참 헤맸다

물론 순탄하지만은 않았다. 처음에 insert가 계속 실패했다. 에러 메시지는 new row violates row-level security policy. 콘솔에는 401도 아니고 403도 아니고, 뭐가 문제인지 한참 몰랐다.

원인은 RLS(Row Level Security). Supabase는 테이블마다 행 단위 접근 제어를 걸어두고, 정책(policy)을 명시하지 않으면 기본적으로 아무것도 허용하지 않는다. anon key가 클라이언트에 노출되는 구조라서, "누가 어떤 행을 읽고 쓸 수 있는가"를 DB 레벨에서 선언해야 한다.

alter table guestbook enable row level security;

-- 누구나 읽기 가능
create policy "public read"
  on guestbook for select using (true);

-- 누구나 쓰기 가능 (방명록이니까)
create policy "public insert"
  on guestbook for insert with check (true);

처음엔 "왜 이렇게까지 막아놨나" 싶었는데, 이해하고 나니 오히려 이 방식이 맞다는 생각이 들었다. 프론트에서 아무리 검증해도 클라이언트는 신뢰할 수 없다. 보안의 최종 방어선은 데이터에 최대한 가까운 곳에 있어야 한다. 프론트만 할 때는 한 번도 해본 적 없는 종류의 생각이었다.

백엔드 감각이 생기니 프론트가 달라진다

만들고 나서 느낀 게 제일 컸다. 데이터가 어디서 태어나서 어떤 규칙으로 흘러오는지를 한 번 직접 설계해보니, 프론트 코드를 보는 눈이 달라졌다.

  • 컴포넌트 props를 설계할 때 "이 데이터의 원본 형태가 뭐지"를 먼저 생각하게 된다
  • 로딩/에러 상태도 당연히 존재하는 상태로 여기고 다루게 된다
  • API 응답을 받아서 프론트에서 열심히 가공하던 코드가, 사실 쿼리 한 줄로 끝날 일이었음을 알게 된다

풀스택이 됐다는 얘기가 아니다. 방명록 하나 만든 걸로 그런 말을 하면 안 된다. 다만 반대편 사정을 아는 프론트엔드와 모르는 프론트엔드는 설계가 다르다는 것, 그 차이를 하루짜리 실험으로 얻었으면 충분히 남는 장사다.

다음은 Auth를 붙여볼 생각이다. 소셜 로그인까지 되면 이 블로그에 댓글 기능을 달아볼지도 모르겠다.

Share
  • Supabase
  • 백엔드
  • Next.js