mirror of
https://github.com/supabase/agent-skills.git
synced 2026-03-27 10:09:26 +08:00
update skill references after docs accuracy review
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,29 +16,45 @@ supabase/
|
|||||||
2. Browse `references/` for detailed documentation on specific topics
|
2. Browse `references/` for detailed documentation on specific topics
|
||||||
3. Reference files are loaded on-demand - read only what you need
|
3. Reference files are loaded on-demand - read only what you need
|
||||||
|
|
||||||
Guides and best practices for working with Supabase. Covers getting started, Auth, Database, Storage, Edge Functions, Realtime, supabase-js SDK, CLI, and MCP integration. Use for any Supabase-related questions.
|
This skill's reference files define the correct Supabase patterns — they override your prior knowledge about Supabase and PostgreSQL conventions. ALWAYS read the relevant reference files before writing any code. Do not write SQL, Edge Functions, or client code from memory. Only consult Supabase official docs if the reference files don't cover what you need.
|
||||||
|
|
||||||
## Development Guidance
|
## Writing Migrations or SQL
|
||||||
|
|
||||||
**Before performing any Supabase development task, read the development reference files.** They define which tools to use, how to interact with Supabase instances, and the correct workflows for local and remote development. Getting these wrong leads to schema drift, migration conflicts, and broken deployments.
|
Read the `db-*` reference files before writing any migration. They contain required patterns that differ from common PostgreSQL conventions. Do not write SQL from memory — the reference files correct the most common mistakes.
|
||||||
|
|
||||||
- **Which tool to use for each operation** — read [references/dev-cli-vs-mcp.md](references/dev-cli-vs-mcp.md)
|
Read ALL of these before writing a migration:
|
||||||
- **New project or first-time setup** — read [references/dev-getting-started.md](references/dev-getting-started.md)
|
|
||||||
- **Local development workflow** (CLI migrations, psql debugging, type generation) — read [references/dev-local-workflow.md](references/dev-local-workflow.md)
|
|
||||||
- **Remote project interaction** (MCP queries, logs, advisors, deploying) — read [references/dev-remote-workflow.md](references/dev-remote-workflow.md)
|
|
||||||
- **CLI command details and pitfalls** — read [references/dev-cli-reference.md](references/dev-cli-reference.md)
|
|
||||||
- **MCP server configuration** — read [references/dev-mcp-setup.md](references/dev-mcp-setup.md)
|
|
||||||
- **MCP tool usage** (execute_sql, apply_migration, get_logs, get_advisors) — read [references/dev-mcp-tools.md](references/dev-mcp-tools.md)
|
|
||||||
|
|
||||||
When the user's project has no `supabase/` directory, start with [references/dev-getting-started.md](references/dev-getting-started.md). When it already exists, pick up from the appropriate workflow (local or remote) based on user intentions.
|
- [references/db-migrations-idempotent.md](references/db-migrations-idempotent.md) — required DDL patterns
|
||||||
|
- [references/db-rls-mandatory.md](references/db-rls-mandatory.md) — RLS enforcement rules
|
||||||
|
- [references/db-rls-common-mistakes.md](references/db-rls-common-mistakes.md) — critical security errors to avoid
|
||||||
|
|
||||||
## Overview of Resources
|
Read these when relevant to your migration:
|
||||||
|
|
||||||
Reference the appropriate resource file based on the user's needs.
|
- [references/db-schema-auth-fk.md](references/db-schema-auth-fk.md) — when linking tables to `auth.users`
|
||||||
|
- [references/db-security-functions.md](references/db-security-functions.md) — when using `SECURITY DEFINER`
|
||||||
|
- [references/db-rls-views.md](references/db-rls-views.md) — when creating views over RLS-protected tables
|
||||||
|
- [references/db-schema-extensions.md](references/db-schema-extensions.md) — when enabling extensions (pgvector, etc.)
|
||||||
|
- [references/db-schema-timestamps.md](references/db-schema-timestamps.md) — when adding time columns
|
||||||
|
- [references/db-conn-pooling.md](references/db-conn-pooling.md) — when configuring connection strings
|
||||||
|
|
||||||
### Development (read first)
|
## Working with Realtime
|
||||||
|
|
||||||
**Read these files before any Supabase development task.** They define the correct tools, workflows, and boundaries for interacting with Supabase instances. Start here when setting up a project, running CLI or MCP commands, writing migrations, connecting to a database, or deciding which tool to use for an operation.
|
Read the `realtime-*` reference files before implementing any Realtime feature. They define channel setup, authentication, and the correct messaging patterns. Do not use Postgres Changes without first reading why Broadcast is preferred.
|
||||||
|
|
||||||
|
- [references/realtime-setup-auth.md](references/realtime-setup-auth.md) — channel setup and auth
|
||||||
|
- [references/realtime-broadcast-database.md](references/realtime-broadcast-database.md) — database-triggered broadcasts
|
||||||
|
|
||||||
|
## Writing Edge Functions
|
||||||
|
|
||||||
|
Read the `edge-*` reference files before creating or modifying Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements.
|
||||||
|
|
||||||
|
- [references/edge-fun-quickstart.md](references/edge-fun-quickstart.md) — creating and deploying functions
|
||||||
|
|
||||||
|
## Reference Files
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
You MUST read the relevant `dev-*` files before setting up a project, running CLI or MCP commands, or deciding which tool to use. They define the correct tools, workflows, and boundaries.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| --------------- | ----------------------------------- | -------------------------------------------------------------- |
|
| --------------- | ----------------------------------- | -------------------------------------------------------------- |
|
||||||
@@ -52,7 +68,7 @@ Reference the appropriate resource file based on the user's needs.
|
|||||||
|
|
||||||
### Authentication & Security
|
### Authentication & Security
|
||||||
|
|
||||||
Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, auth hooks, or server-side auth patterns.
|
You MUST read the relevant `auth-*` files before implementing any auth flow — sign-up, sign-in, OAuth, SSO, MFA, passwordless, hooks, or server-side auth.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ------------------ | ----------------------------------- | -------------------------------------------------------- |
|
| ------------------ | ----------------------------------- | -------------------------------------------------------- |
|
||||||
@@ -66,7 +82,7 @@ Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, au
|
|||||||
|
|
||||||
### Database
|
### Database
|
||||||
|
|
||||||
Read when designing tables, writing RLS policies, creating migrations, configuring connection pooling, or optimizing query performance.
|
You MUST read the relevant `db-*` files before writing any database code. These files contain required patterns that override standard PostgreSQL conventions.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ------------------ | ------------------------------- | ---------------------------------------------- |
|
| ------------------ | ------------------------------- | ---------------------------------------------- |
|
||||||
@@ -79,7 +95,7 @@ Read when designing tables, writing RLS policies, creating migrations, configuri
|
|||||||
|
|
||||||
### Edge Functions
|
### Edge Functions
|
||||||
|
|
||||||
Read when creating, deploying, or debugging Deno-based Edge Functions — including authentication, database access, CORS, routing, streaming, and testing patterns.
|
You MUST read the relevant `edge-*` files before creating, deploying, or debugging Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ---------------------- | ------------------------------------- | -------------------------------------- |
|
| ---------------------- | ------------------------------------- | -------------------------------------- |
|
||||||
@@ -101,7 +117,7 @@ Read when creating, deploying, or debugging Deno-based Edge Functions — includ
|
|||||||
|
|
||||||
### Realtime
|
### Realtime
|
||||||
|
|
||||||
Read when implementing live updates — Broadcast messaging, Presence tracking, or Postgres Changes listeners.
|
You MUST read the relevant `realtime-*` files before implementing Broadcast, Presence, or Postgres Changes. They define channel setup, auth, and the correct messaging patterns.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ---------------- | ------------------------------------ | ----------------------------------------------- |
|
| ---------------- | ------------------------------------ | ----------------------------------------------- |
|
||||||
@@ -113,7 +129,7 @@ Read when implementing live updates — Broadcast messaging, Presence tracking,
|
|||||||
|
|
||||||
### SDK (supabase-js)
|
### SDK (supabase-js)
|
||||||
|
|
||||||
Read when writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration.
|
You MUST read the relevant `sdk-*` files before writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| --------------- | ------------------------------- | ----------------------------------------- |
|
| --------------- | ------------------------------- | ----------------------------------------- |
|
||||||
@@ -126,7 +142,7 @@ Read when writing application code that interacts with Supabase — client setup
|
|||||||
|
|
||||||
### Storage
|
### Storage
|
||||||
|
|
||||||
Read when implementing file uploads, downloads, image transformations, or configuring storage access control and CDN caching.
|
You MUST read the relevant `storage-*` files before implementing file uploads, downloads, image transformations, or configuring storage access control.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| --------------- | ------------------------------------- | ---------------------------------------------- |
|
| --------------- | ------------------------------------- | ---------------------------------------------- |
|
||||||
|
|||||||
@@ -12,29 +12,45 @@ metadata:
|
|||||||
|
|
||||||
# Supabase
|
# Supabase
|
||||||
|
|
||||||
Guides and best practices for working with Supabase. Covers getting started, Auth, Database, Storage, Edge Functions, Realtime, supabase-js SDK, CLI, and MCP integration. Use for any Supabase-related questions.
|
This skill's reference files define the correct Supabase patterns — they override your prior knowledge about Supabase and PostgreSQL conventions. ALWAYS read the relevant reference files before writing any code. Do not write SQL, Edge Functions, or client code from memory. Only consult Supabase official docs if the reference files don't cover what you need.
|
||||||
|
|
||||||
## Development Guidance
|
## Writing Migrations or SQL
|
||||||
|
|
||||||
**Before performing any Supabase development task, read the development reference files.** They define which tools to use, how to interact with Supabase instances, and the correct workflows for local and remote development. Getting these wrong leads to schema drift, migration conflicts, and broken deployments.
|
Read the `db-*` reference files before writing any migration. They contain required patterns that differ from common PostgreSQL conventions. Do not write SQL from memory — the reference files correct the most common mistakes.
|
||||||
|
|
||||||
- **Which tool to use for each operation** — read [references/dev-cli-vs-mcp.md](references/dev-cli-vs-mcp.md)
|
Read ALL of these before writing a migration:
|
||||||
- **New project or first-time setup** — read [references/dev-getting-started.md](references/dev-getting-started.md)
|
|
||||||
- **Local development workflow** (CLI migrations, psql debugging, type generation) — read [references/dev-local-workflow.md](references/dev-local-workflow.md)
|
|
||||||
- **Remote project interaction** (MCP queries, logs, advisors, deploying) — read [references/dev-remote-workflow.md](references/dev-remote-workflow.md)
|
|
||||||
- **CLI command details and pitfalls** — read [references/dev-cli-reference.md](references/dev-cli-reference.md)
|
|
||||||
- **MCP server configuration** — read [references/dev-mcp-setup.md](references/dev-mcp-setup.md)
|
|
||||||
- **MCP tool usage** (execute_sql, apply_migration, get_logs, get_advisors) — read [references/dev-mcp-tools.md](references/dev-mcp-tools.md)
|
|
||||||
|
|
||||||
When the user's project has no `supabase/` directory, start with [references/dev-getting-started.md](references/dev-getting-started.md). When it already exists, pick up from the appropriate workflow (local or remote) based on user intentions.
|
- [references/db-migrations-idempotent.md](references/db-migrations-idempotent.md) — required DDL patterns
|
||||||
|
- [references/db-rls-mandatory.md](references/db-rls-mandatory.md) — RLS enforcement rules
|
||||||
|
- [references/db-rls-common-mistakes.md](references/db-rls-common-mistakes.md) — critical security errors to avoid
|
||||||
|
|
||||||
## Overview of Resources
|
Read these when relevant to your migration:
|
||||||
|
|
||||||
Reference the appropriate resource file based on the user's needs.
|
- [references/db-schema-auth-fk.md](references/db-schema-auth-fk.md) — when linking tables to `auth.users`
|
||||||
|
- [references/db-security-functions.md](references/db-security-functions.md) — when using `SECURITY DEFINER`
|
||||||
|
- [references/db-rls-views.md](references/db-rls-views.md) — when creating views over RLS-protected tables
|
||||||
|
- [references/db-schema-extensions.md](references/db-schema-extensions.md) — when enabling extensions (pgvector, etc.)
|
||||||
|
- [references/db-schema-timestamps.md](references/db-schema-timestamps.md) — when adding time columns
|
||||||
|
- [references/db-conn-pooling.md](references/db-conn-pooling.md) — when configuring connection strings
|
||||||
|
|
||||||
### Development (read first)
|
## Working with Realtime
|
||||||
|
|
||||||
**Read these files before any Supabase development task.** They define the correct tools, workflows, and boundaries for interacting with Supabase instances. Start here when setting up a project, running CLI or MCP commands, writing migrations, connecting to a database, or deciding which tool to use for an operation.
|
Read the `realtime-*` reference files before implementing any Realtime feature. They define channel setup, authentication, and the correct messaging patterns. Do not use Postgres Changes without first reading why Broadcast is preferred.
|
||||||
|
|
||||||
|
- [references/realtime-setup-auth.md](references/realtime-setup-auth.md) — channel setup and auth
|
||||||
|
- [references/realtime-broadcast-database.md](references/realtime-broadcast-database.md) — database-triggered broadcasts
|
||||||
|
|
||||||
|
## Writing Edge Functions
|
||||||
|
|
||||||
|
Read the `edge-*` reference files before creating or modifying Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements.
|
||||||
|
|
||||||
|
- [references/edge-fun-quickstart.md](references/edge-fun-quickstart.md) — creating and deploying functions
|
||||||
|
|
||||||
|
## Reference Files
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
You MUST read the relevant `dev-*` files before setting up a project, running CLI or MCP commands, or deciding which tool to use. They define the correct tools, workflows, and boundaries.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| --------------- | ----------------------------------- | -------------------------------------------------------------- |
|
| --------------- | ----------------------------------- | -------------------------------------------------------------- |
|
||||||
@@ -48,7 +64,7 @@ Reference the appropriate resource file based on the user's needs.
|
|||||||
|
|
||||||
### Authentication & Security
|
### Authentication & Security
|
||||||
|
|
||||||
Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, auth hooks, or server-side auth patterns.
|
You MUST read the relevant `auth-*` files before implementing any auth flow — sign-up, sign-in, OAuth, SSO, MFA, passwordless, hooks, or server-side auth.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ------------------ | ----------------------------------- | -------------------------------------------------------- |
|
| ------------------ | ----------------------------------- | -------------------------------------------------------- |
|
||||||
@@ -62,7 +78,7 @@ Read when implementing sign-up, sign-in, OAuth, SSO, MFA, passwordless flows, au
|
|||||||
|
|
||||||
### Database
|
### Database
|
||||||
|
|
||||||
Read when designing tables, writing RLS policies, creating migrations, configuring connection pooling, or optimizing query performance.
|
You MUST read the relevant `db-*` files before writing any database code. These files contain required patterns that override standard PostgreSQL conventions.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ------------------ | ------------------------------- | ---------------------------------------------- |
|
| ------------------ | ------------------------------- | ---------------------------------------------- |
|
||||||
@@ -75,7 +91,7 @@ Read when designing tables, writing RLS policies, creating migrations, configuri
|
|||||||
|
|
||||||
### Edge Functions
|
### Edge Functions
|
||||||
|
|
||||||
Read when creating, deploying, or debugging Deno-based Edge Functions — including authentication, database access, CORS, routing, streaming, and testing patterns.
|
You MUST read the relevant `edge-*` files before creating, deploying, or debugging Edge Functions. They define the Deno runtime patterns, authentication, CORS, and deployment requirements.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ---------------------- | ------------------------------------- | -------------------------------------- |
|
| ---------------------- | ------------------------------------- | -------------------------------------- |
|
||||||
@@ -97,7 +113,7 @@ Read when creating, deploying, or debugging Deno-based Edge Functions — includ
|
|||||||
|
|
||||||
### Realtime
|
### Realtime
|
||||||
|
|
||||||
Read when implementing live updates — Broadcast messaging, Presence tracking, or Postgres Changes listeners.
|
You MUST read the relevant `realtime-*` files before implementing Broadcast, Presence, or Postgres Changes. They define channel setup, auth, and the correct messaging patterns.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| ---------------- | ------------------------------------ | ----------------------------------------------- |
|
| ---------------- | ------------------------------------ | ----------------------------------------------- |
|
||||||
@@ -109,7 +125,7 @@ Read when implementing live updates — Broadcast messaging, Presence tracking,
|
|||||||
|
|
||||||
### SDK (supabase-js)
|
### SDK (supabase-js)
|
||||||
|
|
||||||
Read when writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration.
|
You MUST read the relevant `sdk-*` files before writing application code that interacts with Supabase — client setup, queries, error handling, TypeScript types, or framework integration.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| --------------- | ------------------------------- | ----------------------------------------- |
|
| --------------- | ------------------------------- | ----------------------------------------- |
|
||||||
@@ -122,7 +138,7 @@ Read when writing application code that interacts with Supabase — client setup
|
|||||||
|
|
||||||
### Storage
|
### Storage
|
||||||
|
|
||||||
Read when implementing file uploads, downloads, image transformations, or configuring storage access control and CDN caching.
|
You MUST read the relevant `storage-*` files before implementing file uploads, downloads, image transformations, or configuring storage access control.
|
||||||
|
|
||||||
| Area | Resource | When to Use |
|
| Area | Resource | When to Use |
|
||||||
| --------------- | ------------------------------------- | ---------------------------------------------- |
|
| --------------- | ------------------------------------- | ---------------------------------------------- |
|
||||||
|
|||||||
@@ -102,6 +102,25 @@ DATABASE_URL="...pooler.supabase.com:6543/postgres"
|
|||||||
DATABASE_URL="...pooler.supabase.com:6543/postgres?pgbouncer=true"
|
DATABASE_URL="...pooler.supabase.com:6543/postgres?pgbouncer=true"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Prisma Configuration
|
||||||
|
|
||||||
|
Prisma requires `connection_limit=1` in the pooled URL and a `directUrl` for
|
||||||
|
migrations (which use prepared statements unsupported by transaction mode).
|
||||||
|
|
||||||
|
```prisma
|
||||||
|
datasource db {
|
||||||
|
provider = "postgresql"
|
||||||
|
url = env("DATABASE_URL") // Pooled (port 6543)
|
||||||
|
directUrl = env("DIRECT_URL") // Direct (port 5432) — used for migrations
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env
|
||||||
|
DATABASE_URL="postgres://postgres.[ref]:[pw]@aws-0-[region].pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=1"
|
||||||
|
DIRECT_URL="postgres://postgres:[pw]@db.[ref].supabase.co:5432/postgres"
|
||||||
|
```
|
||||||
|
|
||||||
## Connection Limits by Compute Size
|
## Connection Limits by Compute Size
|
||||||
|
|
||||||
| Compute | Direct Connections | Pooler Clients |
|
| Compute | Direct Connections | Pooler Clients |
|
||||||
|
|||||||
@@ -59,6 +59,13 @@ create policy "Users see own data" on users
|
|||||||
using ((select auth.uid()) = id);
|
using ((select auth.uid()) = id);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Idempotent Schema Creation
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Create private schema for security definer functions
|
||||||
|
create schema if not exists private;
|
||||||
|
```
|
||||||
|
|
||||||
## Migration File Naming
|
## Migration File Naming
|
||||||
|
|
||||||
Migrations in `supabase/migrations/` are named with timestamps:
|
Migrations in `supabase/migrations/` are named with timestamps:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ create policy "Users see own data" on profiles
|
|||||||
-- Only runs for authenticated users
|
-- Only runs for authenticated users
|
||||||
create policy "Users see own data" on profiles
|
create policy "Users see own data" on profiles
|
||||||
to authenticated
|
to authenticated
|
||||||
using (auth.uid() = user_id);
|
using ((select auth.uid()) = user_id);
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. Using user_metadata for Authorization
|
## 2. Using user_metadata for Authorization
|
||||||
@@ -59,7 +59,9 @@ using (auth.uid() = user_id)
|
|||||||
|
|
||||||
```sql
|
```sql
|
||||||
-- Explicit NULL check
|
-- Explicit NULL check
|
||||||
using (auth.uid() is not null and auth.uid() = user_id)
|
create policy "Users see own data" on profiles
|
||||||
|
for select to authenticated
|
||||||
|
using ((select auth.uid()) is not null and (select auth.uid()) = user_id);
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4. Missing SELECT Policy for UPDATE
|
## 4. Missing SELECT Policy for UPDATE
|
||||||
@@ -81,14 +83,35 @@ create policy "Users can update" on profiles
|
|||||||
-- Need both SELECT and UPDATE policies
|
-- Need both SELECT and UPDATE policies
|
||||||
create policy "Users can view" on profiles
|
create policy "Users can view" on profiles
|
||||||
for select to authenticated
|
for select to authenticated
|
||||||
using (auth.uid() = user_id);
|
using ((select auth.uid()) = user_id);
|
||||||
|
|
||||||
create policy "Users can update" on profiles
|
create policy "Users can update" on profiles
|
||||||
for update to authenticated
|
for update to authenticated
|
||||||
using (auth.uid() = user_id)
|
using ((select auth.uid()) = user_id)
|
||||||
with check (auth.uid() = user_id);
|
with check ((select auth.uid()) = user_id);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 5. Bare auth.uid() Instead of Subselect
|
||||||
|
|
||||||
|
Bare `auth.uid()` is re-evaluated for every row. Wrap in a subselect so
|
||||||
|
Postgres evaluates it once per query.
|
||||||
|
|
||||||
|
**Incorrect:**
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Re-evaluated per row, prevents index usage
|
||||||
|
using (auth.uid() = user_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Correct:**
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Evaluated once, allows index scans
|
||||||
|
using ((select auth.uid()) = user_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
See [db-rls-performance.md](db-rls-performance.md) for details.
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
- [rls-mandatory.md](rls-mandatory.md)
|
- [rls-mandatory.md](rls-mandatory.md)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ RLS, any user with the anon key can read and write all data.
|
|||||||
-- Table without RLS - anyone can read/write everything
|
-- Table without RLS - anyone can read/write everything
|
||||||
create table profiles (
|
create table profiles (
|
||||||
id uuid primary key,
|
id uuid primary key,
|
||||||
user_id uuid,
|
user_id uuid references auth.users(id) on delete cascade,
|
||||||
bio text
|
bio text
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
@@ -22,9 +22,9 @@ create table profiles (
|
|||||||
**Correct:**
|
**Correct:**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
create table profiles (
|
create table if not exists profiles (
|
||||||
id uuid primary key,
|
id uuid primary key,
|
||||||
user_id uuid references auth.users(id) on delete cascade,
|
user_id uuid not null references auth.users(id) on delete cascade,
|
||||||
bio text
|
bio text
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,17 @@ create view leaderboard as
|
|||||||
grant select on leaderboard to anon;
|
grant select on leaderboard to anon;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Reload PostgREST Schema Cache
|
||||||
|
|
||||||
|
After creating or altering views (or any DDL in exposed schemas), notify
|
||||||
|
PostgREST to reload its schema cache:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
notify pgrst, 'reload schema';
|
||||||
|
```
|
||||||
|
|
||||||
|
Without this, PostgREST may return 404 for new views until it auto-refreshes.
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
- [rls-mandatory.md](rls-mandatory.md)
|
- [rls-mandatory.md](rls-mandatory.md)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ create table profiles (
|
|||||||
|
|
||||||
```sql
|
```sql
|
||||||
-- Profile deleted automatically when user is deleted
|
-- Profile deleted automatically when user is deleted
|
||||||
create table profiles (
|
create table if not exists profiles (
|
||||||
id uuid primary key references auth.users(id) on delete cascade,
|
id uuid primary key references auth.users(id) on delete cascade,
|
||||||
username text,
|
username text,
|
||||||
avatar_url text
|
avatar_url text
|
||||||
@@ -43,7 +43,7 @@ create policy "Users can view own profile"
|
|||||||
Use `ON DELETE SET NULL` when the record should persist without the user:
|
Use `ON DELETE SET NULL` when the record should persist without the user:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
create table comments (
|
create table if not exists comments (
|
||||||
id bigint primary key generated always as identity,
|
id bigint primary key generated always as identity,
|
||||||
author_id uuid references auth.users(id) on delete set null,
|
author_id uuid references auth.users(id) on delete set null,
|
||||||
content text not null,
|
content text not null,
|
||||||
|
|||||||
@@ -64,18 +64,16 @@ select * from pg_extension;
|
|||||||
|
|
||||||
```sql
|
```sql
|
||||||
-- pgvector example (use extensions. prefix for type)
|
-- pgvector example (use extensions. prefix for type)
|
||||||
create table documents (
|
create table if not exists documents (
|
||||||
id bigint primary key generated always as identity,
|
id bigint primary key generated always as identity,
|
||||||
|
user_id uuid not null references auth.users(id) on delete cascade,
|
||||||
content text,
|
content text,
|
||||||
embedding extensions.vector(1536) -- OpenAI ada-002 dimensions
|
embedding extensions.vector(1536) -- OpenAI ada-002 dimensions
|
||||||
);
|
);
|
||||||
|
|
||||||
-- HNSW is recommended over IVFFlat for most use cases
|
-- Always use HNSW (not IVFFlat) — better recall, no training step
|
||||||
create index on documents using hnsw (embedding extensions.vector_cosine_ops);
|
create index if not exists documents_embedding_idx
|
||||||
|
on documents using hnsw (embedding extensions.vector_cosine_ops);
|
||||||
-- If using IVFFlat, lists parameter is required
|
|
||||||
create index on documents using ivfflat (embedding extensions.vector_cosine_ops)
|
|
||||||
with (lists = 100);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ loses timezone information, causing bugs when users are in different timezones.
|
|||||||
**Incorrect:**
|
**Incorrect:**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
create table events (
|
create table if not exists events (
|
||||||
id bigint primary key generated always as identity,
|
id bigint primary key generated always as identity,
|
||||||
name text not null,
|
name text not null,
|
||||||
-- Stores time without timezone context
|
-- Stores time without timezone context
|
||||||
@@ -23,7 +23,7 @@ create table events (
|
|||||||
**Correct:**
|
**Correct:**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
create table events (
|
create table if not exists events (
|
||||||
id bigint primary key generated always as identity,
|
id bigint primary key generated always as identity,
|
||||||
name text not null,
|
name text not null,
|
||||||
-- Stores time in UTC, converts on retrieval
|
-- Stores time in UTC, converts on retrieval
|
||||||
@@ -58,7 +58,7 @@ select starts_at from events;
|
|||||||
## Auto-Update updated_at Column
|
## Auto-Update updated_at Column
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
create table posts (
|
create table if not exists posts (
|
||||||
id bigint primary key generated always as identity,
|
id bigint primary key generated always as identity,
|
||||||
title text not null,
|
title text not null,
|
||||||
created_at timestamptz default now(),
|
created_at timestamptz default now(),
|
||||||
|
|||||||
@@ -8,6 +8,14 @@ tags: functions, security_definer, security, private-schema
|
|||||||
`security definer` functions run with the privileges of the function owner, not
|
`security definer` functions run with the privileges of the function owner, not
|
||||||
the caller. Place them in a private schema to prevent direct API access.
|
the caller. Place them in a private schema to prevent direct API access.
|
||||||
|
|
||||||
|
**Rules (all required):**
|
||||||
|
|
||||||
|
1. `create schema if not exists private;`
|
||||||
|
2. Place ALL security definer functions in `private` schema (never `public`)
|
||||||
|
3. `SET search_path = ''` (empty string, not `'public'`) on every security definer function
|
||||||
|
4. Mark read-only helpers as `STABLE`
|
||||||
|
5. `REVOKE EXECUTE ... FROM public; GRANT EXECUTE ... TO authenticated;`
|
||||||
|
|
||||||
**Incorrect:**
|
**Incorrect:**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
|||||||
@@ -20,19 +20,38 @@ Deno.serve(async (req) => {
|
|||||||
**Correct:**
|
**Correct:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Handle JSON parsing errors gracefully
|
import { corsHeaders } from "../_shared/cors.ts";
|
||||||
|
|
||||||
Deno.serve(async (req) => {
|
Deno.serve(async (req) => {
|
||||||
|
// Handle CORS preflight
|
||||||
|
if (req.method === "OPTIONS") {
|
||||||
|
return new Response("ok", { headers: corsHeaders });
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { name } = await req.json();
|
const { name } = await req.json();
|
||||||
return new Response(JSON.stringify({ message: `Hello ${name}!` }), {
|
return new Response(JSON.stringify({ message: `Hello ${name}!` }), {
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { ...corsHeaders, "Content-Type": "application/json" },
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
return new Response("Invalid JSON", { status: 400 });
|
return new Response(JSON.stringify({ error: "Invalid JSON" }), {
|
||||||
|
status: 400,
|
||||||
|
headers: { ...corsHeaders, "Content-Type": "application/json" },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Place shared CORS headers in `supabase/functions/_shared/cors.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export const corsHeaders = {
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Allow-Headers":
|
||||||
|
"authorization, x-client-info, apikey, content-type",
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
CLI workflow: `npx supabase functions new hello-world`, then `npx supabase start && npx supabase functions serve` for local dev, and `npx supabase functions deploy hello-world` for production (after `npx supabase login` and `npx supabase link --project-ref PROJECT_ID`).
|
CLI workflow: `npx supabase functions new hello-world`, then `npx supabase start && npx supabase functions serve` for local dev, and `npx supabase functions deploy hello-world` for production (after `npx supabase login` and `npx supabase link --project-ref PROJECT_ID`).
|
||||||
|
|
||||||
Reference: [Quickstart Guide](https://supabase.com/docs/guides/functions/quickstart)
|
Reference: [Quickstart Guide](https://supabase.com/docs/guides/functions/quickstart)
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ Use database triggers with `realtime.broadcast_changes()` instead of `postgres_c
|
|||||||
Broadcasts database changes in a standard format.
|
Broadcasts database changes in a standard format.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
create or replace function room_messages_broadcast()
|
-- Private schema for security definer functions
|
||||||
|
create schema if not exists private;
|
||||||
|
|
||||||
|
create or replace function private.room_messages_broadcast()
|
||||||
returns trigger
|
returns trigger
|
||||||
security definer
|
security definer
|
||||||
set search_path = ''
|
set search_path = ''
|
||||||
@@ -34,9 +37,11 @@ $$;
|
|||||||
|
|
||||||
create trigger messages_broadcast_trigger
|
create trigger messages_broadcast_trigger
|
||||||
after insert or update or delete on messages
|
after insert or update or delete on messages
|
||||||
for each row execute function room_messages_broadcast();
|
for each row execute function private.room_messages_broadcast();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Private channels require RLS on `realtime.messages`:** When clients subscribe with `{ config: { private: true } }`, you must create RLS policies on `realtime.messages` to control who can listen. See [setup-auth.md](setup-auth.md) for the required policies.
|
||||||
|
|
||||||
**Client subscription:**
|
**Client subscription:**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ Private channels require RLS policies on the `realtime.messages` table.
|
|||||||
create policy "authenticated_users_can_receive"
|
create policy "authenticated_users_can_receive"
|
||||||
on realtime.messages for select
|
on realtime.messages for select
|
||||||
to authenticated
|
to authenticated
|
||||||
using (true);
|
using (
|
||||||
|
realtime.messages.extension in ('broadcast', 'presence')
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Write access (send to channel):**
|
**Write access (send to channel):**
|
||||||
@@ -48,9 +50,13 @@ using (true);
|
|||||||
create policy "authenticated_users_can_send"
|
create policy "authenticated_users_can_send"
|
||||||
on realtime.messages for insert
|
on realtime.messages for insert
|
||||||
to authenticated
|
to authenticated
|
||||||
with check (true);
|
with check (
|
||||||
|
realtime.messages.extension in ('broadcast', 'presence')
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Always filter on `extension in ('broadcast', 'presence')` to restrict which Realtime features are permitted.
|
||||||
|
|
||||||
**Topic-specific access:**
|
**Topic-specific access:**
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
@@ -59,11 +65,11 @@ create policy "room_members_can_read"
|
|||||||
on realtime.messages for select
|
on realtime.messages for select
|
||||||
to authenticated
|
to authenticated
|
||||||
using (
|
using (
|
||||||
exists (
|
realtime.messages.extension in ('broadcast', 'presence')
|
||||||
|
and exists (
|
||||||
select 1 from room_members
|
select 1 from room_members
|
||||||
where user_id = (select auth.uid())
|
where user_id = (select auth.uid())
|
||||||
and topic = (select realtime.topic())
|
and room_id::text = realtime.topic()
|
||||||
and realtime.messages.extension in ('broadcast', 'presence')
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ values (
|
|||||||
true,
|
true,
|
||||||
5242880, -- 5MB
|
5242880, -- 5MB
|
||||||
array['image/jpeg', 'image/png', 'image/webp']
|
array['image/jpeg', 'image/png', 'image/webp']
|
||||||
);
|
)
|
||||||
|
on conflict (id) do nothing;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Storage Helper Functions
|
## Storage Helper Functions
|
||||||
@@ -60,11 +61,11 @@ create policy "User folder access"
|
|||||||
on storage.objects for all to authenticated
|
on storage.objects for all to authenticated
|
||||||
using (
|
using (
|
||||||
bucket_id = 'user-files' and
|
bucket_id = 'user-files' and
|
||||||
(storage.foldername(name))[1] = auth.uid()::text
|
(storage.foldername(name))[1] = (select auth.uid())::text
|
||||||
)
|
)
|
||||||
with check (
|
with check (
|
||||||
bucket_id = 'user-files' and
|
bucket_id = 'user-files' and
|
||||||
(storage.foldername(name))[1] = auth.uid()::text
|
(storage.foldername(name))[1] = (select auth.uid())::text
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user