📦 실제 페이지 → m.hsmoa.com/stock-out
네 줄 요약
- 홈쇼핑 방송 후 남은 재고를 인플루언서 채널로 빠르게 소진하는 B2B 파트너십 신청 페이지 제작
- 스택: Next.js (Pages Router) + TypeScript + Tailwind CSS — 그리고 별도 백엔드 서버 없이 로우코드 DB(Budibase) + Slack 웹훅으로 신청 처리
- 신청이 들어오면 Budibase에 저장 후 동시에 Slack으로 실시간 알림 — 알림 실패가 신청 저장을 막지 않도록 격리
- 단순 랜딩이 아니라 SEO/AEO(AI 검색 최적화) 까지 신경 써서, JSON-LD·질문형 헤딩·llms.txt로 검색·AI 노출을 노렸다
1. 왜 만들었나
홈쇼핑은 방송이 끝나고 나면 남은 재고가 생깁니다. 잘 팔린 회차는 문제없지만, 그렇지 못한 물량은 어딘가로 빠르게 흘려보내야 합니다. 창고 비용은 계속 나가고, 시즌 상품은 시간이 갈수록 가치가 떨어지니까요.
여기서 시작된 게 재고소진(Stock-Out) 파트너십입니다. 방송 후 남은 재고를 인플루언서 네트워크 기반의 SNS·라이브커머스 채널로 연결해 빠르게 판매하는 B2B 프로그램이죠.
문제는, 이걸 알리고 신청을 받을 창구가 없었다는 점입니다. 제휴 문의가 들어와도 메일과 전화로 산발적으로 받다 보니 누락도 생기고 응대도 느렸습니다. 그래서 결정했습니다. “신청을 받는 페이지 하나 제대로 만들자.”
요구사항은 세 가지였습니다.
- 파트너사가 보고 바로 신청할 수 있는 랜딩 + 신청 폼
- 신청이 들어오면 놓치지 않고 즉시 인지할 수 있을 것
- 검색해서 들어오는 자연 유입까지 잡을 것 (= SEO/AEO)
2. “이 작은 페이지에 백엔드 서버를 붙일 것인가”
가장 먼저 한 고민입니다. 신청 폼 하나 받자고 별도 API 서버를 세우고 DB 스키마를 짜고 운영까지 하는 건 명백한 오버였습니다.
신청 폼의 본질은 “데이터를 어딘가 안전하게 쌓고, 담당자가 빨리 보는 것”뿐이다.
그래서 구조를 이렇게 잡았습니다.
사용자 신청
→ Next.js API Route (/api/stock-out)
→ Budibase 테이블에 row 저장 (영속 데이터)
→ Slack 웹훅으로 실시간 알림 (담당자 인지)
→ 성공 응답
- Budibase: 로우코드 데이터베이스. 테이블만 만들면 REST API가 바로 나오고, 비개발 담당자도 관리자 화면에서 신청 내역을 직접 조회·관리할 수 있습니다. 별도 DB 운영 부담 0.
- Slack 웹훅: 신청이 들어오는 즉시 담당 채널에 기업명·담당자·연락처가 요약되어 꽂힙니다. “메일함 새로고침”이 사라졌습니다.
- Next.js API Route: 이 둘을 연결하는 얇은 글루 코드. 서버를 새로 띄울 필요 없이 기존 mobile-web 프로젝트 안에서 끝납니다.
3. API 한 파일이 하는 일
핵심은 pages/api/stock-out.ts 한 파일입니다. 길지도 않습니다. 그런데 한 가지 신경 쓴 디테일이 있습니다.
// Budibase 저장이 성공한 뒤에 Slack 알림을 보낸다.
// Slack이 실패해도 사용자 신청은 이미 저장됐으므로 절대 실패로 처리하지 않는다.
const slackWebhookUrl = process.env.SLACK_STOCK_OUT_WEBHOOK_URL;
if (slackWebhookUrl) {
try {
await fetch(slackWebhookUrl, {
/* ... 신청 요약 ... */
});
} catch (slackError) {
console.error('Slack webhook failed', slackError);
// 여기서 throw 하지 않는다 — 알림은 부가 기능일 뿐
}
}
return res.status(200).json({ success: true });
알림(Slack)의 실패가 본질(저장)의 실패로 번지지 않게 격리하는 것. 별것 아닌 것 같지만, 이걸 안 하면 Slack 측 일시 장애 한 번에 “신청은 됐는데 사용자에겐 실패 메시지가 뜨는” 최악의 경험이 생깁니다. 사용자 입장에서 신청은 이미 DB에 안전하게 들어갔으니, 부가 알림 실패로 재신청을 유도해선 안 됩니다.
신청 폼은 기업명·담당자명·연락처·이메일을 필수로, 브랜드명·직함·진행 요청 제품·문의 내용을 선택으로 받습니다. 이메일 형식 검증 등 1차 검증은 클라이언트에서, 저장은 서버에서 처리하는 평범한 구조입니다.
4. 단순 랜딩에서 끝내지 않은 이유 — SEO와 AEO
여기가 이 프로젝트에서 시간을 가장 많이 쓴 부분입니다.
“홈쇼핑 재고 소진”, “재고 처리 제휴” 같은 키워드로 검색해서 들어오는 잠재 파트너사가 분명히 있을 거라고 봤습니다. 그렇다면 이 페이지는 광고로만 띄우는 랜딩이 아니라, 검색에 걸리는 자산이어야 했습니다.
SEO — 검색 엔진을 위한 구조화
- JSON-LD 구조화 데이터:
Service(서비스 정보),Organization(회사 정보),FAQPage(자주 묻는 질문)를 마크업으로 심어 검색 결과 리치 스니펫을 노렸습니다. - 키워드 본문 빈도 보강: ‘재고 소진’ 같은 핵심 키워드가 본문에 자연스럽게 반복되도록 카피를 다듬었습니다.
- 메타/OG 태그: 공유 시 미리보기와 검색 타이틀을 정리했습니다.
AEO — AI 검색을 위한 최적화
요즘은 사람만 검색하지 않습니다. 네이버 AI 브리핑, ChatGPT, Claude 같은 AI가 페이지를 읽고 요약해 답변합니다. 그래서 AI가 읽기 좋은 형태를 따로 챙겼습니다.
- H2 헤딩을 질문형으로: “서비스 소개” 대신 “재고소진 파트너십이란 무엇인가요?”처럼, AI가 Q&A로 추출하기 좋게 바꿨습니다.
- 핵심요약·비교표 섹션: 답변에 그대로 인용되기 쉬운 요약 블록과 비교표를 컴포넌트로 추가했습니다.
- llms.txt: AI 크롤러에게 회사·서비스 정보를 명시적으로 제공하는 파일을 두었습니다.
검색 엔진과 AI, 두 종류의 독자를 모두 염두에 두고 만든 페이지인 셈입니다.
5. 레이아웃을 여러 버전으로 만들어 본 이야기
랜딩 톤을 한 번에 정하지 못해서, 다크 버전·라이트 버전·풀스크린 버전·MDS(디자인 시스템 적용) 버전을 각각 만들어 비교했습니다. 마케팅 채널과 브랜드 톤에 따라 어떤 버전이 맞을지 실제로 띄워 놓고 보는 게 빨랐습니다.
이 과정에서 풀스크린 세로 중앙 정렬에서 푸터가 잘리는 문제, 다크 버전 배경·헤드라인 스타일이 따로 노는 문제 등을 잡았습니다. 한 화면으로 끝나는 작은 페이지일수록 여백과 정렬 디테일이 인상의 전부라는 걸 다시 느꼈습니다.
6. 브랜드 일반화 — 협력에서 단독 서비스로
처음 이 프로그램은 외부 파트너(리씽크몰)와의 협력 형태로 시작했습니다. 그래서 초기 페이지에는 “홈쇼핑모아 × 리씽크몰” 같은 공동 브랜드 표기가 들어가 있었죠.
이후 프로그램이 홈쇼핑모아 단독 서비스로 일반화되면서, 특정 파트너 브랜드 표기를 걷어내고 “홈쇼핑모아 재고소진 제휴 파트너십”으로 카피·메타·구조화 데이터를 일괄 정리했습니다.
서비스 카피가 바뀌면 본문만 고치면 끝이 아니다 —
<title>, OG 태그, JSON-LD의Organization/Service, llms.txt까지 검색·AI가 읽는 모든 표면을 같이 맞춰야 한다.
이때 SEO를 위해 곳곳에 심어둔 구조화 데이터가 오히려 “고쳐야 할 곳 체크리스트”가 됐습니다.
7. 만들면서 느낀 것
작은 기능일수록 “안 만들 것”을 정하는 게 먼저다
신청 폼 하나에 백엔드 서버를 세웠다면, 기능 대비 운영 부담이 말이 안 됐을 겁니다. 로우코드 DB + 웹훅 조합으로 개발자가 만들고 비개발 담당자가 운영하는 구조를 만든 게 이 프로젝트의 핵심 판단이었습니다.
실패는 격리하라
Slack 알림 실패를 신청 실패로 처리하지 않은 것 — 코드 몇 줄 차이지만, 사용자 경험에서는 결정적입니다. 부가 기능의 장애가 본질 기능을 끌어내리면 안 됩니다.
이제 랜딩은 사람만 보지 않는다
검색 엔진과 AI를 독자로 상정하고 페이지를 설계하는 건 이제 선택이 아니라 기본이 되어가고 있습니다. 질문형 헤딩, 구조화 데이터, llms.txt — 들이는 시간 대비 자연 유입 효과가 분명한 영역입니다.
🔗 링크
- 📦 재고소진 파트너십: m.hsmoa.com/stock-out
- 📁 프로젝트 포트폴리오: drawyourmind.com/works/hsmoa-stock-out
