podcast-guest-crm について
Podcast Guest CRMは、ポッドキャストのブッキングチームや代理店向けに、ゲストの発見からフォローアップまでを管理するフルスタックCRMです。6段階のパイプラインに、AIによる招待文、インタビュー準備資料、SNS投稿の生成を組み合わせています。
主な機能
- 016段階のゲストパイプライン
- 02AIによる個別化された招待文
- 03ゲストの適合度スコア
- 04インタビュー概要とSNS投稿
- 05フォローアップメールの連続作成
- 06パイプラインとアウトリーチの分析
活用シーン
- 01ゲストの発見からフォローアップまで追跡
- 02個別化された招待メールを作成
- 03質問と話題の要点を準備
- 04アウトリーチとパイプラインの傾向を確認
MCP 対応
タグラインでは、ゲストのパイプライン、招待文の下書き、分析を扱う5つのMCPツールに言及していますが、READMEの抜粋には名称や動作の説明がありません。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
5掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| page | integer | いいえ | ページ番号(デフォルトは 1) |
| limit | integer | いいえ | 1 ページあたりの結果数。最大 100(デフォルトは 20) |
| stage | enum | いいえ | ライフサイクルのステージで絞り込みますdiscover | outreach | scheduled | recorded | published | follow_up |
| search | string | いいえ | 氏名、会社、トピックをフリーテキスト検索します |
| priority | enum | いいえ | 優先度で絞り込むlow | medium | high |
詳細
🎙️ ポッドキャストゲスト CRM
技術スタックのバッジ一覧
ポッドキャストのブッキングを支えるオペレーティングシステム。
AIネイティブ。キーボードファースト。エージェンシー向け。

420万のポッドキャスト。400億ドル超のクリエイターエコノミー。専用に設計されたワークフローソフトウェアはゼロ。
この10年間、存在すべきだったツールを作りました。
Rudrendu Paul と Sourav Nandy が開発 & Claude Code でエンジニアリング
クイックスタート · 課題 · 製品 · AIレイヤー · アーキテクチャ · 技術スタック
クイックスタート
git clone https://github.com/RudrenduPaul/podcast-guest-crm
cd podcast-guest-crm
pnpm install
pnpm dev
アプリは初回起動時からシードデータで動作します。パイプラインの全6段階にわたる、現実的なゲスト34人分のデータが含まれています。環境変数は不要です。
web: http://localhost:3000
api: http://localhost:3001
docs: http://localhost:3001/docs ← Swagger UI, auto-generated from route schemas
メモ
ゼロ設定で利用できるのは、シードデータを使ってローカル開発モードで実行する場合のみです。本番環境へのデプロイでは、Supabase と Anthropic の実際の認証情報を環境変数に設定する必要があります。設計上、
packages/configの Zod 環境変数スキーマは、必須のシークレットが不足しているとサーバー起動時にクラッシュします。
課題
ポッドキャストのホストが使うツールは、どれも別の用途向けに作られています。 HubSpot は営業 CRM です。PodMatch はゲストを見つけるためのマーケットプレイスです。Notion は、実用的なものにするにはエンジニアリングが必要な白紙のキャンバスです。どれも、ゲストのライフサイクル(候補の発見から、アプローチ、スケジュール調整、収録、公開、フォローアップまでの一連の流れ)を中核的なオブジェクトとして扱っていません。
このツールはそれを実現します。ゲストとの適合度のスコアリング、パーソナライズされたアプローチ文の作成、インタビューの準備、フォローアップの一連の連絡は、claude-sonnet-4-6 を使って実行します。これにより、こうした特定の作業を自動化することが、数年前にはできなかった形で今では可能になっています。
製品
6つのページと11の機能を備え、細部へのこだわりに一切妥協しない、フルスタックのAIネイティブ CRM です。
コアワークフロー
Discover → Outreach → Scheduled → Recorded → Published → Follow-up
すべてのゲストが、このライフサイクルに沿って進みます。すべての遷移は検証され、記録され、適切に処理されます。システムは、すべてのゲストがどこにいるか、最後に連絡を受けたのはいつか、次に何をすべきかを把握しています。あなたが覚えておく必要はありません。
機能一覧
| 機能 | 内容 |
|---|---|
| Cmd+K パレット | 名前、会社、トピックでゲストを検索できます。6つのページすべてに移動できます。アクションを実行できます。すべてキーボードで操作できます。アプリ内のあらゆる機能に最速でアクセスできます。 |
| カンバンパイプライン | 6列のドラッグ&ドロップボードです。楽観的更新に対応しています。ライフサイクルのルールはサービスレイヤーで適用されます。「Discover」から「Published」へ直接進むことはできません。予約が確定するたびに紙吹雪が舞います。 |
| AI メール作成機能 | ゲストを選択して「Generate」をクリックします。AI がゲストに合わせた150~250語の提案文を、1文字ずつストリーミング表示します。スピナーではなく、タイプライターのような効果です。信頼度スコアも含まれます。 |
| インタビューブリーフ | 録音前のブリーフをワンクリックで作成できます。プロフィール紹介、対象に合わせた5種類の質問、話題のポイント、締めのフックが含まれます。そのままコピーできます。 |
| ソーシャル投稿 | LinkedIn の投稿、Twitter/X のスレッド(文字数表示付きの5件のツイート)、Instagram のキャプションを作成できます。プラットフォーム別のタブがあり、それぞれワンクリックでコピーできます。 |
| 通知センター | 通知ベルから常時表示されるドロップダウンです。7日以上返信がないゲストと、間近に迫った録音予定を表示します。いつでも表示され、すぐに対応できます。 |
| 今日の注目事項 | 今日対応が必要な項目を正確に表示するダッシュボードのセクションです。手動で優先順位を付ける必要はありません。 |
| ゲスト詳細 | アニメーション付きの適合度スコアリングリング(0からカウント)、ライフサイクルの進捗タイムライン、連絡先リンク一覧、生成パネルが3つあるAIアクションサイドバーを表示します。 |
| 分析 | ステージ別の棒グラフ、トピック別のドーナツグラフ、12週間のアプローチ活動のタイムライン、コンバージョン指標を表示します。バックエンドに依存せずに動作します。 |
| ゲスト追加モーダル | どこからでも Cmd+N で開けます。名前、メールアドレス、役職、会社、プロフィール、トピック、LinkedIn、Twitter、ステージ、優先度を入力できます。作成時に適合度スコアが自動生成されます。 |
| スマートなリマインダー | 返信がないままアプローチ中の状態が7日を超えたゲストがいる場合、ダッシュボードの読み込み時にトーストが表示されます。積極的に知らせますが、ゲストを名指しするだけで、しつこく催促するものではありません。 |
キーボードショートカット
このアプリは、キーボードを優先するワークフローを前提に設計されています。パワーユーザーは、主要なタスクでマウスを使う必要がありません。
| ショートカット | 操作 |
|---|---|
⌘K | コマンドパレットを開きます。ゲストの検索、移動、アクションの実行ができます |
⌘N | ゲスト追加モーダルを直接開きます |
↑ ↓ | パレットの検索結果を移動します |
↵ | 選択します |
Esc | モーダルを閉じます |
AI レイヤー
AI 関連の機能はすべて packages/ai にあります。コードベース内で @anthropic-ai/sdk をインポートするのはここだけです。各機能は型付けされた関数を呼び出します。SDK に直接アクセスすることはありません。
モードは2つあります。completeJSON<T>() はジェネリック型推論を使った構造化出力向け、stream() はリアルタイムのタイプライター効果向けです。アプローチ文の作成機能では、両方を同時に使います。ライブプレビューにはストリーミングを使い、信頼度スコア付きのコピー可能な結果には JSON を使います。
// packages/ai/src/client.ts. The single seam for all AI calls
export class ClaudeClient {
async completeJSON<T>(system: string, user: string): Promise<T>
async stream(system: string, user: string): AsyncIterable<string>
}
// Feature code never touches the SDK. It calls typed prompt functions:
const brief = await generateInterviewBrief(guest); // → InterviewBrief
const email = await draftOutreachEmail(guest, show); // → OutreachEmail
const score = await scoreGuestFit(guest, workspace); // → FitScore
プロンプトモジュール
| 機能 | ファイル | 出力 |
|---|---|---|
| アプローチメール | outreach-email.ts | 件名、150~250語の本文、信頼度スコア(0~100)、理由 |
| ゲスト適合度スコア | guest-research.ts | スコア、適合性の根拠、懸念事項、予約の難易度 |
| インタビューブリーフ | interview-brief.ts | プロフィール紹介、5種類の質問、話題のポイント、締めのフック |
| トピックのタグ付け | topic-tagging.ts | プロフィールと LinkedIn に基づく3~8個のタグ、主要カテゴリ、信頼度 |
| フォローアップの流れ | follow-up-sequence.ts | 3通のメール構成:7日目のリマインド、14日目のフォローアップ、21日目の最終連絡 |
| ソーシャル投稿 | social-post.ts | LinkedIn の投稿、Twitter のスレッド、Instagram のキャプション。トーンはプラットフォームごとに異なります |
プロンプトエンジニアリングのアプローチ
汎用的なプロンプトを使っているわけではありません。アウトリーチモジュールで実際に使用している制約セットを紹介します。具体性こそが優位性の源です。
export const OUTREACH_EMAIL_SYSTEM_PROMPT = `You are an expert podcast booking agent
working on behalf of a host with a specific audience and brand.
Your emails must:
1. Be authentic, specific, and not generic. Reference the guest's actual recent work
2. Clearly state the show's value proposition and the size and shape of the audience
3. Make the ask simple and low-friction. One clear question, not a pitch deck
4. Be concise: 150–250 words for the body
5. Have a subject line under 70 characters that doesn't feel like a cold email
6. NEVER use: "passionate", "synergy", "journey", "touch base", "hop on a call"
7. End with a single clear call-to-action. Not multiple options`;
適合度スコアリングのプロンプトでは、番組固有のトピック分類に照らしてゲストを評価します。汎用的な関連性の指標は使いません。インタビュー概要では、ポッドキャストの形式に合わせて調整した質問タイプ(掘り下げ、反対意見、将来展望)を生成します。これは製品設計としてのプロンプトエンジニアリングであり、ちょっとした見せ物としてのプロンプトエンジニアリングではありません。
アーキテクチャ
システム図
Browser (Next.js 14 App Router)
├── TanStack Query v5 : server state, optimistic updates, stale-while-revalidate
│ every query falls back to seed data on API error
├── Zustand : UI state (sidebar, modals, ⌘K palette, filters)
│ persisted to localStorage via middleware
├── lib/api.ts : typed fetch wrapper; catches 503, returns seed data
└── components/ : shadcn/ui primitives + Framer Motion feature components
│ HTTP/REST + JWT (Bearer token)
▼
Fastify v5 API (Node.js 20, TypeScript strict mode)
├── Plugins: CORS (allowlist), @fastify/rate-limit (100/min), @fastify/jwt, swagger-ui
├── Routes: /guests, /outreach, /ai, /analytics ← all require authentication
├── Middleware: Zod schemas on every route. Body, query params, path params
└── Services: guestService (in-memory store seeded from packages/db on startup)
│ │
▼ ▼
packages/db packages/ai
Drizzle ORM schema + ClaudeClient +
34 seed guests 6 typed prompt modules
SQLite (dev) │
Turso (prod) ▼
Anthropic API
claude-sonnet-4-6
知っておく価値のある5つのアーキテクチャ上の決定
1. 共有型はpackages/typesに置き、apps/内にインラインで定義しない。
API 境界を越えるすべてのインターフェース(Guest、OutreachEmail、Workspace、AnalyticsOverview)を単一のパッケージに置き、API とウェブアプリの両方からインポートします。フロントエンドで TypeScript エラーが発生すれば、API の契約が壊れていることを出荷前に検知できます。
2. AI の接点をpackages/aiに一本化する。
@anthropic-ai/sdkをインポートするのはClaudeClientだけです。429および5xxエラー時の指数バックオフ、呼び出しごとのトークン追跡、JSON レスポンスからの Markdown 除去、AsyncIterableによるストリーミングを処理します。機能コードは型付けされた関数を呼び出すだけで、SDK の存在を意識しません。モデルやプロバイダーの切り替えは、1つのファイルを変更するだけです。
3. グレースフルデグラデーションは後付けではなく、設計要件です。 すべての TanStack Query フックは API エラーを捕捉してシードデータを返します。すべてのミューテーションには合成フォールバックがあります。バックエンドが稼働していなくても、アプリは完全に操作できます。これは意図的な設計です。サーバーのダウンによってデモが失敗することがあってはなりません。
4. ロールバックを必須とする楽観的更新。
カンバンボードでのステージ遷移は UI 上ですぐに反映されます。サーバーは非同期で確定します。サーバーが遷移を拒否した場合(ライフサイクルのルールは厳格で、discoverからpublishedへ直接移動することはできません)、以前の状態に戻し、エラートーストを表示します。ドラッグ&ドロップの反映をユーザーが待つ必要はありません。状態を破損させることなく、エラーが明確に通知されます。
5. あらゆる境界で Zod を使用する。
必須シークレットが不足している場合、環境変数のスキーマによってサーバーは起動時にクラッシュします。設定ミスを黙って見過ごすより、はっきりと失敗するほうが望ましいためです。すべての API ルートに、ボディ、クエリ、パラメーター用の Zod スキーマがあります。CI パイプラインは、スキーマのないルートを拒否します。共有スキーマはpackages/configに置き、フロントエンドとバックエンドで同一の契約を適用します。
サブエージェントアーキテクチャ(Claude Code)
このコードベースは、ドメインごとに範囲を限定した4つの専門 Claude Code サブエージェントを並行して稼働させて構築しました。これはワークフロー上の好みではありません。ツール層で強制されるアーキテクチャ上の分離です。
| エージェント | 制約ファイル | 担当範囲 |
|---|---|---|
| UI エージェント | .claude/agents/ui-agent.md | apps/web/のみ。必要な場合に限りuse clientを使用。すべてのリストアニメーションに Framer Motion を使用。 |
| DB エージェント | .claude/agents/db-agent.md | packages/db/のみ。スキーマ、シード、マイグレーションを担当。ルートや UI には触れられません。 |
| AI 機能エージェント | .claude/agents/ai-features-agent.md | packages/ai/のみ。プロンプト、ストリーミング、JSON モードを担当。anyやハードコードされた番組コンテキストは使用しません。 |
| テストエージェント | .claude/agents/test-agent.md | 他のエージェントが構築したすべてのものをテスト。マージ前にカバレッジ70%超が必須。 |
UI エージェントは Drizzle クエリを書けません。DB エージェントは React コンポーネントを作成できません。制約がアーキテクチャになります。 UI の変更によってスキーマが気付かないうちに変更されていないか、疑う必要がなくなります。
.claude/commands/内のカスタムスラッシュコマンド:
/new-feature <name>:機能一式(API ルート+Zod スキーマ+サービス+ページ+コンポーネント+TanStack フック+テスト)のひな型を生成/review-pr:マージ前に、セキュリティ、型安全性、MLP のチェックリストを実行
MLP:クラフトの基準
「素早くリリースする」ことの優位性は、もう失われました。有能な開発者なら、週末のうちに CRM の骨組みを作れます。私たちのソリューションなら、それを数時間に短縮できます。今や差別化の鍵は、クラフトです。その時間で作り上げるものの品質です。
すべての PR で、Minimum Lovable Product の基準を満たすことを求めます。Elena Verna の表現を借りれば、製品がユーザーに単なる十分な実用性ではなく、心から愛されるようになる水準です。
意図して作り込んだ体験:
- 予約時の紙吹雪。 ゲストが「Scheduled」に移動すると、紙吹雪が舞います。予約確定は本当にうれしい出来事です。アプリもそう扱うべきです。
- AI 出力のタイプライター効果。 生成されたメールが、1 文字ずつ表示されます。ストリーミングによって、ツールを待つのではなく、共同作業者と一緒に取り組んでいる感覚が生まれます。
- フィットスコアのカウントアップ。 リングが 600ms かけて 0 から実際のスコアまでアニメーションします。ユーザーはその様子を見ています。この待ち時間が、スコアを自分で獲得したもののように感じさせます。
- コマンドパレット。 ⌘K ですべてのゲスト、ページ、アクションに、キーを 1 回押すだけでアクセスできます。パワーユーザーがマウスに手を伸ばす必要はありません。
- 今日のフォーカス。 ダッシュボードでは、今日注意を向けるべき相手(停滞しているアプローチ、近日予定の収録)がひと目でわかります。何を確認すべきか覚えておく必要はありません。
- 名前付きのリマインダー。 「Sara から 8 日間返信がありません」は、「フォローアップが 3 件保留中」よりもわかりやすく、具体的で、行動につながります。
- 空の状態に個性のあるコピーを表示。 「発見リストは空です。次のすばらしいエピソードは、あと 1 件のアプローチで実現します」と伝えれば、次に何をすべきかわかります。「データが見つかりません」では伝わりません。
MLP チェックリスト。すべての PR で必須です:
- 空の状態には、「データが見つかりません」ではなく、個性のあるコピーがある
- 読み込み中の状態では、空白の画面ではなく
Skeletonコンポーネントを使う - エラーには、「問題が発生しました」ではなく、次に取るべき行動がわかるメッセージがある
- 重要なインタラクションに Framer Motion のアニメーションがある
- 驚きと感動をもたらす瞬間は何ですか? なければ、マージする前に見つけてください。
料金
2 段階の SaaS です。顧客の成長に合わせて拡張できる、シンプルな料金体系です。
| プラン | 料金 | 対象 |
|---|---|---|
| Solo | $29/month | 1 番組を管理し、年間 20~100 人のゲストを扱う個人ポッドキャストホスト |
| Agency | $99/month | 3 番組以上と年間 200 件以上の売り込みを管理するブッキングエージェンシー |
基本プランを超える AI クレジットは使用量に応じた料金です。月 200 回までの AI 呼び出し(アプローチメール、フィットスコア、ブリーフ、ソーシャル投稿)は含まれ、それを超えた分はチームの使用量に応じて課金されます。
競合状況
違いは機能ではありません。考え方のモデルです。
| Google Sheets | HubSpot / Pipedrive | PodMatch | Podcast Guest CRM | |
|---|---|---|---|---|
| ゲストのライフサイクル(6 段階) | 手動 | カスタムフィールドが必要 | ❌ | 標準搭載、必須化 |
| AI によるアプローチ(パーソナライズ) | ❌ | ❌ | ❌ | ストリーミング、信頼度スコア |
| ゲストの適合度スコア | ❌ | ❌ | 基本機能 | トピックとの適合度を AI が採点 |
| インタビュー用ブリーフ | ❌ | ❌ | ❌ | ワンクリックで作成、すぐにコピー可能 |
| フォローアップシーケンス(AI) | ❌ | アドオン($$$) | ❌ | 3 通のメール構成、AI が作成 |
| ソーシャル投稿ジェネレーター | ❌ | ❌ | ❌ | LinkedIn + Twitter + Instagram |
| コマンドパレット(⌘K) | ❌ | ❌ | ❌ | キーボードでの完全なナビゲーション |
| スマート通知センター | ❌ | ❌ | ❌ | リマインダー + 収録アラート |
| エージェンシー向け複数番組ワークスペース | ❌ | $$$ | ❌ | 付属 |
| 料金 | $0 | $45–800/月 | $27–97/月 | $29–99/月 |
PodMatch が解決するのは発見、つまりゲスト探しです。私たちが解決するのはワークフローです。売り込み、フォローアップ、日程調整、準備、収録、公開、関係の維持にわたる、数か月単位のプロセスです。この 2 つは同じ問題ではありません。発見ツールを作った企業は、ワークフローの問題に手を付けませんでした。そこにギャップがあります。
MCP 連携ポイント
すべての連携ポイントはインターフェースの背後にあります。MCP サーバーは、リファクタリングなしで組み込めます。
| MCP サーバー | 状態 | 連携ポイント |
|---|---|---|
| GitHub MCP | 開発環境で稼働中 | .github/:ターミナルからの PR 自動化、CI ステータス確認、Issue 管理 |
| Supabase MCP | 接続準備完了 | packages/db/:クエリの作成前に実際のスキーマを確認し、フィールド名の不具合を解消 |
| Gmail MCP | 接続準備完了 | apps/api/src/routes/outreach.ts:アウトリーチメールの送信は sendEmail() インターフェース経由 |
| Google Calendar MCP | 接続準備完了 | apps/api/src/routes/guests.ts:予約確認と収録日の同期 |
| Exa Search MCP | 接続準備完了 | packages/ai/src/prompts/guest-research.ts:適合度スコアリングのパイプラインに最新のウェブデータを反映 |
Gmail MCP が有効になると、アウトリーチメールは下書きからワンクリックで送信済みになります。Calendar MCP を使えば、ゲストのステータスが Scheduled に変わると、収録イベントが自動的に作成されます。Exa を使えば、適合度スコアリングでウェブ上からゲストの最新の活動を取得できます。プロフィールに書かれている情報だけではありません。
技術スタック
すべての選択に根拠があります。履歴書映えのための開発はしません。
| レイヤー | 技術 | 率直な理由 |
|---|---|---|
| モノレポ | Turborepo + pnpm workspaces | リモートビルドキャッシュ。workspace:* プロトコル。ルートで pnpm install を一度実行するだけで、すべてが連携します。 |
| フロントエンド | Next.js 14 App Router | 静的表示を優先するレンダリングに RSC を活用。ファイルベースのルーティング。別途ゲートウェイを用意せずに、組み込みの BFF パターンを利用できます。 |
| UI | Tailwind CSS + shadcn/ui | shadcn はリポジトリにコードをコピーします。バージョンではなく、コードそのものを所有できます。破壊的変更を含むリリースで依存関係に悩まされることもありません。 |
| アニメーション | Framer Motion | リストの並べ替え時のレイアウトアニメーションは一行で実装できます。AnimatePresence がマウント時と終了時の処理を担います。バンドルサイズに見合う価値があります。 |
| ドラッグ&ドロップ | @hello-pangea/dnd | react-beautiful-dnd から派生した、本番環境で実績のあるフォークです。メンテナンスされており、アクセシビリティにも配慮されています。置き換えても同じように動作します。 |
| サーバー状態 | TanStack Query v5 | stale-while-revalidate。楽観的更新。バックグラウンドでの自動再取得。カンバンボードが瞬時に反応するのはこれのおかげです。 |
| UI 状態 | Zustand | 最小限の API。サイドバー、モーダル、コマンドパレット、フィルターを管理します。ミドルウェアを一行追加するだけで、すべてを localStorage に永続化できます。 |
| API | Fastify v5 | p99 で Express の約 2 倍の速度。TypeScript を第一級でサポート。@fastify/swagger がルートスキーマから OpenAPI を自動生成します。 |
| バリデーション | Zod | スキーマ一つで、TypeScript 型一つと実行時バリデーター一つを定義できます。すべてのルートで適用します。例外はありません。 |
| ORM | Drizzle ORM | コード生成は不要。スキーマはプレーンな TypeScript で記述します。マイグレーションはプレーンな SQL です。クエリは完全に型安全です。 |
| データベース | SQLite(開発環境)/Turso(本番環境) | ローカルでは設定不要。本番環境と同一のスキーマです。必要になったときに、Turso でグローバルなエッジ配信を追加できます。 |
| AI | claude-sonnet-4-6 | 利用可能な中で、構造化 JSON の出力と指示に従う能力が最も優れています。ここで使うプロンプトのパターンには、これが必要です。 |
| 認証 | Supabase Auth | JWT + Row Level Security。開発環境では dev-mock-token を使用します。本番環境では RLS がデータベース層でワークスペースの分離を強制します。 |
| メール | Resend + React Email | テンプレートを React コンポーネントとして作成します。バージョン管理やテストができ、ブラウザーでプレビューできます。開発環境ではモックを使用します。 |
| チャート | Recharts | React にネイティブ対応。組み合わせ可能。TypeScript との相性も良好です。この用途では、組み合わせやすさで Chart.js を上回りました。 |
| CI/CD | GitHub Actions | すべての PR で lint → 型チェック → テスト → 監査を実行します。CodeQL は毎週実行します。すべて成功しなければマージできません。 |
プロジェクト構成
podcast-guest-crm/
├── apps/
│ ├── web/ # Next.js 14 App Router
│ │ ├── app/
│ │ │ ├── (auth)/login/ # Demo login (route group)
│ │ │ └── dashboard/ # Protected routes. No route group by design
│ │ │ ├── page.tsx # Overview · Today's Focus · Recent Activity
│ │ │ ├── layout.tsx # Sidebar + Navbar + GlobalModals
│ │ │ ├── guests/ # Table · filters · Add Guest modal
│ │ │ ├── pipeline/ # Kanban board
│ │ │ │ └── [id]/ # Guest detail · AI action sidebar
│ │ │ ├── outreach/ # AI email composer (streaming)
│ │ │ ├── analytics/ # Charts · conversion metrics
│ │ │ └── settings/ # Workspace · AI model config
│ │ ├── components/
│ │ │ ├── ui/ # shadcn/ui primitives
│ │ │ ├── shared/ # Sidebar · Navbar · CommandPalette
│ │ │ │ # NotificationDropdown · GlobalModals · EmptyState
│ │ │ ├── guests/ # GuestCard · GuestTable · AddGuestModal
│ │ │ │ # InterviewBriefPanel · SocialPostsPanel
│ │ │ ├── pipeline/ # KanbanBoard · KanbanColumn
│ │ │ └── outreach/ # AIAssistPanel (streaming typewriter)
│ │ ├── hooks/ # TanStack Query hooks. Graceful fallback on every query
│ │ ├── lib/ # api.ts · mock-data.ts · utils.ts
│ │ └── stores/ # Zustand. Sidebar · modals · palette · filters
│ │
│ └── api/ # Fastify v5 backend
│ └── src/
│ ├── plugins/ # cors · rate-limit · jwt · swagger-ui
│ ├── routes/ # /guests · /outreach · /ai · /analytics
│ ├── services/ # guestService. In-memory store, seeded on startup
│ └── tests/ # Vitest. Coverage gate >70%
│
├── packages/
│ ├── types/ # Shared TypeScript interfaces. Single source of truth
│ ├── config/ # Zod env validation · shared constants
│ ├── db/ # Drizzle schema · 34 seed guests · migrations
│ ├── ai/ # ClaudeClient · 6 typed prompt modules
│ ├── cli/ # podcast-guest-crm-cli: TypeScript CLI, wraps apps/api
│ └── cli-pypi-wrapper/ # Thin pip/pipx wrapper, shells out to the npm CLI
│
├── .claude/
│ ├── commands/ # /new-feature · /review-pr
│ └── agents/ # ui · db · ai-features · test. Scoped sub-agents
│
├── .github/
│ ├── workflows/ # ci.yml · security.yml (CodeQL)
│ └── PULL_REQUEST_TEMPLATE.md # Includes MLP checklist
│
└── docs/
├── architecture/ # system-design.md · security.md · ai-layer.md
└── decisions/ # ADR 001 (monorepo) · 002 (Drizzle) · 003 (Fastify)
API リファレンス
OpenAPI ドキュメントは http://localhost:3001/docs に自動生成されます。
GET /health Health check + readiness probe
GET /api/v1/guests List, paginated, filterable by stage/topic/priority
POST /api/v1/guests Create guest, triggers async fit scoring
GET /api/v1/guests/:id Guest detail
PUT /api/v1/guests/:id Update fields
PATCH /api/v1/guests/:id/stage Lifecycle transition, service validates allowed paths
DELETE /api/v1/guests/:id Soft delete
POST /api/v1/outreach/draft AI draft, JSON or streaming mode
POST /api/v1/outreach/send Send via Resend (mocked in dev)
GET /api/v1/outreach/:guestId Outreach history
POST /api/v1/ai/fit-score Score 0–100 + rationale + red flags
POST /api/v1/ai/interview-brief Pre-recording brief with question structure
POST /api/v1/ai/social-post LinkedIn + Twitter thread + Instagram caption
GET /api/v1/analytics/overview Dashboard metrics + recent activity feed
GET /api/v1/analytics/pipeline Stage funnel + outreach activity timeline
警告
PATCH /guests/:id/stage、POST /guests、GET /guests/:idは現在、apps/api/src/routes/guests.tsで、プロパティが列挙されていない{ type: 'object' }のみをレスポンスの形状として宣言しています。その結果、操作自体は成功していても、Fastify の JSON シリアライザーによってレスポンスボディが{}に削られます。guest listには影響しません。CLI がこれを回避する方法については、FAQ をご覧ください。
サービスレイヤーで適用されるライフサイクルの遷移:
discover → outreach → scheduled → recorded → published → follow_up
↑___________↑ ↑__________↑
(reschedule) (re-record needed)
CLI
podcast-guest-crm-cli は、上記と同じ API をラップする、実際に動作する TypeScript CLI(packages/cli)です。すべてのコマンドは実際のルートに対応しており、架空のエンドポイントはありません。
npm install -g podcast-guest-crm-cli
# or, for Python-first / pip environments (thin wrapper, shells out to the npm package via npx):
pip install podcast-guest-crm-cli
podcast-guest-crm-cli login
podcast-guest-crm-cli guest list --stage published --limit 5
podcast-guest-crm-cli guest show <id>
podcast-guest-crm-cli guest add --name "Ada Lovelace" --email [email protected] --title "Engineer" --company "Analytical Engines"
podcast-guest-crm-cli guest stage <id> outreach --reason "replied positively"
podcast-guest-crm-cli outreach draft <guest-id> --episode-angle "AI safety"
podcast-guest-crm-cli analytics summary
podcast-guest-crm-cli analytics pipeline
スクリプトやエージェント向けに、データを返す任意のコマンドに --json を追加すると、機械可読な形式で出力できます。
podcast-guest-crm-cli guest list --stage discover --json
login は、ウェブアプリと同じ ID プロバイダーである Supabase 独自の REST 認証エンドポイント(POST <SUPABASE_URL>/auth/v1/token?grant_type=password)に対して直接認証します。apps/api/src/plugins/auth.ts にある開発専用の Bearer dev-mock-token によるショートカットは使用しません。このバイパスは、ローカル API テスト専用です。セッションは ~/.config/podcast-guest-crm-cli/credentials.json(パーミッション 0600)にキャッシュされ、期限切れになると保存済みのリフレッシュトークンを使ってサイレントに更新されます。


MCP サーバー
podcast-guest-crm-cli には Model Context Protocol サーバーが付属しています(上記に記載されている、このアプリが連携できるサードパーティの MCP サーバーとは別のものです)。podcast-guest-crm-cli mcp を実行すると、stdio 経由で起動し、各 CLI コマンドが使用するものと同じ API 境界を直接呼び出す 5 つのツールを公開します。ツールは list_guests、add_guest、update_guest_stage、draft_outreach_email、get_analytics_summary です。
npm install -g podcast-guest-crm-cli
podcast-guest-crm-cli login
{
"mcpServers": {
"podcast-guest-crm": {
"command": "npx",
"args": ["podcast-guest-crm-cli", "mcp"]
}
}
}
ライフサイクルの主要ツールに対して実際に tools/call で {"name": "update_guest_stage", "arguments": {"id": "guest_1", "stage": "outreach"}} を呼び出すと、CLI で guest stage <id> outreach --json を実行したときと同じエンベロープが返されます。ツールの完全なリファレンスについては、packages/cli の README をご覧ください。
セキュリティ
初日から本番環境レベルの対策を適用しています。後付けでセキュリティ対策を加えることはありません。
| 管理項目 | 実装 |
|---|---|
| 認証 | @fastify/jwt による JWT 認証。すべてのルートで preHandler: [server.authenticate] を指定します。開発環境も含め、例外はありません。 |
| ワークスペースの分離 | すべてのクエリで JWT ペイロードの workspaceId によるフィルタリングを行います。本番環境では Supabase RLS が DB レイヤーでこれを適用します。 |
| レート制限 | @fastify/rate-limit により、IP ごとに 1 分あたり 100 件です。環境ごとに設定できます。 |
| 入力検証 | すべてのルートで Zod を使用します。ボディ、クエリ、パスパラメーターが対象です。スキーマがなければリリースしません。 |
| SQL インジェクション | 全体を通じて Drizzle ORM のパラメーター化クエリを使用します。このコードベースに生の SQL はありません。 |
| XSS | Next.js のデフォルトのエスケープ処理と、next.config.ts の制限的な CSP ヘッダーを使用します。 |
| シークレット | Zod の環境変数スキーマにより、必須変数が欠けている場合はサーバー起動時にクラッシュします。気付かれないままの設定ミスはセキュリティ上のバグです。 |
| CORS | 許可リスト方式です。ワイルドカードは一切使用しません。 |
| SAST | すべての PR と毎週のスケジュールで CodeQL を実行します。 |
| 依存関係 | CI で pnpm audit を実行します。重大度の高い脆弱性があると、ビルドは失敗します。 |
ロードマップ
短期(今後60日間):
- MCP:Gmail + Google Calendar: 営業連絡の下書きから送信までワンクリックで完了し、予約確認時にカレンダーの予定を自動作成します
- MCP:Exa Search: ゲストとの適合度スコアリングで、プロフィール文だけでなく最新のウェブデータを取得します
- Stripe による請求: Solo は月額29ドル、Agency は月額99ドル、プランの上限を超えた AI クレジットは従量課金です
中期:
- トランスクリプトの取り込み: エピソードをアップロードすると、具体的なハイライトに言及したソーシャル投稿とフォローアップメールを自動生成します
- クライアントポータル: エージェンシーのクライアント向けにトークンベースの読み取り専用画面を提供し、週次のステータス報告メールを不要にします
- Zapier / Make コネクター: Cal.com、Notion、HubSpot と双方向に同期します
- RSS 抽出: ポッドキャストの RSS URL を入力すると、ホストの連絡先情報と番組の統計を自動で入力します
長期:
- モバイル(React Native): 同じ API を使い、ネイティブな操作感で、外出先でもパイプラインを確認できます
- 複数番組ダッシュボード: エージェンシー向けに、管理するすべての番組を1つの画面で確認できます
- フォローアップの予測: 返信率データでトレーニングした ML モデルにより、営業連絡の最適なタイミングを予測します
チーム
Rudrendu Paul と Sourav Nandy が、この本番環境対応の AI ネイティブソフトウェアを開発しました。
使用している技術スタック:
- フルスタック TypeScript モノレポ(Turborepo + pnpm)。型パッケージを共有し、CI レイヤーで適用しています
- Fastify API。Zod によるスキーマ検証、JWT 認証、行レベルセキュリティを採用しています。例外はありません
- AI 搭載の機能レイヤー。型付きプロンプトモジュール、ストリーミング、JSON 抽出、指数バックオフを採用しています
- Next.js 14 App Router フロントエンド。TanStack Query、Zustand、Framer Motion、shadcn/ui を採用しています
- Claude Code サブエージェントアーキテクチャ。ツールレイヤーでドメイン境界を適用します
FAQ
podcast-guest-crm-cli とは何ですか?ウェブアプリを使う場合とどう違いますか?
これは、Next.js ウェブアプリが呼び出すものと同じ API を利用する、実際の TypeScript コマンドラインクライアント(packages/cli)です。ゲストのライフサイクルに関するエンドポイント(guest list/add/show/stage)、AI による営業連絡の下書きエンドポイント(outreach draft)、分析エンドポイント(analytics summary/pipeline)をラップしています。特徴はエージェントネイティブな出力です。データを返すすべてのコマンドが --json に対応しているため、スクリプトや AI エージェントは HTML をスクレイピングしたり、独自の HTTP クライアントを管理したりすることなく、人間がダッシュボードから操作するのと同じパイプラインを実行できます。
対応しているプラットフォームとランタイムは何ですか?
npm パッケージ(npm 上の podcast-guest-crm-cli。Node.js 20 以降が必要)は、Node が動作する macOS、Linux、Windows で利用できます。同じ名前の PyPI パッケージ(packages/cli-pypi-wrapper)は、pip/pipx ユーザー向けの薄いラッパーです。CLI を Python で再実装するのではなく、node と npx が PATH 上にあることを確認してから、ラッパー自身のバージョンに固定した npm パッケージを起動します。その正確なバージョンが npm に公開されていない場合は、完全に失敗するのではなく、npm の latest リリースにフォールバックします。
ログインの仕組みを教えてください。
podcast-guest-crm-cli login を実行すると、メールアドレスとパスワードの入力が求められ、その後、Supabase プロジェクト固有の REST エンドポイント(POST <SUPABASE_URL>/auth/v1/token?grant_type=password)に直接認証します。これはウェブアプリが使用するものと同じ ID プロバイダーです。デプロイ環境の Supabase プロジェクト URL と anon key(--supabase-url / --supabase-anon-key、または PODCAST_GUEST_CRM_SUPABASE_URL / PODCAST_GUEST_CRM_SUPABASE_ANON_KEY)が必要です。これらは、デプロイ環境ですでに設定されている NEXT_PUBLIC_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_ANON_KEY と一致している必要があります。取得したアクセストークンとリフレッシュトークンは、アクセス権限 0600 で ~/.config/podcast-guest-crm-cli/credentials.json にキャッシュされ、アクセストークンの有効期限が切れると自動的に更新されます。
コマンドを実行したら、期待したフィールドではなく {"data": {}} が出力されたのはなぜですか?
これは CLI のバグではなく、API 自身の Fastify レスポンススキーマに現時点で存在する実際の不足です(apps/api/src/routes/guests.ts)。PATCH /guests/:id/stage、POST /guests、GET /guests/:id などのルートでは、レスポンスの形式がプロパティの一覧を持たない単なる { type: 'object' } として宣言されているため、成功時でも Fastify の JSON シリアライザーによってレスポンス本文が空のオブジェクトに削られます。CLI はこれを検知し、フィールドの欠落でクラッシュする代わりに、生の(空の)レスポンスを出力します。guest list は、スキーマで固定された項目形式を持たない配列として宣言されているため、影響を受けません。
この CLI を自動化パイプラインで使ったり、AI エージェントに渡したりできますか?
はい。それが主な設計目標です。データを返すすべてのコマンドは構造化出力用の --json を受け付け、失敗時には 0 以外の終了コードを返します。また、--json が指定されている場合、エラーレスポンスは error、message、statusCode フィールドを含む JSON オブジェクトになります。login のパスワードプロンプトを除き、どのコマンドにも対話操作が必須の経路はありません。login も、非対話的に使うための --email および --password フラグを受け付けます。MCP ネイティブのエージェント(Claude Desktop、Claude Code)では、podcast-guest-crm-cli mcp を実行すると stdio MCP サーバーが起動し、同じゲストのライフサイクル管理、アウトリーチ文面の作成、分析機能が呼び出し可能なツールとして公開されます。上記の MCP Server を参照してください。
この CLI や、このコードベースのほかの部分を商用利用できますか?
はい。このリポジトリ(packages/cli と packages/cli-pypi-wrapper を含む)は MIT ライセンスで、Rudrendu Paul と Sourav Nandy が共同で所有しています。すべての条件については LICENSE を参照してください。商用利用、改変、再配布はいずれも許可されています。
CLI はパスワードを保存または送信しますか?
いいえ。login プロンプトで入力したパスワードは、HTTPS 経由で Supabase のパスワードグラントエンドポイントに一度だけ直接送信され、ディスクに書き込まれることはありません。ローカルにキャッシュされるのは、取得したアクセストークン、リフレッシュトークン、およびそれらの有効期限のみです。
コマンドの実行中にセッションの有効期限が切れた場合はどうなりますか?
CLI はリクエストごとに、キャッシュされたアクセストークンの有効期限を(30 秒の余裕を設けて)確認します。有効期限が切れている場合、CLI は保存済みのリフレッシュトークンを使って Supabase のリフレッシュトークングラントを呼び出し、新しいセッションを保存してから再試行します。これらはすべて、再ログインを求めることなく行われます。再び login エラーが表示されるのは、リフレッシュトークン自体が無効になった場合(たとえば、パスワードの変更後)のみです。
ライセンス
MIT です。すべての条件については LICENSE を参照してください。商用利用、改変、再配布はいずれも許可されています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。