Design leak-proof multi-tenant PostgreSQL Row-Level Security (RLS) policies. Generates verified SQL migrations, foreign key indexes, TypeScript models, and Zod schemas.
Policy 'org_creator_insert' uses unrestricted 'USING (true)' for INSERT. Anyone can mutate data!
-- Supabase PostgreSQL Row Level Security (RLS) Migration
-- Generated by Supabase RLS & Schema Policy Architect
-- 1. Helper security definer function for tenant membership caching
CREATE OR REPLACE FUNCTION auth.is_org_member(lookup_org_id UUID)
RETURNS BOOLEAN
LANGUAGE sql
SECURITY DEFINER
SET search_path = public
STABLE
AS $$
SELECT EXISTS (
SELECT 1 FROM organization_members
WHERE org_id = lookup_org_id
AND user_id = auth.uid()
);
$$;
-- Table: organizations
CREATE TABLE IF NOT EXISTS organizations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT,
slug TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "org_members_select" ON organizations;
CREATE POLICY "org_members_select" ON organizations
FOR SELECT TO authenticated
USING (auth.is_org_member(id));
DROP POLICY IF EXISTS "org_creator_insert" ON organizations;
CREATE POLICY "org_creator_insert" ON organizations
FOR INSERT TO authenticated
USING (true)
WITH CHECK (auth.uid() IS NOT NULL);
-- Table: projects
CREATE TABLE IF NOT EXISTS projects (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
title TEXT,
status TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_projects_org_id ON projects(org_id);
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "projects_org_select" ON projects;
CREATE POLICY "projects_org_select" ON projects
FOR SELECT TO authenticated
USING (auth.is_org_member(org_id));
DROP POLICY IF EXISTS "projects_org_insert" ON projects;
CREATE POLICY "projects_org_insert" ON projects
FOR INSERT TO authenticated
USING (auth.is_org_member(org_id))
WITH CHECK (auth.is_org_member(org_id));
DROP POLICY IF EXISTS "projects_org_update" ON projects;
CREATE POLICY "projects_org_update" ON projects
FOR UPDATE TO authenticated
USING (auth.is_org_member(org_id))
WITH CHECK (auth.is_org_member(org_id));
DROP POLICY IF EXISTS "projects_org_delete" ON projects;
CREATE POLICY "projects_org_delete" ON projects
FOR DELETE TO authenticated
USING (auth.is_org_member(org_id));
I build end-to-end applications with secure PostgreSQL schemas, real-time sync, Next.js App Router frontends, and automated CI/CD database migrations.
Get battle-tested PostgreSQL templates, RLS indexing tips, and Next.js + Supabase auth integration patterns.
No spam. Unsubscribe anytime.
Discover more utility-driven tools designed to enhance your workflow and technical excellence.
Generate .gitignore files from 30+ templates — Node, Python, Go, Rust, Java, macOS, Windows, IDEs, and more. Copy or download instantly.
Generate production-ready Dockerfiles and .dockerignore for Node, Python, Go, Rust, Java, and Next.js — multi-stage, distroless-aware.
Searchable reference for every HTTP status code — 1xx to 5xx — with meanings, typical use cases, and developer-friendly explanations.