Caluru

Caluru - Data Model Reference

This document describes all data models, their fields, relationships, and how data flows through the system.


๐Ÿ“Š Entity Relationship Overview

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   UserProfile   โ”‚ โ”€โ”€โ”€โ”€ Singleton; onboarding fields, targets, legacy
โ”‚ (hasCompleted   โ”‚       onboardingCompletedAt โ†’ onboarding gate
โ”‚  Onboarding)    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  WeightEntry    โ”‚       โ”‚   UserProfile   โ”‚ (linked by app; no FK)
โ”‚ (weight log)   โ”‚       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    FoodItem     โ”‚       โ”‚     Recipe      โ”‚
โ”‚  (40+ seeded)   โ”‚       โ”‚  (20+ seeded)   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                        โ”‚
         โ”‚                        โ”‚ contains
         โ”‚                        โ–ผ
         โ”‚               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
         โ”‚               โ”‚   Ingredient    โ”‚ (Codable struct)
         โ”‚               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚
         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       
โ”‚   LoggedItem    โ”‚ โ†โ”€โ”€โ”€โ”€ Created when user logs food/recipe
โ”‚ (Codable struct)โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚
         โ”‚ grouped by
         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   MealEntry     โ”‚ (Codable struct: desayuno/comida/cena/snack)
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚
         โ”‚ belongs to
         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    DailyLog     โ”‚ โ”€โ”€โ”€โ”€ One per day
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   WeeklyPlan    โ”‚ โ”€โ”€โ”€โ”€โ–บ โ”‚   PlannedDay    โ”‚ (7 per plan)
โ”‚ (one per week)  โ”‚       โ”‚ (Codable struct)โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                  โ”‚
                                  โ”‚ references
                                  โ–ผ
                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                          โ”‚  PlannedRecipe  โ”‚ (Codable snapshot)
                          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  ShoppingList   โ”‚ โ”€โ”€โ”€โ”€โ–บ โ”‚ShoppingListItem โ”‚ (Codable struct)
โ”‚ (one per week)  โ”‚       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Not in SwiftData: OnboardingState (UserDefaults), AssistantAction and related structs (Codable, parsed from AI or in-memory).


๐Ÿ“‹ Model Definitions

UserProfile

File: Models/UserProfile.swift
Type: SwiftData @Model
Purpose: User profile: onboarding answers, nutrition targets, preferences, segmentation.

Field Type Description
id UUID Unique identifier
name String? Display name
age Int? Age (for BMR/targets)
height Double? Height in cm (base unit)
weight Double? Weight in kg (base unit)
profileImageData Data? Profile picture (JPEG)
Onboarding ย  ย 
goalTypeRaw String? GoalType raw
otherGoalTagsData Data? [OtherGoalTag]
privacyPreferenceRaw String? PrivacyPreference
unitSystemRaw String? UnitSystem (metric/imperial)
sexEstimationRaw String? SexEstimation (for BMR)
activityLevelRaw String? ActivityLevel
trainingDays Int? Training days per week
goalPaceRaw String? GoalPace
trackingModeRaw String? TrackingMode
dietaryPreferencesData Data? [DietaryPreference]
allergiesAvoidsData Data? [AllergyType]
cookingTimeRaw String? Legacy unused (was CookingTime preference)
confidence Int? 1โ€“5 nutrition/cooking experience (from onboarding skill step)
snackingFrequencyRaw String? SnackingFrequency
dessertFrequencyRaw String? DessertFrequency
Targets ย  ย 
calorieTarget Int Daily calorie goal
proteinTarget Int Protein goal (g)
carbsTarget Int Carbs goal (g)
fatTarget Int Fat goal (g)
Segmentation ย  ย 
structureNeedScore Int? 0โ€“10
performanceOrientationScore Int? 0โ€“10
constraintComplexityScore Int? 0โ€“10
archetypeRaw String? SegmentationArchetype
Timestamps ย  ย 
createdAt Date Creation
updatedAt Date? Last update
onboardingCompletedAt Date? When onboarding finished; used for onboarding gate
Legacy ย  ย 
language String Default โ€œesโ€
goal String? โ€œloseโ€, โ€œmaintainโ€, โ€œgainโ€
dietTypeRaw String? DietType (DietType enum)
allergiesData Data? [String] (legacy)
maxPrepTimeMinutes Int? Legacy unused (was max prep time preference)
(others) ย  Placeholders for budget, cuisine, meal timing, etc.

Computed: goalType, unitSystem, currentActivityLevel, goalPace, trackingMode, dietaryPreferences, allergiesAvoids, snackingFrequency, dessertFrequency, estimationMode, supportLevel, archetype, hasCompletedOnboarding (= onboardingCompletedAt != nil), hasMinimumDataForPlanning, bmi, displayWeight, displayHeight, legacy allergies, dietType, etc.

Notes:


FoodItem

File: Models/FoodItem.swift
Type: SwiftData @Model
Purpose: Individual food items for quick-add and scanning.

Field Type Description
id UUID Unique identifier
name String Food name (e.g., โ€œPechuga de polloโ€)
brand String? Optional brand name
servingSize String Display serving (e.g., โ€œ100gโ€)
servingGrams Double Serving weight in grams
calories Int Calories per serving
protein Double Protein in grams
carbs Double Carbohydrates in grams
fat Double Fat in grams
category String Raw value of FoodCategory
barcode String? Optional barcode for scanning
createdAt Date Creation timestamp

Computed Properties:

FoodCategory Enum:

enum FoodCategory: String {
    case protein = "proteรญna"
    case carb = "carbohidrato"
    case fat = "grasa"
    case produce = "frutas y verduras"
    case other = "otros"
}

Recipe

File: Models/Recipe.swift
Type: SwiftData @Model
Purpose: Complete recipes with ingredients and preparation steps.

Field Type Description
id UUID Unique identifier
title String Recipe name
mealType String Raw value of MealType
imageName String Asset image name (placeholder)
servings Int Number of servings
prepTime Int Preparation time in minutes
calories Int Total calories per serving
protein Double Protein per serving
carbs Double Carbs per serving
fat Double Fat per serving
ingredientsData Data? JSON-encoded [Ingredient]
stepsData Data? JSON-encoded [String]
createdAt Date Creation timestamp
isFavorite Bool User favorite flag

Computed Properties:

MealType Enum:

enum MealType: String {
    case desayuno = "desayuno"  // Breakfast
    case comida = "comida"       // Lunch
    case cena = "cena"           // Dinner
    case snack = "snack"
    case postre = "postre"       // Dessert
}

Ingredient

File: Models/Ingredient.swift
Type: Codable struct
Purpose: Single ingredient within a recipe.

Field Type Description
id UUID Unique identifier
name String Ingredient name
quantity Double Amount
unit String Unit (g, ml, unidad, etc.)
category String Raw value of FoodCategory

Computed Properties:


DailyLog

File: Models/DailyLog.swift
Type: SwiftData @Model
Purpose: Daily nutrition tracking log.

Field Type Description
id UUID Unique identifier
date Date Day (start of day)
entriesData Data? JSON-encoded [MealEntry]

Computed Properties (Aggregated):

Methods:

Aggregation Logic:

var totalCalories: Int {
    entries.reduce(0) { $0 + $1.totalCalories }
}

Each MealEntry sums its items, and each LoggedItem applies servingsMultiplier.


MealEntry

File: Models/MealEntry.swift
Type: Codable struct
Purpose: Collection of logged items for a specific meal.

Field Type Description
id UUID Unique identifier
mealType String Raw value of MealType
items [LoggedItem] Logged foods/recipes

Computed Properties:


LoggedItem

File: Models/LoggedItem.swift
Type: Codable struct
Purpose: Single logged food or recipe with serving multiplier.

Field Type Description
id UUID Unique identifier
name String Display name
servingsMultiplier Double Portion multiplier (default: 1.0)
baseCalories Int Calories before multiplier
baseProtein Double Protein before multiplier
baseCarbs Double Carbs before multiplier
baseFat Double Fat before multiplier
isRecipe Bool True if from recipe
sourceId UUID? Reference to original FoodItem/Recipe

Computed Properties:

var calories: Int {
    Int(Double(baseCalories) * servingsMultiplier)
}

Factory Methods:


WeeklyPlan

File: Models/WeeklyPlan.swift
Type: SwiftData @Model
Purpose: 7-day meal plan for a given week.

Field Type Description
id UUID Unique identifier
weekStartDate Date Monday of the week
daysData Data? JSON-encoded [PlannedDay]

Computed Properties:

Methods:


PlannedDay

File: Models/PlannedDay.swift
Type: Codable struct
Purpose: Single day within a weekly plan.

Field Type Description
id UUID Unique identifier
date Date Day date
breakfastRecipe PlannedRecipe? Assigned breakfast
lunchRecipe PlannedRecipe? Assigned lunch
dinnerRecipe PlannedRecipe? Assigned dinner

Computed Properties:


PlannedRecipe

File: Models/PlannedDay.swift
Type: Codable struct
Purpose: Lightweight recipe snapshot for planning.

Field Type Description
id UUID Snapshot identifier
recipeId UUID Original recipe ID
title String Recipe title
imageName String Image asset
calories Int Calories
protein Double Protein
carbs Double Carbs
fat Double Fat
ingredients [Ingredient] For shopping list

Constructor:

init(from recipe: Recipe) {
    // Copies recipe data into snapshot
}

ShoppingList

File: Models/ShoppingList.swift
Type: SwiftData @Model
Purpose: Shopping list for a weekโ€™s ingredients.

Field Type Description
id UUID Unique identifier
weekStartDate Date Week this list is for
itemsData Data? JSON-encoded [ShoppingListItem]

Computed Properties:

Methods:


ShoppingListItem

File: Models/ShoppingListItem.swift
Type: Codable struct
Purpose: Single item on shopping list.

Field Type Description
id UUID Unique identifier
name String Item name
quantity Double Amount
unit String Unit
category String FoodCategory raw value
isChecked Bool Completion status

WeightEntry

File: Models/WeightEntry.swift
Type: SwiftData @Model
Purpose: Weight log entry (profile weight history).

Field Type Description
id UUID Unique identifier
weight Double Weight in kg (base unit)
date Date Day of entry (start of day)
notes String? Optional notes
createdAt Date Creation timestamp

Methods: displayWeight(unitSystem:) returns weight in kg or lb based on UnitSystem.


OnboardingState (Not SwiftData)

File: Models/OnboardingState.swift
Type: Codable struct; persisted in UserDefaults
Purpose: Draft state during onboarding so user can resume if app closes.

Stores: currentScreen, optional screens shown, name, privacy policy accepted, goalType, otherGoalTags, privacyPreference, unitSystem, age, sexEstimation, heightCm, weightKg, activityLevel, trainingDays, goalPace, trackingMode, snackingFrequency, dessertFrequency, dietaryPreferences, allergiesAvoids, confidence, targets review response and adjusted values.
Computed: estimationMode, hasDietaryRestrictions, supportLevel, displayWeight, displayHeight.
Persistence: OnboardingState.load(), save(), clear().


OnboardingTypes (Enums)

File: Models/OnboardingTypes.swift
Purpose: Typed enums for onboarding and profile.

Includes: GoalType, OtherGoalTag, PrivacyPreference, UnitSystem, SexEstimation, ActivityLevel, GoalPace, TrackingMode, DietaryPreference, AllergyType, EstimationMode, SupportLevel, TargetsReviewResponse, SnackingFrequency, DessertFrequency, OnboardingScreen, SegmentationArchetype, ProfileCardType.
Also: CalculatedTargets, SegmentationScores (structs).


AssistantAction (Not SwiftData)

File: Models/AssistantAction.swift
Type: Codable enum
Purpose: Actions the AI assistant can trigger in the app.

Case Payload Description
logMeal LogMealAction Log a meal (name, calories, protein, carbs, fat, mealType)
createRecipe CreateRecipeAction Create recipe (title, mealType, servings, prepTime, macros, ingredients, steps)
generateMealPlan GenerateMealPlanAction Generate weekly plan (daysCount, preferences, calorieTarget)
adjustTarget AdjustTargetAction Change target (targetType, newValue)
viewRecipe String Recipe title to open
viewProgress โ€” Open progress view

Supporting structs: LogMealAction, CreateRecipeAction, GenerateMealPlanAction, AdjustTargetAction.
Parsing: ActionParser.parse(from:) reads a trailing structured CALURU_ACTIONS JSON block (not free-text keywords). Invalid or incomplete actions are dropped so chips only appear for confirmed payloads.


๐ŸŒฑ Seed Data

When Seeding Occurs

SeedDataService.seedIfNeeded(context:) is called in MainTabView.task:

.task {
    SeedDataService.seedIfNeeded(context: modelContext)
}

Seeded Content

Entity Count Source
UserProfile 1 Created if none; targets from SeedDataService or onboarding
Recipe 20+ createRecipes()
FoodItem 45+ createFoodItems()
DailyLog 1 Empty log for today
WeeklyPlan 1 Empty plan for this week
ShoppingList 1 Empty list
WeightEntry 0 User-created only

Recipe Categories

Category Count Examples
Desayunos 4 Avena con frutas, Huevos revueltos
Comidas 5 Pollo a la plancha, Ensalada Cรฉsar
Cenas 4 Sopa de verduras, Wrap de pollo
Snacks 4 Yogur griego, Hummus con vegetales
Postres 3 Mousse de chocolate, Chia pudding

Food Item Categories

Category Count Examples
Proteรญnas 10 Pollo, Salmรณn, Huevo
Carbohidratos 10 Arroz, Pasta, Avena
Grasas 7 Aguacate, Almendras, Aceite
Frutas/Verduras 10 Plรกtano, Brรณcoli, Tomate
Otros 5 Leche, Miel, Proteรญna en polvo

๐Ÿงฎ Computed Totals Logic

Daily Calories Calculation

DailyLog.totalCalories
    โ””โ”€โ”€ Sum of MealEntry.totalCalories (for each meal type)
            โ””โ”€โ”€ Sum of LoggedItem.calories (for each item)
                    โ””โ”€โ”€ baseCalories ร— servingsMultiplier

Progress Calculation

// In HomeViewModel
var calorieProgress: Double {
    Double(consumedCalories) / Double(targetCalories)
}

Weekly Plan Totals

// In NutritionCalculator
static func calculateWeeklyTotals(from plan: WeeklyPlan) -> NutritionSummary {
    var total = NutritionSummary.zero
    for day in plan.days {
        // Add breakfast + lunch + dinner calories/macros
    }
    return total
}

๐Ÿ”— Data Relationships

One-to-One

One-to-Many (via JSON encoding)

Snapshot References


โš ๏ธ Known Data Considerations

  1. No Cascade Deletes: Deleting a Recipe doesnโ€™t update PlannedDay snapshots
  2. JSON Overhead: Large entry lists may have encoding/decoding overhead
  3. No Migrations: Schema changes require manual migration logic
  4. CloudKit Sync: SwiftData uses CloudKit private database; onboarding gate depends on UserProfile.hasCompletedOnboarding syncing (short delay on reinstall)
  5. OnboardingState: Stored in UserDefaults only; not synced across devices