Skip to content

Database & RLS

PostgreSQL with Row-Level Security on every user-facing table. 58 tables, 118 RLS policies — verified identical between Dev and Prod at baseline. The schema is captured as a one-time squash migration: supabase/migrations/20260710134136_baseline_schema_from_prod.sql.

profiles is the identity hub — one row per auth user, referenced across all three pillars.

Entity map (grouped by pillar)

Table groups

GroupTables (representative)
Identity & platformprofiles, profile_items, profile_revisions, profile_analytics, platform_features, domain_features, business_domains, user_domains, reserved_slugs
Subscriptionssubscription_tiers, user_subscriptions, subscription_usage_logs, user_feature_permissions
Digital Menudigital_menus, digital_menu_categories, digital_menu_items, digital_menu_item_variants, digital_menu_item_images, digital_menu_item_favorites, digital_menu_item_revisions, digital_menu_settings, digital_menu_qr_codes, digital_menu_qr_scan_analytics, digital_menu_analytics, digital_menu_cash_counts
BioLinkbio_pages, bio_links
Studio / My Setustudio_websites, studio_pages, studio_blocks_library, studio_analytics_page_views, setu_pages, setu_blocks, templates, template_selections
Engagements / Feedbackengagement_forms, engagement_responses, engagement_response_contacts
QR & remindersqr_codes, reminders, reminder_categories
vCard / business cardvcard_customizations, service_customizations
public_page_ops (Type B ops)public_page_ops_cache_master, *_cache_log, *_cache_operations, *_cron_jobs, *_cron_executions, *_edge_function_logs, *_cleanup_log, *_housekeeping_config (+ dated partitions)

See documentation/02-technical/database-schema-snapshot.md for the full column-level snapshot.

RLS model

  • RLS on every user-facing table — defense-in-depth. The Edge Function is the primary write-enforcement layer; both are always required.
  • Append-only tables carry no UPDATE/DELETE policy (e.g. analytics / log tables).
  • Public pages read through get_public_* RPCs (SECURITY DEFINER) that project row_to_json so the anon role never touches base tables directly.

DB rules [ENFORCED]

  • Migrations: 14-digit YYYYMMDDHHMMSS_name.sql (prefer npx supabase migration new; never the old NNN_ form — it collides on the version parser).
  • Never edit a merged migration — add a new one.
  • Expand-contract always: add-nullable → backfill → switch → drop. Never a breaking change in one step.
  • Use row_to_json(table.*) in RPCs for forward-compat.
  • Capture cron (pg_cron) schedules and storage buckets as migrations, not just live DB state.

[TRANSITIONAL] — not yet replicated to Dev

  • The pg_cron job hardcodes Prod's own Edge Function URL — needs a project-URL-aware rewrite before Dev gets one.
  • The profile-pictures storage bucket — environment-specific data, not portable schema.

See Migrations guide and Supabase integration.