Supabase
基本原則
1. Supabaseは頻繁に変更されます — 実装前に必ずチェンジログと最新のドキュメントで確認してください。
Supabaseの機能についてトレーニングデータに依存しないでください。関数シグネチャ、config.tomlの設定、APIの規約はバージョン間で変更されます。
まず、https://supabase.com/changelog.md(軽量なサマリーインデックス — 重いプルではありません)を取得し、自分のタスクに関連するbreaking-changeタグをスキャンし、該当するものがあればリンク先のページを参照してください。次に、以下のドキュメントアクセス方法を使用して関連トピックを調べてください。
2. 作業を検証してください。 修正を実装した後は、必ずテストクエリを実行して変更が機能することを確認してください。確認なしの修正は不完全です。
3. エラーから回復し、ループしないでください。 アプローチが2〜3回試行しても失敗した場合は、停止して再検討してください。別の方法を試すか、ドキュメントを確認するか、エラーをより詳細に調査するか、利用可能なログを確認してください。Supabaseの問題は、同じコマンドを再試行するだけで解決できるとは限りません。また、答えが常にログにあるとは限りませんが、先に進む前にログを確認する価値は多くの場合あります。
4. Data APIへのテーブルの公開: ユーザーのData API設定によっては、新しく作成されたテーブルがData (REST) APIを介して自動的に公開されない場合があります。この場合、anonロールとauthenticatedロールに明示的にアクセスを許可する必要があります。
これはRLSとは別のものであることに注意してください。RLSはテーブルがアクセス可能になった後にどの行が表示されるかを制御するものであり、テーブル自体がアクセス可能かどうかを制御するものではありません。
ユーザーがSQLで作成したテーブルに予期せずアクセスできないと報告した場合は、Data API設定と、明示的なGRANT SQLを介してロールにアクセスが許可されているかどうかを確認してください。パブリックアクセス(anon/authenticated)を許可する場合は、必ずRLSも有効にしてください。完全なセットアップのワークフローについては、Data APIへのテーブルの公開を参照してください。
5. 公開スキーマでのRLS。
公開されているすべてのスキーマ(デフォルトではpublicを含む)のすべてのテーブルでRLSを有効にしてください。これはSupabaseでは重要です。公開スキーマ内のテーブルは、anon/authenticatedロールがアクセス権を持つ場合(Data APIへのテーブルの公開を参照)、Data APIを介して到達可能になる可能性があるためです。プライベートスキーマの場合も、多層防御としてRLSを使用することをお勧めします。RLSを有効にした後は、すべてのテーブルに同じauth.uid()パターンをデフォルトで適用するのではなく、実際のアクセスモデルに一致するポリシーを作成してください。
6. セキュリティチェックリスト。 認証、RLS、ビュー、ストレージ、ユーザーデータに触れるSupabaseタスクを実行するときは、このチェックリストを確認してください。これらは、脆弱性を静かに作り出すSupabase固有のセキュリティトラップです。
-
認証とセッションのセキュリティ
- JWTベースの認可決定に
user_metadataクレームを決して使用しないでください。 Supabaseでは、raw_user_meta_dataはユーザーが編集可能であり、auth.jwt()に表示される可能性があるため、RLSポリシーやその他の認可ロジックには安全ではありません。代わりに、認可データをraw_app_meta_data/app_metadataに保存してください。 - ユーザーを削除しても、既存のアクセストークンは無効になりません。 最初にサインアウトするかセッションを取り消し、機密性の高いアプリではJWTの有効期限を短く保ち、厳格な保証が必要な場合は、機密性の高い操作で
siauth.session_idをsiauth.sessionsに対して検証してください。 - 認可に
app_metadataまたはauth.jwt()を使用する場合、JWTクレームはユーザーのトークンが更新されるまで常に最新であるとは限らないことに注意してください。
- JWTベースの認可決定に
-
APIキーとクライアントの露出
- パブリッククライアントで
service_roleキーやシークレットキーを決して公開しないでください。 フロントエンドコードには公開可能なキーを使用してください。レガシーなanonキーは互換性のためだけにあります。Next.jsでは、NEXT_PUBLIC_で始まるすべての環境変数はブラウザに送信されます。 - Management API、CLI、MCPサーバーには、スコープ指定された個人用アクセストークンを使用してください。 従来の個人用アクセストークンは、すべての組織とプロジェクトに対してユーザーの完全なアカウントアクセスを保持します。スクリプト、CI、エージェントの場合は、タスクに必要な組織、プロジェクト、および権限に制限されたスコープ指定トークンをユーザーに作成してもらってください。個人用アクセストークンガイドには、各Management APIエンドポイントおよびMCPツールに必要な権限が記載されています。推測するのではなく、そこで権限を調べてください。
- パブリッククライアントで
-
RLS、ビュー、特権データベースコード
- ビューはデフォルトでRLSをバイパスします。 Postgres 15以降では、
CREATE VIEW ... WITH (security_invoker = true)を使用してください。古いバージョンのPostgresでは、anonロールとauthenticatedロールからアクセス権を取り消すか、公開されていないスキーマに配置してビューを保護してください。 - UPDATEにはSELECTポリシーが必要です。 Postgres RLSでは、UPDATEは最初に行をSELECTする必要があります。SELECTポリシーがない場合、更新は静かに0行を返します — エラーはなく、変更もありません。
auth.role()は非推奨です — 代わりにTO句を使用してください。 Supabaseはauth.role()を非推奨とし、代わりにポリシーでターゲットロールをTO authenticatedまたはTO anonで直接指定することを推奨しています。非推奨に加えて、auth.role() = 'authenticated'は匿名サインインが有効な場合に静かに壊れます。匿名ユーザーはauthenticatedのPostgresロールを持ち、ユーザーが実際にサインインしているかどうかに関係なくチェックを通過するためです。-- 非推奨(使用しないでください) create policy "example" on table_name for select using ( auth.role() = 'authenticated' );TO authenticatedだけでは認証であり認可ではありません(BOLA / IDOR)。TO authenticatedを使用するとロールのみがチェックされます — ユーザーがアクセスできる行は制限されません。正しいパターンは、TO authenticatedをUSING内の所有権述語と組み合わせることです:create policy "example" on table_name for select to authenticated using ( (select auth.uid()) = user_id );- UPDATEポリシーには
USINGとWITH CHECKの両方が必要です。WITH CHECKがないと、ユーザーは行のuser_idを別のユーザーに再割り当てできます:create policy "example" on table_name for update to authenticated using ( (select auth.uid()) = user_id ) with check ( (select auth.uid()) = user_id ); SECURITY DEFINER関数はRLSをバイパスします。SECURITY DEFINER関数は、作成者の権限(通常はbypassrlsを持つロール(例:postgres))で実行されます。権限エラーを解決するためにSECURITY DEFINERを追加しないでください。根本的な原因を修正せずに、静かにアクセス制御を削除します。SECURITY INVOKERを優先してください。public内のSECURITY DEFINER関数は、すべてのロールから呼び出し可能です。 Postgresはすべての新しい関数に対してデフォルトでPUBLICにEXECUTEを許可するため、public内のSECURITY DEFINER関数は、追加の許可なしでanonとauthenticated(PUBLICから継承)から呼び出し可能なパブリックAPIエンドポイントになります。SECURITY DEFINERが本当に必要な場合(例:内部参照テーブルでRLSをバイパスする場合)は、関数を公開されていないスキーマに保持し、関数本体内に常にauth.uid()チェックを含め、変更後にsupabase db advisorsを実行してください。
- ビューはデフォルトでRLSをバイパスします。 Postgres 15以降では、
-
ストレージアクセス制御
- StorageのupsertにはINSERT + SELECT + UPDATEが必要です。 INSERTのみを許可すると新しいアップロードは可能ですが、ファイルの置き換え(upsert)は静かに失敗します。3つすべてが必要です。
-
依存関係とサプライチェーンセキュリティ
- Supabaseパッケージ(
supabase-js、@supabase/ssr、supabase-pyなど)をインストールする際は、必ずパッケージバージョンを固定し、ロックファイルをコミットしてください。 完全なチェックリストについては、npmセキュリティガイドを参照してください。
- Supabaseパッケージ(
上記以外のセキュリティ上の懸念事項については、Supabaseプロダクトセキュリティインデックスを取得してください:https://supabase.com/docs/guides/security/product-security.md
Supabase CLI
常に--helpでコマンドを発見してください — 推測しないでください。CLIの構造はバージョン間で変更されます。
supabase --help # すべてのトップレベルコマンド
supabase <group> --help # サブコマンド(例:supabase db --help)
supabase <group> <command> --help # 特定のコマンドのフラグ
Supabase CLIの既知の落とし穴:
supabase db queryにはCLI v2.79.0以上が必要です → フォールバックとしてMCPexecute_sqlまたはpsqlを使用してくださいsupabase db advisorsにはCLI v2.81.3以上が必要です → フォールバックとしてMCPget_advisorsを使用してくださいsupabase loginのブラウザフローは、完全なアカウントアクセスを持つ従来のトークンを作成します。CIでは、代わりにSUPABASE_ACCESS_TOKENをスコープ指定された個人用アクセストークンに設定してください。これは保存されたログインよりも優先されます。データベースパスワード(--passwordまたはSUPABASE_DB_PASSWORD、例:supabase db push)で接続するコマンドは、トークンの権限によって制限されません。- 命令型マイグレーションプロジェクトでは、最初に
supabase migration new <name>で新しい手作りのマイグレーションファイルを作成してください。マイグレーションファイル名を自分で作成したり、期待される形式を記憶に頼ったりしないでください。宣言型スキーマプロジェクトはsupabase/schemas/からマイグレーションを生成します。以下の「スキーマ変更の作成とコミット」を参照してください。
バージョンチェックとアップグレード: supabase --versionを実行して確認してください。CLIのチェンジログとバージョン固有の機能については、CLIドキュメントまたはGitHubリリースを参照してください。
Supabase MCPサーバー
セットアップ手順、サーバーURL、設定については、MCPセットアップガイドを参照してください。
接続の問題のトラブルシューティング — 次の手順を順に実行してください:
-
サーバーに到達可能かどうかを確認します:
curl -so /dev/null -w "%{http_code}" https://mcp.supabase.com/mcp401が期待されます(トークンなし)が、サーバーは起動しています。タイムアウトまたは「connection refused」は、サーバーがダウンしている可能性があります。 -
.mcp.jsonの設定を確認します: プロジェクトルートに正しいサーバーURLを持つ有効な.mcp.jsonがあることを確認します。ない場合は、https://mcp.supabase.com/mcpを指すものを作成します。 -
MCPサーバーを認証します: サーバーに到達可能で
.mcp.jsonが正しいにもかかわらずツールが表示されない場合、ユーザーは認証する必要があります。Supabase MCPサーバーはOAuth 2.1を使用します — ユーザーにエージェントで認証フローをトリガーし、ブラウザで完了し、セッションをリロードするように指示します。 CIやブラウザフローが実行できないその他の環境では、代わりにAuthorization: Bearerヘッダーでスコープ指定された個人用アクセストークンを渡します。 -
スコープ指定トークンの権限を確認します: スコープ指定された個人用アクセストークンを使用中にツールが「このアクションを実行する権限がありません」で失敗した場合、トークンにそのツールの権限がないか、プロジェクトがトークンのスコープ外にあります。ツールに必要な権限を個人用アクセストークンガイドで確認してください。
Supabaseドキュメント
Supabaseの機能を実装する前に、関連するドキュメントを見つけてください。以下の方法を優先順位順に使用してください:
- MCP
search_docsツール(推奨 — 関連するスニペットを直接返します) - ドキュメントページをMarkdownとして取得 — 任意のドキュメントページは、URLパスに
.mdを追加することで取得できます。 - Web検索 — どのページを見ればよいかわからない場合のSupabase固有のトピック用。
スキーマ変更の作成とコミット
まず、プロジェクトがどのスキーマワークフローを使用しているかを判断します。
オプションA: 宣言型スキーマ
supabase/schemas/が存在する場合、またはconfig.tomlでschema_pathsが設定されている場合にこれを使用します。目的のスキーマ状態をそれらのファイルで編集し、マイグレーションを生成して確認します。最初にマイグレーションを手書きしないでください。宣言型データベーススキーマガイドを参照してください。
オプションB: 命令型マイグレーション
プロジェクトが宣言型スキーマを使用していない場合にこれを使用します。
スキーマ変更を行うには、execute_sql(MCP)またはsupabase db query(CLI)を使用してください。 これらはマイグレーション履歴エントリを作成せずにデータベースで直接SQLを実行するため、自由に反復し、準備ができたときにクリーンなマイグレーションを生成できます。
ローカルデータベーススキーマを変更するためにapply_migrationを使用しないでください — 呼び出しごとにマイグレーション履歴エントリが書き込まれるため、反復できなくなり、supabase db diff / supabase db pullは空または競合する差分を生成します。これを使用すると、最初の試行で渡したSQLに固執することになります。
変更をマイグレーションファイルにコミットする準備ができたら:
- アドバイザを実行 →
supabase db advisors(CLI v2.81.3以上)またはMCPget_advisors。問題を修正します。 - 上記のセキュリティチェックリストを確認 — 変更にビュー、関数、トリガー、またはストレージが含まれる場合。
- マイグレーションを生成 →
supabase db pull <descriptive-name> --local --yes - 確認 →
supabase migration list --local
デバッグ
Supabase関連のリクエストでエラー(例:Supabase REST API、Postgresデータベース、またはPostgRESTからのエラーコード、空の結果、予期せずRLSにブロックされる、またはAuth、Realtime、Edge Functions、StorageなどのSupabaseサービスからのエラー)が発生した場合、記憶に頼って診断や修正を提案するのではなく、Supabaseのモニタリングとデバッグドキュメントを必ず取得してください。同じドキュメントでは、遅いクエリや欠落しているインデックスなどのパフォーマンス最適化についても説明しています。
リファレンスガイド
- スキルフィードバック → references/skill-feedback.md ユーザーがこのスキルが誤ったアドバイスをした、または情報が不足していると報告した場合は必ず読んでください