Files
supabase-postgres-best-prac…/packages/evals/scenarios/SCENARIOS.md
2026-02-20 15:02:59 +00:00

8.4 KiB

Supabase Skills Eval Scenarios

Scenario 1: auth-rls-new-project

Description: Set up a new Supabase project from scratch and add authentication with RLS. The agent must initialize the project with the CLI, start the local Supabase stack, then create a tasks table with proper security (RLS policies, auth FK, indexes) in a single idempotent migration.

Setup: The workspace starts empty (no supabase/ directory). The agent is expected to run npx supabase init and npx supabase start before creating the migration.

Expected skill files read:

  • SKILL.md (skill body with reference file index)
  • references/dev-getting-started.md
  • references/db-rls-mandatory.md
  • references/db-rls-policy-types.md
  • references/db-rls-common-mistakes.md
  • references/db-schema-auth-fk.md
  • references/db-schema-timestamps.md
  • references/db-migrations-idempotent.md

Expected result:

The agent initializes a Supabase project and creates a migration file that:

  • Creates tasks table with timestamptz columns
  • Has user_id FK to auth.users(id) with ON DELETE CASCADE
  • Enables RLS (ALTER TABLE tasks ENABLE ROW LEVEL SECURITY)
  • Creates per-operation policies using (select auth.uid()) with TO authenticated
  • Creates index on user_id
  • Uses IF NOT EXISTS for idempotency

Scorer: Binary pass/fail (12 vitest assertions)

Test What it checks
supabase project initialized supabase/config.toml exists after agent runs
migration file exists Agent created a .sql file in supabase/migrations/
creates tasks table SQL contains CREATE TABLE ... tasks
enables RLS ALTER TABLE tasks ENABLE ROW LEVEL SECURITY
FK to auth.users REFERENCES auth.users
ON DELETE CASCADE Cascade delete on auth FK
(select auth.uid()) Subselect form in policies (performance)
TO authenticated Policies scoped to authenticated role
timestamptz No plain timestamp for time columns
index on user_id CREATE INDEX on the FK column
IF NOT EXISTS Idempotent migration
overall quality At least 4/5 best-practice signals present

Scenario 2: team-rls-security-definer

Description: Create a SQL migration for a team-based project management app where users belong to organizations via a membership table. The migration must define tables for organizations, memberships, and projects, then secure them with RLS policies that use a security definer helper function in a private schema to efficiently resolve team membership without per-row joins.

Setup: The workspace starts with a pre-initialized Supabase project (supabase/config.toml exists, empty supabase/migrations/ directory). The agent creates migration files within this structure.

Expected skill files read:

  • SKILL.md (skill body with reference file index)
  • references/db-rls-mandatory.md
  • references/db-rls-policy-types.md
  • references/db-rls-common-mistakes.md
  • references/db-rls-performance.md
  • references/db-security-functions.md
  • references/db-schema-auth-fk.md
  • references/db-schema-timestamps.md
  • references/db-perf-indexes.md
  • references/db-migrations-idempotent.md

Expected result:

The agent creates a migration file that:

  • Creates organizations, memberships, and projects tables with timestamptz columns
  • Has user_id FK to auth.users(id) with ON DELETE CASCADE on memberships
  • Has org_id FK on projects referencing organizations
  • Enables RLS on all three tables
  • Creates a private schema with a security definer helper function (SET search_path = '')
  • Creates RLS policies using (select auth.uid()) with TO authenticated
  • Creates indexes on membership lookup columns (user_id, org_id)
  • Has a delete policy on projects restricted to owner role
  • Uses IF NOT EXISTS for idempotency

Scorer: Binary pass/fail (16 vitest assertions)

Test What it checks
migration file exists A .sql file exists in supabase/migrations/
creates organizations table SQL contains CREATE TABLE for organizations
creates memberships table SQL contains CREATE TABLE for memberships
creates projects table SQL contains CREATE TABLE for projects
enables RLS on all tables ALTER TABLE ... ENABLE ROW LEVEL SECURITY for all three tables
FK to auth.users with ON DELETE CASCADE memberships references auth.users with cascade
org_id FK on projects projects references organizations
private schema created CREATE SCHEMA ... private present
security_definer helper function Function in private schema with SECURITY DEFINER and SET search_path = ''
policies use (select auth.uid()) Subselect form in all policies referencing auth.uid()
policies use TO authenticated All policies scoped to authenticated role
index on membership lookup columns CREATE INDEX on user_id and/or org_id in memberships
uses timestamptz No plain timestamp for time columns
idempotent DDL Uses IF NOT EXISTS or DROP ... IF EXISTS patterns
delete policy restricted to owner role A delete policy on projects checks for owner/admin role
overall quality score At least 10/14 best-practice signals present

Scenario 3: storage-rls-user-folders

Description: Create a SQL migration that sets up Supabase Storage buckets with RLS policies for user-content. An avatars bucket (public reads, authenticated uploads restricted to user folders) and a documents bucket (fully private, user-isolated), with file type restrictions, storage helper functions in policies, and a file_metadata tracking table secured with RLS.

Setup: Pre-initialized Supabase project (supabase/config.toml exists) with an empty supabase/migrations/ directory. The agent creates migration files within this structure.

Expected skill files read:

  • SKILL.md (skill body with reference file index)
  • references/storage-access-control.md
  • references/db-rls-mandatory.md
  • references/db-rls-common-mistakes.md
  • references/db-rls-performance.md
  • references/db-schema-auth-fk.md
  • references/db-schema-timestamps.md
  • references/db-perf-indexes.md
  • references/db-migrations-idempotent.md

Expected result:

The agent creates a migration file that:

  • Inserts avatars bucket into storage.buckets with public = true, MIME type restrictions, and file size limit
  • Inserts documents bucket with public = false
  • Creates RLS policies on storage.objects using storage.foldername(name) with auth.uid()::text
  • Scopes upload policies TO authenticated and avatars SELECT policy TO public
  • Creates file_metadata table with FK to auth.users with ON DELETE CASCADE
  • Enables RLS on file_metadata with policies using (select auth.uid())
  • Uses timestamptz for time columns, indexes user_id, and IF NOT EXISTS for idempotency

Scorer: Binary pass/fail (17 vitest assertions)

Test What it checks
migration file exists A .sql file exists in supabase/migrations/
creates avatars bucket SQL inserts into storage.buckets with id 'avatars' and public = true
creates documents bucket SQL inserts into storage.buckets with id 'documents' and public = false
avatars bucket has mime type restriction allowed_mime_types includes image types (jpeg, png, webp)
avatars bucket has file size limit file_size_limit set (around 2MB / 2097152 bytes)
storage policy uses foldername or path for user isolation Policy references storage.foldername(name) with auth.uid()::text
storage policy uses TO authenticated Storage upload/delete policies scoped to TO authenticated
public read policy for avatars A SELECT policy on storage.objects for avatars allows public/anon access
documents bucket is fully private Policies for documents restrict all operations to authenticated owner
creates file_metadata table SQL contains CREATE TABLE for file_metadata
file_metadata has FK to auth.users with CASCADE REFERENCES auth.users with ON DELETE CASCADE
RLS enabled on file_metadata ALTER TABLE file_metadata ENABLE ROW LEVEL SECURITY
file_metadata policies use (select auth.uid()) Subselect form in policies
uses timestamptz for time columns No plain timestamp in file_metadata
index on file_metadata user_id CREATE INDEX on user_id column
idempotent DDL Uses IF NOT EXISTS patterns
overall quality score At least 11/15 best-practice signals present