랜딩 페이지에서 쓰는 Supabase
진지한 리드 제너레이션 운영자는 결국 원본 데이터를 직접 관리하는 데이터베이스에 두고 싶어 합니다. 리드와 광고비를 조인하고, 리드 품질에 SQL을 돌리고, 구매자 포털이나 영업 담당자 앱에 데이터를 넣기 위해서. 보통 막히는 부분은 리드를 받는 엔드포인트를 만드는 일입니다. 누군가 작성하고 계속 돌아가게 관리해야 하니까요.
Supabase는 그 부분을 없앱니다. 모든 테이블에 이미 REST 엔드포인트가 있고, LanderLab의 웹훅이 리드를 열 이름과 값의 평평한 묶음으로 그곳에 포스트합니다. Postgres가 행을 넣고, Row Level Security가 요청이 할 수 있는 일을 정하며, 리드는 캠페인과 변형을 단 채 내 데이터베이스에 들어갑니다.
내 스키마에 리드마다 Postgres 행 하나
요청 본문은 열마다 키 하나인 평평한 구조라서, 리드마다 타입이 지정된 열, 열 기본값에서 오는 created_at 타임스탬프, 다른 시스템이 참조할 수 있는 id를 가진 행이 됩니다. 어떤 열과도 맞지 않는 키는 거절되므로, 엉뚱한 데이터가 테이블에 들어오지 않습니다.
Postgres이므로 행은 SQL로 할 수 있는 모든 일에 바로 쓸 수 있습니다. 일별·캠페인별 리드 뷰, 비용 테이블과의 조인, 그리고 중복 제출을 두 번 저장하기보다 거절하고 싶다면 이메일에 unique 인덱스.
Row Level Security로 잠그기
웹훅은 프로젝트의 publishable 키로 쓰고, Row Level Security가 그 키로 할 수 있는 일을 정합니다. 리드 테이블에 insert만 허용하고 나머지는 막으면, 그 키로는 리드를 추가할 수만 있고 읽거나 바꾸거나 지울 수 없으므로, 키가 비밀이 아니어도 리드 데이터에는 손이 닿지 않습니다.
Row Level Security를 우회하는 secret 키는 내 백엔드 밖으로 나갈 필요가 없습니다. 리드 양식에는 필요 없으니까요.
리드 품질에 대한 나만의 단일 기준
빌더, CRM, 트래커는 각자 이야기의 일부만 쥐고 있습니다. 모든 리드와 그 utm_campaign, 클릭 ID, 랜딩 페이지, 변형을 담은 Supabase 테이블은 내가 관리하는 부분입니다. 두 번째 테이블에 일일 광고비를 넣으면 SQL 뷰가 캠페인별, 변형별 리드당 비용을 보여 주고, 구매자나 영업 담당자가 기록한 결과를 더하면 판매당 비용을 보여 줍니다.
분할 테스트를 정직하게 판가름하는 방법이 바로 이것입니다. 어느 변형이 양식 제출을 더 받았는지가 아니라, 어느 변형의 리드가 돈이 됐는지.
insert가 실패해도 살아남는 리드
컴플라이언스 리드 전송이 켜져 있지 않다면, 모든 리드는 LanderLab 리드 탭에도 보관되고 날짜와 변형으로 필터링할 수 있으며 Grow 이상에서는 CSV로 내보낼 수 있습니다. 열 이름을 바꾼 뒤처럼 insert가 실패해도 리드는 사라지지 않습니다. 테이블을 고치고 내보낸 파일로 채워 넣으면 됩니다. 대신 LanderLab 워크플로(베타)로 보내면 실행 화면에서 어떤 리드의 요청이 실패했는지 정확히 보입니다.