
Static HTML과 Supabase를 사용하여 0달러로 실시간 글로벌 스코어보드를 구축한 방법
요약
Static HTML과 Supabase를 활용하여 서버 비용 없이 실시간 글로벌 스코어보드를 구축하는 방법을 소개합니다. 데이터베이스 부하를 최소화하기 위해 행 구조 최적화, 폴링 방식 채택, PostgreSQL 함수를 통한 보안 강화 전략을 사용합니다.
핵심 포인트
- 국가별 단일 행 구조로 데이터베이스 크기 및 쿼리 성능 최적화
- 웹소켓 대신 2초 간격의 폴링을 사용하여 무료 티어 연결 제한 회피
- PostgreSQL 함수와 security definer를 활용한 클라이언트 측 쓰기 보안 강화
- Netlify와 Supabase를 조합한 완전한 제로 백엔드 스택 구현
저는 서버를 구동하거나, 호스팅 비용을 지불하거나, 트래픽 급증 시 무료 티어 데이터베이스를 과부하시키지 않고 **$0 제로 백엔드 스택 (zero-backend stack)**을 어디까지 밀어붙일 수 있는지 확인하고 싶었습니다.
그 결과물은 **Tap The World**입니다. 이는 지구상의 모든 방문자가 단 한 번의 탭을 할 수 있는 단일 공유 글로벌 스코어보드로, IP 지오로케이션 (IP geolocation)을 통해 실시간으로 각 방문자의 국가가 기록됩니다.
🔴 라이브 데모 시도하기: taptheworld.netlify.app
스택 (총 비용 $0)
- 프론트엔드 (Frontend): 단일 정적
index.html파일 (HTML, CSS, vanilla JS) - 데이터베이스 (Database): Supabase (무료 티어의 PostgreSQL)
- 호스팅 (Hosting): Netlify (정적 에지 배포)
- 지오로케이션 (Geolocation):
ipwho.is(무료 클라이언트 사이드 IP 조회, CORS 활성화)
제로 서버 및 무료 티어 제한을 위한 엔지니어링
실시간 공개 카운터를 구축할 때, 기본 본능은 모든 탭에 대해 이벤트를 기록하고 웹소켓 (WebSockets)을 사용하여 실시간 업데이트를 푸시하는 것입니다. 무료 티어에서는 이렇게 하면 몇 분 만에 데이터베이스가 망가질 것입니다.
제가 이러한 제약 사항을 고려하여 설계한 방법은 다음과 같습니다:
1. 국가당 하나의 행 (탭당 하나의 행이 아님)
클릭당 이벤트 행을 삽입하는 대신, PostgreSQL 테이블은 다음과 같이 구조화됩니다:
create table country_counts (
country_code text primary key,
country_name text,
...
데이터베이스 테이블은 영원히 약 200개의 행 미만으로 유지됩니다. 사이트에 10번의 탭이 들어오든 10,000번의 탭이 들어오든, 쿼리 성능과 저장 용량은 완전히 일정하게 유지됩니다.
2. 실시간 웹소켓 대신 폴링 (Polling)
동시 접속하는 모든 방문자를 위해 지속적인 웹소켓 (WebSocket) 연결을 유지하는 것은 Supabase 무료 티어의 연결 제한을 빠르게 소진시킵니다.
대신, 프론트엔드는 2초마다 SELECT * FROM country_counts를 폴링 (polling) 합니다. 다크 스플릿 플랩 (split-flap) 출발 안내판 미학을 위해, 2초 간격의 기계적 틱 (tick)은 자연스럽게 느껴지며 서버 부하를 예측 가능하게 유지합니다.
3. security definer를 통한 쓰기 권한 잠금
백엔드 서버가 없기 때문에 브라우저가 Supabase와 직접 통신합니다. 누군가 브라우저 콘솔을 열어 UPDATE country_counts SET count = 999999와 같은 명령을 보내는 것을 방지하기 위해, 익명 사용자(anonymous users)에 대한 테이블의 직접적인 INSERT 및 UPDATE 권한을 취소했습니다.
모든 탭(tap)은 커스텀 PostgreSQL 함수를 통해 전달됩니다:
create or replace function tap(p_country_code text, p_country_name text)
returns bigint
language plpgsql
...
공개 API 키(public API key)는 tap() 함수에 대한 EXECUTE 권한만 가지고 있으므로, REST API를 통한 스키마 손상(schema corruption)이 불가능합니다.
다음 단계는?
현재 백엔드 서버 비용을 추가하지 않으면서 클라이언트 측의 localStorage 스팸 체크를 보완할 수 있는 가벼운 에지 속도 제한(edge-rate-limiting)을 탐색하고 있습니다.
다음 사항에 대해 여러분의 피드백을 듣고 싶습니다:
- PostgreSQL 스키마 및 함수 설계.
- 순수 정적(static)/서버리스(serverless) 환경에서 속도 제한(rate-limiting)을 어떻게 처리하시나요!
여러분의 국가를 위해 탭을 누르고, 댓글로 의견을 남겨주세요! 👇
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기