Supabase Architecture¶
This page explains how Supabase is used as the backend for Workbench AI: schema, auth, row‑level security, and edge functions.
This is a high-level map, not a full schema dump. See the API/Data section for table-by-table details.
Supabase project & configuration¶
Supabase project configuration lives under the supabase/ directory:
supabase/config.toml- Contains the
project_idand CLI configuration. - Used by the Supabase CLI for local development and migrations.
- Contains the
supabase/migrations/- Timestamped SQL files that define the Postgres schema and RLS policies.
- Examples include:
20250110000000_create_companies_and_user_profiles.sql20250110000001_add_tenant_id_to_tables.sql20250111000000_create_repair_settings.sql
supabase/functions/- Edge Functions written in TypeScript, deployed to Supabase’s Deno runtime.
- Handle Stripe webhooks, checkout/portal sessions, subscription sync, etc.
Local vs production configuration¶
-
Local dev
- Run via Supabase CLI (
supabase start,supabase db reset, etc.). - Uses
supabase/config.tomlto connect to a local Postgres instance and apply migrations. - Local env vars (Supabase URL, anon key, service role key, Stripe keys) are set in the local environment (e.g.
.envfiles or CLI config).
- Run via Supabase CLI (
-
Production
- Managed Supabase project in the cloud.
- Migrations from
supabase/migrations/are applied via CI/CD or Supabase migration tools. - Production env vars are configured in Supabase dashboard:
SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEYSTRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET, price IDs, etc.
Secrets and keys
All secrets (Stripe keys, Supabase service role key, etc.) are managed as environment variables in Supabase and/or the hosting platform. They must never be committed to this repo or documented as raw values.
High-level schema¶
The exact schema is defined by the SQL migrations, but at a high level the system is organized around:
-
Companies / tenants
- Table(s) representing each store/company (multitenancy).
- Likely fields:
id,name, contact info, plan, status. - Each company is the root of a tenant, and most business data is tied to a company ID.
-
Users & profiles
auth.users(managed by Supabase Auth) holds base user accounts.user_profilestable (referenced from migrations and RPC) stores:idmatchingauth.users.id.tenant_id/company_idlinking the user to a company.role(owner,tenant,admin).- Additional metadata (email, name, etc.).
-
Subscriptions & billing mirror
subscriptionstable mirrors Stripe subscription state:company_id(FK to companies).stripe_subscription_id,stripe_customer_id.- Status fields (active, trialing, canceled, etc.).
- Plan information (starter/professional/enterprise).
webhook_events_processedtable records processed Stripe webhook event IDs for idempotency.- Additional tables like
payment_historyor invoice tracking are maintained by edge functions.
-
Inventory & catalog
- Tables to represent inventory items, categories, and attributes.
- Likely keyed by
company_idwith RLS enforcing tenant isolation.
-
Orders & work orders
- Tables for customer orders and work orders (repairs, custom pieces).
- Status fields for workflow (active, completed, etc.).
- Linked to clients and inventory items.
-
Repairs & pricing configuration
repair_settings(from migrations) stores pricing defaults and rules.- Repair calculators in the frontend (ring sizing, soldering, etc.) read/write these settings.
-
Content & AI artifacts
- Tables for blog requests, library files, and certificates (from migrations like
create_blog_requests_table,create_library_files_table,create_certificates). - Used by AI/automation flows for content generation and document storage.
- Tables for blog requests, library files, and certificates (from migrations like
Schema details
For table-by-table columns, see the API/Data → Supabase Tables page, which summarizes key tables and their relationships.
Auth & roles¶
Supabase Auth is the identity layer; application roles and tenancy are layered on top.
Identity¶
auth.usersholds the canonical user identity (email, auth provider data).- The frontend uses the Supabase JS client to sign in/out and read sessions.
Profiles and roles¶
user_profilestable is linked 1:1 toauth.users(user_profiles.id = auth.users.id).- It stores:
tenant_id/company_id– which company the user belongs to.role–owner,tenant, oradmin.
In the frontend:
AuthProvider(React context) wraps the app and- Reads the Supabase session.
- Calls a Postgres RPC (
get_tenant_info_for_user) to fetch:- Role
- Tenant/company ID
- Company name
- Caches some of this profile in
localStoragefor faster reloads.
ProtectedRouteuses the role and helper functions (hasRequiredRole,isOwner) to gate routes.
Row-Level Security (RLS)¶
- RLS policies (defined in migrations) ensure that:
- Regular users only access rows belonging to their
tenant_id/company_id. - Owners/admins can see/manage data across their company.
- Regular users only access rows belonging to their
- Edge Functions authenticate using the service role key, allowing them to bypass RLS when necessary (e.g., for cross-tenant operations or admin tasks).
RLS details
RLS policies are enforced in the database layer. The frontend should never assume access based on role alone; it must be consistent with the policies defined in migrations.
Edge Functions¶
Edge Functions live under supabase/functions/ and are written in TypeScript targeting Deno.
Current functions include (one folder per function):
-
stripe-webhook/index.tsimplements Stripe webhook handling.- Uses
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY. - Verifies signatures, ensures idempotency via
webhook_events_processed, and updates subscription/payment tables.
-
create-checkout-session/- Creates Stripe Checkout Sessions for subscriptions.
- Ensures a Stripe customer exists for the company.
- Uses environment variables for Stripe price IDs.
- Returns a
checkout.urlfor the frontend to redirect to.
-
create-portal-session/- Creates Stripe Billing Portal sessions.
- Looks up
stripe_customer_id(or derives it from a subscription) and returns a portal URL.
-
sync-stripe-subscriptions/- Keeps local
subscriptionstable in sync with Stripe data.
- Keeps local
-
sync-payment-history/- Synchronizes payment history records from Stripe into Supabase.
-
get-stripe-subscription/,get-upcoming-invoice/,get-customer-invoices/- Read-only helpers for the frontend to fetch subscription and invoice details via secure backend calls.
-
reactivate-subscription/- Handles reactivation flows for canceled or paused subscriptions.
-
generate-nameplate/- Backend logic for the nameplate generator (part of the design studio).
-
submit-affiliate-application/- Handles affiliate application submissions and persistence.
Function discovery
This list is based on directory names and representative code samples. See the API/Data → Edge Functions page for per-function request/response contracts.
Data flow overview¶
flowchart LR
U[User Browser] --> SPA[Frontend SPA]
SPA -->|Supabase JS client| SBAUTH[Supabase Auth]
SPA -->|queries/mutations| SBD[(Supabase DB)]
SPA -->|HTTP calls| SBFX[Supabase Edge Functions]
SBFX --> ST[Stripe]
ST -->|webhooks| SBFX
SBFX -->|DB writes| SBD
click SPA "../architecture/frontend/" "Frontend architecture"
click SBAUTH "../architecture/supabase/" "Auth & roles (this page)"
click SBD "../api/supabase-tables/" "Supabase tables overview"
click SBFX "../api/edge-functions/" "Edge functions API surface"
click ST "../flows/billing-stripe/" "Billing & Stripe flows"
At this level:
- The frontend uses the Supabase client for most reads/writes.
- Edge Functions handle:
- Stripe webhooks
- Sensitive operations requiring service role access
- Stripe session creation/portal access
- Stripe is the authoritative source of billing events, while Supabase stores a mirrored view for application logic.