Skip to main content

Overview

Recipe Room has three deployment targets, each serving a different purpose in the current phased rollout:
AppPlatformStatusWhat It Deploys
apps/mobileEAS → App StoreActive — primary productiOS app via TestFlight / App Store
apps/web-interimVercelActive — supports mobileAuth callbacks, deep links, landing page
apps/webVercelPhase 2 — not deployedFull web client (future)
The mobile app is the production product. The web interim exists to handle things the mobile app can’t do on its own — email confirmation callbacks, password reset flows, universal link verification, and a public landing page with waitlist signup. The full web app will be deployed in Phase 2 when the web client is built out.

Mobile Deployment (EAS)

The iOS app is built and submitted via Expo Application Services (EAS). This is the primary deployment pipeline.

Build Profiles

Defined in apps/mobile/eas.json:
ProfilePurposeCommand
developmentDev client with debugging toolspnpm eas:build:dev
previewTestFlight / internal testingpnpm eas:build:preview
productionApp Store releasepnpm eas:build

Submitting to App Store

Run commands from apps/mobile/:
pnpm eas:build:submit
pnpm eas:build:submit:no-fingerprint
pnpm eas:submit
Detailed mobile build rules are centralized in Mobile Build Workflow.

Mobile Environment Variables

Set in apps/mobile/.env locally, and in EAS secrets for CI builds:
VariableRequiredDescription
EXPO_PUBLIC_SUPABASE_URLYesSupabase project URL
EXPO_PUBLIC_SUPABASE_ANON_KEYYesSupabase anonymous key
EXPO_CONFIG_MODENoSet automatically by the mobile scripts and EAS build profiles
EXPO_CONFIG_MODE controls which app config is used — development for Expo Go compatibility, production for EAS builds with the production bundle identifier. See Mobile Build Workflow for the current setup.

Web Interim Deployment (Vercel)

apps/web-interim deploys to Vercel automatically on push to the main branch. It runs on a separate Vercel project from the future web app.

What It Serves

  • Auth callback pages (email confirmation, password reset, email change)
  • Deep link verification files (.well-known/apple-app-site-association, .well-known/assetlinks.json)
  • Content redirect pages (/recipes/[id], /posts/[id], /collections/[id]) that either deep link into the app or show an “app only” fallback
  • Public landing page with waitlist signup (via marketing-events Supabase edge function)

Environment Variables

Set in Vercel project settings:
VariableRequiredDescription
NEXT_PUBLIC_SUPABASE_URLYesSupabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEYYesSupabase anonymous key
That’s it — web interim doesn’t need the service role key because it doesn’t do server-side data mutations. The /api/waitlist route invokes the marketing-events Supabase edge function, which handles the Loops API key server-side.

Build Command

pnpm build --filter @recipe-room/web-interim
Vercel should be configured to build from apps/web-interim/ with the root directory set accordingly.

Web App Deployment (Phase 2)

apps/web is scaffolded but not deployed yet. When Phase 2 begins, it will deploy to Vercel as a separate project.

How It Will Differ from Web Interim

The full web app will route all data mutations through server-side API routes (using the service role key), unlike the mobile app which talks to Supabase directly. This means:
  • API routes handle auth, CRUD, and business logic server-side
  • The service role key stays on the server (never exposed to the browser)
  • Middleware handles route protection and auth redirects
  • next/image and Vercel’s image CDN handle image optimization

Future Environment Variables

VariableRequiredDescription
NEXT_PUBLIC_SUPABASE_URLYesSupabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEYYesSupabase anonymous key (safe for client)
SUPABASE_SERVICE_ROLE_KEYYesSupabase service role key (server-only)
SUPABASE_SERVICE_ROLE_KEY must never be prefixed with NEXT_PUBLIC_. It is only used in API routes (server-side).
Phase II web routes should reuse the same marketing-events edge function used by mobile and web interim. No app-level Loops API key is expected in the web app environment.

Middleware (Phase 2)

The Next.js middleware (apps/web/src/middleware.ts) will handle route protection: Protected routes (redirect to /login if unauthenticated): /me, /settings, /recipes/new, /collections/new, /favorites, any route containing /edit. Auth routes (redirect to / if already authenticated): /login, /register. The middleware uses supabase.auth.getUser() to validate the JWT. When redirecting to login, the original path is preserved as a redirect query parameter so the user returns to their intended destination after logging in.

Loops.so Integration

Recipe Room uses Loops.so for transactional emails and audience management. The integration is optional — if the edge function secret is not set, all Loops operations are silently skipped.

What It Does

EventActionWhere
User registersCreates contact in Loops, sends welcome emailMobile: marketingGateway.registerUserMarketing() via marketing-events edge function
User deletes accountRemoves contact from LoopsMobile: marketingGateway.removeUserMarketing() via marketing-events edge function
Waitlist signupAdds email to Loops audienceapps/web-interim /api/waitlist route via marketing-events edge function
All Loops API calls are routed through the marketing-events Supabase edge function. The Loops API key is stored as an edge function secret — it never appears in client or server code. The future web app should reuse the same edge function pattern rather than introducing a separate Loops key.

Configuring Loops

  1. Create an account at loops.so
  2. Create a transactional email template with ID welcome-email
  3. Add the firstName data variable to the template
  4. Add your API key as a Supabase edge function secret (LOOPS_API_KEY)
All Loops calls are wrapped in try/catch — failures are logged but never block the primary operation.