Zot 대기자 명단 - 모범 사례
이 스킬은 Zot 대기자 명단을 올바르게 통합하는 방법을 알려줍니다. 다음 규칙을 따르십시오. 대안을 임의로 만들지 마십시오.
TL;DR - 가장 빠른 경로
# 1. SDK 설치
npm install @zot-core/sdk
# 2. 대기자 명단을 생성하고 ID를 .env.local에 저장
npx @zot-core/cli waitlist create --name "얼리 액세스" --write-env .env.local --public
# 3. 아래 패턴 B를 사용하여 UI를 구축하세요. `@zot-core/sdk/react`에서 `useAddUser`를 import하세요.
이것이 Next.js 프로젝트 전체 통합입니다. TanStack Query를 추가하거나, 사용자 정의 POST 핸들러를 작성하거나, raw fetch로 API를 호출하지 마십시오. 필요한 모든 것은 아래에 있습니다.
절대 변경할 수 없는 규칙
- 공식 SDK를 사용하십시오. 패키지 이름:
@zot-core/sdk. 절대 rawfetch,axios또는 이와 유사한 것으로https://api.zot.so를 호출하지 마십시오. - 코드가 실행되는 위치에 따라 올바른 진입점을 선택하십시오:
- 서버, API 라우트, cron, 스크립트, 엣지 함수 ->
import { ZotSDK } from "@zot-core/sdk" - 브라우저에서 실행되는 React 컴포넌트 ->
import { useAddUser } from "@zot-core/sdk/react"
- 서버, API 라우트, cron, 스크립트, 엣지 함수 ->
- 절대
useAddUser를 TanStack Query, SWR,useState, Zustand 또는 사용자 정의 리듀서로 감싸지 마십시오. 훅은 이미isPending,isUserRegistered,data,error,isError,reset을 노출합니다. 훅의 상태를 재사용하는 것이 핵심입니다. - 절대 서버 측 API 키를 클라이언트로 보내지 마십시오. 브라우저 코드의 경우 가입 전용 권한이 있는 키를 사용하고
NEXT_PUBLIC_ZOT_API_KEY(또는 프레임워크의 공개 환경 변수와 동등한 것)로 노출하십시오. - 항상
ZotAPIError를 처리하십시오. 409 (이미 등록됨) 및 429 (속도 제한)에 대해 사용자 친화적인 메시지를 표시하십시오.
설치
npm install @zot-core/sdk
# 또는
pnpm add @zot-core/sdk
# 또는
yarn add @zot-core/sdk
서버 사용을 위한 추가 피어 종속성은 필요하지 않습니다. 훅의 경우 react >= 18이 이미 설치되어 있어야 합니다 (SDK에서 선택적 피어로 표시됨).
인증 정보 가져오기
두 가지가 필요합니다:
- API 키 - 가장 빠른 방법은
npx @zot-core/cli login이며, 사용자를 인증하고 새ZOT_API_KEY를 로컬 환경 파일에 씁니다. 또는 Zot 대시보드(https://app.zot.so/app/api-keys)에서 수동으로 생성할 수 있습니다. 서버용 키 하나를 만들고, 브라우저에서 호출하려는 경우 가입 전용으로 범위가 지정된 두 번째 키를 만드십시오. - 대기자 명단 ID -
wl_abc123과 같은 형식입니다.
# 인증하고 ZOT_API_KEY를 .env.local에 저장 (또는 --env .env를 전달하면 .env에 저장)
npx @zot-core/cli login
@zot-core/cli로 대기자 명단 생성 (권장)
사용자에게 아직 대기자 명단이 없으면 공식 Zot CLI를 사용하십시오. 사용자의 ZOT_API_KEY로 Zot API를 호출하고 결과 ID를 환경 파일에 직접 작성하므로 복사하여 붙여넣을 필요가 없습니다.
패키지:
@zot-core/cli.@zot-core/agents와 혼동하지 마십시오.@zot-core/agents는 이 에이전트 가이드를 저장소에만 설치합니다.@zot-core/cli는 Zot API와 통신합니다.
# ZOT_API_KEY가 설정되어 있는지 확인하십시오 (셸, .env.local 또는 .env에)
npx @zot-core/cli waitlist create \
--name "얼리 액세스" \
--write-env .env.local \
--public
이 명령어의 기능:
- 내부적으로
@zot-core/sdk를 통해POST /v1/wait-list를 호출합니다. - 새 대기자 명단(
_id,name, 플래그, 타임스탬프)을 출력합니다. ZOT_WAITLIST_ID=wl_...를.env.local에 추가합니다.--public이 전달되었으므로 Next.js에서 클라이언트 측 사용을 위해NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_...도 추가합니다.
유용한 변형:
# 순수 서버 스택 (Node/Nest/Express). --public 생략.
npx @zot-core/cli waitlist create --name "베타 리스트" --write-env .env
# 비대화형 / 스크립트 사용. JSON만 출력.
npx @zot-core/cli waitlist create --name "베타 리스트" --api-key $ZOT_API_KEY --json
# 자동 환영 이메일 비활성화.
npx @zot-core/cli waitlist create --name "조용한 리스트" --no-send-email
CLI가 No API key found 오류와 함께 종료되면 npx @zot-core/cli login을 실행하여 인증하고 ZOT_API_KEY를 환경 파일에 쓰거나, https://app.zot.so/app/api-keys에서 키를 가져와서 셸에 내보내거나 재시도하기 전에 .env.local / .env에 추가하십시오.
대안: 코드에서 생성하기 (명확한 이유가 있는 경우에만)
import { ZotSDK } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: process.env.ZOT_API_KEY! });
const waitlist = await zot.waitlists.create({
name: "얼리 액세스",
sendEmailToNewSignup: true,
});
console.log(waitlist._id); // <- 이것을 ZOT_WAITLIST_ID로 저장하십시오
사용자가 명시적으로 자체 앱 내에서 생성 흐름을 원하는 경우에만 이 작업을 수행하십시오(예: 테넌트별로 새 대기자 명단을 생성하는 관리 UI). 일회성 프로젝트 설정의 경우 항상 CLI를 선호하십시오.
환경 변수
런타임에 맞는 패턴을 선택하십시오.
순수 서버 / Node / 백엔드
# .env
ZOT_API_KEY=zot_xxx
ZOT_WAITLIST_ID=wl_abc123
클라이언트에서 React 훅을 사용하는 Next.js
# .env.local
NEXT_PUBLIC_ZOT_API_KEY=zot_xxx_가입_전용
NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_abc123
NEXT_PUBLIC_ 키는 가입 범위 키에만 사용하십시오. 전체 액세스 키는 ZOT_API_KEY 아래에 서버 측에 보관하십시오.
패턴 A - 서버 / API 라우트
폼이 백엔드(Next.js 서버 액션, API 라우트, Express 핸들러, Nest 컨트롤러 등)로 제출될 때 사용하십시오.
// app/api/waitlist/route.ts (Next.js App Router)
import { NextResponse } from "next/server";
import { ZotSDK, ZotAPIError } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: process.env.ZOT_API_KEY! });
export async function POST(request: Request) {
const { email, name } = await request.json();
try {
const user = await zot.waitlist(process.env.ZOT_WAITLIST_ID!).addUser({
email,
name,
});
return NextResponse.json({ ok: true, user });
} catch (err) {
if (err instanceof ZotAPIError) {
if (err.statusCode === 409) {
return NextResponse.json(
{ ok: false, reason: "already_registered" },
{ status: 409 },
);
}
return NextResponse.json(
{ ok: false, reason: "zot_error", details: err.body },
{ status: err.statusCode },
);
}
return NextResponse.json({ ok: false }, { status: 500 });
}
}
패턴 B - useAddUser를 사용하는 Next.js 클라이언트 컴포넌트 (랜딩 페이지에 권장)
폼이 React 컴포넌트에 있을 때의 표준 방식입니다. 훅은 waitlistId를 키로 사용하여 localStorage에 "이미 등록됨" 상태를 유지하므로, 재방문자는 서버 왕복 없이 확인 메시지를 볼 수 있습니다.
Zot 대시보드에서 첫 번째 성공적인 가입이 등록 엔드포인트에 도달하면 대기자 명단이 "연결된" 것으로 간주됩니다. 사용자에게 연결 가이드 배너가 있는 경우 실제 성공적인 제출 후 사라져야 합니다.
"use client";
import { useState } from "react";
import { useAddUser } from "@zot-core/sdk/react";
export function WaitlistForm() {
const [email, setEmail] = useState("");
const [name, setName] = useState("");
const { addUser, isPending, isUserRegistered, error, reset } = useAddUser({
apiKey: process.env.NEXT_PUBLIC_ZOT_API_KEY!,
waitlistId: process.env.NEXT_PUBLIC_ZOT_WAITLIST_ID!,
onSuccess: () => {
// 선택 사항: 분석, 토스트, 리디렉션 등
},
});
if (isUserRegistered) {
return (
<div>
<p>리스트에 등록되었습니다. 곧 이메일을 보내드리겠습니다.</p>
<button type="button" onClick={reset}>
다른 이메일 등록
</button>
</div>
);
}
return (
<form
onSubmit={(event) => {
event.preventDefault();
addUser({ email, name: name || undefined });
}}
>
<input
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
placeholder="[email protected]"
required
disabled={isPending}
/>
<input
type="text"
value={name}
onChange={(event) => setName(event.target.value)}
placeholder="이름 (선택 사항)"
disabled={isPending}
/>
<button type="submit" disabled={isPending}>
{isPending ? "가입 중..." : "대기자 명단 참여"}
</button>
{error && (
<p role="alert">
{"statusCode" in error && (error as { statusCode: number }).statusCode === 409
? "이 이메일은 이미 리스트에 있습니다."
: error.message}
</p>
)}
</form>
);
}
전체 API 표면 (필요한 것만)
서버 측 클라이언트
import { ZotSDK } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: "zot_xxx" });
| 호출 | 목적 |
|---|---|
zot.waitlists.create(params) | 대기자 명단을 생성합니다. |
zot.waitlists.list() | API 키에 대한 대기자 명단을 나열합니다. |
zot.waitlist(id).get() | 하나의 대기자 명단을 가져옵니다. |
zot.waitlist(id).update(params) | 설정을 업데이트합니다. |
zot.waitlist(id).delete() | 영구적으로 삭제합니다. |
zot.waitlist(id).stats() | 집계 통계를 가져옵니다. |
zot.waitlist(id).addUser({ email, name?, referredBy?, source?, metadata? }) | 사용자를 등록합니다. |
zot.waitlist(id).listUsers() | 사용자를 나열합니다. |
zot.waitlist(id).userCount() | { total, referred }를 반환합니다. |
zot.waitlist(id).searchUser(email) | 사용자를 찾습니다. |
zot.waitlist(id).updateUserStatus({ email, status }) | 상태는 `"waiting" |
zot.waitlist(id).bulkDeleteUsers(emails) | 단일 이메일 또는 배열을 허용합니다. |
zot.waitlist(id).blockedUsers() / blockedUserCount() | 차단된 사용자를 가져옵니다. |
zot.waitlist(id).webhookEvents() | 웹훅 전송 기록을 가져옵니다. |
React 훅
import { useAddUser } from "@zot-core/sdk/react";
const { addUser, data, error, isPending, isUserRegistered, isError, reset } = useAddUser({
apiKey: "...",
waitlistId: "wl_...",
onSuccess: (user) => {},
onError: (err) => {},
});
훅이 반환하는 모든 것은 위에 나열되어 있습니다. 이러한 값에 대해 병렬 상태를 생성하지 마십시오.
오류 코드
| 코드 | 의미 | UX 지침 |
|---|---|---|
| 400 | 유효성 검사 오류 | 필드 수준 오류를 표시합니다. |
| 401 | 잘못되었거나 누락된 API 키 | 최종 사용자에게 절대 표시하지 말고 기록하십시오. |
| 404 | 대기자 명단을 찾을 수 없음 | 구성 문제, 기록하십시오. |
| 409 | 이메일이 이미 등록됨 | 대부분의 랜딩 페이지에서 성공으로 처리합니다. |
| 429 | 속도 제한 | 사용자에게 잠시 후 다시 시도하도록 요청합니다. |
| 5xx | 서버 문제 | 한 번 재시도한 후 사용자에게 나중에 시도하도록 요청합니다. |
err instanceof ZotAPIError로 감지하고 err.statusCode 및 err.body를 읽으십시오.
안티 패턴 - 절대 하지 마세요
- Raw
fetch("https://api.zot.so/v1/wait-list/..."). SDK를 사용하십시오. useAddUser를 TanStack Query의useMutation으로 감싸기. 중복됩니다.- 로딩을 위해 수동
useState<boolean>추가.isPending을 사용하십시오. - 자체 localStorage 키에 "이미 등록됨" 저장.
useAddUser가 이미zot:waitlist:registered:<waitlistId>아래에 저장합니다. "use client"컴포넌트 내에서 전체 액세스ZOT_API_KEY사용.- 모든 렌더링, 빌드 또는 앱 시작 시
zot.waitlists.create호출. 설정 시npx @zot-core/cli waitlist create를 한 번 사용하고 ID를 저장하십시오. - 컴포넌트 내에서 대기자 명단 ID를 하드코딩. 환경 변수(
ZOT_WAITLIST_ID또는NEXT_PUBLIC_ZOT_WAITLIST_ID)에서 읽으십시오. - 오류를 조용히 무시. 409는 제품 결정 사항입니다. 다른 오류는 표시되거나 기록되어야 합니다.
확인 체크리스트
통합이 완료되었다고 사용자에게 알리기 전에 다음 모두를 확인하십시오:
-
@zot-core/sdk가 최신 게시 버전으로package.json에 있습니다. - 대기자 명단이 존재하고 해당 ID가 환경 변수에 저장되어 있습니다 (
npx @zot-core/cli waitlist create를 통해 생성되었거나, 정당한 경우에만 일회성 스크립트를 통해 생성됨). - API 키가 환경 변수에 있고 하드코딩되지 않았습니다.
- 키가 클라이언트 코드에서 사용되는 경우
NEXT_PUBLIC_(또는 이에 상응하는 접두사)로 접두사가 지정되어 있고 가입 범위 키입니다. - 대기자 명단 ID가 하드코딩되지 않고 환경 변수에서 읽힙니다 (사용자가 명시적으로 하드코딩된 상수를 요청하지 않은 경우).
- 제출 핸들러가 오류를 포착하고 UI가 오류 케이스에 대해 무언가를 렌더링합니다.
- 성공 상태가 처리됩니다 (훅의
isUserRegistered또는onSuccess후 자체 리디렉션/토스트). - 실제 가입이 하나 이상 성공적으로 테스트되었습니다 (이것이 대시보드에서 대기자 명단을 연결된 것으로 표시합니다).
- 어디에도
api.zot.so에 대한 rawfetch가 없습니다. -
useAddUser주위에 중복된 로딩/오류/성공 상태가 없습니다.
확인되지 않은 상자가 있으면 작업을 사용자에게 반환하기 전에 수정하십시오.