| | 2 | |
| | 3 | **Descriptive documentation and argumentation**\\ |
| | 4 | |
| | 5 | 1. User & Role Management (User, Roles, User_roles)\\ |
| | 6 | |
| | 7 | The User table is the central entity of the entire model. Rather than embedding |
| | 8 | a role directly into the User table as a simple string or enum (e.g. role VARCHAR(20)), |
| | 9 | the decision was made to create a separate Roles table and a User_roles junction table. |
| | 10 | |
| | 11 | **Why this way:** |
| | 12 | A simple enum column would restrict each user to exactly one role and make it difficult to |
| | 13 | add new roles in the future without altering the table structure. By using a junction table, |
| | 14 | the model supports many-to-many role assignment — a user could theoretically be both a |
| | 15 | nutritionist and an admin simultaneously. It also means new roles can be added simply by |
| | 16 | inserting a new row into Roles, with no schema changes required. This is a much more scalable |
| | 17 | and flexible design for a platform that may evolve over time. |
| | 18 | |
| | 19 | 2. Food Categorization (Category — self-referencing)\\ |
| | 20 | |
| | 21 | The Category table contains a self-referencing foreign key ParentCategory_id |
| | 22 | that points back to its own primary key. |
| | 23 | |
| | 24 | **Why this way:** |
| | 25 | Food categories in the real world are hierarchical. For example "Chicken Breast" belongs |
| | 26 | to "Poultry", which belongs to "Meat & Fish", which belongs to "Protein Sources". A flat |
| | 27 | single-level category system would not capture this hierarchy. By making Category self-referencing, |
| | 28 | the model supports unlimited nesting depth of categories without needing additional tables. |
| | 29 | The ParentCategory_id is nullable, meaning top-level categories simply have no parent. |
| | 30 | ON DELETE SET NULL ensures that if a parent category is deleted, its children are not deleted |
| | 31 | — they simply become top-level categories themselves |
| | 32 | |
| | 33 | 3. Nutritional Tracking (Food, Nutrient, Food_nutrients)\\ |
| | 34 | |
| | 35 | Rather than adding individual columns to the Food table for each nutrient |
| | 36 | (e.g. protein INT4, carbs INT4, fat INT4), the model uses a separate Nutrient |
| | 37 | table and a Food_nutrients junction table. |
| | 38 | |
| | 39 | **Why this way:** |
| | 40 | The number of nutrients tracked can vary enormously — from basic macros (protein, carbs, fat) |
| | 41 | to micronutrients (Vitamin C, Iron, Calcium, Omega-3 etc.). Hardcoding nutrient columns into |
| | 42 | Food would make the schema inflexible and would require an ALTER TABLE every time a new |
| | 43 | nutrient needs to be tracked. The junction table approach allows any number of nutrients |
| | 44 | to be associated with any food, and new nutrients can be added simply by inserting into the Nutrient |
| | 45 | table. |
| | 46 | |
| | 47 | 4. Serving Sizes (ServingSize)\\ |
| | 48 | |
| | 49 | ServingSize is modeled as a separate table linked to Food with a many-to-one relationship, |
| | 50 | rather than a single serving size column on Food. |
| | 51 | |
| | 52 | **Why this way:** |
| | 53 | A single food can have multiple valid serving sizes. For example "Oats" could be measured |
| | 54 | as "1 cup (90g)", "1 tablespoon (10g)", or "100g". If serving size were a single column |
| | 55 | on Food, users would be forced to always log in the same unit, which is unrealistic. |
| | 56 | The separate table allows the platform to offer users a dropdown of recognized serving sizes |
| | 57 | when logging food, improving accuracy and user experience. The amount and unit columns together |
| | 58 | define exactly how much that serving represents. |
| | 59 | |
| | 60 | 5. Exercise & Muscle Targeting (Exercise, Muscle, Exercise_muscles, Activity)\\ |
| | 61 | |
| | 62 | Exercises are organized under Activities and linked to Muscles through a junction table. |
| | 63 | |
| | 64 | **Why this way:** |
| | 65 | The Activity table (e.g. "Cardio", "Strength Training", "Flexibility") acts as a high-level |
| | 66 | grouping for exercises, allowing users to filter and browse exercises by type. This is kept |
| | 67 | separate from Exercise because one activity type contains many exercises. |
| | 68 | |
| | 69 | The Exercise_muscles junction table exists because a single exercise targets multiple muscles |
| | 70 | (e.g. a bench press works the chest, triceps, and shoulders simultaneously), and a single muscle |
| | 71 | is targeted by many exercises. This is a true many-to-many relationship that cannot be modeled |
| | 72 | with a simple FK column. By tracking this explicitly, the platform can show users a muscle map |
| | 73 | of which areas they are training, and generate reports like "you haven't trained your legs this week." |
| | 74 | |
| | 75 | 6. Diet Planning (Diet, Diet_foods, Diet_Exercise_Targets)\\ |
| | 76 | |
| | 77 | The Diet table acts as a plan template rather than a per-user record. |
| | 78 | Users are linked to diets through the User_Diets junction table. |
| | 79 | |
| | 80 | **Why this way:** |
| | 81 | If diet data were embedded directly into a user record, the same diet plan could not be shared |
| | 82 | across multiple users. By separating the Diet as its own entity, the same diet plan |
| | 83 | (e.g. "Keto Diet", "High Protein Plan") can be assigned to many users simultaneously. |
| | 84 | The company's nutritionists can create a library of diet plans that any user can be enrolled in. |
| | 85 | As well as giving users the option to create their own custom diets where they input their own |
| | 86 | foods and exercises in accordance to their needs. |
| | 87 | |
| | 88 | Diet_foods specifies exactly which foods are part of the diet and in what amounts, while Diet_Exercise_Targets |
| | 89 | specifies which exercises should be performed and how many times per week. Together these two tables fully |
| | 90 | define what a user on a given diet should eat and how they should exercise, giving the platform |
| | 91 | enough data to track compliance and progress. |
| | 92 | |
| | 93 | 7. Gamification (Streak, Streak_type, Achievements, User_achievements)\\ |
| | 94 | |
| | 95 | The gamification layer is modeled with full normalization rather than simple counters. |
| | 96 | |
| | 97 | **Why this way:** |
| | 98 | Streak_type is separated from Streak for the same reason Nutrient is separated from Food |
| | 99 | — there can be many types of streaks (logging streaks, calorie streaks, workout streaks) |
| | 100 | and new types should be addable without schema changes. Each user's Streak record tracks |
| | 101 | both current_count and longest_count, the latter being historically significant even when |
| | 102 | a streak is broken. The CHECK constraint longest_count >= current_count enforces this business |
| | 103 | rule at the database level. |
| | 104 | |
| | 105 | Achievements are similarly separated from User_achievements. The Achievements table defines |
| | 106 | the achievement criteria (what needs to be done, how many times, in what period), while User_achievements |
| | 107 | simply records when a specific user met those criteria. This means achievements are defined |
| | 108 | once and can be earned by any number of users, rather than duplicating achievement definitions per user. |
| | 109 | |
| | 110 | 8. Goals (Goal, User_goals)\\ |
| | 111 | |
| | 112 | Goals are modeled as a shared reference table linked to users through User_goals, |
| | 113 | with each goal tied to a specific diet plan. |
| | 114 | |
| | 115 | **Why this way:** |
| | 116 | A goal like "Lose Weight" or "Gain Weight" is a general concept that many users share. |
| | 117 | Rather than each user defining their own goal from scratch, goals are predefined and |
| | 118 | linked to appropriate diet plans. This means when a user selects a goal, the system can |
| | 119 | automatically suggest or assign the corresponding diet plan. The User_goals junction table |
| | 120 | adds start_date and end_date to give each user's goal a defined timeframe, making progress |
| | 121 | trackable and time-bound. |
| | 122 | |
| | 123 | |
| | 124 | |