jpskill.com
🛠️ 開発・MCP コミュニティ

supabase-patterns

Generic Supabase best practices for Row Level Security, realtime subscriptions, storage, and edge functions. Framework-agnostic.

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o supabase-patterns.zip https://jpskill.com/download/18057.zip && unzip -o supabase-patterns.zip && rm supabase-patterns.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/18057.zip -OutFile "$d\supabase-patterns.zip"; Expand-Archive "$d\supabase-patterns.zip" -DestinationPath $d -Force; ri "$d\supabase-patterns.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して supabase-patterns.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → supabase-patterns フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Supabase パターン Skill

あらゆるプロジェクトで Supabase を扱うための普遍的なパターンです。RLS ポリシー、リアルタイム、ストレージ、Edge Functions、およびマイグレーションを網羅します。

設計原則

この Skill は フレームワークに依存しません。普遍的な Supabase パターンを提供します。

  • Book-Vetting、ocr-service、または特定のプロジェクトに特化したものではありません
  • すべての Supabase プロジェクトに適用可能な共通パターンを網羅します
  • プロジェクト固有の構成は、プロジェクト固有の Skill に記述します

変数

変数 デフォルト 説明
SUPABASE_DIR supabase Supabase 構成のディレクトリ
ENFORCE_RLS true すべてのテーブルで RLS を必須にする
REALTIME_ENABLED auto リアルタイムテーブルを自動検出する

手順

必須 - 以下のワークフローの手順を順番に実行してください。

  1. Supabase プロジェクトの構成を確認する
  2. 既存の RLS ポリシーを確認する
  3. セキュリティ優先のパターンに従う
  4. マイグレーションを整理する

危険信号 - 停止して再検討

もしあなたが以下をしようとしているなら:

  • RLS ポリシーなしでテーブルを作成する
  • クライアント側のコードでサービスロールキーを使用する
  • スキーマの変更のためにマイグレーションをスキップする
  • リアルタイムで機密データを公開する

停止 -> RLS ポリシーを追加 -> 適切なキーを使用 -> その後続行

クックブック

RLS ポリシー

  • IF: RLS ポリシーを作成または変更する場合
  • THEN: ./cookbook/rls-policies.md を読んで実行する

リアルタイムサブスクリプション

  • IF: リアルタイム機能を設定する場合
  • THEN: ./cookbook/realtime-subscriptions.md を読んで実行する

ストレージパターン

  • IF: Supabase Storage を扱う場合
  • THEN: ./cookbook/storage-patterns.md を読んで実行する

クイックリファレンス

プロジェクト構造

supabase/
├── config.toml           # プロジェクト構成
├── migrations/           # SQL マイグレーション
│   ├── 20231201000000_initial.sql
│   └── 20231202000000_add_users.sql
├── seed.sql             # シードデータ
└── functions/           # Edge Functions
    └── hello/
        └── index.ts

主要なコマンド

# プロジェクトの初期化
supabase init

# ローカル開発の開始
supabase start

# マイグレーションの生成
supabase migration new my_migration

# リモートへのプッシュ
supabase db push

# 型の生成
supabase gen types typescript --local > types/supabase.ts

RLS ポリシーパターン

-- RLS の有効化
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- ユーザーが自分の投稿を閲覧できる
CREATE POLICY "Users can view own posts"
  ON posts FOR SELECT
  USING (auth.uid() = user_id);

-- ユーザーが自分の投稿を作成できる
CREATE POLICY "Users can create posts"
  ON posts FOR INSERT
  WITH CHECK (auth.uid() = user_id);

-- パブリック読み取り
CREATE POLICY "Public read"
  ON posts FOR SELECT
  USING (is_public = true);

クライアントパターン

// クライアントの初期化
import { createClient } from '@supabase/supabase-js';
import type { Database } from './types/supabase';

const supabase = createClient<Database>(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_ANON_KEY!
);

// 型付きクエリ
const { data, error } = await supabase
  .from('posts')
  .select('*')
  .eq('user_id', userId);

// 挿入
const { data, error } = await supabase
  .from('posts')
  .insert({ title, content, user_id: userId })
  .select()
  .single();

リアルタイムパターン

// 変更のサブスクライブ
const subscription = supabase
  .channel('posts')
  .on(
    'postgres_changes',
    { event: '*', schema: 'public', table: 'posts' },
    (payload) => {
      console.log('Change:', payload);
    }
  )
  .subscribe();

// クリーンアップ
subscription.unsubscribe();

ストレージパターン

// ファイルのアップロード
const { data, error } = await supabase.storage
  .from('avatars')
  .upload(`${userId}/avatar.png`, file, {
    upsert: true,
    contentType: 'image/png'
  });

// パブリック URL の取得
const { data: { publicUrl } } = supabase.storage
  .from('avatars')
  .getPublicUrl(`${userId}/avatar.png`);

セキュリティチェックリスト

本番環境前

  • [ ] すべてのテーブルで RLS が有効になっている
  • [ ] クライアントコードにサービスロールキーが含まれていない
  • [ ] 匿名キーはパブリック操作のみに使用する
  • [ ] ストレージバケットにポリシーがある
  • [ ] 機密性の高い列はリアルタイムから除外されている
  • [ ] API レート制限が構成されている
  • [ ] CORS が適切に構成されている

RLS チェックリスト

  • [ ] すべてのテーブルで RLS が有効になっている
  • [ ] SELECT ポリシーが定義されている
  • [ ] INSERT/UPDATE/DELETE ポリシーが定義されている
  • [ ] ポリシーが異なるロールでテストされている
  • [ ] 過度に寛容なポリシーがない

統合

スキーマ整合性との統合

Supabase のマイグレーションは ORM モデルと整合している必要があります。

-- supabase/migrations/20231201000000_users.sql
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email TEXT UNIQUE NOT NULL,
  name TEXT,
  created_at TIMESTAMPTZ DEFAULT now()
);

以下と一致する必要があります。

# SQLAlchemy モデル
class User(Base):
    id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
    email: Mapped[str] = mapped_column(unique=True)
    name: Mapped[str | None]
    created_at: Mapped[datetime] = mapped_column(server_default=func.now())

型生成

# ローカルスキーマから TypeScript 型を生成
supabase gen types typescript --local > types/supabase.ts

# クライアントでの使用
import type { Database } from './types/supabase';
type Post = Database['public']['Tables']['posts']['Row'];

ベストプラクティス

  1. RLS 優先: テーブルを作成するときは常に RLS ポリシーを追加する
  2. すべての変更にマイグレーション: スキーマを直接変更しない
  3. 型安全性: TypeScript 型を生成して使用する
  4. キーの衛生: クライアント側では匿名キー、サーバー側のみでサービスキーを使用する
  5. ポリシーのテスト: 実際のユーザーコンテキストで RLS をテストする
  6. リアルタイムは慎重に: 必要なテーブルのみで有効にする
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Supabase Patterns Skill

Universal patterns for working with Supabase in any project. Covers RLS policies, realtime, storage, edge functions, and migrations.

Design Principle

This skill is framework-generic. It provides universal Supabase patterns:

  • NOT tailored to Book-Vetting, ocr-service, or any specific project
  • Covers common patterns applicable across all Supabase projects
  • Project-specific configurations go in project-specific skills

Variables

Variable Default Description
SUPABASE_DIR supabase Directory for Supabase config
ENFORCE_RLS true Require RLS on all tables
REALTIME_ENABLED auto Auto-detect realtime tables

Instructions

MANDATORY - Follow the Workflow steps below in order.

  1. Check Supabase project configuration
  2. Review existing RLS policies
  3. Follow security-first patterns
  4. Keep migrations organized

Red Flags - STOP and Reconsider

If you're about to:

  • Create a table without RLS policies
  • Use service role key in client-side code
  • Skip migrations for schema changes
  • Expose sensitive data in realtime

STOP -> Add RLS policies -> Use appropriate keys -> Then proceed

Cookbook

RLS Policies

  • IF: Creating or modifying RLS policies
  • THEN: Read and execute ./cookbook/rls-policies.md

Realtime Subscriptions

  • IF: Setting up realtime features
  • THEN: Read and execute ./cookbook/realtime-subscriptions.md

Storage Patterns

  • IF: Working with Supabase Storage
  • THEN: Read and execute ./cookbook/storage-patterns.md

Quick Reference

Project Structure

supabase/
├── config.toml           # Project config
├── migrations/           # SQL migrations
│   ├── 20231201000000_initial.sql
│   └── 20231202000000_add_users.sql
├── seed.sql             # Seed data
└── functions/           # Edge functions
    └── hello/
        └── index.ts

Key Commands

# Initialize project
supabase init

# Start local development
supabase start

# Generate migration
supabase migration new my_migration

# Push to remote
supabase db push

# Generate types
supabase gen types typescript --local > types/supabase.ts

RLS Policy Patterns

-- Enable RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- User owns row
CREATE POLICY "Users can view own posts"
  ON posts FOR SELECT
  USING (auth.uid() = user_id);

-- User can insert own
CREATE POLICY "Users can create posts"
  ON posts FOR INSERT
  WITH CHECK (auth.uid() = user_id);

-- Public read
CREATE POLICY "Public read"
  ON posts FOR SELECT
  USING (is_public = true);

Client Patterns

// Initialize client
import { createClient } from '@supabase/supabase-js';
import type { Database } from './types/supabase';

const supabase = createClient<Database>(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_ANON_KEY!
);

// Query with types
const { data, error } = await supabase
  .from('posts')
  .select('*')
  .eq('user_id', userId);

// Insert
const { data, error } = await supabase
  .from('posts')
  .insert({ title, content, user_id: userId })
  .select()
  .single();

Realtime Pattern

// Subscribe to changes
const subscription = supabase
  .channel('posts')
  .on(
    'postgres_changes',
    { event: '*', schema: 'public', table: 'posts' },
    (payload) => {
      console.log('Change:', payload);
    }
  )
  .subscribe();

// Cleanup
subscription.unsubscribe();

Storage Pattern

// Upload file
const { data, error } = await supabase.storage
  .from('avatars')
  .upload(`${userId}/avatar.png`, file, {
    upsert: true,
    contentType: 'image/png'
  });

// Get public URL
const { data: { publicUrl } } = supabase.storage
  .from('avatars')
  .getPublicUrl(`${userId}/avatar.png`);

Security Checklist

Before Production

  • [ ] RLS enabled on ALL tables
  • [ ] Service role key NOT in client code
  • [ ] Anon key for public operations only
  • [ ] Storage buckets have policies
  • [ ] Sensitive columns excluded from realtime
  • [ ] API rate limiting configured
  • [ ] CORS properly configured

RLS Checklist

  • [ ] Every table has RLS enabled
  • [ ] SELECT policies defined
  • [ ] INSERT/UPDATE/DELETE policies defined
  • [ ] Policies tested with different roles
  • [ ] No overly permissive policies

Integration

With Schema Alignment

Supabase migrations should align with ORM models:

-- supabase/migrations/20231201000000_users.sql
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email TEXT UNIQUE NOT NULL,
  name TEXT,
  created_at TIMESTAMPTZ DEFAULT now()
);

Should match:

# SQLAlchemy model
class User(Base):
    id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
    email: Mapped[str] = mapped_column(unique=True)
    name: Mapped[str | None]
    created_at: Mapped[datetime] = mapped_column(server_default=func.now())

Type Generation

# Generate TypeScript types from local schema
supabase gen types typescript --local > types/supabase.ts

# Use in client
import type { Database } from './types/supabase';
type Post = Database['public']['Tables']['posts']['Row'];

Best Practices

  1. RLS first: Always add RLS policies when creating tables
  2. Migrations for everything: Never modify schema directly
  3. Type safety: Generate and use TypeScript types
  4. Key hygiene: Use anon key client-side, service key server-side only
  5. Test policies: Test RLS with actual user contexts
  6. Realtime carefully: Only enable for tables that need it