Supabase Setup
Set up Supabase auth, database, storage, and Edge Functions.
Supabase backs the Expo template's Auth, Postgres data, private Storage, Edge
Functions, and account-bound entitlement read model. Unlike the native Swift
sibling, this template ships the full app schema as migrations, so supabase db push can stand up the working backend in one pass.
Create the project
Create a Supabase project
Create a project in the Supabase dashboard, then copy the project URL and anon
key from Project Settings → API into soar-expo/.env.local:
EXPO_PUBLIC_SUPABASE_URL=https://your-project-ref.supabase.co
EXPO_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_PROJECT_ID=your-project-refThe URL and anon key are public client values. Keep service-role keys out of Expo env files.
Link the CLI
brew install supabase/tap/supabase
supabase login
supabase link --project-ref <ref>supabase/config.toml includes the per-function JWT settings the template
relies on.
Apply every migration
supabase db push --project-ref <ref>The repository ships four migrations:
| Migration | What it creates |
|---|---|
20240101000000_init_profiles.sql | profiles, RLS, and a sign-up trigger that copies full_name from user metadata |
20240101000001_init_todos.sql | todos, ordering indexes, updated_at trigger, and owner-scoped CRUD policies |
20240101000003_step7_examples.sql | sample_uploads, private sample-uploads bucket, 50 MB limit, and folder-scoped Storage policies |
20260630120000_billing_entitlements.sql | subscriptions and payments, shared with soar-electron; clients get SELECT-only RLS |
All migrations use if not exists, create or replace, or guarded policies, so
re-applying them is safe. If you cannot use the CLI, paste the migration SQL
files into the dashboard SQL editor in timestamp order.
Generate client types
pnpm gen:typesThe script runs Supabase type generation against SUPABASE_PROJECT_ID and
writes types/database.ts. Re-run it after any schema change before writing
new app queries.
Auth URLs
The current app uses typed OTP entry for email flows and native ID-token sign-in for Apple and Google:
- Email sign-up and password reset call Supabase Auth, then verify the code in the app.
- Apple and Google call
supabase.auth.signInWithIdToken(...), so Supabase does not redirect back into the app.
For this code path, there is no app callback route to implement. Still set a dashboard Site URL for local web testing:
http://localhost:3000If you later change a flow to link-based OAuth or magic links, allow the variant
schemes from app.config.ts:
soar-starter-expo-dev://
soar-starter-expo-preview://
soar-starter-expo://For Google native sign-in, the Supabase provider itself still needs the standard provider callback URL in the Google Cloud Web OAuth client:
https://<ref>.supabase.co/auth/v1/callbackSee Authentication for Apple and Google setup.
Edge Functions
Deploy the functions from soar-expo/supabase/functions:
supabase functions deploy revenuecat-webhook --no-verify-jwt --project-ref <ref>
supabase functions deploy delete-account --project-ref <ref>
# Optional APNs debug artifact:
supabase functions deploy send-test-push --project-ref <ref>functions/_shared/ is bundled into the functions that import it. Do not deploy
_shared by itself.
| Function | JWT | Purpose |
|---|---|---|
revenuecat-webhook | Off | RevenueCat calls it without a Supabase JWT; it verifies the static Authorization header and writes subscriptions / payments with the service role |
delete-account | On | Signed-in users call it to delete rows, files under sample-uploads/<user-id>/, then the auth user |
send-test-push | On | Optional APNs sender copied from the Swift template; it expects a device_tokens table the Expo template does not ship |
The Expo client gets an Expo push token in lib/notifications.tsx, but it does
not persist tokens to Supabase. Treat send-test-push as an optional backend
artifact until you add a token table and registration flow.
Edge secrets
Set only server-side secrets in Supabase:
supabase secrets set REVENUECAT_WEBHOOK_AUTH=<long-random-string> --project-ref <ref>| Secret | Used by | Notes |
|---|---|---|
REVENUECAT_WEBHOOK_AUTH | revenuecat-webhook | Must match the RevenueCat webhook Authorization header |
APNS_TEAM_ID | send-test-push | Optional Apple Developer Team ID |
APNS_KEY_ID | send-test-push | Optional APNs auth key ID |
APNS_BUNDLE_ID | send-test-push | Optional iOS bundle ID such as expo.soarstarter.com |
APNS_PRIVATE_KEY | send-test-push | Optional .p8 private key contents |
Do not set SUPABASE_URL, SUPABASE_ANON_KEY, or the service-role key as
Edge secrets. Supabase injects the runtime values automatically.
Local function development
supabase functions serve --env-file supabase/functions/.env
deno test supabase/functions/_shared/revenuecat.test.tsfunctions serve exposes local functions under
http://localhost:54321/functions/v1/....
Verify the backend
- Sign up in the app, verify the email code, and confirm a
profilesrow appears for the user. - Create, edit, reorder, and delete todos; relaunch and confirm they persist.
- Upload a file in the Upload sample and confirm both a Storage object and a
sample_uploadsrow exist. - Run
supabase functions list --project-ref <ref>and confirm deployed functions appear. - Re-run
pnpm gen:typesafter schema edits and commit the updatedtypes/database.ts.
