Communitygithub.com

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Next.js 랜딩페이지용 Sepay VietQR 결제 인프라를 구축합니다. Sepay 계정 설정, 은행 연결, 프로젝트 내 전체 결제 흐름을 안내합니다.

MKT.LANDINGPAGE.SKILLS란 무엇인가요?

이 스킬은 Next.js 랜딩페이지에 베트남 VietQR 결제 시스템(Sepay)을 완전히 통합하는 방법을 제공합니다. 7단계(Phase)로 구성되어 있으며, 사용자가 Next.js 스택을 감지하고 Vercel KV 또는 Supabase Free 중 리드 저장소를 선택하도록 안내합니다. Sepay 계정 등록, 은행 연결, API 키 발급, 웹훅 URL 설정을 단계별로 안내한 후, 선택한 저장소에 맞춰 데이터베이스 마이그레이션, 환경 변수 설정, 코드 스캐폴딩을 자동으로 수행합니다. 또한 `/api/checkout`, `/api/sepay-webhook`, `/api/admin/leads` API 라우트를 생성하고, VietQR을 랜딩페이지에 삽입하는 3가지 UX 패턴을 제공합니다. 최종적으로 5단계 테스트 계획을 통해 전체 결제 흐름을 검증합니다. Supabase Free의 경우 자동 일시 중지를 방지하기 위해 Vercel Cron 또는 GitHub Actions를 통한 주기적인 핑을 설정합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/lexuanthanhhy/MKT.LANDINGPAGE.SKILLS/tree/main/.claude/skills/biz-setup-sepay-payment

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Biz Setup Sepay Payment — Next.js용 VietQR 결제 인프라 종합 설정

이 스킬은 Sepay(베트남 VietQR 결제 게이트웨이)를 사용하여 Next.js 랜딩페이지를 위한 완전한 결제 인프라를 구축합니다. 완료 후: 고객이 양식을 작성 → 주문 생성 → QR 스캔 → 계좌 이체 → Sepay 웹훅 수신 → 확인 + 리드 조회 + 이메일/텔레그램 트리거. 모든 과정이 자동화되며 관리자의 수동 확인이 필요하지 않습니다.

철학: Sepay는 베트남에서 가장 쉬운 경로입니다 — VietQR + 은행 네이티브 API, 고객이 별도로 가입할 필요 없이 기존 은행 앱으로 QR을 스캔하면 됩니다. 수수료 1.5-2%로 Stripe(4-5%)보다 저렴하고, T+1 정산되며, 월 100건 미만 랜딩페이지에 적합한 무료 등급이 있습니다.

리드 저장소가 필요한 이유: Sepay 웹훅은 content(고객이 이체 시 입력한 텍스트)와 금액만 보냅니다. Sepay는 고객이 누구인지 알 수 없습니다. content를 리드 {name, phone, email, product, amount}에 매핑하려면 로컬 리드 저장소가 필요합니다.

2가지 리드 저장소 옵션 — 사용자가 0단계에서 선택:

  • Vercel KV (Upstash Redis) — 2분 설정, 네이티브 TTL, 월 30,000 명령어 무료 → 월 500건 미만
  • Supabase Free (Postgres) — 5분 설정, SQL 쿼리 + Studio UI, 무료 등급 약 50배 더 넓음 → 월 2000건 미만. 권장.

API 라우트(/api/checkout, /api/sepay-webhook, /api/admin/leads)는 lib/leads-store.ts 씬 re-export을 통해 공급자에 독립적입니다. 나중에 공급자를 변경하려면 1줄만 수정하면 됩니다.

스킬은 사용자를 대신해 Sepay 계정을 등록하지 않습니다 (KYC 비즈니스 + 은행 필요). 사용자를 단계별로 안내한 후 전체 코드를 연결합니다.


이 스킬을 사용해야 하는 경우

  • 사용자가 디지털 제품/코스/코칭을 출시하고 온라인 결제를 받아야 하는 경우.
  • 사용자가 이미 Next.js 랜딩페이지(ui-ux-pro-max 또는 유사)를 보유하고 결제 흐름을 추가하려는 경우.
  • 사용자가 biz-email-setup 또는 biz-telegram-payment-notify를 연결할 준비가 되었지만 결제 인프라가 없는 경우 → 이 스킬이 전제 조건입니다.

다음 경우에는 이 스킬을 사용하지 마십시오:

  • 사용자가 Stripe/PayPal(국제 카드 결제)을 사용하는 경우 → 다른 사용 사례.
  • 사용자가 수동 은행 송금 + 자체 확인(소규모, 권장하지 않음)을 수락하는 경우.
  • 사용자가 이미 결제 인프라를 보유하고 알림만 필요한 경우 → /biz-email-setup 또는 /biz-telegram-payment-notify로 바로 이동.

전체 워크플로 (7단계)

Phase 0: Next.js 스택 감지 + 공급자(KV/Supabase) 질문 — GATE
       ↓
Phase 1: 사용자 Sepay 계정 설정 안내 — 수동 GATE 사용자 완료 대기
       ↓
Phase 2A (KV 선택 시): Vercel KV 설정 (패키지 설치 + env vars + KV 네임스페이스)
Phase 2B (Supabase 선택 시): Supabase 설정 (프로젝트 생성 + SQL 마이그레이션 + service_role)
       ↓
Phase 3: lib/leads-store.ts (re-export 래퍼) + lib/leads-{kv|supabase}.ts (구현) 스캐폴딩
       ↓
Phase 4: /api/checkout 라우트 스캐폴딩 (양식 → 주문 → 저장)
       ↓
Phase 5: /api/sepay-webhook 라우트 스캐폴딩 (확인 + 조회 + 사이드 이펙트 플레이스홀더)
       ↓
Phase 6: VietQR을 랜딩페이지에 삽입 (3가지 UX 패턴 중 선택)
       ↓
Phase 7: 5단계 테스트 계획 (저장소 → 체크아웃 → 웹훅 → 프로덕션 → (Supabase 전용) cron 핑)

Phase 0 + 1에는 사용자 대기 게이트가 있습니다. Phase 2/3/4/5/6은 스킬이 능동적으로 수행합니다.


Phase 0 — Next.js 스택 감지 + 공급자 선택

0.1 스택 감지

test -f next.config.js -o -f next.config.mjs -o -f next.config.ts && echo "Next.js: ✓"
test -d app && echo "Router: App"
test -d pages && echo "Router: Pages"
test -f tsconfig.json && echo "TS: ✓"
test -f pnpm-lock.yaml && echo "pkg: pnpm" || test -f yarn.lock && echo "pkg: yarn" || echo "pkg: npm"

Next.js가 아닌 경우: 중단. 알림: "이 스킬은 현재 Next.js만 지원합니다. 현재 스택은 [X]입니다. Vercel Function을 사용하여 Vite/정적 사이트로 로직을 포팅할까요?" — 사용자 대기.

app/와 pages/가 모두 있는 경우: 사용자에게 어떤 것을 사용할지 물어봅니다.

0.2 기존 인프라 확인

ls app/api/ pages/api/ lib/ 2>/dev/null
grep -E '"@vercel/kv"|"@supabase/supabase-js"|"@upstash/redis"' package.json
grep -E "SEPAY|KV_REST|SUPABASE_" .env.local 2>/dev/null

0.3 사용자에게 공급자 선택 질문

Next.js [App/Pages] Router + TypeScript + [pnpm/yarn/npm]을 사용 중이신 것으로 확인했습니다.

리드 저장소를 어디에 저장하시겠습니까?

1. Vercel KV (Upstash Redis)
   ✓ 2분 빠른 설정 (Vercel 대시보드에서 1클릭)
   ✓ 네이티브 TTL — 프로젝트 일시 중지 걱정 없음
   ✗ 무료 월 30,000 명령어만 → 월 ~500건
   ✗ SQL 없음 — 관리자 필터가 복잡하고 어려움

2. Supabase Free (Postgres) — 권장
   ✓ 가장 넓은 무료 등급 (500MB DB + 5GB 대역폭, 무제한 쿼리)
   ✓ Postgres = 강력한 SQL 쿼리, Supabase Studio UI로 데이터 보기에 좋음
   ✓ TypeScript 타입 안전 자동 생성
   ✓ 5분 설정 (콘솔 + 2개의 env vars 붙여넣기)
   ⚠️ 7일간 사용 없으면 프로젝트 자동 일시 중지 → 6일마다 Vercel Cron 핑 `/api/health`를 연결하여 해결
   ⚠️ TTL은 pg_cron을 통해 수동으로 관리 (SQL 마이그레이션에 이미 연결됨)
   → 월 2000건 미만에 적합, 관리자 기능 확장 용이

1 또는 2를 선택해주세요.

GATE: 사용자가 선택할 때까지 Phase 1로 이동하지 않습니다. 기본적으로 Supabase를 제안하지만 명시적으로 선택하도록 합니다.

사용자가 선택한 후, 계획 요약:

**[Vercel KV / Supabase]**를 선택하셨습니다. 다음을 수행하겠습니다:

  1. Sepay 계정 설정 안내 (5-10분)
  2. 선택한 공급자에 따라 리드 저장소 설정
  3. 코드 연결: lib/leads-store.ts + /api/checkout + /api/sepay-webhook + VietQR 삽입
  4. 테스트

Phase 1을 시작할 준비가 되셨습니까?


Phase 1 — 사용자 Sepay 계정 설정 안내

전체 가이드는 references/sepay-account-setup.md를 참조하세요. 사용자에게 5단계 요약:

1단계 — my.sepay.vn에 가입

  1. https://my.sepay.vn 방문 → 가입
  2. 전화번호, 이메일, 비밀번호 입력 → OTP 인증
  3. 프로필 완료: 이름 + CCCD/CMND (개인) 또는 세금 코드 (회사)

2단계 — 은행 계좌 연결

대시보드 → 은행 계좌 → 계좌 추가:

  • 은행 선택 (Vietcombank, Techcombank, MB, ACB, VPBank, BIDV, VietinBank, TPBank, ...)
  • 계좌 번호 + 예금주 이름 입력 (은행 앱과 일치해야 함)
  • 자동 인증 (은행 API를 통해) 또는 수동 인증 (Sepay가 제공하는 확인 코드로 1,000-10,000 VND 이체)

3단계 — API 키 발급

대시보드 → 설정 → API 및 웹훅 → 새 API 키 생성:

  • 이름: landing-page-prod
  • 권한: webhook:read
  • 키 복사 (한 번만 표시됨)

4단계 — 웹훅 URL 설정

같은 페이지 → 웹훅 → 웹훅 추가:

  • URL: https://yourdomain.vn/api/sepay-webhook (배포 후 활성화)
  • 인증: API Key → 방금 생성한 키 붙여넣기
  • 이벤트: transaction:incoming
  • 저장

⚠️ 로컬 개발: Sepay 테스트를 위해 ngrok을 사용하여 localhost:3000을 노출하세요.

5단계 — 스킬에 붙여넣기

SEPAY_WEBHOOK_API_KEY=sk_xxxxxxxxxxxxxxxxxxxx
SEPAY_BANK_ACCOUNT_NUMBER=1023456789
SEPAY_BANK_NAME=Vietcombank
SEPAY_ACCOUNT_NAME=NGUYEN VAN A

GATE: 사용자가 모두 붙여넣을 때까지 Phase 2로 이동하지 않습니다.


Phase 2A — Vercel KV 설정 (Phase 0에서 사용자가 KV를 선택한 경우에만)

Vercel KV = 관리형 Upstash Redis. 월 30,000 명령어 무료.

2A.1 KV 네임스페이스 생성

Vercel 대시보드 → 프로젝트 → Storage → Create Database → KV (Redis) → 이름 sepay-leads → 생성.

4개의 env vars 자동 생성:

KV_URL=...
KV_REST_API_URL=...
KV_REST_API_TOKEN=...
KV_REST_API_READ_ONLY_TOKEN=...

Connect to Project 클릭 → Vercel이 env 주입 (Production + Preview + Development).

2A.2 로컬로 env 가져오기

npm i -g vercel    # 아직 없는 경우
vercel link
vercel env pull .env.local

2A.3 패키지 설치

pnpm add @vercel/kv  # 또는 yarn / npm install

2A.4 확인

node -e "
const { kv } = require('@vercel/kv');
kv.set('test', 'hello').then(() => kv.get('test')).then(v => {
  console.log('KV OK:', v);
  return kv.del('test');
});
"

KV OK: hello 출력 예상. Phase 3으로 이동.


Phase 2B — Supabase Free 설정 (Phase 0에서 사용자가 Supabase를 선택한 경우에만)

전체 6단계 상세 가이드는 references/supabase-setup.md를 참조하세요. 요약:

2B.1 Supabase 계정 + 프로젝트 생성

  1. https://supabase.com → Start your project → GitHub 로그인
  2. New project:
    • 이름: sepay-leads-<브랜드명>
    • 데이터베이스 비밀번호: Generate 클릭 → 저장
    • 리전: ⚠️ Southeast Asia (Singapore) (기본 us-east 지연 시간 250ms+)
    • 가격: Free
  3. ~2분 프로비저닝 대기

2B.2 SQL 마이그레이션 실행

사이드바 → SQL Editor → New query → templates/supabase-migration.sql 내용 붙여넣기 → Run.

4개 테이블 + 인덱스 + next_order_id() 함수 + RLS 활성화 + pg_cron 일일 정리 작업 생성.

출력 확인: 4개 테이블 (leads/phone_index/order_counter/webhook_dedup) + 1 pg_cron 작업 + next_order_id()가 "DH000001" 반환.

카운터 초기화 (확인으로 인해 카운터가 증가했으므로):

UPDATE order_counter SET current_value = 0 WHERE id = 1;
DELETE FROM leads WHERE order_id = 'DH000001';

2B.3 API 자격 증명 가져오기

Project Settings → API:

  • Project URL 복사 (https://xxxxx.supabase.co)
  • service_role 시크릿 복사 (anon 키 아님 — service_role은 RLS를 우회하며 서버에서 사용)

2B.4 env vars 붙여넣기

SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJI...

스킬 자동 확인:

  • URL이 ^https://[a-z0-9]+\.supabase\.co$와 일치하는지 확인
  • 키가 JWT를 디코딩하고 role: "service_role"을 확인 (anon 아님)

오류 시 → 오류 보고, 다시 붙여넣기 요청.

2B.5 패키지 설치

pnpm add @supabase/supabase-js

2B.6 Vercel Cron 핑 연결 (일시 중지 방지)

Supabase Free는 7일간 사용 없으면 자동으로 일시 중지됩니다. 해결 방법: 6일마다 /api/health 핑.

스킬이 app/api/health/route.ts (templates/api-health-route.ts에서) 스캐폴딩하고 vercel.json에 다음을 추가합니다:

{
  "crons": [
    { "path": "/api/health", "schedule": "0 3 */6 * *" }
  ]
}

⚠️ Vercel Cron Hobby는 월 2회 cron으로 제한됩니다. */6 days 패턴 = 월 ~5회 → 할당량 초과. 옵션:

  1. Vercel Pro ($20/월) — 무제한 cron
  2. GitHub Actions 워크플로 .github/workflows/keep-alive.yml (무료) — 리포지토리가 GitHub인 경우 스킬이 스캐폴딩
  3. cron-job.org (무료) — 수동 설정, URL /api/health 붙여넣기

스킬은 기본적으로 GitHub 원격이 있는 .git/config가 있는 리포지토리의 경우 옵션 2(GitHub Actions)를 선택합니다. 그렇지 않으면 옵션 3 설명을 출력합니다.

2B.7 확인

node -e "
const { createClient } = require('@supabase/supabase-js');
const sb = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY);
sb.from('order_counter').select('current_value').eq('id', 1).single().then(r => {
  if (r.error) { console.error('FAIL:', r.error.message); process.exit(1); }
  console.log('Supabase OK. current_value =', r.data.current_value);
});
"

Supabase OK. current_value = 0 출력 예상. Phase 3으로 이동.


Phase 3 — lib/leads-store.ts + 구현 스캐폴딩

공급자 추상화: API 라우트는 lib/leads-store.ts에서 가져오며, 내부가 KV인지 Postgres인지 알지 못합니다.

KV 선택 시 (Phase 0)

2개 파일 스캐폴딩:

  • lib/leads-store.ts ← templates/lib-leads-store-kv.ts 복사 (1줄 export * from './leads-kv')
  • lib/leads-kv.ts ← templates/lib-leads-kv.ts 복사 (KV 구현, ~160줄)

Supabase 선택 시

3개 파일 스캐폴딩:

  • lib/leads-store.ts ← templates/lib-leads-store-supabase.ts 복사 (Supabase re-export)
  • lib/leads-supabase.ts ← templates/lib-leads-supabase.ts 복사 (Postgres 구현 + 관리자용 listLeads)
  • lib/supabase-admin.ts ← templates/lib-supabase-admin.ts 복사 (service_role을 사용하는 캐시된 싱글톤 관리자 클라이언트)

공통 API 표면 (두 구현 모두):

  • createLead(input) → { orderId, lead } — 원자적 ID + 삽입 + 보조 인덱스
  • getLeadByOrderId(orderId) → Lead | null
  • getLeadByPhone(phone) → Lead | null — 폴백 조회
  • findPendingLeadByAmountAndTime(amount, start, end) → Lead[] — 전략 3 웹훅 매칭
  • markLeadPaid(orderId, payment) → Lead | null
  • isTransactionProcessed(sepayId) → boolean — 중복 제거
  • markTransactionProcessed(sepayId) → void

TTL: 7일 보류 / 90일 완료. KV는 ex: 매개변수 사용. Supabase는 expire_at 필드 + pg_cron 일일 삭제 사용.

나중에 공급자 변경 = leads-store.ts 1줄 수정 (API 코드 건드리지 않음).

자세한 근거는 references/leads-kv-schema.md (KV) 또는 references/supabase-leads-schema.md (Supabase)를 참조하세요.


Phase 4 — /api/checkout 라우트 스캐폴딩

templates/api-checkout-app-router.ts (App Router) 또는 templates/api-checkout-pages-router.ts (Pages Router)를 읽고 해당 경로에 복사합니다.

두 템플릿 모두 import { createLead } from '@/lib/leads-store' — 공급자 독립적.

흐름:

클라이언트 POST /api/checkout { name, phone, email, productName, amount }
  ↓
서버:
  1. 유효성 검사 (베트남 전화번호 형식, 이메일 정규식, amount > 0)
  2. createLead() → { orderId: "DH000123" }
  3. Sepay QR URL 생성: https://qr.sepay.vn/img?acc=X&bank=Y&amount=Z&des=DH000123&template=compact
  4. { orderId, amount, bankInfo, content, qrUrl } 반환
  ↓
클라이언트: QR 모달 표시 또는 /checkout/DH000123으로 리디렉션

Phase 5 — /api/sepay-webhook 라우트 스캐폴딩

templates/api-sepay-webhook-app-router.ts를 읽고 app/api/sepay-webhook/route.ts에 복사합니다.

템플릿은 import ... from '@/lib/leads-store' — 공급자 독립적.

흐름:

Sepay POST /api/sepay-webhook
  Authorization: Apikey {SEPAY_WEBHOOK_API_KEY}
  본문: SepayWebhookPayload
  ↓
서버:
  1. timingSafeEqual을 통한 인증 확인 — 타이밍 공격 방지
  2. 초기 중복 제거: isTransactionProcessed(payload.id) → 200 반환
  3. 중복 제거 먼저 기록 — 처리 실패에도 멱등성 보장
  4. transferType === 'in' 필터링 (나가는 거래 제외)
  5. 다중 전략 매칭:
     a. content → order_id (정규식 /DH\d+/)
     b. content → phone (정규식 /0\d{9}/) → getLeadByPhone
     c. amount + timestamp ±30분 → findPendingLeadByAmountAndTime (길이가 1인 경우만 허용)
  6. 부족 결제 거부, 초과 결제 수락
  7. markLeadPaid(orderId, payment) → 저장소 업데이트
  8. try/catch 루프를 통한 사이드 이펙트 팬아웃 (Promise.all 아님)
  9. 항상 200 반환 (내부 오류 포함) — Sepay는 200이 아닌 경우 Fibonacci 방식으로 최대 7회 재시도

biz-email-setup + biz-telegram-payment-notify를 위한 사이드 이펙트 플레이스홀더는 나중에 연결됩니다.

중복 제거 근거 및 재시도 동작은 references/sepay-webhook-flow.md를 참조하세요.


Phase 6 — VietQR을 랜딩페이지에 삽입

3가지 UX 패턴, 사용자에게 1개 선택 요청:

패턴사용 시기UX
A. 모달 팝업단일 제품 / 충동 구매양식 제출 → 원래 페이지에서 QR 모달 팝업
B. /checkout/[orderId] 페이지다중 제품 / URL 공유 필요양식 제출 → /checkout/DH000123으로 이동하여 QR + 상태 표시
C. QR 인라인 + 복사 내용최소 설정 / 기술 사용자양식 바로 아래 QR + 내용 복사 버튼, 자동 새로고침 없음

스킬이 선택한 패턴에 따라 새 파일을 스캐폴딩하거나 기존 파일을 수정합니다. 참조 템플릿 참조: templates/qr-modal.tsx (A), templates/checkout-page.tsx (B), templates/qr-inline.tsx (C).


Phase 7 — 5단계 테스트 계획

레벨 1: 저장소 테스트

node -e "
const { createLead, getLeadByOrderId } = require('./lib/leads-store');
createLead({ name: 'Test', phone: '0987654321', email: '[email protected]', productName: 'Test', amount: 100000 })
  .then(r => console.log('생성됨:', r.orderId))
  .then(() => getLeadByOrderId('DH000001'))
  .then(l => console.log('조회됨:', l?.name))
  .catch(e => console.error('실패:', e.message));
"

예상: 생성됨: DH000001 + 조회됨: Test.

레벨 2: 체크아웃 API 테스트

curl -X POST http://localhost:3000/api/checkout \
  -H 'Content-Type: application/json' \
  -d '{"name":"Test UX","phone":"0909123456","email":"[email protected]","productName":"UX Pro Max","amount":299000}'

예상: {"orderId":"DH000002","amount":299000,"bankInfo":{...},"content":"DH000002","qrUrl":"https://qr.sepay.vn/img?..."}.

레벨 3: 웹훅 시뮬레이션

Sepay 대시보드 → Webhook Logs → Send test 또는 curl로 시뮬레이션:

curl -X POST http://localhost:3000/api/sepay-webhook \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Apikey sk_test_xxx' \
  -d '{"id":"test_001","transferType":"in","accountNumber":"1023456789","amount":299000,"content":"DH000002","transactionDate":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}'

확인: getLeadByOrderId("DH000002") → payment.paid = true, payment.sepayId = "test_001".

중복 제거 확인: 동일한 페이로드로 다시 보내기 → success: true이지만 중복 플래그.

레벨 4: 프로덕션 체크리스트

  • NODE_ENV=production 환경에 배포됨
  • SEPAY_WEBHOOK_API_KEY가 프로덕션 env vars에 설정됨
  • Sepay 대시보드의 웹훅 URL이 프로덕션 URL을 가리킴
  • (Supabase 전용) KEEP_ALIVE_CRON 활성화됨 (GitHub Actions 또는 cron-job.org)
  • SSL/HTTPS 활성화됨 (Vercel 기본값)
  • /api/sepay-webhook 및 /api/health가 200 반환

레벨 5: (Supabase 전용) Cron 핑 확인

curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/api/health

예상: 200.

GitHub Actions 워크플로 로그 확인: 성공적인 실행 확인.


체크리스트 (완료 시 사용자에게 제공)

  • Sepay 계정 등록 + 은행 연결됨
  • 환경 변수 설정됨 (SEPAY_*, 공급자 *)
  • lib/leads-store.ts + 구현 스캐폴딩됨
  • /api/checkout 활성화됨
  • /api/sepay-webhook 활성화됨
  • VietQR이 랜딩페이지에 삽입됨
  • 저장소 테스트 통과
  • 체크아웃 API 테스트 통과
  • 웹훅 시뮬레이션 통과
  • 프로덕션 체크리스트 완료
  • (선택 사항) biz-email-setup 연결
  • (선택 사항) biz-telegram-payment-notify 연결
  • (선택 사항) /api/admin/leads 보안 + UI 추가 (프로젝트에 따라 다름)

참고 자료

파일목적
references/sepay-account-setup.mdSepay 계정 설정 전체 가이드
references/supabase-setup.mdSupabase 프로젝트 설정 가이드
references/leads-kv-schema.mdKV 데이터 구조 및 TTL 근거
references/supabase-leads-schema.mdSupabase 테이블 구조 및 인덱스
references/sepay-webhook-flow.md웹훅 처리 파이프라인 및 중복 제거
templates/supabase-migration.sqlSupabase 4개 테이블 + pg_cron SQL
templates/api-health-route.tsSupabase 일시 중지 방지 핑
templates/api-checkout-app-router.tsApp Router 체크아웃 API
templates/api-checkout-pages-router.tsPages Router 체크아웃 API
templates/api-sepay-webhook-app-router.tsApp Router 웹훅 API
templates/lib-leads-store-kv.tsKV 스토어 진입점
templates/lib-leads-store-supabase.tsSupabase 스토어 진입점
templates/lib-leads-kv.tsKV 구현
templates/lib-leads-supabase.tsSupabase 구현
templates/lib-supabase-admin.tsSupabase 관리자 클라이언트
templates/qr-modal.tsx패턴 A: 모달 팝업
templates/checkout-page.tsx패턴 B: 체크아웃 페이지
templates/qr-inline.tsx패턴 C: 인라인 QR

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Best practices for Remotion - Video creation in React

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Scaffold trang `/admin` CRM-style trực quan vào Next.js project (Supabase backend) — KHÔNG còn variant Vercel KV. Layout 1CRM-inspired: sidebar 3 tab (Tổng quan / Khách hàng / Email marketing) + popup nhập mã đăng nhập. **Tab Tổng quan**: 4 KPI cards (Tổng leads / Đã thanh toán / Tỷ lệ chuyển đổi / Doanh thu) có delta arrow vs kỳ trước, line chart leads+paid+revenue theo ngày dùng `recharts`, donut trạng thái paid/pending/expired, period selector pill 7d/30d/90d, list 5 thanh toán gần nhất. **Tab Khách hàng**: bảng leads + search + filter trạng thái + filter ngày + CSV export. **Tab Email marketing**: form soạn chiến dịch (tên + tiêu đề + body chọn định dạng **văn bản thường HOẶC HTML** + placeholder `{{name}}` + audience 4 loại all/paid/pending/last_days + tên người gửi) — có nút **Xem trước** mở modal iframe render đúng email thật (text → auto convert + wrap khung; HTML fragment → wrap khung, HTML đầy đủ giữ nguyên) → gửi bulk qua SMTP (reuse `nodemailer` của `biz-email-setup` — KHÔN

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Deploy landing page / website (React, Next.js, Vite, static HTML) lên Vercel — tự kiểm tra Vercel CLI hoặc Vercel MCP đã cài chưa, nếu chưa thì cài qua npm/pnpm và hướng dẫn user authenticate (vercel login), tự detect framework (Next.js / Vite / CRA / static), auto-generate vercel.json khi cần, chạy `vercel --prod`, trả về live URL + inspect URL + hướng dẫn custom domain. USE WHEN user says 'deploy lên vercel', 'đẩy landing page lên vercel', 'publish website', 'go live', 'deploy nextjs', 'deploy react', 'deploy vite', 'tạo URL live', 'đưa lên production', 'biz-deploy-vercel', 'host landing page', 'vercel deploy', 'ship lên vercel', 'đẩy code lên vercel'. Skill này áp dụng cho cả case dùng Vercel CLI lẫn Vercel MCP server.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Setup SMTP-based email auto-responder cho landing page bán hàng — tự động gửi email sau khi user điền form (tên/SĐT/email), KHÔNG cố định vào provider nào. Skill này (1) hỏi user chọn SMTP provider (Gmail/Google Workspace, Resend SMTP, SendGrid, Mailgun, Brevo, Zoho, hoặc SMTP custom của hosting VN) và detect Next.js stack đang dùng, (2) đọc context từ `offer.json` + `conversion-copy.md` (từ `/biz-offer-alex-hormozi`) HOẶC đọc trực tiếp Next.js project đã build qua `ui-ux-pro-max` (file `app/page.tsx`) HOẶC đọc HTML landing page đã deploy để hiểu offer, dream outcome, mechanism, bonus. Lưu ý: skill `biz-sales-page-layout` đã DEPRECATED 2026-05-14 — pipeline mới skip layout/copy.json, (3) **draft 2 email**: email A — auto-responder gửi cho lead (warm welcome + deliver lead magnet/booking confirm/payment link tuỳ offer type), email B — notification gửi cho owner (lead alert + thông tin liên hệ), (4) **show draft cho user duyệt và chỉnh sửa** trước khi wire vào code, (5) cài `nodemailer`

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Cài chatbot AI dạng floating widget góc dưới phải vào project Next.js có sẵn (App Router hoặc Pages Router), responsive đầy đủ web + tablet + mobile, gọi LLM qua OpenRouter (mặc định google/gemini-3-flash-preview, có thể đổi sang anthropic/claude-sonnet-4.6), streaming response, RENDER MARKDOWN trong assistant bubble (bold / list / link / code) qua react-markdown + remark-gfm — KHÔNG hiện raw **bold** dạng text — có knowledge base từ FAQ + tài liệu sản phẩm/khóa học do user cung cấp để chatbot tự động trả lời khách hàng, và TỰ ĐỘNG EXTRACT + LƯU LEAD (tên + SĐT + email) vào Upstash Redis/Vercel KV dưới namespace `chat-lead:{phone}` khi user cung cấp đầy đủ thông tin trong chat — dedupe theo SĐT, TTL 90 ngày, fire-and-forget không block stream. Skill tự detect số lượng project Next.js — nếu có nhiều hơn 1 sẽ hỏi user chọn project nào để cài; tự detect TypeScript/JS, App Router/Pages Router, Tailwind/CSS module, KV/Upstash availability (skip auto-save nếu chưa có); tự install react-markd

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Đóng gói offer **không thể chối từ** (grand slam offer) theo phương pháp Alex Hormozi ($100M Offers) — nhận input pains/gains/customer jobs theo Value Proposition Design (Osterwalder 2014) + sản phẩm/dịch vụ, rồi sinh ra: (1) markdown report tiếng Việt đầy đủ Value Equation scoring + Core Offer + 3-4 Bonus stack + Guarantee + Urgency + Pricing, (2) offer.json structured cho pipeline downstream (`ui-ux-pro-max` build sales page production-ready), (3) conversion copy block (headline + subheadline + CTA) sẵn sàng paste landing page. 2 input mode: (B) user paste sẵn pains + gains + product, (C) user chỉ có sản phẩm — skill phỏng vấn theo VPD framework để surface pain/gain trước. Bonus stack mode hybrid: skill brainstorm 5-7 candidate có justification value rồi user pick/chỉnh 3-4 cái. Tiếng Việt thuần (xưng anh/chị), giá VND charm pricing (X99K), 3-tier decoy structure. USE WHEN user says 'đóng gói offer', 'tạo offer', 'thiết kế offer Hormozi', 'grand slam offer', 'value stack', 'offer sta

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Nâng cấp copy sales page tiếng Việt — biến copy có sẵn (từ `offer.json` + `conversion-copy.md` của `/biz-offer-alex-hormozi`, HOẶC từ Next.js project đã build qua `ui-ux-pro-max`, HOẶC user paste block copy bất kỳ) thành **copy chất lượng cao chốt đơn**: headline punchy hơn, pain agitation đau hơn, mechanism rõ hơn, benefit cụ thể hơn, FAQ xử lý đúng objection của thị trường VN, CTA mạnh hơn. Skill này có 3 INTENSITY LEVEL: (1) **Polish** — light edit + power word + sửa nhịp; (2) **Conversion-optimized** — rewrite 5 block critical + tạo A/B variants cho hero/CTA; (3) **Sales-letter** — long-form story-driven full rewrite kèm P.S.. Mỗi section áp dụng đúng formula thuyết phục (PAR cho pain, BAB cho solution, FEP cho benefit, PVEN cho final CTA, Star-Chain-Hook cho testimonial). Output gồm 4 file: `copy-upgraded.md`, `copy-variants.md` (A/B test bank — 3 hero + 3 CTA + 3 final-CTA), `copy-changes.md` (diff Trước/Sau + lý do), `copy.json` (structured downstream). Giọng văn tiếng Việt thuầ

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

⚠️ DEPRECATED (2026-05-14) — Skill này KHÔNG còn trong pipeline chuẩn. Quy trình mới đã bỏ bước wireframe markdown trung gian: sau `/biz-offer-alex-hormozi` đi THẲNG sang `ui-ux-pro-max` để build Next.js sales page production-ready (có design language nhất quán: style + palette + font pairing, không phải Tailwind defaults). Lý do deprecate: wireframe markdown làm thêm 1 bước trung gian không tạo giá trị — `ui-ux-pro-max` đọc trực tiếp `offer.json` đã đầy đủ anchor + core + bonus + guarantee + urgency + pricing rồi ra HTML production luôn. Chỉ dùng skill này KHI user EXPLICITLY yêu cầu wireframe markdown để review/in/share trước khi build code (rare case). KHÔNG trigger trên các keyword 'tạo sales page', 'tạo landing page bán hàng' nữa — những keyword đó giờ trigger `ui-ux-pro-max`.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Setup Telegram bot notification cho thanh toán thành công từ Sepay webhook trong Next.js project. Skill này: (1) hướng dẫn user 3 bước tạo Telegram bot riêng qua @BotFather + lấy bot token + chat_id (qua @userinfobot cho chat 1-1, hoặc /getUpdates API cho group), (2) tạo helper function `sendTelegramNotification()` reusable trong `lib/telegram.ts`, (3) detect existing Sepay webhook route trong project (thường là `/api/sepay-webhook`, `/api/payment-success`, hoặc tương đương) và wire Telegram call CÙNG CHỖ với email auto-responder (Resend) — gửi parallel qua `Promise.allSettled` để Telegram fail KHÔNG block 200 response trả Sepay (Sepay sẽ retry webhook nếu nhận non-200, gây duplicate notification), (4) draft message format mặc định tiếng Việt: emoji + tên khách + SĐT + email + amount (charm pricing VND định dạng `499.000đ`) + tên sản phẩm + timestamp giờ VN dd/mm/yyyy HH:mm, (5) update `.env.local` với `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID`, add vào `.gitignore`, nhắc user paste vào

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Convert a single MP3 voiceover file into a single HeyGen avatar lip-sync MP4 video. Single-purpose — no planning, no SRT, no chunking, no Remotion compositing. Hybrid path — REST upload (helper script) + HeyGen MCP for video creation, because the post-2026 MCP no longer exposes an asset-upload tool. Reads avatar look pool (`HEYGEN_AVATAR_LOOKS`) from `.env` and HeyGen API key (`HEYGEN_API_KEY`) for the upload step. USE WHEN user says "tạo video heygen từ mp3", "mp3 to heygen", "heygen mp4 từ audio", "convert mp3 sang heygen video", "tạo avatar video từ file mp3", "lip sync mp3 heygen", "biến mp3 thành video heygen", or any time the user has exactly one MP3 file and wants exactly one HeyGen avatar MP4 out.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Demand-side market research cho digital product / service ở Việt Nam — đo cầu thật + WTP + channel-market fit + defensibility qua keyword volume, marketplace sales (Shopee/Unica/Edumall/Gitiho/KyNa), community signal (FB groups, TikTok hashtag, Zalo OA), competitor pricing, unit economics — không phải macro PESTEL. Output: keyword portfolio + Niche Score 100 điểm 7-dimension có evidence + go/no-go decision + falsification protocol. Force triangulate ≥3 sources cho mỗi claim quan trọng. USE WHEN user says 'nghiên cứu thị trường', 'market research', 'validate niche', 'keyword research', 'demand validation', 'niche có nên làm không', 'có ai làm chưa', 'thị trường đủ lớn không', 'có lời không', 'chọn ngách', 'kiểm tra cầu'. Cũng trigger khi user mô tả 1 ý tưởng kinh doanh cụ thể và muốn check feasibility. Skill này KHÔNG fit: high-ticket transactional sale (BĐS, ô tô), B2B enterprise (sales cycle 6+ tháng), hyper-local geo micro-market (1 toà nhà, 1 phường). KHÔNG làm: macro PESTEL/Porter

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Transcribe an MP3 voiceover into an SRT subtitle file and a word-level segments JSON using local OpenAI Whisper. Input is a single MP3 path; output is `<stem>.srt` + `<stem>_segments.json` written next to the MP3 (or to a custom output dir). USE WHEN the user says 'extract srt from mp3', 'trích srt từ mp3', 'transcribe voiceover', 'tạo file srt và segments', 'whisper transcribe', 'bóc transcript có timestamp', 'extract voiceover segments', 'tách SRT từ audio', or any time a downstream skill (plan-short-video-edit, heygen-remotion-short-video-editor) needs an SRT + word-level segments JSON from a voiceover MP3 and one does not already exist.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Convert Vietnamese/English script text to MP3 voiceover using ElevenLabs TTS API. Calls POST /v1/text-to-speech/{voice_id}, streams audio bytes, writes MP3 directly. Locked to Hoang's brand voice ID by default. USE WHEN user says 'tạo mp3 elevenlabs', 'elevenlabs tts', 'eleven labs voice', 'text to speech elevenlabs', 'tạo voiceover elevenlabs', 'đọc text bằng elevenlabs', 'tts elevenlabs to mp3', 'eleven labs script to mp3', 'voiceover bằng elevenlabs', 'giọng elevenlabs'.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

End-to-end orchestrator: **script → final MP4 16:9 (1920×1080) podcast-keynote**.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

End-to-end short-video pipeline — từ kịch bản (Việt/Anh) ra MP4 TikTok/Reels 9:16 hoàn chỉnh. Orchestrator 3 phase ghép skill có sẵn — (1) TTS provider chọn được giữa `mkt-elevenlabs-tts-to-mp3` (default, voice của Hoàng) hoặc `mkt-video-script-to-mp3` (MiniMax speech-2.8-hd), (2) checkpoint user duyệt MP3, (3) `heygen-mp3-to-mp4` lip-sync avatar HeyGen, (4) delegate Phase 3 packaging cho sub-agent `mkt-full-video-phase3-packager` (transcribe + scene outline + checkpoint + fan-out N scene writers parallel + scaffold + preview Studio). API key + voice ID cho cả 2 provider lưu ở `.env`. USE WHEN user nói "tạo full video từ script", "script to tiktok video", "pipeline full video heygen + hyperframe", "tạo video từ kịch bản đến mp4", "elevenlabs heygen hyperframe full pipeline", "minimax heygen pipeline", "kịch bản ra video tiktok", hoặc có sẵn 1 script + (optional) ảnh b-roll và muốn ra MP4 9:16 đóng gói có captions, SFX, b-roll.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Build a TikTok/Reels/YouTube **landscape 16:9 (1920×1080)** short video from a pre-recorded talking-head MP4 using HyperFrames — transcribe Vietnamese audio, scaffold a complete preview-ready 1920×1080 project with a slide pane (1200px) on the left and a floating avatar frame on the right, GSAP timeline có SPLIT↔PIP transitions (slide full-screen + avatar PIP corner thumbnail), breathing yoyo zoom + beat-driven punch-in trên avatar, 5 scene compositions kiểu "tier-row" pattern (post-stack hook / chats-stack problem / hero-orb solution / counter-row recap / terminal-row CTA), optional cream-paper editorial infographic image slots với `<img onerror>` fallback, 6 SFX wired tại scene boundaries, **NO captions** (giọng avatar là spine). USE WHEN user nói "edit video 16:9 từ HeyGen MP4", "scaffold project landscape", "podcast keynote editor", "talking head + slide editor", "build hyperframes 1920×1080", "tạo project 16:9 từ avatar mp4", "scaffold 16:9 hyperframes", "hyperframe landscape vide

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Pipeline đóng gói: từ MP4 quay sẵn (talking head 9:16) tới HyperFrames preview project hoàn chỉnh có captions, SFX, zoom hooks, b-roll toàn cảnh có hiệu ứng rich, và CTA finale.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Audit bài Facebook / Reels / YouTube để phát hiện 4 downward drivers (over-branding, over-production, stock imagery, standardized aesthetic) + frequency-over-quality. Mỗi anti-pattern bị drop ~75% performance nếu hiện diện. USE WHEN user says 'audit content', 'check anti pattern', 'content có lỗi gì không', 'kiểm tra over branding', 'vì sao video bị chết', 'vì sao post không ai xem', 'content audit', 'kiểm tra chất lượng content'.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Tìm viral pattern ở ngành khác (bác sĩ, luật sư, tài chính, bất động sản, thủ công) có thể apply cho niche AI/automation của Hoang. Ngách AI educator VN còn ít format được khai thác — cross-industry adaptation là blue ocean. USE WHEN user says 'tìm format ngành khác', 'cross industry research', 'học format từ ngành khác', 'blue ocean format', 'tìm format chưa ai làm', 'adapt format từ niche khác', 'cross industry viral'.

lexuanthanhhy/MKT.LANDINGPAGE.SKILLS

Rewrite CTA kiểu autocratic (Mua ngay! Follow ngay! Đăng ký liền!) sang 3 variants Democratic / Benevolent / Laissez-faire — reach 85% dân số thay vì chỉ 5% (action-based). Áp dụng cho landing page, caption FB, CTA video, email. USE WHEN user says 'rewrite cta', 'sửa cta', 'cta không autocratic', 'viết lại kêu gọi hành động', 'cta cho landing page', 'cta nhẹ nhàng hơn', 'inclusive cta', 'cta democratic benevolent'.

관련 스킬