개발 slecs

광고 슬롯을 DB 기반으로 설계해 배포 없이 설정 변경 가능하게 개선

목차

광고 슬롯 컴포넌트를 처음부터 새로 설계하면서 DB 패턴을 함께 도입한 작업이었다.

배경: 왜 admin_db 패턴이 필요했나

기존에는 광고 관련 설정값을 환경변수나 하드코딩으로 박아두는 방식이 많았다. 작은 프로젝트에서는 그게 제일 빠르기도 하고. 그런데 SITE_SLUG라는 개념이 생기면서 상황이 달라졌다. 같은 코드베이스 위에 여러 사이트 슬러그가 올라타는 구조가 되면, 각 슬롯의 광고 ID나 노출 위치가 사이트마다 달라져야 한다. 그걸 전부 env로 관리하면 변수명이 폭발하고, 코드 분기는 더 심해진다.

admin_db 패턴은 그 문제에 대한 대답이다. 광고 설정을 DB 레이어에서 슬러그 기반으로 조회해서 컴포넌트에 넘기는 방식. 운영자가 어드민에서 슬롯 ID나 활성화 여부를 바꿔도 배포 없이 반영된다는 점이 핵심이다. 이번엔 SITE_SLUG=psy로 특정 사이트를 먼저 타깃으로 잡았고, 그 위에서 index 페이지와 result 페이지 두 군데에 광고 호출을 붙이는 게 목표였다.

작업 내용

변경된 파일들을 보면 레이어가 꽤 고르게 퍼져 있다.

파일 역할 이번 변경 의미
src/lib/db.ts DB 접근 유틸 admin_db 패턴 쿼리 로직 추가
src/components/MobonSlot.astro 광고 슬롯 컴포넌트 신규 생성 — DB에서 받은 설정으로 렌더링
src/pages/index.astro 메인 페이지 MobonSlot 호출 추가
src/pages/t/[slug]/r/[result].astro 결과 페이지 MobonSlot 호출 추가
package.json / package-lock.json 의존성 Mobon 관련 패키지 혹은 DB 클라이언트 추가

db.ts에서의 변경이 제일 핵심이다. 슬러그를 받아서 해당 사이트의 광고 슬롯 설정을 가져오는 함수 하나가 생겼을 텐데, 이걸 어떻게 설계하느냐가 이후 확장성을 결정한다. 대략 이런 패턴으로 잡았다.

// src/lib/db.ts (패턴 예시)
export async function getAdSlotConfig(siteSlug: string, slotKey: string) {
  const row = await db
    .selectFrom('ad_slots')
    .where('site_slug', '=', siteSlug)
    .where('slot_key', '=', slotKey)
    .where('is_active', '=', true)
    .selectAll()
    .executeTakeFirst();

  return row ?? null;
}

MobonSlot.astro 컴포넌트는 이 함수를 Astro의 서버 렌더링 시점에 호출해서 슬롯 ID를 받아 스크립트를 주입하는 구조다. 컴포넌트 안에 직접 DB 콜이 들어가는 게 불편하면 페이지에서 미리 조회해서 props로 내려주는 방식도 있는데, 이번엔 슬롯 컴포넌트가 자기 데이터를 직접 책임지는 쪽으로 갔다.

---
// src/components/MobonSlot.astro
import { getAdSlotConfig } from '../lib/db';

const { siteSlug, slotKey } = Astro.props;
const config = await getAdSlotConfig(siteSlug, slotKey);
---

{config && (
  <div id={`mobon-${slotKey}`}>
    <script async src={`https://ad.mobon.net/...${config.slot_id}...`} />
  </div>
)}

null 체크로 슬롯이 없거나 비활성이면 아무것도 안 그리도록 한 게 포인트. 광고 컴포넌트가 조용히 사라지는 게 에러 내뱉는 것보다 훨씬 낫다.

회고

index 페이지와 result 페이지에 동시에 붙인 건 의도적인 판단이었다. 메인과 결과 페이지는 트래픽 성격이 다르고 광고 노출 목적도 다를 수 있는데, 같은 컴포넌트를 slotKey만 다르게 넘겨서 재사용하는 구조가 제대로 동작하는지 초반에 두 곳에서 동시에 검증하고 싶었다.

한 가지 신경 쓰인 건 DB 호출 타이밍이다. Astro SSR에서 컴포넌트마다 DB를 찌르면 페이지 하나에 슬롯이 여러 개 들어갈 경우 N번 쿼리가 나간다. 당장은 슬롯이 많지 않으니 괜찮지만, 나중에 슬롯이 늘어나면 페이지 레벨에서 한 번에 조회해서 컨텍스트로 내려주는 방식을 고려해야 할 것 같다.

  • 슬롯 수가 적을 때: 컴포넌트 자체 조회 → 캡슐화 좋음
  • 슬롯 수가 많아질 때: 페이지에서 배치 조회 → 쿼리 수 절감
  • 설정 변경 빈도가 높을 때: 짧은 TTL 캐싱 레이어 추가 검토

SITE_SLUG=psy를 먼저 잡은 건 이 사이트가 가장 빠르게 광고 붙여야 하는 우선순위였기 때문이다. 패턴이 검증되면 다른 슬러그로 확장하는 건 DB에 row 하나 추가하는 수준이 된다. 그게 이 설계의 목적이었고, 일단 그 방향으로 잘 잡힌 것 같다.

끝.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.