Supabase rules
This profile targets a Supabase backend: Postgres schema + RLS in supabase/migrations/, seed data in supabase/seed/, and Deno Edge Functions in supabase/functions/. The runtime is Deno, not Node — there’s no package.json/npm here. This runs on GitHub-hosted runners (no Apple toolchain).
Tooling — Deno, not npm
Section titled “Tooling — Deno, not npm”- Format / lint / type-check / test with the Deno toolchain, never npm:
deno fmt,deno lint,deno check,deno test --allow-all. A synceddeno.jsoncholds the fmt/lint config anddeno taskshortcuts. - Pin every remote import to an exact version —
https://deno.land/std@0.168.0/…,https://esm.sh/@supabase/supabase-js@2.39.0. Never import an unpinned URL; a moving dependency breaks reproducibility and is a supply-chain risk. - Prefer the
supabaseCLI for everything local:supabase start(boots Postgres + Studio + the functions runtime),supabase db reset(recreate + migrate + seed),supabase functions serve,supabase gen types typescript.
Migrations (supabase/migrations/)
Section titled “Migrations (supabase/migrations/)”- Idempotent:
create table if not exists,create or replace function,drop … if exists. A migration must be safe to re-run. enable row level securityimmediately on every new table — in the same migration that creates it. A table without RLS is a data leak.- Explicit foreign-key
on deletebehavior (cascade/set null/restrict) — never rely on the default. - Seed data lives in
supabase/seed/, never in a migration. Migrations are schema; seeds are data. - Migrations are forward-only and append-only once applied to a shared/remote DB — never edit a migration that has shipped; write a new one.
Row-Level Security (the security boundary)
Section titled “Row-Level Security (the security boundary)”- Every table has RLS enabled with explicit policies. Default-deny: no policy means no access.
- Published/public rows are readable by
anon; all user data is owner-scoped (auth.uid() = user_id). Writes are owner-scoped too. - The service-role key bypasses RLS — it’s server-only (Edge Functions, CI). It must never reach a client or a committed file. Clients use the
anonkey + the user’s JWT.
Edge Functions (supabase/functions/, Deno)
Section titled “Edge Functions (supabase/functions/, Deno)”- Route shared logic through
_shared/(e.g.r2.ts,errors.ts) — reuse the helpers, don’t reinvent CORS / error shapes / storage signing per function. - Auth on every endpoint: verify the caller’s JWT before doing work; gate premium/subscription features explicitly. Return the shared error shapes.
- Standard CORS headers on every response (including
OPTIONSpreflight). - Signed, expiring URLs for all object storage (R2 / Supabase Storage) — never hand out a public or long-lived URL. Apply per-user rate limits where relevant.
- Validate and narrow every input (auth header, body, params) at the top of the handler before touching the DB or storage.
Secrets
Section titled “Secrets”- Server secrets (service-role key,
R2_*, third-party keys) live insupabase secrets set …for deployed functions and in GitHub Actions secrets for CI — and in a gitignored.env.localfor local dev. Commit.env.example. - Never log a secret or return it in a response.
Git hooks & commits
Section titled “Git hooks & commits”lefthook.yml is synced — install once with npx lefthook install (or brew install lefthook). It runs deno fmt --check + deno lint (scoped to the component via lefthook’s root:) and a secrets scan pre-commit, and enforces Conventional Commits via the shared scripts/check-commit-msg.sh.
Testing & CI
Section titled “Testing & CI”deno test --allow-allfor Edge Function logic; keep_shared/helpers unit-tested. The syncedsupabase-ci.ymlrunsdeno fmt --check,deno lint,deno check, anddeno testonubuntu-latest.- CI also checks the schema, not just the functions:
supabase db lint --level warning(Splinter — flags missing-RLS / security-definer issues) andsupabase test db(pgTAP againstsupabase/tests/*.sql, no-op until you add the first test). Write pgTAP tests that assert RLS actually denies cross-user access — the lint catches a missing policy, a test catches a wrong one. - See the
supabase-postgres-best-practicesskill (in the skills catalog) for schema design, indexing, RLS performance, and query patterns.