Files
Sauci/CLAUDE.md
T
2025-12-31 12:20:23 +00:00

7.2 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Sauci is a couples intimacy app featuring swipeable question packs with partner matching. Users swipe on questions (yes/no/maybe), and when both partners answer positively, a "match" is created that unlocks a chat thread for that question.

Commands

# Install dependencies (from root)
npm install

# Start all apps in development
npm run dev

# Run specific apps
cd apps/mobile && npm run dev      # Expo mobile app
cd apps/admin && npm run dev       # React Admin dashboard

# Type checking
npm run typecheck

# Linting
npm run lint

# Build all
npm run build

Mobile-specific commands

cd apps/mobile
npm run ios       # Run on iOS simulator
npm run android   # Run on Android emulator
npm run web       # Run in browser

Supabase commands

supabase start                                    # Start local Supabase
supabase db reset                                 # Reset DB and run all migrations
supabase functions serve                          # Run edge functions locally
supabase migration new <name>                     # Create new migration

Supabase Environments

There are two Supabase projects configured via MCP servers:

Environment Project Ref URL MCP Server
Production ckjcrkjpmhqhiucifukx https://ckjcrkjpmhqhiucifukx.supabase.co sauci-prod
Non-Production itbzhrvlgvdmzbnhzhyx https://itbzhrvlgvdmzbnhzhyx.supabase.co sauci-non-prod

When using Claude Code with MCP tools:

  • Use mcp__sauci-prod__* tools for production database operations
  • Use mcp__sauci-non-prod__* tools for development/staging database operations
  • Always verify which environment you're targeting before running migrations or destructive operations

Architecture

Monorepo Structure (Turborepo)

  • apps/mobile - Expo React Native app (expo-router for navigation)
  • apps/admin - React Admin dashboard for content management
  • apps/supabase - Database migrations and edge functions
  • packages/shared - Shared TypeScript types (@sauci/shared)

Mobile App Architecture

  • Routing: Expo Router with file-based routing (app/ directory)
    • (auth)/ - Authentication screens
    • (app)/ - Main app screens (protected)
  • State Management: Zustand stores in src/store/index.ts
    • useAuthStore - User, couple, partner state
    • useMatchStore - Matches and notifications
    • usePacksStore - Question packs and enabled packs per couple
    • useMessageStore - Chat messages and unread counts
    • useSubscriptionStore - RevenueCat subscription state
  • Backend: Supabase client in src/lib/supabase.ts
  • UI Components: Glass-morphism themed components in src/components/ui/

Data Model (Core Entities)

  • Profile - User profile extending Supabase auth (has couple_id)
  • Couple - Two users linked via invite code
  • QuestionPack - Collection of questions (can be premium)
  • Question - Individual question with intensity level (1-5)
  • Response - User's answer (yes/no/maybe) to a question
  • Match - Created when both partners answer positively (yes_yes, yes_maybe, maybe_maybe)

Edge Functions

Edge functions in apps/supabase/functions/ handle complex operations:

  • submit-response - Saves response, checks for matches, triggers notifications
  • manage-couple - Join/leave couple operations
  • send-notification - Push notifications for matches
  • revenuecat-webhook - Subscription webhook handler
  • sync-subscription - Syncs RevenueCat subscription status
  • redeem-code - Redeems promotional codes for premium access (website only)

Edge Function Deployment Guidelines

When deploying edge functions via MCP tools (mcp__sauci-*__deploy_edge_function):

IMPORTANT: Always use verify_jwt: false for all edge functions. Supabase's built-in JWT verification causes 401 errors even with valid tokens. Instead, handle authentication manually in the function code using:

const { data: { user }, error: authError } = await supabase.auth.getUser(
    authHeader.replace("Bearer ", "")
);

This approach:

  • Gives better error messages
  • Allows custom auth handling
  • Avoids mysterious 401 failures

Current function settings (all should be verify_jwt: false):

Function verify_jwt Auth Method
manage-couple false Manual via getUser()
submit-response false Manual via getUser()
sync-subscription false Manual via getUser()
delete-relationship false Manual via getUser()
redeem-code false Manual via getUser()
revenuecat-webhook false Webhook signature validation
send-notification false Internal trigger (no auth)
send-message-notification false Internal trigger (no auth)

Database Best Practices

  • Always use .maybeSingle() instead of .single() when the row might not exist. .single() throws an error if 0 or >1 rows are returned.
  • Profile creation trigger: The on_auth_user_created trigger automatically creates a profile when a user signs up. Never assume a profile exists without checking.
  • Check for null profiles in edge functions before performing operations.

Key Patterns

  • Responses use UPSERT with onConflict: "user_id,question_id"
  • Match detection happens in submit-response edge function after each response
  • Real-time subscriptions used for chat messages
  • RevenueCat handles in-app purchases and subscription management
  • RLS policies enforce couple-level data isolation

Redemption Code System

Promotional codes that grant users premium access. Codes can only be redeemed on the website, NOT in the mobile app.

Database Tables:

  • redemption_codes - Stores codes with max_uses, current_uses, expiration, active status
  • code_redemptions - Tracks which users redeemed which codes

Components:

  • Admin UI (apps/admin/src/pages/RedemptionCodesPage.tsx) - Super admins can generate, manage, and view redemption codes
  • Edge Function (apps/supabase/functions/redeem-code/) - Validates and processes code redemption
  • Database Function (redeem_code(p_code)) - Atomic redemption with validation (active, not expired, has uses remaining, user hasn't redeemed)

Flow:

  1. Admin generates code in admin dashboard
  2. User enters code on website (NOT mobile app)
  3. redeem-code edge function calls redeem_code() database function
  4. On success, user's profiles.is_premium is set to true

Important: Do NOT add redemption code UI to the mobile app. Apple requires in-app purchases for premium features purchased within iOS apps.

Mobile UI - DO NOT CHANGE

Tab Bar Background

NEVER set backgroundColor: 'transparent' on the tab bar. Always use a semi-transparent solid color:

backgroundColor: 'rgba(18, 18, 18, 0.85)',

The BlurView in tabBarBackground is unreliable and can fail during re-renders/transitions, causing a fully transparent tab bar. The solid rgba background acts as a fallback while still allowing the blur effect on top.

Location: apps/mobile/app/(app)/_layout.tsx - tabBarStyle