Agreements
Naming of schemas, columns, RLS policies, auth helpers, indexes. Stable, documented conventions so your team has one way to name things.
One prefix per domain
Each project receives four subschemas prefixed project_{uuid}. Your business tables go into the main schema; never create objects in system schemas.
SchemaOwnerUsage
project_{uuid}youTables, views, business functions
project_{uuid}_authaura-authUsers, sessions, MFA — do not touch
project_{uuid}_storageaura-storageBuckets, objects, policies storage
project_{uuid}_platformplatformFunctions, jobs, cron, secrets
snake_case, plural, id uuid
- Plural tables:
posts,comments,invoices - Columns in
snake_case:created_at,user_id,last_seen_at - Primary keys
id uuid primary key default gen_random_uuid()— nouuid_generate_v4() - Timestamps
timestamptz, nevertimestampnaked - FKs suffixed
_id:author_id,tenant_id - Booleans prefixed
is_orhas_ - No column
project_id— the schematic is already the insulator
Never add a project_idcolumn. Insulation is already guaranteed by the diagram. A column holding would multiply the indexes and weaken security.
Three functions injected into each session
The gateway opens Postgres connections with request.jwt.claims specified. The three helpers below read these claims and can be used anywhere in your policies.
HelperBack
auth.uid()uuid of the current user, NULL if anon
auth.role()text · anon / authenticated / service_role
auth.tenant()uuid of the current tenant (multi-tenant RBAC)
auth.has_role(name)boolean · true if the user has this application role
auth.email()text · user email, read from the JWT
auth.claim(key)jsonb · raw access to a custom claim
A predictable name, an operation, a role
Convention: <table>_<scope>_<operation>. Example: posts_own_read, orders_admin_delete. Always specify to aura_authenticated or to aura_anon.
Naming and when to index
- Name:
idx_<table>_<colonnes>oruq_<table>_<colonnes>(unique) - Always index: FKs, frequent
filter/order_bycolumns,whereof RLS policies - Do not index: Boolean columns with high cardinality low (use partial index), tables < 1000 rows
- pgvector:
using hnswfor > 100k vectors,ivfflatotherwise