Supabase backend
WeSpend uses Supabase from day one: Postgres for storage, Row Level Security for authorization, anonymous auth for onboarding, and Realtime for live multi-device sync.
1. Create a project
Sign in at supabase.com and create a new project. Once it is provisioned, grab the project URL and anon key from Project Settings -> API and put them in your .env.
2. Run the migrations
The schema lives in supabase/migrations/, applied in order:
| File | Contents |
|---|---|
0001_initial_schema.sql | Tables, constraints, indexes |
0002_rls_policies.sql | Row Level Security policies |
0003_functions.sql | Bootstrap RPCs, role-guard trigger, realtime publication |
0004_device_push_tokens.sql | Expo push tokens per device for household activity notifications |
0005_meal_card.sql | meal_card_settings and the card value on expenses.paid_from |
0006_notifications.sql | In-app notifications feed table |
0007_settlement_reminder_function.sql | Postgres function for the weekly settlement reminder |
0008_enable_cron_and_net_extensions.sql | Enables pg_cron and pg_net |
0009_schedule_settlement_reminder_cron_jobs.sql | Cron jobs that POST the reminder via an Edge Function (auth by CRON_SECRET) |
0010_add_is_active_to_members.sql | members.is_active for archive/reactivate |
0011_bills.sql | bill_settings, bill_categories, bill_entries + realtime |
0012_bill_settings_realtime.sql | Adds bill_settings to the realtime publication |
Option A: SQL editor
Open SQL Editor in the dashboard and paste the contents of each file in order, running each one.
Option B: Supabase CLI
npm install -g supabase
supabase link --project-ref YOUR-PROJECT-REF
supabase db push3. Enable anonymous sign-in
Onboarding signs members in anonymously, so enable it under Authentication -> Providers -> Anonymous.
How authorization works
Every household-scoped table carries a household_id. The is_household_member(household_id) function checks whether the current auth.uid() belongs to that household, and every RLS policy uses it for both reads and writes.
Two operations run as security definer because the caller is not yet a member when they happen:
create_household(household_name, owner_name)- creates the household, the owner member, and seeds default budget and bill categories.accept_invite(invite_code)- binds the caller's identity to a pre-created member slot (only if unclaimed).
A members_role_guard trigger ensures only the household owner can change the is_owner / is_finance_manager columns.
Realtime
The supabase_realtime publication includes budgets, expenses, settlements, members, categories, and the bill tables (bill_settings, bill_categories, bill_entries). The app subscribes per household and invalidates the matching TanStack Query caches on any change, so every member's device updates live. See use-household-realtime.
For the full schema and ER diagram, see the Data model.