A comprehensive iOS nutrition tracking and meal planning app built with SwiftUI, SwiftData, Supabase, and CloudKit.
Caluru is a hybrid local + cloud nutrition app that helps users:
The app UI is in Spanish (localized strings, labels, recipe content).
| Technology | Version / Note | Purpose |
|---|---|---|
| Swift | 5.9+ | Language |
| SwiftUI | iOS 17+ | UI |
| SwiftData | iOS 17+ | Local persistence |
| CloudKit | iOS 17+ | Sync (private container iCloud.com.agarcia.caluru) |
| Supabase | β | Auth (Sign in with Apple), Edge Function (openai-proxy) |
| OpenAI API | β | GPT-4o-mini (Assistant), GPT-4o (food photo); key server-side only |
| Open Food Facts | β | Barcode product lookup |
| AVFoundation | β | Camera / barcode scanning |
| UserNotifications | β | Meal, goal, streak, weight reminders |
| SF Symbols | β | Icons |
SUPABASE_URL, SUPABASE_ANON_KEY in appcd /path/to/Caluru
open Caluru.xcodeproj
# Or press Cmd+R in Xcode
UserProfile with onboardingCompletedAt (e.g. fresh install or CloudKit not yet synced), onboarding is shown (fullScreenCover).UserProfile (or uses existing), 20+ recipes, 40+ food items, empty DailyLog, WeeklyPlan, ShoppingList.Caluru/ # repo root
βββ Caluru.xcodeproj
βββ Caluru/ # app source
βββ CaluruApp.swift # @main; ModelContainer (SwiftData + CloudKit); theme; notifications; AppDelegate (notifications)
βββ ContentView.swift # β MainTabView
βββ Config.swift # SupabaseConfig (url, anonKey from Info.plist)
β
βββ Models/
β βββ UserProfile.swift # Extended: onboarding, targets, legacy (dietType, allergies, etc.)
β βββ FoodItem, Recipe, Ingredient, DailyLog, MealEntry, LoggedItem
β βββ WeeklyPlan, PlannedDay, ShoppingList, ShoppingListItem
β βββ WeightEntry.swift
β βββ OnboardingState.swift, OnboardingTypes.swift # Onboarding enums & draft state
β βββ AssistantAction.swift # LogMeal, CreateRecipe, GenerateMealPlan, AdjustTarget, viewRecipe, viewProgress
β βββ CloudRecipe.swift (if used)
β
βββ Views/
β βββ MainTabView.swift # 5 tabs; onboarding fullScreenCover; progressive profiling overlay
β βββ Home/ (HomeView, AddFoodSheet)
β βββ Plan/ (WeeklyPlanView)
β βββ Scan/ (ScanView)
β βββ Recipes/ (RecipesView, RecipeDetailView, AddRecipeSheet)
β βββ ShoppingList/ (ShoppingListView)
β βββ Assistant/ (AssistantView)
β βββ Profile/ (ProfileView, AppPreferencesView, WeightTrackingView, NotificationsSettingsView, LegalView)
β βββ Onboarding/
β βββ OnboardingFlowView.swift
β βββ Screens/ (S0Welcome, S1WelcomeGoal, SMotivations, S15Confidence, EncouragementGoals, SQuickBasics, SBodyMetrics, S8βS10, S12βS13, SMealsDessert, SDislikedFoods, STargetsReveal, SignIn, S0aName, S0bUsername, SFirstLogNudge, AdjustTargetsSheet)
β βββ Components/ (shared onboarding UI in OnboardingFlowView)
β
βββ ViewModels/
β βββ HomeViewModel, WeeklyPlanViewModel, RecipesViewModel
β βββ ScanViewModel, ShoppingListViewModel, AssistantViewModel
β βββ ProfileViewModel, OnboardingViewModel
β βββ (Models/HomeViewModel.swift if present)
β
βββ Services/
β βββ NutritionCalculator, SeedDataService, ShoppingListBuilder
β βββ AssistantResponseService.swift # AIAssistantService (GPT-4o-mini via OpenAIProxyService)
β βββ OpenAIProxyService # Calls Supabase Edge Function openai-proxy
β βββ OpenFoodFactsService # Barcode lookup
β βββ FoodRecognitionService # Photo β GPT-4o Vision via proxy
β βββ MockFoodRecognitionService # Fallback/offline
β βββ SupabaseClient.swift # SupabaseManager (shared client)
β βββ AuthService # Sign in with Apple, session restore, signOut
β βββ TargetCalculator # Mifflin-St Jeor; onboarding targets
β βββ MealPlanGenerator # Auto-generate weekly plan
β βββ ProgressiveProfilingService # Post-onboarding profile cards
β βββ NotificationService # Meal, goal, streak, weight reminders
β βββ AccountResetService # Reset data / re-onboard
β βββ RecipeService, OnboardingAnalytics
β βββ ...
β
βββ DesignSystem/
β βββ AppColors, AppTypography, AppSpacing
β βββ Components/ (Card, PillSegment, MacroChip, PrimaryButton, IconButton, EmptyState, ProgressRing, SearchBar, RecipeCard, StreakBadge, ...)
β
βββ Assets.xcassets/
Default targets are defined in Services/SeedDataService.swift:
UserProfile(
calorieTarget: 3500,
proteinTarget: 190,
carbsTarget: 250,
fatTarget: 85,
language: "es"
)
Edit DesignSystem/AppColors.swift:
| Color | Hex | Usage |
|---|---|---|
accentGreen |
#8FB996 |
Primary accent, buttons, progress |
background |
#F5F6F8 |
Screen backgrounds |
cardBackground |
#FFFFFF |
Card surfaces |
textPrimary |
#1A1A2E |
Main text |
textSecondary |
#6B7280 |
Secondary text |
SUPABASE_URL - Project URL (e.g. xxx.supabase.co; app may prepend https://)SUPABASE_ANON_KEY - Anon/public keyNSCameraUsageDescription - Barcode and food photo scanning (branded as Caluru)NSPhotoLibraryUsageDescription - Profile photo and food analysisCFBundleDisplayName - Caluru (home screen name)The app does not request microphone access (NSMicrophoneUsageDescription is not present).
See App Store Connect listing for store metadata that matches in-app branding.
| Command | Action |
|---|---|
Cmd+R |
Build and run |
Cmd+B |
Build only |
Cmd+U |
Run tests |
Cmd+Shift+K |
Clean build folder |
# Unit tests
xcodebuild test -scheme Caluru -destination 'platform=iOS Simulator,name=iPhone 15'
The project auto-generates Info.plist. Delete any manually created Info.plist file in the source folder.
Ensure the ModelContainer is configured with isStoredInMemoryOnly: false in CaluruApp.swift.
Camera features require a physical device. The simulator will show a blank preview.
Cmd+Shift+K)The project uses SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor. ViewModels that access UI state from async contexts must be marked @MainActor.
This project is for educational and demonstration purposes.