One policy file
Relations read from your own columns and tables, permissions built from them, inherited down trees of folders or teams, and a rule for each table command.
Write who can do what in one small file. rowfence compiles it into row-level security, and Postgres enforces it on every query.
app role app_user -- the Postgres role the app connects as
type user = app.users
type folder = app.folders
owner : user = owner_id -- a relation read from a column
parent : folder = parent_id
editor : user = app.folder_editors(folder_id -> user_id) -- ... or from a link table
can edit = owner or editor or parent.edit -- inherited down the tree
can view = edit
rules app.folders
select : view
update : editThe app says who is asking, then runs its usual queries:
BEGIN;
SELECT authz.act_as('user', '42');
SELECT * FROM app.folders; -- only the folders 42 may view
UPDATE app.folders SET name = 'Plans' WHERE id = 7; -- 0 rows unless 42 may edit folder 7
COMMIT;The SDKs turn a write that changed nothing into a 404 (the row can't be seen) or a 403 that says which rule refused it and why.
Next: Getting started goes from a schema to a policy, its tests, the edit loop and the first migration. Pick your stack for the SDK that does the signing in for you.