This document describes all data models, their fields, relationships, and how data flows through the system.
โโโโโโโโโโโโโโโโโโโ
โ 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).
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:
hasCompletedOnboarding.SeedDataService.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: FoodCategory - Typed getter/setter for categoryFoodCategory Enum:
enum FoodCategory: String {
case protein = "proteรญna"
case carb = "carbohidrato"
case fat = "grasa"
case produce = "frutas y verduras"
case other = "otros"
}
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:
mealTypeEnum: MealType - Typed getter/setteringredients: [Ingredient] - Decoded from ingredientsDatasteps: [String] - Decoded from stepsDataMealType Enum:
enum MealType: String {
case desayuno = "desayuno" // Breakfast
case comida = "comida" // Lunch
case cena = "cena" // Dinner
case snack = "snack"
case postre = "postre" // Dessert
}
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:
displayQuantity: String - Formatted โ2 cucharadasโfoodCategory: FoodCategory - Typed getter/setterFile: 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):
entries: [MealEntry] - Decoded meal entriestotalCalories: Int - Sum of all logged caloriestotalProtein: Double - Sum of all proteintotalCarbs: Double - Sum of all carbstotalFat: Double - Sum of all fatMethods:
getEntry(for mealType: MealType) -> MealEntry?addItem(_ item: LoggedItem, to mealType: MealType)removeItem(at index: Int, from mealType: MealType)Aggregation Logic:
var totalCalories: Int {
entries.reduce(0) { $0 + $1.totalCalories }
}
Each MealEntry sums its items, and each LoggedItem applies servingsMultiplier.
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:
totalCalories, totalProtein, totalCarbs, totalFatFile: 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:
static func from(foodItem: FoodItem, multiplier: Double) -> LoggedItemstatic func from(recipe: Recipe, multiplier: Double) -> LoggedItemFile: 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:
days: [PlannedDay] - 7 days (initialized if empty)Methods:
setRecipe(_ recipe: PlannedRecipe?, for date: Date, mealType: MealType)getDay(for date: Date) -> 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:
hasAnyMeal: BooltotalCalories: IntFile: 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
}
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:
items: [ShoppingListItem]itemsByCategory: [FoodCategory: [ShoppingListItem]]uncheckedCount, checkedCountMethods:
toggleItem(withId: UUID)addItem(_ item: ShoppingListItem)removeCheckedItems()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 |
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.
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().
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).
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.
SeedDataService.seedIfNeeded(context:) is called in MainTabView.task:
.task {
SeedDataService.seedIfNeeded(context: modelContext)
}
| 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 |
| 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 |
| 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 |
DailyLog.totalCalories
โโโ Sum of MealEntry.totalCalories (for each meal type)
โโโ Sum of LoggedItem.calories (for each item)
โโโ baseCalories ร servingsMultiplier
// In HomeViewModel
var calorieProgress: Double {
Double(consumedCalories) / Double(targetCalories)
}
// 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
}
sourceId but no direct relationshipUserProfile.hasCompletedOnboarding syncing (short delay on reinstall)