Files
Sauci/CLAUDE.md
T

9.5 KiB

CLAUDE.md

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

Important: Design Guidelines

Always read apps/mobile/DESIGN.md before making UI/UX changes to the mobile app. This file contains the design system, visual language, and styling patterns that must be followed for consistency. Agents and subagents should read this file when:

  • Creating new screens or components
  • Modifying existing UI elements
  • Adding animations or visual effects
  • Working with colors, typography, or spacing

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 (unauthenticated, accepts email + code)
  • Database Function (redeem_code_by_email(p_email, p_code)) - Atomic redemption with validation (active, not expired, has uses remaining, user hasn't redeemed)
  • Web UI (apps/web/app/redeem/page.tsx) - Public redemption page

Flow:

  1. Admin generates code in admin dashboard
  2. User visits /redeem on website and enters email + code
  3. redeem-code edge function calls redeem_code_by_email() database function
  4. Database function looks up user by email, validates code, and sets profiles.is_premium = 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

E2EE (End-to-End Encryption) Implementation

Chat messages (text, images, videos) are encrypted client-side using AES-256-GCM with triple-wrapped RSA keys.

Architecture

  • Full documentation: See docs/e2ee-implementation.md for complete details
  • Encryption library: apps/mobile/src/lib/encryption/
  • React hooks: apps/mobile/src/hooks/useEncryptionKeys.ts, useDecryptedMessage.ts
  • Edge functions: handle-key-rotation, reencrypt-pending-messages

Key Concepts

  1. Message versions: v1 = plaintext (legacy), v2 = E2EE
  2. Triple-wrapped keys: Each message's AES key is RSA-encrypted for sender, recipient, and admin
  3. Device recovery: When user gets new device, admin key re-wraps messages for new user key

Database Tables

  • messages.version - Encryption version (1 or 2)
  • messages.encrypted_content - Base64 ciphertext
  • messages.encryption_iv - Base64 IV for AES-GCM
  • messages.keys_metadata - JSONB with wrapped keys
  • profiles.public_key_jwk - User's RSA public key
  • master_keys - Admin RSA public keys

Setup Required

  1. Run node scripts/generate-admin-keys.mjs to generate admin keypair
  2. Insert public key into master_keys table
  3. Store private key in ADMIN_PRIVATE_KEY_JWK environment variable for edge functions
  4. Install crypto dependency: npm install react-native-quick-crypto@^0.7.x
  5. Run npx expo prebuild --clean after installation

Edge Functions for E2EE

Function verify_jwt Purpose
handle-key-rotation false Re-wraps message keys when user gets new device
reencrypt-pending-messages false Wraps keys for recipient after they generate keys