Create Supabase PostgreSQL migration files for the Fala Processing database. Use for: writing new SQL migrations, creating RPC functions (aggregate with scalar helpers, composed dashboard, search + filter + pagination + sort, chart time-series, batch write over UUID arrays), adding tables, indexes, RLS policies, or triggers. Enforces SECURITY DEFINER, plpgsql, data/error envelope, soft-delete filtering, farmer self-lock, p_limit clamping, and grant patterns.
Generates a correct, standards-compliant Supabase SQL migration for the Fala Processing database. Full rule reference and SQL patterns: references/patterns.md.
supabase/migrations/Ask the user these questions before choosing a template:
user_profile?| If the function… | Template |
|---|---|
| Returns a raw NUMERIC / BIGINT scalar — no auth, called only by other functions | fn-scalar-helper.sql |
| Returns a single JSON aggregate object; delegates to Layer 1 scalar helpers | fn-rpc-aggregate.sql |
| Combines results from 2+ Layer 2 functions into one dashboard payload | fn-rpc-composed.sql |
| Returns a paginated, searchable, filterable, sortable list — admin table, page-jump UX, bounded dataset | fn-rpc-search-paginated.sql |
| Returns a cursor-paginated list — infinite scroll, large/fast-growing dataset, stable on inserts | fn-rpc-cursor-paginated.sql |
Returns time-series rows for chart visualization (RETURNS TABLE) | fn-rpc-chart.sql |
| Writes (soft-delete / update) to an array of IDs in a loop | fn-rpc-batch-write.sql |
A single migration can contain multiple sections — for example, one scalar helper (Layer 1) plus one aggregate RPC (Layer 2) that calls it. Use migration-header.sql for the file-level boilerplate.
npm run migration to generate the timestamped filename, then write to:
supabase/migrations/YYYYMMDDHHMMSS_descriptive_name.sql{PLACEHOLDER} with real names, columns, and types.public. prefix.YYYYMMDDHHMMSS_descriptive_name.sql — timestamp matches current date/timeDROP FUNCTION IF EXISTS public.{name}({old_param_types}) present if the function's parameter signature changed from a previous version (CREATE OR REPLACE only works for identical signatures)CREATE TABLE and CREATE INDEX use IF NOT EXISTSpublic. prefix — no bare unqualified namesLANGUAGE plpgsql SECURITY DEFINER — never LANGUAGE sqlSELECT query includes WHERE is_deleted = FALSE — never rely on RLS for thisauth.uid() — never trusts the passed p_user_id parameter value{data, error} — no success field anywhereEXCEPTION WHEN OTHERS returns the fixed string 'An unexpected error occurred' — no SQLERRM in production-facing errorsGRANT EXECUTE ON FUNCTION public.{name}(...) TO authenticated block at the endCOMMENT ON FUNCTION public.{name}(...) present describing purpose, role behaviour, and index used