Sabo uses Supabase for authentication and database access. This page shows where the clients and types live, how dashboard pages map to tables, and patterns to read/write data safely.
Where things live
- Server client:
sabo/src/lib/supabase/server.ts(SSR/server actions; cookies wired) - Browser client:
sabo/src/lib/supabase/client.ts(client components; limited usage) - Types:
sabo/src/lib/types/database.ts(UserProfile, UserSubscription, PaymentHistory)
Database Schema
Sabo’s database includes four main tables with Row Level Security (RLS) enabled:1. user_profiles
Stores user profile information, preferences, and notification settings. Schema:user_id- Foreign key toauth.users, unique (one profile per user)username- Unique username, nullablepush_notifications- Values:"all","mentions","none"updated_at- Automatically updated via trigger
- Users can SELECT/INSERT/UPDATE/DELETE their own profile only
- Policy checks:
auth.uid() = user_id
2. user_subscriptions
Stores Stripe subscription data for billing management. Schema:user_id- One subscription per userstripe_customer_id- Stripe Customer ID (e.g.,cus_...)stripe_subscription_id- Stripe Subscription ID (e.g.,sub_...), uniquestripe_price_id- Stripe Price ID (e.g.,price_...)status- Subscription status:"active","trialing","past_due","canceled", etc.billing_cycle-"monthly"or"yearly"cancel_at_period_end- Iftrue, subscription cancels at period endcanceled_at- When cancellation was requestedcancel_at- Future date when subscription will actually end
- Users can SELECT their own subscription only
- No INSERT/UPDATE/DELETE policies (webhooks use service client to bypass RLS)
3. payment_history
Stores payment records for invoices and transactions. Schema:user_id- Foreign key toauth.usersstripe_subscription_id- Associated subscription (nullable for one-time payments)stripe_payment_intent_id- Stripe Payment Intent ID (e.g.,pi_...)amount- Amount in cents (e.g.,1200= $12.00)currency- ISO currency code (e.g.,"usd","eur")status- Payment status:"succeeded","failed","pending", etc.invoice_url- Stripe-hosted invoice URL
- Users can SELECT their own payment history only
- No INSERT/UPDATE/DELETE policies (webhooks use service client)
4. stripe_products
Stores Stripe product catalog (optional, for dynamic pricing displays). Schema:- Anyone (authenticated) can SELECT active products
- No INSERT/UPDATE/DELETE policies (managed via webhooks or admin)
Tables and Settings Mapping
The dashboard settings pages map to these tables:| Settings Page | Table | Key Fields |
|---|---|---|
| General Settings | user_profiles | language, timezone |
| Account Settings | user_profiles | full_name, username, bio, website, phone, birth_date |
| Billing Settings | user_subscriptions | plan_name, status, current_period_end |
| Billing Settings | payment_history | amount, status, invoice_url, created_at |
| Notification Settings | user_profiles | email_notifications, push_notifications, communication_emails, social_emails, security_emails |
Settings implementation: General/Notifications update
UserProfile; Account uses supabase.auth.updateUser(); Billing reads UserSubscription/PaymentHistory and links to Stripe Portal.Recommended patterns
- Prefer the server client (
createClient) in Server Components and server actions for reads/writes. - Revalidate affected paths after writes (e.g.,
revalidatePath('/dashboard/settings/general')). - Keep types centralized in
database.ts, and import them where needed for safety. - Handle errors explicitly; return predictable shapes to the UI.
Future work (optional)
- Migrations and type generation from Supabase schema
- RLS policies and role-based access
- Seed scripts and local development workflow