supabaselisted
Install: claude install-skill kouroshez/coding-os
# Supabase
Supabase is Postgres with a public API in front of it. That inversion is the whole risk model: the `anon` key ships to the browser, so **the database — not the application — is the security boundary**. Row Level Security is not optional hardening; it is the only thing standing between a user and everyone else's rows.
> Scan a migration for tables left without RLS:
> `python3 scripts/check_rls.py supabase/migrations/*.sql`
## RLS is the security boundary (enable it on every table)
```sql
-- Wrong — table is reachable via the anon key with NO policy = fully public
create table notes (id uuid primary key, user_id uuid, body text);
-- Correct — enable RLS, then policies grant the minimum
create table notes (id uuid primary key, user_id uuid references auth.users, body text);
alter table notes enable row level security;
create policy "owner reads own notes" on notes
for select using (auth.uid() = user_id);
create policy "owner writes own notes" on notes
for insert with check (auth.uid() = user_id);
```
A table created without `enable row level security` is readable and writable by
anyone holding the `anon` key — which is every visitor. Enable RLS on **every**
table in a public schema, then add policies. `using` filters which rows are
visible/updatable; `with check` validates rows being inserted/updated. Detail →
[references/rls-and-auth.md](references/rls-and-auth.md).
## The two keys — never confuse them
```
anon key → ships to the browser. RLS appl