Next.jsでスケーラブルなディレクトリサイトを設計する方法
目次
訪問者が検索バーに都市名を入力します。3秒が経過します。地図がカクつきます。彼らはタブを閉じます。ディレクトリサイト — Yelpクローン、プロフェッショナル検索ツール、ローカルビジネスアグリゲーター — ブログテンプレートのように構築されると、自身のデータ量で崩壊します。1000件のリスティングは問題なく動作します。半径検索、ファセットフィルター、リアルタイムマップピンを備えた10000件のリスティング?ほとんどのNext.jsディレクトリがここで停滞します。違いはReact対サーバーコンポーネントではありません。最初のユーザーがリスティングを送信する前に行う9つのアーキテクチャの決定です — データベースインデックス、検索戦略、キャッシングレイヤー、Googleが実際にクロールできるようにルートを構造化する方法に関する決定です。ほとんどのチームは50000件のリスティングで間違いに気付き、リファクタリングには6桁のコストがかかります。しかし、最初の日からスキーマ、検索、SEOの基礎を正しく設計すれば、ディレクトリはコアを書き直さずに数百万のエントリまでスケーリングします。
ディレクトリサイトが機能する理由
ディレクトリサイトは、人をビジネス、サービス、またはリソースに接続します。Yelp、Zocdoc、Avvo、またはローカルレストランガイドやプロフェッショナルサービスディレクトリなどのニッチなディレクトリを考えてください。このモデルは実績があり、需要は一定です — すべての業界にディレクトリの機会があります。
成功したディレクトリと失敗したディレクトリを分けるのは、3つのことに帰結します:データの品質、検索体験、SEO。リスティングが不完全である場合、検索が遅い場合、またはGoogleがページを見つけられない場合 — ディレクトリは失敗します。
Next.jsはディレクトリに独自に適している理由は、基本的な矛盾を解決するためです:ディレクトリは数千のSEOに優しい静的ページ(リスティングとカテゴリ用)が必要ですが、動的でインタラクティブな機能(検索、フィルタリング、地図、ユーザーアカウント)も必要です。Next.jsはリスティングページの静的生成とダイナミック機能のサーバーコンポーネントの両方で両方を処理します。
ディレクトリサイトの種類
ビジネスディレクトリ — ローカルまたは業界固有のビジネスリスティング。フィーチャーリスティングと広告からの収益。
プロフェッショナルディレクトリ — 医師、セラピスト、コンサルタント向けのプロバイダー検索ディレクトリ。サブスクリプションとリード生成からの収益。
リソースディレクトリ — ツール、ソフトウェア、コース、またはデータセットのキュレーションリスト。アフィリエイトリンクとスポンサーシップからの収益。
マーケットプレイスディレクトリ — ブッキングまたは購入機能付きのリスティング(Airbnbモデル)。取引手数料からの収益。
コミュニティディレクトリ — 協会、同窓会ネットワーク、または組織のメンバーディレクトリ。
適切なアーキテクチャの選択
レンダリング戦略
50000件未満のリスティングがあるディレクトリの場合、ISR(増分静的再生成)を備えた静的生成が最適なアプローチです:ビルド時にすべてのリスティングページを生成して、インスタント読み込み時間と完璧なSEOを実現し、ISRを60秒の再検証ウィンドウで使用して、更新が1分以内に表示され、サーバーコンポーネントは検索結果とフィルター表示を処理して、常に新しいデータを実現します。
100000件以上のリスティングを持つディレクトリの場合、オンデマンドISRに切り替えます。ここで、ページは初回訪問時に生成されてキャッシュされます。
データレイヤー
**PostgreSQL(Supabaseまたはneon経由)**が推奨事項です。tsvectorで全文検索をネイティブに処理し、PostGISで地理クエリをサポートし、柔軟なリスティング属性にはJSONBを使用します。1つのデータベースがすべてを処理します。
代替案: 高度な検索機能用のElasticsearch、ホスト型検索サービス用のAlgolia、またはセルフホスト型オプションとしてのMeilisearch。
リスティング用のデータベース設計
コアテーブル
listings — 中央テーブル。すべてのリスティングには、名前、スラッグ、説明、カテゴリ、位置(緯度/経度)、連絡先情報、ステータス、および柔軟な属性用のメタデータJSONB列があります。
categories — parent_idセルフリファレンスを使用した階層的カテゴリ。Healthcare > Dentists > Cosmetic Dentistryのようなネストされたカテゴリをサポートします。
locations — 正規化されたロケーションデータ:都市、州/州、国、郵便番号、座標。座標列にはPostGIS地理タイプを使用してください。
reviews — ユーザーレビューで、評価(1-5)、テキスト、著者参照、リスティング参照を含みます。集計評価は、高速読み込みのためにリスティングに保存されます。
media — リスティングに添付された画像とドキュメント。URL、ファイルではなくを保存してください。画像配信にはCDNを使用してください。
JSONBを使用した柔軟な属性
すべての業界には一意のリスティング フィールドがあります。レストランディレクトリには、料理の種類、価格帯、営業時間が必要です。歯科医ディレクトリには、受け入れた保険、専門、認証が必要です。各垂直線に対して個別のテーブルを作成する代わりに、JSONB属性列を使用してください。これにより、スキーマ移行なしに新しいフィールドを追加しながら、PostgreSQL JSONBオペレーターを介してフィルターされたクエリをサポートできます。
実際に機能する検索とフィルタリング
検索は、ディレクトリサイトのコアインタラクションです。結果が200msを超えて表示されるのに時間がかかる場合、ユーザーは離脱します。
全文検索
PostgreSQL全文検索は、外部サービスなしでほとんどのディレクトリニーズを処理します。名前、説明、カテゴリテキストを組み合わせたtsvector列を作成し、高速ルックアップ用のGINインデックスをビルドし、関連性スコアリングにはts_rankを使用し、フレーズマッチングとブール演算子をサポートしてください。
自動補完の場合、trigram インデックス付き(pg_trgm拡張機能)の個別のsearch_terms具体化されたビューを作成してください。これにより、タイプミスに対応する即座のタイプアヘッド候補が有効になります。
ファセットフィルタリング
重要なのは事前計算されたフィルターカウントです。ユーザーが「ロンドン」の「歯科医」を選択するとき、クリック前に各サブフィルターと一致する結果の数を表示します。これは並列でカウントクエリを実行する必要があり、適切なインデックスを備えたPostgreSQLは効率的に処理します。
マップ統合と地理的位置情報
マッププロバイダーの選択
Mapbox GL JS — 最良の開発者エクスペリエンス、美しいデフォルトスタイル、寛大な無料ティア(月50000マップロード)。推奨です。
Google Maps — ユビキタスだがスケールで高価。
Leaflet + OpenStreetMap — 完全に無料で、オープンソース。
マップUXパターン
- ズームアウト時のクラスターマーカー
- マップが移動したときにリストを更新 — 目に見えるマップエリアでリスティング結果を同期
- ホバー時にハイライト — ユーザーがリスティングをホバーするとき、そのマップマーカーをハイライト
- モバイル:リスト優先 — デフォルトでモバイルのリストを表示し、マップトグルを表示
ユーザーサブミッションとリスティングの請求
サブミッション フロー
ビジネスオーナーが多段階フォーム(基本情報、詳細、メディア、検証、管理者による承認)を通じてリスティングを送信できるようにします。
既存のリスティングの請求
ディレクトリにデータを事前入力した場合、ビジネスオーナーは電話通話、郵便、またはビジネスメールドメインマッチングによる検証を通じてリスティングを請求する方法が必要です。請求されると、オーナーはダッシュボード経由でリスティングを編集できます。
ディレクトリサイトのSEO
URL構造
ユーザーと検索エンジン向けのURLを設計してください:
- /dentists/ — カテゴリランディング
- /dentists/london/ — カテゴリ+都市
- /dentists/london/cosmetic/ — カテゴリ+都市+サブカテゴリ
- /listing/smile-dental-clinic — 個別リスティング
プログラムによるSEO
50都市で10専門を対象とする歯科医ディレクトリの場合、つまり500個のユニークなランディングページがテンプレートから生成されます — 各特定のロングテールキーワードをターゲットにします。これはNext.jsでのディレクトリSEOの力です。
収益化モデル
フィーチャーリスティング — 月額$50-500。サブスクリプション階層 — 無料ベーシック、有料プレミアム月額$20-100。リード生成 — リード当たり$5-50。広告 — トラフィックの多いページの表示広告。データライセンス — 匿名化されたディレクトリデータを販売。アフィリエイトと紹介 — ブッキングの手数料。
スケールでのパフォーマンス
キャッシング戦略
エッジCDNから提供される静的ページ、60秒間Redisでキャッシュされた検索結果、プロバイダーで処理されたマップタイル、CDN経由で提供される画像と積極的なキャッシング。
ビルド時間の最適化
10000件以上のリスティングページを使用すると、デプロイ時にすべてのページをビルドする代わりにオンデマンドISRを使用し、更新頻度でグループページを作成し、ページネーションでgenerateStaticParamsを使用して生成を並列化してください。
FAQ
ディレクトリを起動するのに何件のリスティングが必要ですか?
フォーカスされた地理的エリアまたはニッチで少なくとも200-500の品質リスティングから開始してください。50のスパースなリスティングを持つディレクトリは、放棄されて見えます。
ディレクトリプラグイン付きのWordPressを代わりに使用する必要がありますか?
WordPressディレクトリプラグインは、5000件のリスティングの周りでパフォーマンスウォールにぶつかります。検索体験は不十分で、マップのインタラクションは遅い、スケーリングには高価なホスティングが必要です。Next.jsは、あらゆるスケールで、より高速で、カスタマイズ可能で、ホストするのが安いです。
ディレクトリサイトを構築するのにはいくらかかりますか?
カスタムNext.jsディレクトリは、複雑さに応じて$15000-80000の範囲です。基本的なMVPは6-8週間で構築できます。
リスティングの重複をどのように処理しますか?
サブミッション時に重複排除を実装してください:名前+住所+電話番号で一致させてください。ファジーマッチングを使用して、ほぼ重複を検出してください。
このアプローチで2側面のマーケットプレイスを構築できますか?
はい。ディレクトリは、ブッキングまたは購入を追加するとマーケットプレイスになります。買い手とプロバイダー間の支払い処理のためにStripe Connectを追加してください。