逆引き:DB・外部API・Token・Intent
DB接続、永続化、Webhook、外部HTTP、スクレイピング、Token、OAuth2、Privileged Intent、最小権限を整理します。
この記事で分かること
- DB URLと環境変数を分ける
- 接続プールと非同期処理を確認する
- 保存単位とschemaを決める
- migrationとbackupを本番前に用意する
- Webhookの受信と送信を分ける
- timeoutとretryを決める
コミュニティの相談ログを匿名化・一般化し、DB・外部API・Token・Intentまわりの安全な切り分けを整理した逆引きです。
DB接続・永続化設計
接続文字列と環境変数
DB URLや認証情報をコードとログから分けます。
値を出さない
DATABASE_URL、ユーザー名、パスワード、host、port、schema名は秘密情報や内部構成につながります。相談時は環境変数名、未設定、接続先の種類、エラー種別だけを出します。
環境ごとに分ける
ローカル、preview、本番で同じDBへ接続していないか確認します。変数変更後は再起動や再デプロイが必要な場合があるため、反映タイミングもログに残します。
確認ポイント
- DATABASE_URLの有無
- 接続先環境
- 値をログへ出さない
- 変更後の再起動
参考(公式ドキュメント)
- https://www.postgresql.org/docs/current/libpq-connect.html
- https://dev.mysql.com/doc/refman/8.4/en/connecting.html
接続プールと非同期DB
コマンドごとに接続を増やしすぎない確認です。
接続を使い回す
Interactionやmessage eventのたびに新しい接続を作ると、同時実行時にDB側の接続上限へ当たりやすくなります。アプリ起動時のpool、処理ごとのacquire/release、終了時のcloseを分けます。
awaitの位置を見る
DB待ちの間にInteraction応答期限を超えないよう、先にdeferする処理、timeoutで諦める処理、管理ログへ残す処理を決めます。
確認ポイント
- pool初期化
- acquire/release
- timeout
- defer/reply
- close
参考(公式ドキュメント)
保存単位とschema
何を1行として保存するかを先に決めます。
IDを軸にする
ユーザー名やチャンネル名は変わるため、guild_id、channel_id、user_id、message_idなどのIDと、表示用の名前を分けて保存します。削除済み対象や外部API結果も、取得時刻と状態を残します。
正規化しすぎない
小さなBotでは、読みやすい単位で履歴テーブル、設定テーブル、状態テーブルを分けるだけでも事故を減らせます。あとから直せるようにmigration前提で設計します。
確認ポイント
- guild_id
- channel_id
- user_id
- 取得時刻
- 設定/履歴/状態
migrationとbackup
本番DBを壊す前に戻す手段を用意します。
schema変更を手順化する
列追加、型変更、index追加、初期データ投入を手作業で行うと、previewと本番で差が出ます。migration名、実行順、失敗時の戻し方を残します。
backupを確認する
削除系コマンド、集計Bot、ログBotでは、DBのバックアップと復元手順を先に確認します。バックアップがあることと、復元できることは別です。
確認ポイント
- migration履歴
- 本番実行前確認
- backup取得
- restore手順
参考(公式ドキュメント)
Webhook・外部HTTP・スクレイピング
Webhookの受信と送信
Discordへ送るWebhookと、外部サービスから受けるWebhookを分けます。
向きを決める
Discord Webhook URLへ投稿する処理と、外部サービスから自分のBot/APIへ通知を受ける処理は設計が違います。URL、secret、署名検証、受け取りendpointを混同しないようにします。
URLを公開しない
Webhook URLは投稿権限を持つ秘密情報として扱います。相談ログや記事にはURLを載せず、送信先チャンネル、失敗status、payload要約だけを残します。
確認ポイント
- 送信/受信
- Webhook URLを伏せる
- secret/署名
- payload要約
参考(公式ドキュメント)
外部HTTP timeoutとretry
外部API待ちでBot全体を止めない設計です。
timeoutを必ず決める
Google、Twitter、Webhook、URL展開などの外部HTTPは、応答が遅い時や落ちている時があります。Interactionなら先にdeferし、通常メッセージでも待機時間の上限を決めます。
再試行を選ぶ
429や一時的な5xxは待機して再試行できる場合がありますが、401/403や入力ミスは再試行では直りません。利用者向け返信と管理ログを分けます。
確認ポイント
- timeout秒数
- HTTP status
- retry可否
- rate limit
- 管理ログ
参考(公式ドキュメント)
URL/OGP/スクレイピングの注意
URL展開やページ取得を無制限にしない確認です。
公式APIを優先する
検索結果、SNS投稿、ページtitle、OGP画像などは、公式APIや利用規約、robots、rate limit、キャッシュ可否を先に確認します。HTML構造へ依存する処理は壊れやすく、画像/Embed付き結果は公開記事へ直接載せません。
取得範囲を絞る
URLのscheme、host、リダイレクト、ファイルサイズ、content-type、timeoutを確認し、内部ネットワークや巨大ファイルへアクセスしないようにします。
確認ポイント
- 公式API/規約確認
- 許可host
- timeout
- content-type
- キャッシュ
API認証と失敗時の返信
OAuth、API key、rate limit、認証切れを利用者体験へ落とします。
認証方式を分ける
Bot自身のAPI key、ユーザーのOAuth、refresh token、Discord OAuth2、外部サービスのWebhook secretを別のものとして扱います。どれも公開ログへ出しません。
失敗を短く返す
利用者には「外部サービスに接続できません」「認証が必要です」など短く返し、管理ログにstatus、endpoint種別、再試行可否、認証切れの可能性を残します。
確認ポイント
- API key
- OAuth
- refresh token
- status
- 再認可
参考(公式ドキュメント)
Token・OAuth2・所有確認
Tokenとclient secretの境界
Botとしてログインできる値とOAuth2の秘密情報を分けます。
Tokenは預からない
Bot TokenはBotとしてログインできる秘密情報です。所有確認やサポート目的でも、第三者に入力させたり、公開チャンネルへ貼らせたりしない設計にします。
漏れた時は再生成する
Tokenやclient secretが漏れた可能性がある場合は、伏せ字にして終わりではなく、Developer Portalで再生成し、古い値を無効化します。
確認ポイント
- Tokenを共有しない
- client secretを公開しない
- 漏洩時は再生成
- 環境変数で扱う
参考(公式ドキュメント)
- https://docs.discord.com/developers/topics/oauth2
- https://docs.discord.com/developers/resources/application
ログとスクリーンショットの伏せ方
相談ログを記事化する前に消す情報を決めます。
テキスト化を優先する
エラーや設定相談は、画像ではなくテキストへ戻すと伏せるべき値を確認しやすくなります。URL、Token、メール、ユーザーID、招待URL、秘密情報を公開本文へ残しません。
画像はローカル確認に留める
スクリーンショットや添付はローカルで読み取って内容を文章化し、websiteには画像ファイルやDiscord CDN URLを不用意に入れません。
確認ポイント
- Token
- client secret
- redirect URLの秘密部分
- Discord招待URL
- 個人情報
参考(公式ドキュメント)
所有確認でTokenを使わない
Bot所有者性やApplication確認を安全に扱います。
Token入力を避ける
Botの所有確認でTokenを提出させると、確認者がBotを乗っ取れる状態になります。OAuth2、Developer Portal上の設定変更、Application情報など、Tokenを預からない方法へ寄せます。
検証範囲を限定する
所有確認のために必要な情報だけを確認し、不要な権限や長期間使える秘密情報を集めないようにします。確認用の一時値は期限と用途を決めます。
確認ポイント
- Token不要
- 確認用一時値
- Application ID
- 期限
参考(公式ドキュメント)
- https://docs.discord.com/developers/resources/application
- https://docs.discord.com/developers/topics/oauth2
stateとredirectを確認する
OAuth2認可が別セッションへ混ざらないようにします。
stateで紐付ける
OAuth2の戻り先では、認可結果が自分の開始したセッションに戻ったかをstateで確認します。stateを使わないと、別ユーザーや別操作の結果を取り違える危険があります。
redirect先を固定する
redirect URIはDeveloper Portal側の登録、サーバー側の受け取り、環境ごとのURLを分けます。公開フロントエンドへclient secretを置かないようにします。
確認ポイント
- state生成
- state検証
- redirect URI登録
- client secretはサーバー側
参考(公式ドキュメント)
Privileged Intent・最小権限
Portal側とコード側Intent
Intent設定を両側で確認します。
両方必要
Gateway Intentは、Developer Portal側で許可する設定と、コード側で要求する設定を分けて確認します。片方だけ有効でも、期待するイベントや本文が届かないことがあります。
再接続して確認する
Intentを変更した後はGateway接続を張り直し、起動ログ、close code、warning、イベント到達ログを確認します。
確認ポイント
- Portal Botページ
- コード側intents
- Bot再起動
- 起動ログ
参考(公式ドキュメント)
Message Contentと代替設計
本文読み取りが必要かを見直します。
本文読み取りを減らす
prefix commandやメッセージ監視はMessage Contentの影響を受けます。slash command、context menu、button、modalへ移せる処理は、本文読み取り前提を減らします。
必要性を説明できるようにする
本文、添付、Embed、componentsを読む必要がある場合は、対象チャンネル、用途、保存期間、ログの伏せ方を決めます。
確認ポイント
- slash command化
- 対象チャンネル限定
- 保存しない設計
- ログ伏せ
参考(公式ドキュメント)
OAuth2 scopeとpermissions
導入URLで要求するものを分けます。
scopeと権限は別
bot、applications.commandsなどのscopeと、Manage Roles、Ban Members、Send Messagesなどのpermissionsは別です。表示されないslash commandと権限不足を混同しないようにします。
必要な権限だけにする
機能ごとに必要権限を洗い出し、導入URL、Botロール、チャンネル上書き、Interactionのapp_permissionsを順に確認します。
確認ポイント
- scope
- permissions
- Botロール
- チャンネル上書き
参考(公式ドキュメント)
- https://docs.discord.com/developers/topics/oauth2
- https://docs.discord.com/developers/topics/permissions
Administratorで原因を隠さない
検証時に権限を広げた後の戻し方です。
原因を分ける
Administratorを付けると一時的に動いても、導入URL、ロール階層、チャンネル上書き、アプリコマンド権限のどこが原因だったか分かりにくくなります。
戻す手順を残す
検証で権限を広げた場合は、必要最小限へ戻す手順を作ります。利用者向け返信と管理ログには、どの権限が足りないかを分けて残します。
確認ポイント
- 一時的な権限変更
- 最小権限へ戻す
- app_permissions
- 管理ログ
参考(公式ドキュメント)
一次情報(公式ドキュメント)
- PostgreSQL documentation
- MySQL Reference Manual
- Python asyncio documentation
- Discord Developer Documentation: Webhooks
- Discord Developer Documentation: Rate Limits
- Discord Developer Documentation: OAuth2
- Discord Developer Documentation: Application Resource
- Discord Developer Documentation: Gateway
- Discord Developer Documentation: Permissions