3〜30のアプリに対応するスケーラブルな統合ディレクトリ設計
シンプルなデータモデル、明確なステータス、権限設計、セットアップ進捗UIで3個から30個まで拡張できる統合ディレクトリを設計する方法。

統合画面が(分かりやすく)すべきこと
人々が統合ディレクトリを開く理由は一つです:ツールをつなげて、日常的に意識せずに動かし続けたいから。画面が何が接続されているか、何が壊れているか、次に何をすれば良いかをユーザーに推測させると、信頼はあっという間に落ちます。
統合が3つならロゴのグリッドでも成立しますが、30個になると破綻します:人はスキャンを止め、サポートチケットは増え、各統合が別々の状態にあるため「Connect」ボタンが落とし穴になりがちです。
各統合カード(または行)は、一目で次の3つに答えるべきです:
- これは何か?(名前と短い用途)
- 今正しく動いているか?(明確なステータス+最終チェック或いは最終同期)
- 次に何をすればいい?(Connect、続けてセットアップ、再認証、管理)
実際のチームでは端的でないケースが常に発生するため、混乱はそこで生まれます。例えば個人アカウントでGoogleを接続してしまった、Stripeのトークンが期限切れで課金同期が止まった、Slackはワークスペースが接続されているが必要なチャンネル権限が付与されておらずセットアップが“半分”のまま見た目は正常に見える、などです。
良い画面はそうした状況を明確にします。ただ「Connected」とだけ出すのではなく、「Connected(権限が必要)」「Connected to: [email protected]」のように表示して、次に取るべきアクションをカード上に置きます。こうすることで推測を減らし、数が増えてもリストを扱いやすく保てます。
シンプルなデータモデル:catalog vs installs vs connections
統合ディレクトリをスケールさせる最も簡単な方法は、次を分けることです:
- 提供するもの(カタログ)
- 各ワークスペースで有効にされたもの(installs)
- 実際に使われている外部アカウントや認証情報(connections)
これなら3個の時でも読みやすく、30個になっても機能します。
3つのコアオブジェクト
Integration はカタログエントリです。グローバルで、特定のワークスペースには紐づきません。
Install はワークスペースがそのIntegrationを有効にしたことを表します(例:「Workspace AでSlackがオンになっている」)。
Connection は実際の外部アカウントや認証情報を表します(例:「OAuth経由のSlackワークスペースX」や「APIキー経由のStripeアカウントY」)。1つのInstallは複数のConnectionを持てます。
スケールしやすい最小限のフィールド例:
- Integration: id, key ("slack"), display_name, category, auth_type (oauth/api_key/webhook), docs_hint(短い説明), created_at
- Install: id, workspace_id, integration_id, status (enabled/disabled), setup_state (not_started/in_progress/complete), created_by, created_at, updated_at
- Connection: id, install_id, label ("Marketing Slack"), connection_status (ok/expired/error), external_account_id (knownなら), scopes/permissions_granted, last_success_at, created_at
設定とシークレット(漏らしてはいけないもの)
ユーザーに見える設定(選択したチャンネル、Webhookのニックネーム、有効イベントなど)はInstallやConnectionに通常データとして保存し、シークレット(OAuthリフレッシュトークン、APIキー、署名シークレットなど)は必ずシークレットストアや厳しいアクセス制御の付いた暗号化フィールドに保存してください。
シークレット、完全な認可コード、生Webhookペイロードをログに出さないでください。ログが必要ならconnection_idの参照やHTTPステータス、エラーコードのような安全なメタデータだけを残します。
OAuth、APIキー、Webhookの違いに柔軟に対応するため、認証固有のフィールドはConnection内に保管し(トークンメタデータ、キーのフィンガープリント、Webhook検証状態など)、UI向けの状態(有効かどうか、セットアップ進捗)はInstallに置くのが便利です。
ユーザーが理解できるステータスとセットアップ進捗
人々が統合ディレクトリを開くのは3つの質問に素早く答えてほしいからです:動いているか、セットアップはどこまで進んでいるか、次に何をすればいいか。ステータスの文言が曖昧だとサポートが増え、信頼は下がります。
長く保てる小さなステータスセットから始めましょう:
- Not set up
- In progress
- Connected
- Needs attention
- Disabled
ラベルは保存された単語よりも派生(derived)して表示する方が望ましいです。保存されたラベルは必ず陳腐化します:誰かが問題を直してもバッジが赤いままになることがあります。派生ステータスは既に追跡している事実(トークンが有効か、必須セットアップが完了しているか、管理者が停止しているかなど)から計算します。何かを保存するなら最終ラベルではなく、最終成功同期時間や最後のエラーコードなどの事実を保存してください。
セットアップ進捗は必須と任意を明確に分けた短いチェックリストが最適です。ステップ定義(統合ごとに静的)とステップ結果(インストールごと)に分けてモデル化します。
例:Slackは「ワークスペースを認可」「チャンネルを選択」を必須とし、「メッセージプレビューを有効化」は任意にする、という具合です。UIは「必須3ステップ中2完了」のように表示し、任意項目はブロッキングせずに見つけやすくします。
1つの統合下に複数の接続がある場合、適切に計画しないとディレクトリが混乱します。カードは統合ごとに一つにし、接続数を表示してステータスを正直に集約します。もしどれか一つの接続に問題があれば「Needs attention」と表示し、例えば「4つのうち1つのワークスペースで再認証が必要」といったヒントを出します。概要は簡潔に保ちつつ、現状を反映できます。
複雑にしすぎない権限とロール
すべてをひとつのスイッチで扱うと権限は混乱します。次のように分けると分かりやすいです:
- 誰が統合を閲覧できるか
- 誰が設定できるか
- 誰が日常的に使えるか
まずどこでも適用できる軽量なロールチェックを始めましょう。多くのケースで3つのロールで十分です:Admin、Manager、Member。Adminはすべての操作が可能、Managerはチーム向けの多くの統合を設定でき、Memberは既に有効な統合を利用できるが設定は変更できない、という分離です。
重要な統合(支払い、給与、エクスポートなど)には個別のフラグを足すだけで十分です。多くの統合(カレンダーやチャット)はデフォルトのロールルールに従えるはずです。Sensitiveなものは「Payments admin」や「Billing manager」のようなフラグを設け、これをInstall上の単純な真偽値として扱うと良いでしょう。
読みやすさを保つマッピング例:
- View: Admin, Manager, Member
- Configure: Admin, Manager(Memberは見られるが接続や編集は不可)
- Use: ワークスペース内の誰でも(制限が無ければ)
- Sensitive override: 特定フラグを持つユーザーのみが設定や操作可能
監査は重くある必要はありませんが、存在するべきです。サポートやセキュリティの質問に素早く答えられる程度に、誰がいつ接続したか、いつ資格情報が変わったか、誰が無効化したかを追跡します。詳細ページに5〜20件程度の最近のイベントを表示する「Activity」パネルがあれば十分なことが多いです。
例:Stripeは誰でも見えるが接続・キーのローテート・支払い無効化はAdmin(または“Billing manager”にマークされたユーザー)だけができる。SlackはManagerが接続でき、Memberは有効化後に通知を受け取れる、のように扱います。
30個でも機能するUIレイアウト
3個なら何でも見せられますが、30個になるとディレクトリは「どれが動いていて、次に何をすればよいか?」に素早く答えなければなりません。もっとも分かりやすいアプローチは「スキャンすること」と「操作すること」を分離することです。
ディレクトリビューは素早い判断に集中させ、重いコントロールは「Manage」ボタンの先の詳細ページに押し込んでください。
一覧では次の情報だけを表示して次のクリックを促します:
- アイコン、名前、一行の説明(長さを揃える)
- 明確なステータスピル(Connected、Needs setup、Error、Disabled)
- 主要なアクションボタン(1つ)
- その他はすべて「Manage」ボタンに
カードの構成は慣習を作るので重要です。主要アクションは常に状態に基づく「次の一手」を意味するべきです:新規ならConnect、途中ならContinue setup、認証切れならReconnect、すべて正常ならManage。カードごとに同じくらい目立つボタンを二つ並べるのは避けてください。ページがうるさく感じられます。
例:
- 「Google」がConnectedなら主要アクションはManageにする。
- 「Slack」が昨晩失敗したならErrorを表示して主要アクションはReconnectにする。
- 「Stripe」が途中ならNeeds setupを表示してContinue setupにする。
空の状態(Empty states)は説明を投げつけるのではなく導くべきです:
- インストールされた統合がない:人気のある2〜3個を提案し、それで何ができるかを示す
- 検索結果なし:"CRM"や"billing"のような簡単な検索のヒントを出す
- 初回セットアップ時:権限とアクセスされるデータについて一文で説明する
30個あってもページが落ち着くのは、各カードが「何か」「大丈夫か」「次に何をするか」を答えているからです。
詳細ページ:セットアップフロー、接続、コントロール
ディレクトリ一覧は人を正しい統合に誘導します。詳細ページは設定するか修正するかオフにするかを決める場です。バックエンドの違いがあってもページ構造は一貫させてください。
コンパクトな概要(統合名、一行説明、明確なステータスラベル)を先に置き、ユーザーが「あとどれくらいで終わるか」を分かるように小さな「Setup progress」行を付けます。
安心できるセットアップフロー
シンプルなウィザードが有効です:3〜6ステップ、画面ごとに1ステップ、常に「戻る」が使えるようにします。ステップ名は平易な言葉にしてください(アカウントを接続、ワークスペースを選ぶ、同期するデータを選ぶ、確認)。任意の選択肢は必ず「任意」と明記して隠さないでください。
途中で中断できるならその旨を明記しましょう:「後で続けられます。選択内容は保存します。」これで離脱の不安が減ります。
後悔しない接続とコントロール
Connectionsは小さなテーブルで表示します:アカウント名、接続したユーザー、作成日、最終同期。
「次の同期」については約束できない時間を示すのは避け、システムが実際に担保できる表現(例:「次の同期:近日予定」「次の同期:1時間以内の予定」)を使ってください。
危険な操作はメインパスから離して置きます。主要アクションは上部(Continue setup、Reconnect)、DisableやDisconnectは下部の「Danger zone」に分け、影響を短く説明します。ロールがあるなら一文で示します(例:「Disconnectは管理者のみ可能」)。
小さなアクティビティログを追加しましょう:最近のイベント(connected、token refreshed、sync failed)、タイムスタンプ、サポートチケットにコピペできる短いエラーメッセージ。
手順別:統合をエンドツーエンドで追加する
統合追加は小さなプロダクトとして扱うと楽です。リスティング、接続方法、接続を保存する場所、成功/失敗のはっきりした結果が必要です。
1) まずカタログエントリ
誰もまだ接続していなくてもディレクトリに表示されるようにIntegrationをカタログに追加します。わかりやすい名前、短い説明、アイコン、1〜2のカテゴリ(Messaging、Paymentsなど)を含めてください。セットアップで何が必要か(OAuthスコープ、必須フィールド、対応機能)をここで定義します。
2) 接続手段を作る
プロバイダに合った最も単純な接続方法を選びます:
- OAuth — ユーザーがサインインしてアクセスを承認する必要がある場合(Google、Slackなどで一般的)
- APIキー — ユーザーがプロバイダからトークンを貼り付ける場合
- Webhook — プロバイダがあなたのアプリにイベントをプッシュする場合
3) 認証情報を保存し、Connectionレコードを作る
ユーザーがフローを完了したら、Connectionレコードを作成してワークスペースやアカウントに紐づけます(単にユーザーに紐づけるのではない)。資格情報は安全に保存し(暗号化して保存し、完全なシークレットを再表示しない)、サポートに必要な基本情報(プロバイダのアカウントID、作成時間、接続したユーザー、付与された権限)を保存します。
4) 初回チェックを実行してステータスと進捗を設定
簡単なテストをすぐ実行します(例:Stripeならアカウント情報を取得)。成功すればConnectedを表示して進捗を完了にします。一部成功(接続はできたが権限が足りない)ならNeeds attentionにして具体的な修正箇所を指示します。
5) 失敗時にユーザーに見せるものを決める
明確なメッセージと推奨アクション、そして安全なフォールバックを一つ出します。例:「Stripeに接続できませんでした。APIキーを確認するか、再試行してください。」一つの統合が壊れていてもディレクトリ全体が使えなくならないようにします。
もしKoder.ai(koder.ai)上で構築しているなら、まずPlanning Modeでカタログ、セットアップフロー、ステータスルールを下書きしてから、その計画をもとにUIとバックエンドを生成すると良いでしょう。
エラー、リトライ、サポート向けの履歴
統合は退屈な理由で失敗します。ディレクトリがその理由を説明できないと、ユーザーはあなたのアプリを責め、サポートは原因が分からなくなります。
失敗は現実的な修正に結びつくバケットに分類してください:ログイン期限切れ、権限不足、プロバイダ障害、レートリミット。内部では詳細なエラーコードを持っていても、ユーザーには分かりやすい短いラベルを出します。
障害時のメッセージは「何が起きたか」「ユーザーがすべきこと」「システムが次に何をするか」を示すべきです。例:「Slack接続が期限切れです。再接続して同期を再開してください。再接続後は自動でリトライします。」これは生のAPIエラーよりも落ち着いて行動しやすくなります。
ユーザーを苛立たせないリトライルール
自動リトライはユーザーが自分で直せない場合に限定します。単純なルールで十分です:
- プロバイダダウンやネットワークエラー:バックオフを伴う自動リトライ、最後の成功時間は保持
- レート制限:一時停止して後で再試行、「Paused (rate limit)」表示
- 認証期限切れ:リトライ停止、ユーザーに再接続を促す
- 権限不足:リトライ停止、必要な権限を具体的に表示
- 設定不備:リトライ停止、修正が必要な設定を指示
ステータスは古くなりやすいので、トークンがまだ有効か、最終同期が行われたか、ディレクトリのバッジが現実と一致しているかを定期的に確認する軽量なヘルスチェックジョブを入れてください。
サポートで使える履歴
各Installに小さなイベント履歴を残します。完全なログは不要で、必要なパンくずだけで十分です:タイムスタンプ、イベント("token refreshed"、"sync failed"など)、短い理由、誰がトリガーしたか(ユーザーまたはシステム)。サポート用に内部専用のメモ欄を設け、サポートが何を変更したか記録できるようにします。
検索、フィルタ、ディレクトリの整理
統合は数が増えるとすぐに混雑します。目的は単純:人が数秒で必要なものを見つけ、どれが問題かを開かずに把握できるようにすることです。
まずは統合名とカテゴリを対象にした基本的な検索から始めてください。多くのユーザーは既に知っている名前を打つので("Slack"、"Stripe")、名前一致がランク付けより重要です。カテゴリ検索は用途(payments、messaging)しか分からない時に役立ちます。
フィルタは現実的な意図を反映させます。通常これら3つで大半をカバーできます:
- Connected(現在動作中)
- Needs attention(エラー、トークン期限切れ、権限不足)
- Not set up(利用可能だがまだインストールされていない)
リストの整理は主要なグルーピングをひとつ選び、それを維持してください。カテゴリでのグルーピングは数が多い場合に有効です(CRM、Payments、Messaging)。人気順はユーザーベースを反映するなら有用ですが、マーケティング的な順位は避けてください。実用的なデフォルトは、よく使われる順に表示し、残りをカテゴリでグループ化することです。
「誰でもすべてを見て良いわけではない」場合の方針も必要です。ある統合が機能フラグやプランの階層によって制限されるなら、大多数のユーザーには隠すか、短い理由("Business plan")を付けて無効表示にしてください。灰色化したカードで画面を埋めるのは避けるべきです。
パフォーマンスはリストと詳細を別ロードにすることで速く保てます。30個の重いカードを一度にレンダリングしないようにページングや仮想化を使い、詳細はユーザーが開いた時に遅延ロードしてください。ディレクトリは要約フィールド(Slack: Connected、Google: Needs attention、Stripe: Not set up)を表示し、詳細ページで完全な接続履歴を取得するのが理想です。
例:実際のアプリでのSlack、Google、Stripe
チームワークスペースアプリをPineworkと想像してください。PineworkにはAdminとMemberの2つのロールがあります。Adminはツールを接続したり設定を変えられます。Memberは接続済みのツールを使えるが追加や削除はできません。
Pineworkの統合ディレクトリでは、各カードに明確なラベル(Connected、Needs setup、Error)、短い用途説明、セットアップ進捗("2 of 3 steps")が表示されます。ユーザーはクリックせずに何が動き、何が保留かを把握できます。
Slackは通知に使われます。AdminがSlackを開くと:Status: Connected、Setup: "3 of 3 steps" と表示されます。MembersもSlackを見ることはできますが、主要アクションは無効で「Ask an Admin to manage」と表示されます。Slackが切断された場合、Membersは何が壊れたかを見られますが、再接続のコントロールは持ちません。
Googleはカレンダーに使われます。Pineworkは2つの部門をサポートするので複数の接続を許容します。GoogleのカードはStatus: Connected (2 accounts) と表示され、下に「Marketing Calendar」「Support Calendar」のように短く一覧します。セットアップは完了していることもあり、詳細ページでAdminは個別に1つだけ取り消せます。
Stripeは請求に使われます。一般的な途中状態はアカウント接続はできているがWebhookが未設定、というものです。カードはStatus: Needs setup、Progress: "2 of 3 steps"、警告として「Payments may not sync」と表示します。詳細ビューでは残りのステップが明確です:
- Connect Stripe account(完了)
- Choose billing plan mapping(完了)
- Add webhook endpoint(未完了)
これで「見た目は接続されているが何も動かない」という痛い状況を避けられます。
統合を管理しにくくするよくあるミス
アプリが数個から数十個に成長すると統合ディレクトリは壊れがちです。問題は大きな技術的欠陥ではなく、日常的に人を混乱させる小さなラベリングやモデリングの誤りです。
よくある問題は「installed」と「connected」を混同することです。Installedは通常「ワークスペースで利用可能になっている」ことを意味し、Connectedは実際に認証情報が存在してデータが流れる状態を意味します。これらが混ざると、ユーザーは準備完了に見える統合をクリックして行き止まりに遭います。
もう一つのミスはステータスを増やしすぎることです。最初はシンプルなバッジから始め、端的なケースを追加していくうちに pending、verifying、partial、paused、degraded、blocked、expiring と増えていきます。時間が経つとこれらは整合性を失います。実際にチェックできる事実に結び付く小さなセットを保ってください(Not connected、Connected、Needs attention など)。
権限を隠すことも問題を招きます。誰かが接続した後で、その統合が予想以上に広いアクセス権を持っていると分かることがあります。最終的な"Connect"ステップの前にスコープを明確に示し、詳細ページでも再び表示して管理者が監査できるようにします。
1統合=1接続と仮定しないこと
多くのアプリは複数の接続を必要とします:2つのSlackワークスペース、複数のStripeアカウント、共有のGoogleアカウントと個人アカウントの併存など。もし "1統合=1接続" をハードコードすると後で醜いワークアラウンドが必要になります。
考慮すべき点:
- 1つの統合下で複数の接続があること
- 必要なら明確な"デフォルト"接続
- 共有接続と個人接続の区別
- 誰が接続したかを見られる場所
一覧ビューは軽量に保ってください。ログやフィールドマッピング、長い説明を詰め込みすぎるとスキャン速度が落ちます。名前、短い用途、セットアップ進捗は一覧へ。履歴や詳細設定は詳細ページへ置きます。
すばやいチェックリストと次のステップ
スケーラブルな統合ディレクトリはシンプルなモデルと正直なUIに尽きます。ユーザーが3つの質問に素早く答えられればシステムは予測可能に感じられます:何が接続されているか、何が壊れているか、次に何をすべきか?
出荷前チェックリスト:
- モデルを分ける: Integration(カタログ) vs Install(ワークスペースで有効) vs Connection(OAuthトークン、APIキー、Webhook)。必要ならEvent(監査/サポート履歴)を追加。
- ステータスは導出する: トークン有効、スコープOK、Webhook到達可能などのチェックからラベルを計算し、バッジの正確さを保つ。
- 一覧をスキャンしやすく保つ: 各行に名前、明確なステータスラベル、1つの"次アクション"(Connect、Continue、Reconnect、Fix permissions)を表示。
- ライフサイクルアクションを主要に: Connect、Continue setup、Reconnect、Disable、Disconnect は見つけやすく、短い確認を付ける。
- 権限を見える化・監査可能に: 誰が接続や切断をできるか表示し、誰がいつ何を変更したかを記録する。
次にやること:既によく知っている3つの統合を選び、エンドツーエンドでモデリングしてください:チャットツール(OAuth)、Google風のアカウント接続(スコープ付きOAuth)、支払いツール(APIキー+Webhook)。これら3つを特別扱いなしで表現できるモデルなら、通常は30個までスケールします。
よくある質問
What’s the one job an integrations directory screen should do?
コントロールパネルとして扱ってください。マーケティングページではありません。各カードは「この統合は何のためか」「今動作しているか」「次にユーザーが取るべき単一のアクションは何か」を素早く示すべきです。ユーザーが「これが接続されているか?」を知るためにクリックしなければならないなら、統合ディレクトリは数が増えると信頼できないものになります。
What should every integration card show at a glance?
基本ルールは、カードが「何か」「健全か」「次に何をするか」を答えることです。通常は名前と一行の用途説明、最近のタイムスタンプ(最終同期または最終チェック)を含むステータス、状態に応じて変わる主要ボタンがあれば十分です。詳細はすべて「Manage」の背後に隠して、一覧をスキャンしやすく保ちます。
Why split the data model into Integration, Install, and Connection?
提供するもの(カタログ)とワークスペースで有効にしたもの、存在する認証情報を分けるためです。グローバルなIntegration(カタログ項目)、Install(ワークスペースで有効になっていること)、Connection(実際のOAuthアカウント、APIキー、Webhook)があれば、「インストール済み」と「接続済み」が混同される混乱を防げます。
How do I handle integrations that need multiple connected accounts?
実際のチームでは同じプロバイダに複数の外部アカウントが必要になることが多いです。MarketingとSupportが別々のGoogleカレンダーを接続したり、複数のStripeアカウントを持ったりします。1つのInstallの下に複数のConnectionを持てるようにモデリングすれば、一覧をシンプルに保ちながら個別管理が可能です。
What status labels should I use so they don’t become confusing later?
長く一貫して使える小さなラベルセットを使ってください。例:Not set up、In progress、Connected、Needs attention、Disabled。これらは、トークンの有効性、必須セットアップ手順の完了、最終同期など、実際にチェックできる事実から導出するようにします。そうすることで、問題が直ったのにバッジが赤いままになるような古い状態を防げます。
How should I model and show setup progress without building a huge wizard?
セットアップ進捗は、必須ステップの短いチェックリスト+ブロッキングしないオプションのステップで表現するのが良いです。ステップ定義は各Integrationに保持し、ステップ結果は各Installに保存します。UIは「必須ステップのうち2/3が完了」といった表示ができ、次の未完了の必須ステップを一目で示せます。
How do I keep integration permissions simple but safe?
まず全体に適用されるシンプルなロールルールを導入し、重要な統合にだけ追加チェックを加えます。多くの製品では Admin、Manager、Member の三役で十分です。Adminは全権、Managerはチーム向けの多くの統合を設定でき、Memberは有効化済み機能を利用できます。支払い等のセンシティブなものは「Billing manager」など単一のフラグで制限する方が、複雑なロールシステムを作るより簡潔です。
Where should I store OAuth tokens and API keys, and what should never go in logs?
ユーザーに見える設定(選択チャネル、Webhookのニックネーム、有効イベントなど)はInstallやConnectionに通常データとして保存し、リフレッシュトークンやAPIキー、署名シークレットなどの機密は必ずシークレットストアや暗号化フィールドに保存してください。生の認可コードやWebhookペイロード、秘密はログに残さないでください。ログする場合はconnection_idなどの参照とHTTPステータスやエラーコードのような安全なメタデータに限定します。
How should the UI handle errors like expired tokens, outages, and missing permissions?
エラー表示は「何が起きたか」「ユーザーがすべきこと」「システムが今後どうするか」を答えるべきです。例:「Slackの接続が期限切れです。再接続すると同期が継続されます。再接続後に自動でリトライします。」という具合に。リトライはユーザーが対処できない一時的な問題(プロバイダ側のダウン、ネットワーク障害)に限定し、認証期限切れや権限不足は停止してユーザーに対処させるのが良いです。
What’s the easiest way to add search, filters, and keep the directory usable at 30+ integrations?
検索はまずプロバイダ名(Slack、Stripeなど)で探せるようにし、次にカテゴリを検索できると実用的です。フィルタはユーザーの意図に沿ったものにして、たとえば Connected、Needs attention、Not set up の3つがあれば多くのケースをカバーできます。Koder.aiで構築するなら、Planning Modeでカタログフィールド、ステータスルール、セットアップ手順をまず設計しておくと、UIとバックエンドが増えても整合性を保ちやすくなります。