lifecarelog
브랜딩·마케팅

auth.uid()로 팀 격리가 안 됐던 날, 개발 실수를 콘텐츠로

auth.uid()만으로는 팀 데이터 격리가 안 되는 이유와, 1인 개발자가 그 교훈을 브랜드 콘텐츠로 바꾸는 법을 정리했어요.

5분 읽기

auth.uid()로 팀 격리가 안 됐던 날, 개발 실수를 콘텐츠로

팀이나 동호회처럼 여러 명이 같은 데이터를 나눠 쓰는 앱을 만들다 보면, 데이터 격리에서 한 번쯤 발이 걸려요. Supabase를 쓰면 RLS(행 수준 보안)로 막는데, 처음엔 auth.uid() 하나면 충분해 보이거든요. 혹시 이런 적 없나요? "로그인한 사람 것만 보이게 하면 되지" 하고 넘어갔다가, 팀 단위에서 구멍이 보이는 순간이요.

auth.uid()가 막는 건 "개인"이지 "팀"이 아니에요

auth.uid()는 로그인한 사용자의 UUID를 돌려줘요. 그래서 user_id = auth.uid() 같은 정책은 "내가 만든 행"만 걸러줍니다. 문제는 멀티테넌트예요. 팀 데이터는 한 사람 소유가 아니라 팀 전체가 나눠 쓰거든요.

여기서 두 갈래로 어긋나요. 정책을 user_id 기준으로만 두면 같은 팀원이 만든 데이터가 서로 안 보이고, 반대로 team_id만 비교하면 그 팀 소속이 맞는지는 확인을 안 해요. 테스트 계정 2개를 각각 다른 팀에 넣고 돌려 보면, 이 빈틈이 바로 드러납니다.

진짜 격리는 "이 사람이 이 팀 맞아?"를 묻는 것

빠지는 조각은 멤버십 확인이에요. 정책에서 팀 소속을 한 번 조인해 주면 됩니다.

요청auth.uid() 확인멤버십 테이블 조인소속 팀 데이터만 통과

어떤 유저가 어떤 팀에 속하는지 담은 멤버십 테이블을 만들고, 정책에서 team_id in (select team_id from memberships where user_id = auth.uid()) 식으로 걸어요. 이러면 소속 팀 데이터만 통과합니다. 성능이 걱정되면 auth.uid()(select auth.uid())로 감싸 결과를 캐싱하고, 멤버십 테이블에 인덱스를 걸면 돼요. 정책 3~4줄 손보고 테스트 계정으로 교차 확인하는 데 10분 남짓이면 충분했어요.

여기서 1인 브랜드가 챙길 건 따로 있어요

기술 얘기는 여기까지고, 브랜드 관점으로 넘어가 볼게요. 이런 "막힌 지점 → 원인 → 해결" 흐름은 그 자체가 좋은 콘텐츠 소재예요. 혼자 운영하면 마케팅에 쓸 시간이 늘 부족한데, 개발하며 걸린 실수를 그대로 기록하면 글감이 저절로 쌓이거든요.

  • 막힌 지점
  • 원인 한 줄
  • 재현 방법
  • 해결 코드

핵심은 결과만 내세우지 않는 거예요. "auth.uid()만 믿었다가 팀 격리에 구멍이 났다"처럼 걸렸던 지점을 솔직하게 적으면, 같은 데서 헤매는 사람이 검색으로 찾아와요. 저는 플랜비(plan-b)를 만들면서 이런 팀 단위 격리를 계속 다루는데, 동호회마다 데이터가 완전히 분리돼야 신뢰가 생기더라고요. 그 과정을 데브로그로 남기는 게 광고보다 오래 남는 자산이 돼요.

정리하면

  • 격리 설계는 "개인"이 아니라 "소속"을 기준으로 다시 보기.
  • 걸렸던 지점을 숨기지 말고 기록하면 그대로 콘텐츠가 됩니다.

법령·판례를 다루는 플랜엘(plan-l)도 월 3건 무료로 열어두면서 이런 기록을 이어가고 있어요. 작은 도구를 만들며 겪은 실수 하나가, 검색으로 누군가를 데려오는 입구가 되기도 해요.

#Supabase RLS#멀티테넌트#데브로그 콘텐츠

라이프케어로그 서비스가 궁금하신가요?

AI 기반 건강·일정·재활 관리 앱을 직접 써보세요.

서비스 살펴보기

관련 글

댓글

아직 댓글이 없어요. 첫 댓글을 남겨주세요.