Zotウェイティングリスト - ベストプラクティス は何をしますか?
このスキルでは、Zot ウェイティングリストを正しく統合する方法を説明します。以下のルールに従ってください。代替案を発明しないでください。
TL;DR - 最短の道のり
# 1. SDKをインストール
npm install @zot-core/sdk
# 2. ウェイティングリストを作成し、そのIDを .env.local に保存
npx @zot-core/cli waitlist create --name "Early Access" --write-env .env.local --public
# 3. 「@zot-core/sdk/react」から `useAddUser` を使用してUIを構築 (以下のパターンB参照)
Next.js プロジェクトの統合はこれで全てです。TanStack Query を追加したり、カスタムのPOSTハンドラーを書いたり、生の fetch でAPIを呼び出したりしないでください。必要なものはすべて以下にあります。
絶対的なルール
- 公式SDKを使用する。 パッケージ名:
@zot-core/sdk。https://api.zot.soを生のfetch、axiosなどで呼び出さないでください。 - コードが実行される場所に基づいて正しいエントリポイントを選択する:
- サーバー、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はそれをオプションのピアとしてマークしています)。
認証情報を取得する
必要なものは2つです:
- APIキー - 最も簡単な方法は
npx @zot-core/cli loginを実行することです。これによりユーザーが認証され、新しいZOT_API_KEYがローカルの env ファイルに書き込まれます。または、Zotダッシュボード (https://app.zot.so/app/api-keys) から手動で生成することもできます。サーバー用のキーを1つ作成し、ブラウザから呼び出す予定がある場合は、サインアップのみにスコープされた2つ目のキーを作成します。 - ウェイティングリスト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を直接envファイルに書き込むため、コピーペーストの必要がありません。
パッケージ:
@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 "Early Access" \
--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 "Beta list" --write-env .env
# 非対話型 / スクリプトでの使用。JSONのみ出力。
npx @zot-core/cli waitlist create --name "Beta list" --api-key $ZOT_API_KEY --json
# 自動ウェルカムメールを無効にする。
npx @zot-core/cli waitlist create --name "Quiet list" --no-send-email
CLI が No API key found で終了した場合は、npx @zot-core/cli login を実行して認証し、ZOT_API_KEY を env ファイルに書き込むか、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: "Early Access",
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_signup_only
NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_abc123
NEXT_PUBLIC_ キーはサインアップのみにスコープされたキーにのみ使用してください。フルアクセスキーはサーバーサイドで ZOT_API_KEY として保持してください。
パターンA - サーバー / API ルート
フォームがバックエンド(Next.js Server Action、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() | 1つのウェイティングリストを取得する。 |
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() | Webhook配信履歴。 |
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 | レート制限 | 1分後に再試行するようにユーザーに依頼する。 |
| 5xx | サーバー問題 | 1回再試行し、その後ユーザーに後で再試行するように依頼する。 |
err instanceof ZotAPIError で検出し、err.statusCode と err.body を読み取ります。
アンチパターン - これらを行わないでください
- 生の
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を1回使用し、IDを保存してください。 - ウェイティングリストIDをコンポーネント内にハードコーディングする。env(
ZOT_WAITLIST_IDまたはNEXT_PUBLIC_ZOT_WAITLIST_ID)から読み取ってください。 - エラーを黙って無視する。409はプロダクトの判断です。それ以外は表面化またはログに記録する必要があります。
検証チェックリスト
統合が完了したことをユーザーに伝える前に、以下のすべてが確認されていることを確認してください:
-
@zot-core/sdkが最新の公開バージョンでpackage.jsonに存在する。 - ウェイティングリストが存在し、そのIDがenvに保存されている(
npx @zot-core/cli waitlist createによって作成された、または正当な理由がある場合のみワンタイムスクリプトによって作成された)。 - APIキーはenv変数にあり、ハードコーディングされていない。
- キーがクライアントコードで使用される場合、
NEXT_PUBLIC_(または同等のもの)がプレフィックスとして付けられており、かつサインアップのみにスコープされたキーである。 - ウェイティングリストIDはenvから読み取られ、ハードコーディングされていない(ユーザーが明示的にハードコーディングされた定数を要求した場合を除く)。
- 送信ハンドラーがエラーをキャッチし、UIがエラーケースに対して何かをレンダリングする。
- 成功状態が処理されている(フックの
isUserRegisteredまたはonSuccess後の独自のリダイレクト/トースト)。 - 少なくとも1つの実際のサインアップが正常にテストされている(これにより、ダッシュボードでウェイティングリストが接続済みとしてマークされます)。
-
api.zot.soへの生のfetchがどこにもない。 -
useAddUserの周りに重複したローディング/エラー/成功状態がない。
いずれかのチェックボックスがオフの場合、タスクをユーザーに返す前に修正してください。