重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
supabase-admin by erichowens/some_claude_skills
npx skills add https://github.com/erichowens/some_claude_skills --skill supabase-admin精通 Supabase 模式设计、行级安全策略、迁移以及生产环境应用的性能优化。
✅ 在以下情况使用此技能:
auth.uid()、auth.jwt())❌ 不要在以下情况使用:
cloudflare-worker-dev 技能始终为用户表启用 RLS:
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;
策略模式:
-- 公开读取,已认证用户写入
CREATE POLICY "Public read" ON posts FOR SELECT USING (true);
CREATE POLICY "Owners can write" ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- 仅所有者访问
CREATE POLICY "Users own their data" ON profiles
FOR ALL USING (auth.uid() = id);
-- 基于角色的访问
CREATE POLICY "Admins can do anything" ON content
FOR ALL USING (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
性能关键:为 auth.uid() 列创建索引:
-- 为 RLS 策略带来 100 倍的性能提升
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_profiles_id ON profiles(id);
JWT 函数的子查询优化:
-- 差:为每一行解析 JWT
CREATE POLICY "slow" ON posts FOR SELECT
USING (user_id = auth.uid());
-- 好:通过子查询解析一次 JWT
CREATE POLICY "fast" ON posts FOR SELECT
USING (user_id = (SELECT auth.uid()));
文件命名约定:
supabase/migrations/
├── 001_initial_schema.sql
├── 002_add_profiles_trigger.sql
├── 003_forum_tables.sql
└── 004_add_rls_policies.sql
迁移模板:
-- Migration: 005_feature_name
-- Description: What this migration does
-- Author: name
-- Date: YYYY-MM-DD
-- Up migration
BEGIN;
-- Your DDL here
CREATE TABLE ...;
ALTER TABLE ...;
CREATE POLICY ...;
COMMIT;
-- Down migration (as comment for reference)
-- DROP TABLE ...;
-- DROP POLICY ...;
安全迁移模式:
-- 添加带默认值的列(无表锁)
ALTER TABLE users ADD COLUMN status text DEFAULT 'active';
-- 安全地添加 NOT NULL 约束
ALTER TABLE users ADD COLUMN email text;
UPDATE users SET email = 'unknown@example.com' WHERE email IS NULL;
ALTER TABLE users ALTER COLUMN email SET NOT NULL;
-- 并发创建索引(无锁)
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);
注册时自动创建配置文件:
-- 创建配置文件的函数
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, email, display_name)
VALUES (
NEW.id,
NEW.email,
COALESCE(NEW.raw_user_meta_data->>'display_name', split_part(NEW.email, '@', 1))
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- 在 auth.users 上的触发器
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
在策略中检查身份验证状态:
-- 仅限已认证用户
CREATE POLICY "Authenticated access" ON data
FOR SELECT USING (auth.role() = 'authenticated');
-- 获取当前用户的 ID
SELECT auth.uid();
-- 获取当前用户的 JWT 声明
SELECT auth.jwt();
带默认值的时间戳:
CREATE TABLE posts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,
content text NOT NULL,
created_at timestamptz DEFAULT now(),
updated_at timestamptz DEFAULT now()
);
-- 自动更新 updated_at
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_posts_updated_at
BEFORE UPDATE ON posts
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
软删除模式:
ALTER TABLE posts ADD COLUMN deleted_at timestamptz;
CREATE POLICY "Hide deleted" ON posts
FOR SELECT USING (deleted_at IS NULL);
全文搜索:
-- 添加搜索向量列
ALTER TABLE posts ADD COLUMN search_vector tsvector;
-- 创建 GIN 索引
CREATE INDEX idx_posts_search ON posts USING GIN(search_vector);
-- 更新函数
CREATE OR REPLACE FUNCTION posts_search_update()
RETURNS TRIGGER AS $$
BEGIN
NEW.search_vector := to_tsvector('english', COALESCE(NEW.title, '') || ' ' || COALESCE(NEW.content, ''));
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 搜索查询
SELECT * FROM posts
WHERE search_vector @@ plainto_tsquery('english', 'search terms');
常见问题:空结果,无错误
-- 检查 RLS 是否启用
SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';
-- 列出所有策略
SELECT * FROM pg_policies WHERE tablename = 'your_table';
-- 以特定角色测试
SET ROLE anon;
SELECT * FROM your_table LIMIT 1;
RESET ROLE;
-- 以特定用户测试
SET request.jwt.claims TO '{"sub": "user-uuid-here"}';
SELECT * FROM your_table;
诊断查询:
-- 检查当前用户能看到什么
SELECT
auth.uid() as current_user,
auth.role() as current_role,
(SELECT count(*) FROM your_table) as visible_rows;
| 任务 | 命令 |
|---|---|
| 启用 RLS | ALTER TABLE t ENABLE ROW LEVEL SECURITY; |
| 创建策略 | CREATE POLICY "name" ON t FOR action USING (condition); |
| 删除策略 | DROP POLICY "name" ON t; |
| 检查策略 | SELECT * FROM pg_policies WHERE tablename = 't'; |
| 当前用户 | SELECT auth.uid(); |
| 强制为所有者启用 RLS | ALTER TABLE t FORCE ROW LEVEL SECURITY; |
查看 /references/ 获取详细指南:
rls-patterns.md - 高级 RLS 策略模式migration-checklist.md - 部署前检查清单performance-tuning.md - 查询和索引优化social-schema.md - 社交功能模式模式每周安装次数
50
代码仓库
GitHub 星标数
80
首次出现
2026年1月24日
安全审计
安装于
cursor45
codex44
gemini-cli44
opencode43
github-copilot41
cline39
Master Supabase schema design, Row Level Security policies, migrations, and performance optimization for production applications.
✅ USE this skill for:
auth.uid(), auth.jwt())❌ DO NOT use for:
cloudflare-worker-dev skillAlways Enable RLS on User Tables:
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;
Policy Patterns:
-- Public read, authenticated write
CREATE POLICY "Public read" ON posts FOR SELECT USING (true);
CREATE POLICY "Owners can write" ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Owner-only access
CREATE POLICY "Users own their data" ON profiles
FOR ALL USING (auth.uid() = id);
-- Role-based access
CREATE POLICY "Admins can do anything" ON content
FOR ALL USING (
EXISTS (
SELECT 1 FROM profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
Performance-Critical: Index auth.uid() Columns:
-- 100x performance improvement for RLS policies
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_profiles_id ON profiles(id);
Subquery Optimization for JWT Functions:
-- BAD: JWT parsed for every row
CREATE POLICY "slow" ON posts FOR SELECT
USING (user_id = auth.uid());
-- GOOD: JWT parsed once via subquery
CREATE POLICY "fast" ON posts FOR SELECT
USING (user_id = (SELECT auth.uid()));
File Naming Convention:
supabase/migrations/
├── 001_initial_schema.sql
├── 002_add_profiles_trigger.sql
├── 003_forum_tables.sql
└── 004_add_rls_policies.sql
Migration Template:
-- Migration: 005_feature_name
-- Description: What this migration does
-- Author: name
-- Date: YYYY-MM-DD
-- Up migration
BEGIN;
-- Your DDL here
CREATE TABLE ...;
ALTER TABLE ...;
CREATE POLICY ...;
COMMIT;
-- Down migration (as comment for reference)
-- DROP TABLE ...;
-- DROP POLICY ...;
Safe Migration Patterns:
-- Add column with default (no table lock)
ALTER TABLE users ADD COLUMN status text DEFAULT 'active';
-- Add NOT NULL constraint safely
ALTER TABLE users ADD COLUMN email text;
UPDATE users SET email = 'unknown@example.com' WHERE email IS NULL;
ALTER TABLE users ALTER COLUMN email SET NOT NULL;
-- Create index concurrently (no lock)
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);
Auto-create Profile on Signup:
-- Function to create profile
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, email, display_name)
VALUES (
NEW.id,
NEW.email,
COALESCE(NEW.raw_user_meta_data->>'display_name', split_part(NEW.email, '@', 1))
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Trigger on auth.users
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
Check Auth Status in Policies:
-- Authenticated users only
CREATE POLICY "Authenticated access" ON data
FOR SELECT USING (auth.role() = 'authenticated');
-- Get current user's ID
SELECT auth.uid();
-- Get current user's JWT claims
SELECT auth.jwt();
Timestamps with Defaults:
CREATE TABLE posts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,
content text NOT NULL,
created_at timestamptz DEFAULT now(),
updated_at timestamptz DEFAULT now()
);
-- Auto-update updated_at
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_posts_updated_at
BEFORE UPDATE ON posts
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
Soft Delete Pattern:
ALTER TABLE posts ADD COLUMN deleted_at timestamptz;
CREATE POLICY "Hide deleted" ON posts
FOR SELECT USING (deleted_at IS NULL);
Full-Text Search:
-- Add search vector column
ALTER TABLE posts ADD COLUMN search_vector tsvector;
-- Create GIN index
CREATE INDEX idx_posts_search ON posts USING GIN(search_vector);
-- Update function
CREATE OR REPLACE FUNCTION posts_search_update()
RETURNS TRIGGER AS $$
BEGIN
NEW.search_vector := to_tsvector('english', COALESCE(NEW.title, '') || ' ' || COALESCE(NEW.content, ''));
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Search query
SELECT * FROM posts
WHERE search_vector @@ plainto_tsquery('english', 'search terms');
Common Problem: Empty Results, No Error
-- Check if RLS is enabled
SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';
-- List all policies
SELECT * FROM pg_policies WHERE tablename = 'your_table';
-- Test as specific role
SET ROLE anon;
SELECT * FROM your_table LIMIT 1;
RESET ROLE;
-- Test with specific user
SET request.jwt.claims TO '{"sub": "user-uuid-here"}';
SELECT * FROM your_table;
Diagnostic Query:
-- Check what the current user can see
SELECT
auth.uid() as current_user,
auth.role() as current_role,
(SELECT count(*) FROM your_table) as visible_rows;
| Task | Command |
|---|---|
| Enable RLS | ALTER TABLE t ENABLE ROW LEVEL SECURITY; |
| Create policy | CREATE POLICY "name" ON t FOR action USING (condition); |
| Drop policy | DROP POLICY "name" ON t; |
| Check policies | SELECT * FROM pg_policies WHERE tablename = 't'; |
| Current user | SELECT auth.uid(); |
| Force RLS for owner | ALTER TABLE t FORCE ROW LEVEL SECURITY; |
See /references/ for detailed guides:
rls-patterns.md - Advanced RLS policy patternsmigration-checklist.md - Pre-deployment checklistperformance-tuning.md - Query and index optimizationsocial-schema.md - Schema patterns for social featuresWeekly Installs
50
Repository
GitHub Stars
80
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
cursor45
codex44
gemini-cli44
opencode43
github-copilot41
cline39
Supabase Postgres 最佳实践指南 - 8大类别性能优化规则与SQL示例
89,100 周安装