ProductReadyProductReady

Busabase CMS 連携

ProductReady の Blog とランディングページに Busabase ワークスペースのコンテンツを取り込み、ローカル MDX と共存させる方法。

Busabase CMS 連携

busabase-cms はホスト型システムではなく、npm の SDK パッケージです。 型付きクライアント ライブラリであり、このモノレポ内では "busabase-cms": "workspace:*"、モノレポ外では npm に公開 されている busabase-cms パッケージをインストールして、自分のサーバーコードから呼び出します。 すでに運用している、あるいはアクセス権のある Busabase ワークスペースと通信するだけで、単独で デプロイするサービスではありません。

ProductReady の Blog(/blog)とランディングページは、デフォルトでは content/blog/ 配下の ローカル MDX コンテンツを使用します——これはセットアップ不要・設定不要・ネットワーク通信ゼロで 動作します。編集者が Git の PR を経由せずに、Busabase ワークスペース (承認優先の ChangeRequest レビューフロー付き) からコンテンツを公開できるようにしたい場合は、 ProductReady を Busabase CMS の Folder に向けるだけで、そのコンテンツがマージされます。

有効化する方法

この連携は 4 つの環境変数で制御され、最初の 3 つをすべて設定したときに有効になります ——専用の機能フラグや管理画面のトグルはありません。

変数役割
BUSABASE_CMS_BASE_URLBusabase ワークスペースのホスト(例: https://busabase.com またはセルフホスト URL)。必須。
BUSABASE_CMS_API_KEY対象スペースへの読み取り権限(初回のスキーマセットアップ時は書き込み権限も)を持つ Busabase API キー。必須。
BUSABASE_CMS_SPACE_ID対象の Busabase Cloud スペース id。リクエストヘッダーとして送信されます。必須。
BUSABASE_CMS_FOLDER_ID任意(推奨): Posts/Pages/Categories/Tags の Base を格納する Busabase Folder。

これらを .env に追加し(正確な形式はコメントアウトされた .env.example のブロックを参照)、 開発サーバーを再起動してください。必須の 3 変数がすべて設定されるまで連携はオフのままです ——設定が不完全な状態では Busabase に到達できないため、毎リクエストで必ず失敗する読み取りを 行うのではなく「オフ」として扱います。BUSABASE_CMS_FOLDER_ID を使う方法が推奨です。初回の 読み取り時に Folder 配下の子 Base を自動検出し、不足しているフィールドのみをプロビジョニングし、 安定した Base ID を Folder の metadata に保存するため、後から Base 名を変更しても壊れません。

Folder id が未設定の場合、ProductReady はアプリ名を接頭辞に持つ 4 つの Base を slug で読み取ります (productready-blog-postsproductready-landing-pagesproductready-categoriesproductready-tags)。これらの既定値は BUSABASE_CMS_POSTS_BASE_SLUGBUSABASE_CMS_PAGES_BASE_SLUGBUSABASE_CMS_CATEGORIES_BASE_SLUGBUSABASE_CMS_TAGS_BASE_SLUG でデプロイごとに上書きできます。

CMS の読み取り結果は Next の data cache に 300 秒キャッシュされます。キャッシュキーはアプリごと (さらに host / スペース / Folder / Base slug ごと)に名前空間が分かれているため、2 つのアプリが 同じ Busabase スペースを指していてもキャッシュエントリを共有することはありません。早期に無効化 したい場合は productready:cms-postsproductready:cms-pagesproductready:cms-categoriesproductready:cms-tagsrevalidateTag を使用してください。

それ以外は何も変更する必要がありません。 これらの環境変数がすべて未設定の状態(デフォルト) では、ProductReady は CMS へのネットワーク呼び出しを一切行いません——Blog とランディングページの ルートは content/blog/ のみを読み取り、この連携が存在しなかったときと全く同じ挙動になります。

CMS コンテンツとローカル MDX の共存方法

両方のソースはリクエストのたびに読み取られ、正規化されたパス(/blog/my-post/ja/blog/my-post など)でマージされます。

  • 同じパスが CMS とローカル MDX の両方に存在する場合は、CMS 側が優先されます——これにより、 ローカル MDX をフォールバックとして残したまま記事を CMS に移行できます。
  • パスがどちらか一方にしか存在しない場合は、そのソースのコンテンツがそのまま表示されます。
  • CMS 連携が無効(環境変数未設定)の場合、マージ時の CMS 側は常に空になるため、すべてのパスは ローカル MDX に解決されます——これは連携導入前の挙動と同一です。

これは Blog の一覧/詳細ルート(src/app/[lang]/blog/[[...slug]]/page.tsx)と、CMS で作成した ランディングページを描画する専用の catch-all ルート (src/app/[lang]/(home)/[...cmsPath]/page.tsx)の両方に適用されます——/pricing のような既存の 静的ルートは、常にこの catch-all より優先されます。

Blog 記事の言語間フォールバック

Blog 記事の詳細ページ(/blog/my-post/ja/blog/my-post など)は次の順序で解決されます。まず リクエストされたロケールの CMS コンテンツ、次にそのロケールのローカル MDX、どちらも存在しない 場合にのみ——CMS・ローカル MDX いずれかの英語版にフォールバックします。これにより、まだ翻訳 されていない記事も 404 にはならず、英語で表示されます。フォールバックが発生した場合、タイトルの 上に訪問者自身のロケールに翻訳された LocaleFallbackNotice バナーが表示され、そのページがまだ 選択言語で提供されていないことを伝えます。この解決ロジックは src/domains/marketing/logic/blog-page-resolver.tsresolveBlogPage)にあります。Blog の 一覧ページはリクエストされたロケールに存在するコンテンツをそのまま列挙するだけなので、この ロジックは不要です。

Category / Tag アーカイブページ

Blog 記事をタクソノミー別に一覧表示する 2 つのルートがあります: /blog/category/[slug]/blog/tag/[slug] です。Category と Tag は CMS にしか存在しない概念であり、ローカル MDX の 記事には対応するフィールドがないため、これらのページは CMS 由来の記事のみを表示します。CMS 連携 が無効な場合、listBusabaseCategoriesOrFallback / listBusabaseTagsOrFallback はいずれも [] に解決され(静的ページは生成されず、すべてのリクエストが 404 になります)、この連携の他の部分と 同じ「オフはオフ」という保証が維持されます。

コードの配置

ProductReady 自身のドメイン駆動設計(DDD)レイアウトに従い、この連携は src/domains/marketing/logic/ に配置されています。

  • busabase-cms-logic.ts —— ProductReady 自身のロケール設定・schema profile・キャッシュ名前空間、 そしてアプリ名を接頭辞に持つ Base slug(productready-blog-posts など)を busabase-cms/integrationcreateCmsIntegration に渡すだけの薄い バインディングです。この SDK を使うすべての kapps アプリが共有するそのファクトリが、オン/オフの 判定(isBusabaseCmsEnabled)、キャッシュ付きクライアント、そして Posts・Pages・Categories・ Tags 用の型付き読み取り関数を持ちます。各関数には ...OrFallback バリアントがあり、あらゆる エラー(ネットワーク、認証、Folder 不在)でページを壊すことなく空の結果へと安全に縮退します。
  • blog-page-resolver.ts —— 上記の Blog 詳細ページの CMS → ローカル MDX → 英語フォールバック解決 ロジック。
  • busabase-cms-page.tssrc/domains/marketing/components/busabase-cms-page.tsx —— 単一の CMS ランディングページを解決・描画し、dangerouslySetInnerHTML の前に HTML をサニタイズします。

SDK の完全なリファレンス

このページは ProductReady 側の連携範囲のみを扱います。busabase-cms の完全な API ——createBusabaseCms、スキーマのプロビジョニング、schemaProfile、キャッシュ用ヘルパー、 Fumadocs 描画用ヘルパー(SafeMarkdownsanitizeLandingPageHtml)——については、モノレポ内の packages/busabase-cms/README.md を参照してください。

On this page