All Work

RLS Generator

A browser-based visual builder that turns a table schema and a per-role access matrix into Supabase Row Level Security SQL, live.

Design + Build · SoloVisit live site
Presets
5
Column types
10
Access toggles
12
Backend
0
02(Context)

This tool turns Row Level Security boilerplate into a point-and-click matrix, emitting the SQL and a row preview of which rows each role can read and write. RLS is the right way to lock down a Supabase table, and the easiest to get subtly wrong by hand. Built for developers who know the access they want, not the exact policy syntax.

03(Design)

Access is a grid: roles down one axis, the four operations across the other, so the whole policy surface is one glance, not a wall of CREATE POLICY statements. There is no Generate button; the SQL and the owner detection are derived on every edit, so input maps to output instantly.

A visual row preview makes the abstract concrete. Alongside the SQL, the tool renders sample rows with per-role read and write badges and highlights the rows a simulated auth.uid() owns, so you can see which rows each role reaches before you run anything.

Owner detection is convention over configuration. The generator scans for user_id, owner_id, or created_by and wires the auth.uid() checks automatically; if no such column exists, it disables the owner row and explains why rather than emitting something misleading.

04(Engineering)

Entirely client-side. There is no database, no API route, no Supabase client, and no auth anywhere; Supabase appears only in the SQL it writes. A single page holds the schema and access rules in React state, and pure functions turn that state into a policy SQL string, the sample rows, and the syntax-highlight tokens. The data model is in-app TypeScript types, not real tables; even the SQL highlighter is a small hand-rolled tokenizer, to keep the dependency list short.

Input
Schema + matrix
Typed columns, role × operation toggles
Output
SQL + row map
Copy or download, visual preview
stack   Next.js · TypeScript · React · Tailwind · lucide-react
05(Why end-to-end)
Because I owned both the row-preview visual and the SQL generator, I could drive them from one source of truth, the same access matrix and owner-detection function feeding both the preview badges and the emitted policies, so the simulated auth.uid() you see in the preview is the exact predicate written into the SQL and the visualization cannot drift from the code.
The case for one person, end to end
06(Outcome)

Public and live at rls-policy-generator.vercel.app. It builds a schema across ten column types, a three-role by four-operation matrix, five preset templates, and owner detection for auth.uid(), then emits live, highlighted SQL to copy or download. The generated policies get the easy-to-miss details right: WITH CHECK on INSERT, both clauses on UPDATE, USING on SELECT and DELETE, and the ENABLE ROW LEVEL SECURITY statement.

7
Runtime deps
07(What I'd do differently)

The correctness of the generated SQL is the whole point, and it has no tests; that is the first thing I'd fix, ideally validating the output against a real Postgres instance. I'd add shareable state so a policy survives a refresh, and broaden the expressiveness past owner-or-everyone to team and organization ownership and custom predicates, where the non-owner policies currently emit a blunt USING (true). The constraint I'd keep is the one that defines the tool: fully client-side, so it never touches your data.

Next project
Theme Studio
Dev tool · Configurator / shadcn/ui · Tailwind
Back to selected work