Index: NutriMatch/Areas/Identity/Pages/Account/ExternalLogin.cshtml
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/ExternalLogin.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Areas/Identity/Pages/Account/ExternalLogin.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,68 @@
+@page
+@model ExternalLoginModel
+@{
+    ViewData["Title"] = "Complete Registration";
+}
+
+<style>
+    :root {
+        --bs-primary: #22c55e;
+        --bs-primary-rgb: 34, 197, 94;
+    }
+
+    .btn-primary {
+        background-color: #22c55e;
+        border-color: #22c55e;
+    }
+
+    .btn-primary:hover {
+        background-color: #16a34a;
+        border-color: #16a34a;
+    }
+
+    .form-control:focus {
+        border-color: #86efac;
+        box-shadow: 0 0 0 0.2rem rgba(34, 197, 94, 0.25);
+    }
+
+    h1 {
+        color: #22c55e;
+        font-weight: 600;
+    }
+</style>
+
+<div class="row mt-5 d-flex justify-content-center">
+    <div class="col-md-6">
+        <h1>@ViewData["Title"]</h1>
+        <h4 class="mt-4">Complete your registration with @Model.ProviderDisplayName</h4>
+        <hr />
+
+        <p class="text-muted mb-4">
+            We need a bit more information to complete your registration.
+            Your email address has been verified by @Model.ProviderDisplayName.
+        </p>
+
+        <form asp-page-handler="Confirmation" asp-route-returnUrl="@Model.ReturnUrl" method="post">
+            <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
+
+            <div class="form-floating mb-3">
+                <input asp-for="Input.Email" class="form-control" placeholder="name@example.com" />
+                <label asp-for="Input.Email">Email</label>
+                <span asp-validation-for="Input.Email" class="text-danger"></span>
+            </div>
+
+            <div class="form-floating mb-3">
+                <input asp-for="Input.Username" class="form-control" placeholder="username" />
+                <label asp-for="Input.Username">Username</label>
+                <span asp-validation-for="Input.Username" class="text-danger"></span>
+                <small class="form-text text-muted">Choose a unique username for your account.</small>
+            </div>
+
+            <button type="submit" class="w-100 btn btn-lg btn-primary">Complete Registration</button>
+        </form>
+    </div>
+</div>
+
+@section Scripts {
+    <partial name="_ValidationScriptsPartial" />
+}
Index: NutriMatch/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Areas/Identity/Pages/Account/ExternalLogin.cshtml.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,292 @@
+#nullable disable
+using System.ComponentModel.DataAnnotations;
+using System.Security.Claims;
+using System.Text;
+using System.Text.Encodings.Web;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Identity.UI.Services;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.AspNetCore.WebUtilities;
+using NutriMatch.Models;
+
+namespace NutriMatch.Areas.Identity.Pages.Account
+{
+    [AllowAnonymous]
+    public class ExternalLoginModel : PageModel
+    {
+        private readonly SignInManager<User> _signInManager;
+        private readonly UserManager<User> _userManager;
+        private readonly IUserStore<User> _userStore;
+        private readonly IUserEmailStore<User> _emailStore;
+        private readonly IEmailSender _emailSender;
+        private readonly ILogger<ExternalLoginModel> _logger;
+
+        public ExternalLoginModel(
+            SignInManager<User> signInManager,
+            UserManager<User> userManager,
+            IUserStore<User> userStore,
+            IEmailSender emailSender,
+            ILogger<ExternalLoginModel> logger)
+        {
+            _signInManager = signInManager;
+            _userManager = userManager;
+            _userStore = userStore;
+            _emailStore = GetEmailStore();
+            _emailSender = emailSender;
+            _logger = logger;
+        }
+
+        [BindProperty]
+        public InputModel Input { get; set; }
+
+        public string ProviderDisplayName { get; set; }
+        public string ReturnUrl { get; set; }
+
+        [TempData]
+        public string ErrorMessage { get; set; }
+
+        public class InputModel
+        {
+            [Required]
+            [EmailAddress]
+            public string Email { get; set; }
+
+            [Required]
+            [StringLength(50, ErrorMessage = "The {0} must be at most {1} characters long.")]
+            [Display(Name = "Username")]
+            public string Username { get; set; }
+        }
+
+        public IActionResult OnGet() => RedirectToPage("./Login");
+
+        public IActionResult OnPost(string provider, string returnUrl = null)
+        {
+            var redirectUrl = Url.Page("./ExternalLogin", pageHandler: "Callback", values: new { returnUrl });
+            var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
+            return new ChallengeResult(provider, properties);
+        }
+
+        public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
+        {
+            returnUrl = returnUrl ?? Url.Content("~/");
+
+            if (remoteError != null)
+            {
+                ErrorMessage = $"Error from external provider: {remoteError}";
+                return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
+            }
+
+            var info = await _signInManager.GetExternalLoginInfoAsync();
+            if (info == null)
+            {
+                ErrorMessage = "Error loading external login information.";
+                return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
+            }
+
+            var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);
+
+            if (result.Succeeded)
+            {
+                var user = await _userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);
+                var currentEmail = info.Principal.FindFirstValue(ClaimTypes.Email);
+
+                if (!string.IsNullOrEmpty(currentEmail) && user.Email != currentEmail)
+                {
+                    _logger.LogInformation($"OAuth email changed from {user.Email} to {currentEmail}");
+                    user.Email = currentEmail;
+                    user.NormalizedEmail = currentEmail.ToUpper();
+                    user.EmailConfirmed = true;
+                    await _userManager.UpdateAsync(user);
+                }
+
+                _logger.LogInformation("{Name} logged in with {LoginProvider} provider.", info.Principal.Identity.Name, info.LoginProvider);
+                return LocalRedirect(returnUrl);
+            }
+
+            if (result.IsLockedOut)
+            {
+                return RedirectToPage("./Lockout");
+            }
+
+            var email = info.Principal.FindFirstValue(ClaimTypes.Email);
+
+            if (string.IsNullOrEmpty(email))
+            {
+                ProviderDisplayName = info.ProviderDisplayName;
+                ReturnUrl = returnUrl;
+                return Page();
+            }
+
+            var existingUser = await _userManager.FindByEmailAsync(email);
+
+            if (existingUser != null)
+            {
+
+                var hasPassword = await _userManager.HasPasswordAsync(existingUser);
+                var addLoginResult = await _userManager.AddLoginAsync(existingUser, info);
+                if (addLoginResult.Succeeded)
+                {
+                    await _signInManager.SignInAsync(existingUser, isPersistent: false);
+                    return LocalRedirect(returnUrl);
+                }
+
+
+                var existingLogins = await _userManager.GetLoginsAsync(existingUser);
+                var alreadyLinked = existingLogins.Any(l =>
+                    l.LoginProvider == info.LoginProvider &&
+                    l.ProviderKey == info.ProviderKey);
+
+                if (!alreadyLinked)
+                {
+                    _logger.LogInformation($"Linking {info.ProviderDisplayName} to existing account with email {email}");
+                    var addLoginRes = await _userManager.AddLoginAsync(existingUser, info);
+
+                    if (addLoginRes.Succeeded)
+                    {
+                        await _signInManager.SignInAsync(existingUser, isPersistent: false);
+                        return LocalRedirect(returnUrl);
+                    }
+
+                    foreach (var error in addLoginRes.Errors)
+                    {
+                        ModelState.AddModelError(string.Empty, error.Description);
+                    }
+                }
+            }
+            else
+            {
+                var username = email.Split('@')[0];
+                var uniqueUsername = username;
+                var counter = 1;
+
+                while (await _userManager.FindByNameAsync(uniqueUsername) != null)
+                {
+                    uniqueUsername = $"{username}{counter}";
+                    counter++;
+                }
+
+                var user = CreateUser();
+                user.ProfilePictureUrl = "/images/DefaultProfile.png";
+                user.EmailConfirmed = true;
+
+                await _userStore.SetUserNameAsync(user, uniqueUsername, CancellationToken.None);
+                await _emailStore.SetEmailAsync(user, email, CancellationToken.None);
+
+                var createResult = await _userManager.CreateAsync(user);
+
+                if (createResult.Succeeded)
+                {
+                    createResult = await _userManager.AddLoginAsync(user, info);
+
+                    if (createResult.Succeeded)
+                    {
+                        _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
+                        await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider);
+                        return LocalRedirect(returnUrl);
+                    }
+                }
+
+                foreach (var error in createResult.Errors)
+                {
+                    ModelState.AddModelError(string.Empty, error.Description);
+                }
+            }
+
+            ProviderDisplayName = info.ProviderDisplayName;
+            ReturnUrl = returnUrl;
+            if (!string.IsNullOrEmpty(email))
+            {
+                Input = new InputModel
+                {
+                    Email = email,
+                    Username = email.Split('@')[0]
+                };
+            }
+            return Page();
+        }
+
+        public async Task<IActionResult> OnPostConfirmationAsync(string returnUrl = null)
+        {
+            returnUrl = returnUrl ?? Url.Content("~/");
+
+            var info = await _signInManager.GetExternalLoginInfoAsync();
+            if (info == null)
+            {
+                ErrorMessage = "Error loading external login information during confirmation.";
+                return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
+            }
+
+            if (ModelState.IsValid)
+            {
+                var existingUserByEmail = await _userManager.FindByEmailAsync(Input.Email);
+                if (existingUserByEmail != null)
+                {
+                    ModelState.AddModelError(string.Empty, $"An account with {Input.Email} already exists. Please use a different email or login with your existing account.");
+                    ProviderDisplayName = info.ProviderDisplayName;
+                    ReturnUrl = returnUrl;
+                    return Page();
+                }
+
+                var existingUserByUsername = await _userManager.FindByNameAsync(Input.Username);
+                if (existingUserByUsername != null)
+                {
+                    ModelState.AddModelError(nameof(Input.Username), "This username is already taken. Please choose another.");
+                    ProviderDisplayName = info.ProviderDisplayName;
+                    ReturnUrl = returnUrl;
+                    return Page();
+                }
+
+                var user = CreateUser();
+                user.ProfilePictureUrl = "/images/DefaultProfile.png";
+                user.EmailConfirmed = true;
+
+                await _userStore.SetUserNameAsync(user, Input.Username, CancellationToken.None);
+                await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
+
+                var result = await _userManager.CreateAsync(user);
+                if (result.Succeeded)
+                {
+                    result = await _userManager.AddLoginAsync(user, info);
+                    if (result.Succeeded)
+                    {
+                        _logger.LogInformation("User created an account using {Name} provider.", info.LoginProvider);
+                        await _signInManager.SignInAsync(user, isPersistent: false, info.LoginProvider);
+                        return LocalRedirect(returnUrl);
+                    }
+                }
+
+                foreach (var error in result.Errors)
+                {
+                    ModelState.AddModelError(string.Empty, error.Description);
+                }
+            }
+
+            ProviderDisplayName = info.ProviderDisplayName;
+            ReturnUrl = returnUrl;
+            return Page();
+        }
+
+        private User CreateUser()
+        {
+            try
+            {
+                return Activator.CreateInstance<User>();
+            }
+            catch
+            {
+                throw new InvalidOperationException($"Can't create an instance of '{nameof(User)}'.");
+            }
+        }
+
+        private IUserEmailStore<User> GetEmailStore()
+        {
+            if (!_userManager.SupportsUserEmail)
+            {
+                throw new NotSupportedException("The default UI requires a user store with email support.");
+            }
+            return (IUserEmailStore<User>)_userStore;
+        }
+    }
+}
Index: NutriMatch/Areas/Identity/Pages/Account/Login.cshtml
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/Login.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Areas/Identity/Pages/Account/Login.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -9,23 +9,31 @@
         --bs-primary-rgb: 34, 197, 94;
     }
+
     .btn-primary {
         background-color: #22c55e;
         border-color: #22c55e;
     }
+
     .btn-primary:hover {
         background-color: #16a34a;
         border-color: #16a34a;
     }
-    .btn-primary:focus, .btn-primary.focus {
+
+    .btn-primary:focus,
+    .btn-primary.focus {
         box-shadow: 0 0 0 0.2rem rgba(34, 197, 94, 0.5);
     }
-    .btn-primary:active, .btn-primary.active {
+
+    .btn-primary:active,
+    .btn-primary.active {
         background-color: #15803d !important;
         border-color: #15803d !important;
     }
+
     .btn-outline-primary {
         color: #22c55e;
         border-color: #22c55e;
     }
+
     .btn-outline-primary:hover {
         background-color: #22c55e;
@@ -33,20 +41,27 @@
         color: white;
     }
-    .btn-outline-primary:focus, .btn-outline-primary.focus {
+
+    .btn-outline-primary:focus,
+    .btn-outline-primary.focus {
         box-shadow: 0 0 0 0.2rem rgba(34, 197, 94, 0.5);
     }
-    .btn-outline-primary:active, .btn-outline-primary.active {
+
+    .btn-outline-primary:active,
+    .btn-outline-primary.active {
         background-color: #15803d !important;
         border-color: #15803d !important;
         color: white !important;
     }
+
     .form-control:focus {
         border-color: #86efac;
         box-shadow: 0 0 0 0.2rem rgba(34, 197, 94, 0.25);
     }
+
     h1 {
         color: #22c55e;
         font-weight: 600;
     }
+
     .register-section {
         background-color: #f0fdf4;
@@ -58,16 +73,74 @@
         justify-content: center;
     }
+
     .register-section h3 {
         color: #16a34a;
         margin-bottom: 20px;
     }
+
     a {
         color: #22c55e;
     }
+
     a:hover {
         color: #16a34a;
     }
+
     #account {
         margin-top: 5rem;
+    }
+
+    .btn-google {
+        background-color: #fff;
+        border: 1px solid #dadce0;
+        color: #3c4043;
+        font-weight: 500;
+    }
+
+    .btn-google:hover {
+        background-color: #f8f9fa;
+        border-color: #dadce0;
+        color: #3c4043;
+    }
+
+    .btn-facebook {
+        background-color: #1877f2;
+        border: 1px solid #1877f2;
+        color: white;
+        font-weight: 500;
+    }
+
+    .btn-facebook:hover {
+        background-color: #166fe5;
+        border-color: #166fe5;
+        color: white;
+    }
+
+    .oauth-buttons {
+        margin-bottom: 1.5rem;
+    }
+
+    .oauth-divider {
+        display: flex;
+        align-items: center;
+        text-align: center;
+        margin: 1.5rem 0;
+    }
+
+    .oauth-divider::before,
+    .oauth-divider::after {
+        content: '';
+        flex: 1;
+        border-bottom: 1px solid #dee2e6;
+    }
+
+    .oauth-divider span {
+        padding: 0 1rem;
+        color: #6c757d;
+        font-size: 0.875rem;
+    }
+
+    section {
+        padding-top: 50px;
     }
 </style>
@@ -75,15 +148,70 @@
     <div class="col-md-4">
         <section>
+            <h2>Log in to your account.</h2>
+            <hr />
+
+            @if (Model.ExternalLogins?.Count > 0)
+            {
+                <div class="oauth-buttons">
+                    @foreach (var provider in Model.ExternalLogins)
+                    {
+                        if (provider.Name == "Google")
+                        {
+                            <form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post">
+                                <button type="submit" class="btn btn-google w-100 mb-2" name="provider" value="@provider.Name"
+                                    title="Log in using your @provider.DisplayName account">
+                                    <svg width="18" height="18" viewBox="0 0 18 18"
+                                        style="vertical-align: middle; margin-right: 8px;">
+                                        <path fill="#4285F4"
+                                            d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z">
+                                        </path>
+                                        <path fill="#34A853"
+                                            d="M9.003 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.258c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332C2.44 15.983 5.485 18 9.003 18z">
+                                        </path>
+                                        <path fill="#FBBC05"
+                                            d="M3.964 10.712c-.18-.54-.282-1.117-.282-1.71 0-.593.102-1.17.282-1.71V4.96H.957C.347 6.175 0 7.55 0 9.002c0 1.452.348 2.827.957 4.042l3.007-2.332z">
+                                        </path>
+                                        <path fill="#EA4335"
+                                            d="M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.428 0 9.002 0 5.485 0 2.44 2.017.96 4.958L3.967 7.29c.708-2.127 2.692-3.71 5.036-3.71z">
+                                        </path>
+                                    </svg>
+                                    Continue with Google
+                                </button>
+                            </form>
+                        }
+                        else if (provider.Name == "Facebook")
+                        {
+                            <form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post">
+                                <button type="submit" class="btn btn-facebook w-100 mb-2" name="provider" value="@provider.Name"
+                                    title="Log in using your @provider.DisplayName account">
+                                    <svg width="18" height="18" viewBox="0 0 24 24" fill="white"
+                                        style="vertical-align: middle; margin-right: 8px;">
+                                        <path
+                                            d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
+                                    </svg>
+                                    Continue with Facebook
+                                </button>
+                            </form>
+                        }
+                    }
+                </div>
+
+                <div class="oauth-divider">
+                    <span>OR</span>
+                </div>
+            }
+
             <form id="account" method="post">
-                <h2>Log in to your account.</h2>
-                <hr />
                 <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
+
                 <div class="form-floating mb-3">
-                    <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" />
-                    <label asp-for="Input.Email" class="form-label">Email</label>
-                    <span asp-validation-for="Input.Email" class="text-danger"></span>
+                    <input asp-for="Input.Username" class="form-control" autocomplete="username" aria-required="true"
+                        placeholder="name@example.com" />
+                    <label asp-for="Input.Username" class="form-label">Username</label>
+                    <span asp-validation-for="Input.Username" class="text-danger"></span>
                 </div>
                 <div class="form-floating mb-3">
-                    <input asp-for="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" />
+                    <input asp-for="Input.Password" class="form-control" autocomplete="current-password"
+                        aria-required="true" placeholder="password" />
                     <label asp-for="Input.Password" class="form-label">Password</label>
                     <span asp-validation-for="Input.Password" class="text-danger"></span>
@@ -104,5 +232,6 @@
             <h3>New here?</h3>
             <p class="mb-3">Create an account to get started with all our features.</p>
-            <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl" class="btn btn-outline-primary btn-lg">Create Account</a>
+            <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl"
+                class="btn btn-outline-primary btn-lg">Create Account</a>
         </section>
     </div>
Index: NutriMatch/Areas/Identity/Pages/Account/Login.cshtml.cs
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/Login.cshtml.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Areas/Identity/Pages/Account/Login.cshtml.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -27,6 +27,5 @@
         {
             [Required]
-            [EmailAddress]
-            public string Email { get; set; }
+            public string Username { get; set; }
             [Required]
             [DataType(DataType.Password)]
@@ -52,18 +51,9 @@
             if (ModelState.IsValid)
             {
-                var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
+                var result = await _signInManager.PasswordSignInAsync(Input.Username, Input.Password, Input.RememberMe, lockoutOnFailure: false);
                 if (result.Succeeded)
                 {
                     _logger.LogInformation("User logged in.");
                     return LocalRedirect(returnUrl);
-                }
-                if (result.RequiresTwoFactor)
-                {
-                    return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
-                }
-                if (result.IsLockedOut)
-                {
-                    _logger.LogWarning("User account locked out.");
-                    return RedirectToPage("./Lockout");
                 }
                 else
Index: NutriMatch/Areas/Identity/Pages/Account/MyAccount.cshtml
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/MyAccount.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Areas/Identity/Pages/Account/MyAccount.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -50,4 +50,9 @@
         color: #166534;
     }
+    .alert-info {
+        background-color: #e0f2fe;
+        border-color: #bae6fd;
+        color: #075985;
+    }
     .profile-picture-section {
         text-align: center;
@@ -84,19 +89,286 @@
         margin-top: 8rem;
     }
+    
+    .notification-preference-item {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding: 15px;
+        background-color: white;
+        border-radius: 8px;
+        margin-bottom: 12px;
+        border: 1px solid #d1fae5;
+        transition: all 0.3s ease;
+    }
+    
+    .notification-preference-item:hover {
+        box-shadow: 0 2px 8px rgba(34, 197, 94, 0.1);
+        border-color: #86efac;
+    }
+    
+    .notification-preference-info {
+        display: flex;
+        align-items: center;
+        gap: 15px;
+    }
+    
+    .notification-icon-circle {
+        min-width: 40px;
+        width: 40px;
+        height: 40px;
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 18px;
+        flex-shrink: 0;
+    }
+    
+    .notification-icon-circle.recipe-rated {
+        background-color: #fff3cd;
+        color: #ffc107;
+    }
+    
+    .notification-icon-circle.recipe-accepted {
+        background-color: #d1f2eb;
+        color: #4caf50;
+    }
+    
+    .notification-icon-circle.recipe-declined {
+        background-color: #f8d7da;
+        color: #f44336;
+    }
+    
+    .notification-icon-circle.restaurant-meal {
+        background-color: #ffe5e5;
+        color: #ff6b6b;
+    }
+    
+    .notification-icon-circle.tags-match {
+        background-color: #d5f4f1;
+        color: #4ecdc4;
+    }
+    
+    .notification-icon-circle.new-restaurant {
+        background-color: #cfe2ff;
+        color: #007bff;
+    }
+    
+    .notification-icon-circle.meal-plan {
+        background-color: #e1d5f0;
+        color: #9c27b0;
+    }
+    
+    .notification-text {
+        flex: 1;
+    }
+    
+    .notification-title {
+        font-weight: 600;
+        color: #166534;
+        margin-bottom: 3px;
+    }
+    
+    .notification-description {
+        font-size: 0.875rem;
+        color: #6b7280;
+    }
+    
+    .custom-switch {
+        position: relative;
+        display: inline-block;
+        width: 50px;
+        height: 26px;
+        flex-shrink: 0;
+    }
+    
+    .custom-switch input {
+        opacity: 0;
+        width: 0;
+        height: 0;
+    }
+    
+    .slider {
+        position: absolute;
+        cursor: pointer;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        background-color: #cbd5e0;
+        transition: 0.3s;
+        border-radius: 34px;
+    }
+    
+    .slider:before {
+        position: absolute;
+        content: "";
+        height: 20px;
+        width: 20px;
+        left: 3px;
+        bottom: 3px;
+        background-color: white;
+        transition: 0.3s;
+        border-radius: 50%;
+    }
+    
+    input:checked + .slider {
+        background-color: #22c55e;
+    }
+    
+    input:checked + .slider:before {
+        transform: translateX(24px);
+    }
+    
+    .notification-section-header {
+        background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
+        color: white;
+        padding: 15px 20px;
+        border-radius: 8px;
+        margin-bottom: 20px;
+    }
+    
+    .notification-section-header h3 {
+        color: white;
+        margin: 0;
+        border: none;
+        padding: 0;
+    }
+    
+    .notification-section-header p {
+        margin: 5px 0 0 0;
+        font-size: 0.9rem;
+        opacity: 0.9;
+    }
+
+    .toast-container {
+        position: fixed;
+        top: 20px;
+        right: 20px;
+        z-index: 9999;
+    }
+
+    .custom-toast {
+        min-width: 300px;
+        background-color: #22c55e;
+        color: white;
+        border-radius: 8px;
+        padding: 16px 20px;
+        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        animation: slideInRight 0.3s ease-out;
+        margin-bottom: 10px;
+    }
+
+    .custom-toast.toast-hide {
+        animation: slideOutRight 0.3s ease-out;
+    }
+
+    .custom-toast-icon {
+        font-size: 24px;
+        flex-shrink: 0;
+    }
+
+    .custom-toast-content {
+        flex: 1;
+    }
+
+    .custom-toast-title {
+        font-weight: 600;
+        margin-bottom: 4px;
+    }
+
+    .custom-toast-message {
+        font-size: 0.875rem;
+        opacity: 0.95;
+    }
+
+    .custom-toast-close {
+        background: none;
+        border: none;
+        color: white;
+        font-size: 20px;
+        cursor: pointer;
+        padding: 0;
+        width: 24px;
+        height: 24px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        opacity: 0.8;
+        transition: opacity 0.2s;
+        flex-shrink: 0;
+    }
+
+    .custom-toast-close:hover {
+        opacity: 1;
+    }
+
+    @@keyframes slideInRight {
+        from {
+            transform: translateX(400px);
+            opacity: 0;
+        }
+        to {
+            transform: translateX(0);
+            opacity: 1;
+        }
+    }
+
+    @@keyframes slideOutRight {
+        from {
+            transform: translateX(0);
+            opacity: 1;
+        }
+        to {
+            transform: translateX(400px);
+            opacity: 0;
+        }
+    }
 </style>
+
 <div id="whole-container" class="container">
-    @if (!string.IsNullOrEmpty(Model.StatusMessage))
-    {
-        <div class="alert alert-success alert-dismissible fade show" role="alert">
-            @Model.StatusMessage
-            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
-        </div>
-    }
+    <div class="toast-container" id="toastContainer"></div>
+
     <div class="row">
         <div class="col-md-3">
             <div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
-                <button class="nav-link @(Model.ActiveTab != "Password" ? "active" : "")" id="v-pills-profile-tab" data-bs-toggle="pill" data-bs-target="#v-pills-profile" type="button" role="tab" aria-controls="v-pills-profile" aria-selected="true">Profile</button>
-                <button class="nav-link @(Model.ActiveTab == "Password" ? "active" : "")" id="v-pills-security-tab" data-bs-toggle="pill" data-bs-target="#v-pills-security" type="button" role="tab" aria-controls="v-pills-security" aria-selected="false">Password</button>
+                <button class="nav-link @(Model.ActiveTab != "Password" && Model.ActiveTab != "Notifications" ? "active" : "")" 
+                        id="v-pills-profile-tab" 
+                        data-bs-toggle="pill" 
+                        data-bs-target="#v-pills-profile" 
+                        type="button" 
+                        role="tab" 
+                        aria-controls="v-pills-profile" 
+                        aria-selected="true">
+                    <i class="fas fa-user me-2"></i>Profile
+                </button>
+                
+                <button class="nav-link @(Model.ActiveTab == "Password" ? "active" : "")" 
+                        id="v-pills-security-tab" 
+                        data-bs-toggle="pill" 
+                        data-bs-target="#v-pills-security" 
+                        type="button" 
+                        role="tab" 
+                        aria-controls="v-pills-security" 
+                        aria-selected="false">
+                    <i class="fas fa-lock me-2"></i>Password
+                </button>
+                
+                <button class="nav-link @(Model.ActiveTab == "Notifications" ? "active" : "")" 
+                        id="v-pills-notifications-tab" 
+                        data-bs-toggle="pill" 
+                        data-bs-target="#v-pills-notifications" 
+                        type="button" 
+                        role="tab" 
+                        aria-controls="v-pills-notifications" 
+                        aria-selected="false">
+                    <i class="fas fa-bell me-2"></i>Notifications
+                </button>
+                
                 <hr class="my-3">
+                
                 <form method="post" asp-page-handler="Logout" class="d-inline">
                     <button type="submit" class="nav-link text-danger border-0 bg-transparent w-100 text-start">
@@ -106,11 +378,17 @@
             </div>
         </div>
+
         <div class="col-md-9">
             <div class="tab-content" id="v-pills-tabContent">
-                <div class="tab-pane fade @(Model.ActiveTab != "Password" ? "show active" : "")" id="v-pills-profile" role="tabpanel" aria-labelledby="v-pills-profile-tab">
+                
+                <div class="tab-pane fade @(Model.ActiveTab != "Password" && Model.ActiveTab != "Notifications" ? "show active" : "")" 
+                     id="v-pills-profile" 
+                     role="tabpanel" 
+                     aria-labelledby="v-pills-profile-tab">
                     <div class="account-section">
                         <form method="post" asp-page-handler="UpdateProfile" enctype="multipart/form-data">
                             <h3>Profile Information</h3>
                             <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
+                            
                             <div class="profile-picture-section">
                                 <img src="@Model.ProfilePictureUrl" alt="Profile Picture" class="profile-picture" id="profilePreview" />
@@ -121,4 +399,5 @@
                                 </div>
                             </div>
+
                             <div class="form-floating mb-3">
                                 <input asp-for="ProfileInput.UserName" class="form-control" placeholder="Username" />
@@ -126,4 +405,5 @@
                                 <span asp-validation-for="ProfileInput.UserName" class="text-danger"></span>
                             </div>
+
                             <div class="form-floating mb-3">
                                 <input asp-for="ProfileInput.Email" class="form-control" placeholder="Email" />
@@ -131,31 +411,204 @@
                                 <span asp-validation-for="ProfileInput.Email" class="text-danger"></span>
                             </div>
-                            <button type="submit" class="btn btn-primary">Update Profile</button>
+
+                            <button type="submit" class="btn btn-primary">
+                                <i class="fas fa-save me-2"></i>Update Profile
+                            </button>
                             @Html.AntiForgeryToken()
                         </form>
                     </div>
                 </div>
-                <div class="tab-pane fade @(Model.ActiveTab == "Password" ? "show active" : "")" id="v-pills-security" role="tabpanel" aria-labelledby="v-pills-security-tab">
+
+                <div class="tab-pane fade @(Model.ActiveTab == "Password" ? "show active" : "")" 
+                     id="v-pills-security" 
+                     role="tabpanel" 
+                     aria-labelledby="v-pills-security-tab">
                     <div class="account-section">
                         <form method="post" asp-page-handler="ChangePassword">
-                            <h3>Change Password</h3>
-                            <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
-                            <div class="form-floating mb-3">
-                                <input asp-for="PasswordInput.CurrentPassword" type="password" class="form-control" placeholder="Current Password" />
-                                <label asp-for="PasswordInput.CurrentPassword" class="form-label">Current Password</label>
-                                <span asp-validation-for="PasswordInput.CurrentPassword" class="text-danger"></span>
-                            </div>
+                            @if (Model.HasPassword)
+                            {
+                                <h3>Change Password</h3>
+                                <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
+                                <div class="form-floating mb-3">
+                                    <input asp-for="PasswordInput.CurrentPassword" type="password" class="form-control" placeholder="Current Password" />
+                                    <label asp-for="PasswordInput.CurrentPassword" class="form-label">Current Password</label>
+                                    <span asp-validation-for="PasswordInput.CurrentPassword" class="text-danger"></span>
+                                </div>
+                            }
+                            else
+                            {
+                                <h3>Set Password</h3>
+                                <div class="alert alert-info" role="alert">
+                                    <i class="fas fa-info-circle me-2"></i>
+                                    You signed in using an external provider (like Google). Set a password to enable direct login with your email and password.
+                                </div>
+                                <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
+                            }
+                            
                             <div class="form-floating mb-3">
                                 <input asp-for="PasswordInput.NewPassword" type="password" class="form-control" placeholder="New Password" />
-                                <label asp-for="PasswordInput.NewPassword" class="form-label">New Password</label>
+                                <label asp-for="PasswordInput.NewPassword" class="form-label">@(Model.HasPassword ? "New Password" : "Password")</label>
                                 <span asp-validation-for="PasswordInput.NewPassword" class="text-danger"></span>
                             </div>
+                            
                             <div class="form-floating mb-3">
                                 <input asp-for="PasswordInput.ConfirmPassword" type="password" class="form-control" placeholder="Confirm New Password" />
-                                <label asp-for="PasswordInput.ConfirmPassword" class="form-label">Confirm New Password</label>
+                                <label asp-for="PasswordInput.ConfirmPassword" class="form-label">@(Model.HasPassword ? "Confirm New Password" : "Confirm Password")</label>
                                 <span asp-validation-for="PasswordInput.ConfirmPassword" class="text-danger"></span>
                             </div>
-                            <button type="submit" class="btn btn-primary">Change Password</button>
+                            
+                            <button type="submit" class="btn btn-primary">
+                                <i class="fas fa-lock me-2"></i>@(Model.HasPassword ? "Change Password" : "Set Password")
+                            </button>
                             <input name="__RequestVerificationToken" type="hidden" value="@Html.AntiForgeryToken().ToString()" />
+                        </form>
+                    </div>
+                </div>
+
+                <div class="tab-pane fade @(Model.ActiveTab == "Notifications" ? "show active" : "")" 
+                     id="v-pills-notifications" 
+                     role="tabpanel" 
+                     aria-labelledby="v-pills-notifications-tab">
+                    <div class="account-section">
+                        <form method="post" asp-page-handler="UpdateNotificationPreferences">
+                            
+                            <h3>User Preferences</h3>
+                            
+                            <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle recipe-rated">
+                                        <i class="fas fa-star"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">Recipe Rated</div>
+                                        <div class="notification-description">Get notified when someone rates your recipe</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyRecipeRated" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle recipe-accepted">
+                                        <i class="fas fa-check-circle"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">Recipe Accepted</div>
+                                        <div class="notification-description">Get notified when your recipe is accepted by admin</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyRecipeAccepted" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle recipe-declined">
+                                        <i class="fas fa-times-circle"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">Recipe Declined</div>
+                                        <div class="notification-description">Get notified when your recipe is declined by admin</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyRecipeDeclined" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle restaurant-meal">
+                                        <i class="fas fa-utensils"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">Restaurant New Meal</div>
+                                        <div class="notification-description">Get notified about new meals from restaurants you follow</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyRestaurantNewMeal" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle tags-match">
+                                        <i class="fas fa-tags"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">Meal Matches Tags</div>
+                                        <div class="notification-description">Get notified when new meals match your dietary preferences</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyMealMatchesTags" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle tags-match">
+                                        <i class="fas fa-tags"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">Recipe Matches Tags</div>
+                                        <div class="notification-description">Get notified when new recipes match your dietary preferences</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyRecipeMatchesTags" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle new-restaurant">
+                                        <i class="fas fa-store"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">New Restaurant</div>
+                                        <div class="notification-description">Get notified when new restaurants are added to the platform</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyNewRestaurant" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <div class="notification-preference-item">
+                                <div class="notification-preference-info">
+                                    <div class="notification-icon-circle meal-plan">
+                                        <i class="fas fa-calendar-check"></i>
+                                    </div>
+                                    <div class="notification-text">
+                                        <div class="notification-title">Meal Plan Updated</div>
+                                        <div class="notification-description">Get notified about updates to your meal plans</div>
+                                    </div>
+                                </div>
+                                <label class="custom-switch">
+                                    <input asp-for="NotificationPreferences.NotifyMealPlanUpdated" type="checkbox" />
+                                    <span class="slider"></span>
+                                </label>
+                            </div>
+
+                            <input type="hidden" name="ActiveTab" value="Notifications" />
+
+                            <button type="submit" class="btn btn-primary mt-3">
+                                <i class="fas fa-save me-2"></i>Save Preferences
+                            </button>
+                            @Html.AntiForgeryToken()
                         </form>
                     </div>
@@ -165,4 +618,5 @@
     </div>
 </div>
+
 <script>
     function previewImage(input) {
@@ -175,5 +629,48 @@
         }
     }
+
+    function showToast(title, message, duration = 4000) {
+        const toastContainer = document.getElementById('toastContainer');
+        
+        const toast = document.createElement('div');
+        toast.className = 'custom-toast';
+        toast.innerHTML = `
+            <div class="custom-toast-icon">
+                <i class="fas fa-check-circle"></i>
+            </div>
+            <div class="custom-toast-content">
+                <div class="custom-toast-title">${title}</div>
+                <div class="custom-toast-message">${message}</div>
+            </div>
+            <button class="custom-toast-close" onclick="closeToast(this)">
+                <i class="fas fa-times"></i>
+            </button>
+        `;
+        
+        toastContainer.appendChild(toast);
+        
+        setTimeout(() => {
+            closeToast(toast.querySelector('.custom-toast-close'));
+        }, duration);
+    }
+
+    function closeToast(button) {
+        const toast = button.closest('.custom-toast');
+        toast.classList.add('toast-hide');
+        setTimeout(() => {
+            toast.remove();
+        }, 300);
+    }
+
+    document.addEventListener('DOMContentLoaded', function() {
+        @if (!string.IsNullOrEmpty(Model.StatusMessage))
+        {
+            <text>
+            showToast('Success', '@Model.StatusMessage');
+            </text>
+        }
+    });
 </script>
+
 @section Scripts {
     <partial name="_ValidationScriptsPartial" />
Index: NutriMatch/Areas/Identity/Pages/Account/MyAccount.cshtml.cs
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/MyAccount.cshtml.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Areas/Identity/Pages/Account/MyAccount.cshtml.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -1,3 +1,2 @@
-
 #nullable disable
 using System.ComponentModel.DataAnnotations;
@@ -7,4 +6,5 @@
 using Microsoft.AspNetCore.Mvc.RazorPages;
 using NutriMatch.Models;
+
 namespace NutriMatch.Areas.Identity.Pages.Account
 {
@@ -16,4 +16,5 @@
         private readonly ILogger<AccountModel> _logger;
         private readonly IWebHostEnvironment _webHostEnvironment;
+
         public AccountModel(
             UserManager<User> userManager,
@@ -27,13 +28,24 @@
             _webHostEnvironment = webHostEnvironment;
         }
+
         [BindProperty]
         public ProfileInputModel ProfileInput { get; set; }
+
         [BindProperty]
         public PasswordInputModel PasswordInput { get; set; }
+
+        [BindProperty]
+        public NotificationPreferencesModel NotificationPreferences { get; set; }
+
         [BindProperty]
         public string ActiveTab { get; set; }
+
         [TempData]
         public string StatusMessage { get; set; }
+
         public string ProfilePictureUrl { get; set; }
+
+        public bool HasPassword { get; set; }
+
         public class ProfileInputModel
         {
@@ -42,16 +54,19 @@
             [Display(Name = "Email")]
             public string Email { get; set; }
+
             [Required]
             [Display(Name = "Username")]
             public string UserName { get; set; }
+
             [Display(Name = "Profile Picture")]
             public IFormFile ProfilePicture { get; set; }
         }
+
         public class PasswordInputModel
         {
-            [Required]
             [DataType(DataType.Password)]
             [Display(Name = "Current Password")]
             public string CurrentPassword { get; set; }
+
             [Required]
             [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at most {1} characters long.", MinimumLength = 6)]
@@ -59,4 +74,5 @@
             [Display(Name = "New Password")]
             public string NewPassword { get; set; }
+
             [DataType(DataType.Password)]
             [Display(Name = "Confirm New Password")]
@@ -64,4 +80,32 @@
             public string ConfirmPassword { get; set; }
         }
+
+        public class NotificationPreferencesModel
+        {
+            [Display(Name = "Recipe Rated")]
+            public bool NotifyRecipeRated { get; set; }
+
+            [Display(Name = "Recipe Accepted")]
+            public bool NotifyRecipeAccepted { get; set; }
+
+            [Display(Name = "Recipe Declined")]
+            public bool NotifyRecipeDeclined { get; set; }
+
+            [Display(Name = "Restaurant New Meal")]
+            public bool NotifyRestaurantNewMeal { get; set; }
+
+            [Display(Name = "Meal Matches Tags")]
+            public bool NotifyMealMatchesTags { get; set; }
+
+            [Display(Name = "Recipe Matches Tags")]
+            public bool NotifyRecipeMatchesTags { get; set; }
+
+            [Display(Name = "New Restaurant")]
+            public bool NotifyNewRestaurant { get; set; }
+
+            [Display(Name = "Meal Plan Updated")]
+            public bool NotifyMealPlanUpdated { get; set; }
+        }
+
         public async Task<IActionResult> OnGetAsync()
         {
@@ -71,7 +115,23 @@
                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
             }
+
+            if (!string.IsNullOrEmpty(Request.Query["activeTab"]))
+            {
+                ActiveTab = Request.Query["activeTab"];
+            }
+            else if (TempData["ActiveTab"] is string activeTab)
+            {
+                ActiveTab = activeTab;
+                TempData.Remove("ActiveTab");
+            }
+            else
+            {
+                ActiveTab = "Account";
+            }
+
             await LoadUserData(user);
             return Page();
         }
+
         public async Task<IActionResult> OnPostUpdateProfileAsync()
         {
@@ -81,6 +141,7 @@
                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
             }
-            var userT = await _userManager.GetUserAsync(User);
+
             bool hasChanges = false;
+
             if (ProfileInput.Email != user.Email)
             {
@@ -92,4 +153,5 @@
                     return Page();
                 }
+
                 user.Email = ProfileInput.Email;
                 user.NormalizedEmail = _userManager.NormalizeEmail(ProfileInput.Email);
@@ -97,4 +159,5 @@
                 hasChanges = true;
             }
+
             if (ProfileInput.UserName != user.UserName)
             {
@@ -106,8 +169,10 @@
                     return Page();
                 }
+
                 user.UserName = ProfileInput.UserName;
                 user.NormalizedUserName = _userManager.NormalizeName(ProfileInput.UserName);
                 hasChanges = true;
             }
+
             if (ProfileInput.ProfilePicture != null)
             {
@@ -121,4 +186,5 @@
                 hasChanges = true;
             }
+
             if (hasChanges)
             {
@@ -133,24 +199,18 @@
                     return Page();
                 }
+
                 await _signInManager.RefreshSignInAsync(user);
                 StatusMessage = "Your profile has been updated successfully.";
                 _logger.LogInformation("User {UserId} updated profile. New Email: {Email}, New UserName: {UserName}",
                     user.Id, user.Email, user.UserName);
-                if (!updateResult.Succeeded)
-                {
-                    foreach (var error in updateResult.Errors)
-                    {
-                        _logger.LogError("Update failed: {Error}", error.Description);
-                        ModelState.AddModelError(string.Empty, error.Description);
-                    }
-                }
             }
             else
             {
-                _logger.LogInformation("Change failed");
                 StatusMessage = "No changes were made to your profile.";
             }
+
             return RedirectToPage();
         }
+
         public async Task<IActionResult> OnPostChangePasswordAsync()
         {
@@ -160,21 +220,85 @@
                 return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
             }
-            var changePasswordResult = await _userManager.ChangePasswordAsync(user, PasswordInput.CurrentPassword, PasswordInput.NewPassword);
-            if (!changePasswordResult.Succeeded)
-            {
-                foreach (var error in changePasswordResult.Errors)
-                {
-                    ModelState.AddModelError($"{nameof(PasswordInput)}.{nameof(PasswordInput.CurrentPassword)}", error.Description);
-                }
-                ActiveTab = "Password";
+
+            HasPassword = await _userManager.HasPasswordAsync(user);
+
+            if (HasPassword)
+            {
+                var changePasswordResult = await _userManager.ChangePasswordAsync(user, PasswordInput.CurrentPassword, PasswordInput.NewPassword);
+                if (!changePasswordResult.Succeeded)
+                {
+                    foreach (var error in changePasswordResult.Errors)
+                    {
+                        ModelState.AddModelError($"{nameof(PasswordInput)}.{nameof(PasswordInput.CurrentPassword)}", error.Description);
+                    }
+                    ActiveTab = "Password";
+                    await LoadUserData(user);
+                    return Page();
+                }
+
+                await _signInManager.RefreshSignInAsync(user);
+                _logger.LogInformation("User changed their password successfully.");
+                StatusMessage = "Your password has been changed successfully.";
+            }
+            else
+            {
+                var addPasswordResult = await _userManager.AddPasswordAsync(user, PasswordInput.NewPassword);
+                if (!addPasswordResult.Succeeded)
+                {
+                    foreach (var error in addPasswordResult.Errors)
+                    {
+                        ModelState.AddModelError($"{nameof(PasswordInput)}.{nameof(PasswordInput.NewPassword)}", error.Description);
+                    }
+                    ActiveTab = "Password";
+                    await LoadUserData(user);
+                    return Page();
+                }
+
+                await _signInManager.RefreshSignInAsync(user);
+                _logger.LogInformation("User set a password successfully.");
+                StatusMessage = "Your password has been set successfully.";
+            }
+
+            PasswordInput = new PasswordInputModel();
+            return RedirectToPage();
+        }
+
+        public async Task<IActionResult> OnPostUpdateNotificationPreferencesAsync()
+        {
+            var user = await _userManager.GetUserAsync(User);
+            if (user == null)
+            {
+                return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
+            }
+
+            user.NotifyRecipeRated = NotificationPreferences.NotifyRecipeRated;
+            user.NotifyRecipeAccepted = NotificationPreferences.NotifyRecipeAccepted;
+            user.NotifyRecipeDeclined = NotificationPreferences.NotifyRecipeDeclined;
+            user.NotifyRestaurantNewMeal = NotificationPreferences.NotifyRestaurantNewMeal;
+            user.NotifyMealMatchesTags = NotificationPreferences.NotifyMealMatchesTags;
+            user.NotifyRecipeMatchesTags = NotificationPreferences.NotifyRecipeMatchesTags;
+            user.NotifyNewRestaurant = NotificationPreferences.NotifyNewRestaurant;
+            user.NotifyMealPlanUpdated = NotificationPreferences.NotifyMealPlanUpdated;
+
+            var updateResult = await _userManager.UpdateAsync(user);
+            if (!updateResult.Succeeded)
+            {
+                foreach (var error in updateResult.Errors)
+                {
+                    ModelState.AddModelError(string.Empty, error.Description);
+                }
+                ActiveTab = "Notifications";
                 await LoadUserData(user);
                 return Page();
             }
+
             await _signInManager.RefreshSignInAsync(user);
-            _logger.LogInformation("User changed their password successfully.");
-            StatusMessage = "Your password has been changed successfully.";
-            PasswordInput = new PasswordInputModel();
+            _logger.LogInformation("User {UserId} updated notification preferences.", user.Id);
+            StatusMessage = "Your notification preferences have been updated successfully.";
+
+            TempData["ActiveTab"] = "Notifications";
             return RedirectToPage();
         }
+
         public async Task<IActionResult> OnPostLogoutAsync()
         {
@@ -183,4 +307,5 @@
             return RedirectToPage("/Index");
         }
+
         private async Task LoadUserData(User user)
         {
@@ -190,8 +315,24 @@
                 UserName = user.UserName
             };
+
+            NotificationPreferences = new NotificationPreferencesModel
+            {
+                NotifyRecipeRated = user.NotifyRecipeRated,
+                NotifyRecipeAccepted = user.NotifyRecipeAccepted,
+                NotifyRecipeDeclined = user.NotifyRecipeDeclined,
+                NotifyRestaurantNewMeal = user.NotifyRestaurantNewMeal,
+                NotifyMealMatchesTags = user.NotifyMealMatchesTags,
+                NotifyRecipeMatchesTags = user.NotifyRecipeMatchesTags,
+                NotifyNewRestaurant = user.NotifyNewRestaurant,
+                NotifyMealPlanUpdated = user.NotifyMealPlanUpdated
+            };
+
             ProfilePictureUrl = !string.IsNullOrEmpty(user.ProfilePictureUrl)
                 ? user.ProfilePictureUrl
                 : GetProfilePictureUrl(user.Id);
-        }
+
+            HasPassword = await _userManager.HasPasswordAsync(user);
+        }
+
         private async Task<(bool Success, string ErrorMessage)> SaveProfilePictureAsync(IFormFile file, string userId)
         {
@@ -202,19 +343,26 @@
                     return (false, "Profile picture must be smaller than 5MB.");
                 }
+
                 var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif" };
                 var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
+
                 if (!allowedExtensions.Contains(fileExtension))
                 {
                     return (false, "Please upload a valid image file (JPG, PNG, or GIF).");
                 }
+
                 var uploadsDir = Path.Combine(_webHostEnvironment.WebRootPath, "images");
                 Directory.CreateDirectory(uploadsDir);
+
                 await DeleteProfilePictureAsync(userId);
+
                 var fileName = $"{userId}_{Guid.NewGuid()}{fileExtension}";
                 var filePath = Path.Combine(uploadsDir, fileName);
+
                 using (var stream = new FileStream(filePath, FileMode.Create))
                 {
                     await file.CopyToAsync(stream);
                 }
+
                 var user = await _userManager.FindByIdAsync(userId);
                 if (user != null)
@@ -223,4 +371,5 @@
                     await _userManager.UpdateAsync(user);
                 }
+
                 return (true, null);
             }
@@ -231,4 +380,5 @@
             }
         }
+
         private async Task DeleteProfilePictureAsync(string userId)
         {
@@ -250,4 +400,5 @@
             }
         }
+
         private string GetProfilePictureUrl(string userId)
         {
@@ -269,4 +420,5 @@
                 _logger.LogError(ex, "Error getting profile picture URL for user {UserId}", userId);
             }
+
             return "https://via.placeholder.com/120x120/22c55e/ffffff?text=User";
         }
Index: NutriMatch/Areas/Identity/Pages/Account/Register.cshtml
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/Register.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Areas/Identity/Pages/Account/Register.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -10,29 +10,31 @@
         --bs-primary-rgb: 34, 197, 94;
     }
-    
+
     .btn-primary {
         background-color: #22c55e;
         border-color: #22c55e;
     }
-    
+
     .btn-primary:hover {
         background-color: #16a34a;
         border-color: #16a34a;
     }
-    
-    .btn-primary:focus, .btn-primary.focus {
+
+    .btn-primary:focus,
+    .btn-primary.focus {
         box-shadow: 0 0 0 0.2rem rgba(34, 197, 94, 0.5);
     }
-    
-    .btn-primary:active, .btn-primary.active {
+
+    .btn-primary:active,
+    .btn-primary.active {
         background-color: #15803d !important;
         border-color: #15803d !important;
     }
-    
+
     .btn-outline-primary {
         color: #22c55e;
         border-color: #22c55e;
     }
-    
+
     .btn-outline-primary:hover {
         background-color: #22c55e;
@@ -40,25 +42,27 @@
         color: white;
     }
-    
-    .btn-outline-primary:focus, .btn-outline-primary.focus {
+
+    .btn-outline-primary:focus,
+    .btn-outline-primary.focus {
         box-shadow: 0 0 0 0.2rem rgba(34, 197, 94, 0.5);
     }
-    
-    .btn-outline-primary:active, .btn-outline-primary.active {
+
+    .btn-outline-primary:active,
+    .btn-outline-primary.active {
         background-color: #15803d !important;
         border-color: #15803d !important;
         color: white !important;
     }
-    
+
     .form-control:focus {
         border-color: #86efac;
         box-shadow: 0 0 0 0.2rem rgba(34, 197, 94, 0.25);
     }
-    
+
     h1 {
         color: #22c55e;
         font-weight: 600;
     }
-    
+
     .login-section {
         background-color: #f0fdf4;
@@ -70,5 +74,5 @@
         justify-content: center;
     }
-    
+
     .login-section h3 {
         color: #16a34a;
@@ -79,34 +83,147 @@
         margin-top: 5rem;
     }
+
+    .btn-google {
+        background-color: #fff;
+        border: 1px solid #dadce0;
+        color: #3c4043;
+        font-weight: 500;
+    }
+
+    .btn-google:hover {
+        background-color: #f8f9fa;
+        border-color: #dadce0;
+        color: #3c4043;
+    }
+
+    .btn-facebook {
+        background-color: #1877f2;
+        border: 1px solid #1877f2;
+        color: white;
+        font-weight: 500;
+    }
+
+    .btn-facebook:hover {
+        background-color: #166fe5;
+        border-color: #166fe5;
+        color: white;
+    }
+
+    .oauth-buttons {
+        margin-bottom: 1.5rem;
+    }
+
+    .oauth-divider {
+        display: flex;
+        align-items: center;
+        text-align: center;
+        margin: 1.5rem 0;
+    }
+
+    .oauth-divider::before,
+    .oauth-divider::after {
+        content: '';
+        flex: 1;
+        border-bottom: 1px solid #dee2e6;
+    }
+
+    .oauth-divider span {
+        padding: 0 1rem;
+        color: #6c757d;
+        font-size: 0.875rem;
+    }
+
+    section {
+        padding-top: 50px;
+    }
 </style>
 
-<div class="row mt-5 mb-5 flex justify-content-center al">
+<div class="row mt-5 mb-5 flex justify-content-center">
     <div class="col-md-4">
-        <form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
+        <section>
             <h2>Create a new account.</h2>
             <hr />
-            <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
-            <div class="form-floating mb-3">
-                <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" />
-                <label asp-for="Input.Email">Email</label>
-                <span asp-validation-for="Input.Email" class="text-danger"></span>
-            </div>
-            <div class="form-floating mb-3">
-                <input asp-for="Input.Username" class="form-control" autocomplete="username" aria-required="true" placeholder="username" />
-                <label asp-for="Input.Username">Username</label>
-                <span asp-validation-for="Input.Username" class="text-danger"></span>
-            </div>
-            <div class="form-floating mb-3">
-                <input asp-for="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
-                <label asp-for="Input.Password">Password</label>
-                <span asp-validation-for="Input.Password" class="text-danger"></span>
-            </div>
-            <div class="form-floating mb-3">
-                <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
-                <label asp-for="Input.ConfirmPassword">Confirm Password</label>
-                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
-            </div>
-            <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
-        </form>
+
+            @if (Model.ExternalLogins?.Count > 0)
+            {
+                <div class="oauth-buttons">
+                    @foreach (var provider in Model.ExternalLogins)
+                    {
+                        if (provider.Name == "Google")
+                        {
+                            <form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post">
+                                <button type="submit" class="btn btn-google w-100 mb-2" name="provider" value="@provider.Name"
+                                    title="Sign up using your @provider.DisplayName account">
+                                    <svg width="18" height="18" viewBox="0 0 18 18"
+                                        style="vertical-align: middle; margin-right: 8px;">
+                                        <path fill="#4285F4"
+                                            d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z">
+                                        </path>
+                                        <path fill="#34A853"
+                                            d="M9.003 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.258c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332C2.44 15.983 5.485 18 9.003 18z">
+                                        </path>
+                                        <path fill="#FBBC05"
+                                            d="M3.964 10.712c-.18-.54-.282-1.117-.282-1.71 0-.593.102-1.17.282-1.71V4.96H.957C.347 6.175 0 7.55 0 9.002c0 1.452.348 2.827.957 4.042l3.007-2.332z">
+                                        </path>
+                                        <path fill="#EA4335"
+                                            d="M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.428 0 9.002 0 5.485 0 2.44 2.017.96 4.958L3.967 7.29c.708-2.127 2.692-3.71 5.036-3.71z">
+                                        </path>
+                                    </svg>
+                                    Sign up with Google
+                                </button>
+                            </form>
+                        }
+                        else if (provider.Name == "Facebook")
+                        {
+                            <form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post">
+                                <button type="submit" class="btn btn-facebook w-100 mb-2" name="provider" value="@provider.Name"
+                                    title="Sign up using your @provider.DisplayName account">
+                                    <svg width="18" height="18" viewBox="0 0 24 24" fill="white"
+                                        style="vertical-align: middle; margin-right: 8px;">
+                                        <path
+                                            d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
+                                    </svg>
+                                    Sign up with Facebook
+                                </button>
+                            </form>
+                        }
+                    }
+                </div>
+
+                <div class="oauth-divider">
+                    <span>OR</span>
+                </div>
+            }
+
+            <form id="registerForm" asp-route-returnUrl="@Model.ReturnUrl" method="post">
+                <div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
+
+                <div class="form-floating mb-3">
+                    <input asp-for="Input.Email" class="form-control" autocomplete="username" aria-required="true"
+                        placeholder="name@example.com" />
+                    <label asp-for="Input.Email">Email</label>
+                    <span asp-validation-for="Input.Email" class="text-danger"></span>
+                </div>
+                <div class="form-floating mb-3">
+                    <input asp-for="Input.Username" class="form-control" autocomplete="username" aria-required="true"
+                        placeholder="username" />
+                    <label asp-for="Input.Username">Username</label>
+                    <span asp-validation-for="Input.Username" class="text-danger"></span>
+                </div>
+                <div class="form-floating mb-3">
+                    <input asp-for="Input.Password" class="form-control" autocomplete="new-password"
+                        aria-required="true" placeholder="password" />
+                    <label asp-for="Input.Password">Password</label>
+                    <span asp-validation-for="Input.Password" class="text-danger"></span>
+                </div>
+                <div class="form-floating mb-3">
+                    <input asp-for="Input.ConfirmPassword" class="form-control" autocomplete="new-password"
+                        aria-required="true" placeholder="password" />
+                    <label asp-for="Input.ConfirmPassword">Confirm Password</label>
+                    <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
+                </div>
+                <button id="registerSubmit" type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
+            </form>
+        </section>
     </div>
     <div class="d-flex align-items-center col-md-6 col-md-offset-2">
@@ -114,5 +231,6 @@
             <h3>Already have an account?</h3>
             <p class="mb-3">Sign in to access your existing account.</p>
-            <a asp-page="./Login" asp-route-returnUrl="@Model.ReturnUrl" class="btn btn-outline-primary btn-lg">Sign In</a>
+            <a asp-page="./Login" asp-route-returnUrl="@Model.ReturnUrl" class="btn btn-outline-primary btn-lg">Sign
+                In</a>
         </section>
     </div>
Index: NutriMatch/Areas/Identity/Pages/Account/Register.cshtml.cs
===================================================================
--- NutriMatch/Areas/Identity/Pages/Account/Register.cshtml.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Areas/Identity/Pages/Account/Register.cshtml.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -81,4 +81,37 @@
             if (ModelState.IsValid)
             {
+                var existingUser = await _userManager.FindByEmailAsync(Input.Email);
+
+                if (existingUser != null)
+                {
+                    var hasPassword = await _userManager.HasPasswordAsync(existingUser);
+
+                    if (!hasPassword)
+                    {
+                        var logins = await _userManager.GetLoginsAsync(existingUser);
+                        var providers = string.Join(" or ", logins.Select(l => l.LoginProvider));
+
+                        ModelState.AddModelError(string.Empty,
+                            $"An account with {Input.Email} already exists. " +
+                            $"You previously registered using {providers}. " +
+                            "Please use that login method, or you can add a password to your existing account in your profile settings.");
+                    }
+                    else
+                    {
+                        ModelState.AddModelError(string.Empty,
+                            "An account with this email already exists.");
+                    }
+
+                    return Page();
+                }
+
+                var existingUsername = await _userManager.FindByNameAsync(Input.Username);
+                if (existingUsername != null)
+                {
+                    ModelState.AddModelError(nameof(Input.Username),
+                        "This username is already taken. Please choose another.");
+                    return Page();
+                }
+
                 var user = CreateUser();
                 user.ProfilePictureUrl = "/images/DefaultProfile.png";
@@ -94,24 +127,9 @@
 
                     var userId = await _userManager.GetUserIdAsync(user);
-                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
-                    code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
-                    var callbackUrl = Url.Page(
-                        "/Account/ConfirmEmail",
-                        pageHandler: null,
-                        values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
-                        protocol: Request.Scheme);
 
-                    await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
-                        $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
+                    await _signInManager.SignInAsync(user, isPersistent: false);
 
-                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
-                    {
-                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
-                    }
-                    else
-                    {
-                        await _signInManager.SignInAsync(user, isPersistent: false);
-                        return LocalRedirect(returnUrl);
-                    }
+                    return LocalRedirect(returnUrl);
+
                 }
                 foreach (var error in result.Errors)
Index: NutriMatch/Controllers/AdminController.cs
===================================================================
--- NutriMatch/Controllers/AdminController.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Controllers/AdminController.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -2,237 +2,381 @@
 using Microsoft.AspNetCore.Mvc;
 using NutriMatch.Models;
+using System.Text.Json;
+using NutriMatch.Services;
 using NutriMatch.Data;
 using Microsoft.EntityFrameworkCore;
-using System.Text.Json;
-
-[Authorize(Roles = "Admin")]
-public class AdminController : Controller
+
+namespace NutriMatch.Controllers
 {
-    private readonly AppDbContext _context;
-    private readonly ILogger<AdminController> _logger;
-
-    public AdminController(AppDbContext context, ILogger<AdminController> logger)
+    [Authorize(Roles = "Admin")]
+    public class AdminController : Controller
     {
-        _context = context;
-        _logger = logger;
-    }
-
-    public async Task<IActionResult> Index()
-    {
-        var pendingRecipes = await _context.Recipes
-            .Where(r => r.RecipeStatus == "Pending")
-            .Include(r => r.User)
-            .ToListAsync();
-
-        return View(pendingRecipes);
-    }
-
-    [HttpPost]
-    [ValidateAntiForgeryToken]
-    public async Task<IActionResult> ApproveRecipe([FromBody] JsonElement request)
-    {
-        try
-        {
-            if (!request.TryGetProperty("recipeId", out var recipeIdProp))
-            {
-                return Json(new { success = false, message = "Recipe ID is required." });
-            }
-
-            int recipeId = recipeIdProp.GetInt32();
-
-
-            var recipe = await _context.Recipes
-                .Include(r => r.RecipeIngredients)
-                .ThenInclude(ri => ri.Ingredient)
-                .FirstOrDefaultAsync(r => r.Id == recipeId);
-
-            if (recipe == null)
-            {
-                return Json(new { success = false, message = "Recipe not found." });
-            }
-
-            recipe.RecipeStatus = "Accepted";
-
-            if (recipe.HasPendingIngredients == true)
-            {
-                var pendingIngredients = recipe.RecipeIngredients
-                    .Where(ri => ri.Ingredient.Status == "Pending")
-                    .Select(ri => ri.Ingredient);
-
-                foreach (var ingredient in pendingIngredients)
-                {
-                    ingredient.Status = null;
-                }
-
-                recipe.HasPendingIngredients = false;
-            }
-
-            await _context.SaveChangesAsync();
-
-            return Json(new { message = "Recipe approved successfully.", success = true });
-        }
-        catch (Exception ex)
-        {
-            _logger.LogError(ex, "Error approving recipe");
-            return Json(new { success = false, message = "An error occurred while approving the recipe." });
-        }
-    }
-
-    [HttpPost]
-    [ValidateAntiForgeryToken]
-    public async Task<IActionResult> DeclineRecipe([FromBody] JsonElement request)
-    {
-        try
-        {
-            if (!request.TryGetProperty("recipeId", out var recipeIdProp))
-            {
-                return Json(new { success = false, message = "Recipe ID is required." });
-            }
-
-            int recipeId = recipeIdProp.GetInt32();
-            string reason = request.TryGetProperty("reason", out var reasonProp) ? reasonProp.GetString() : "No reason provided.";
-            string notes = request.TryGetProperty("notes", out var notesProp) ? notesProp.GetString() : "No notes provided.";
-
-            var recipe = await _context.Recipes.Include(r => r.RecipeIngredients)
-                .ThenInclude(ri => ri.Ingredient).FirstOrDefaultAsync(r => r.Id == recipeId);
-            if (recipe == null)
-            {
-                return Json(new { success = false, message = "Recipe not found." });
-            }
-
-            recipe.RecipeStatus = "Declined";
-            recipe.DeclineReason = reason ?? string.Empty;
-            recipe.AdminComment = notes ?? string.Empty;
-
-            await _context.SaveChangesAsync();
-
-            return Json(new { message = "Recipe declined successfully.", success = true });
-        }
-        catch (Exception ex)
-        {
-            _logger.LogError(ex, "Error declining recipe");
-            return Json(new { success = false, message = "An error occurred while declining the recipe." });
-        }
-    }
-
-    [HttpPost]
-    [ValidateAntiForgeryToken]
-    public async Task<IActionResult> BulkApproveRecipes([FromBody] JsonElement request)
-    {
-        try
-        {
-            if (!request.TryGetProperty("recipeIds", out var recipeIdsProp))
-            {
-                return Json(new { success = false, message = "Recipe IDs are required." });
-            }
-
-            List<int> recipeIds = recipeIdsProp.EnumerateArray()
-                .Select(x => x.GetInt32())
-                .ToList();
-
-            if (!recipeIds.Any())
-            {
-                return Json(new { success = false, message = "No recipe IDs provided." });
-            }
-
-            var recipes = await _context.Recipes
-                .Include(r => r.RecipeIngredients)
-                .ThenInclude(ri => ri.Ingredient)
-                .Where(r => recipeIds.Contains(r.Id))
-                .ToListAsync();
-
-            if (!recipes.Any())
-            {
-                return Json(new { success = false, message = "No recipes found." });
-            }
-
-            int approvedCount = 0;
-            foreach (var recipe in recipes)
-            {
-                recipe.RecipeStatus = "Accepted";
-
-                if (recipe.HasPendingIngredients == true)
-                {
-                    var pendingIngredients = recipe.RecipeIngredients
-                        .Where(ri => ri.Ingredient.Status == "Pending")
-                        .Select(ri => ri.Ingredient);
-
-                    foreach (var ingredient in pendingIngredients)
-                    {
-                        ingredient.Status = null;
-                    }
-
-                    recipe.HasPendingIngredients = false;
-                }
-
-                approvedCount++;
-            }
-
-            await _context.SaveChangesAsync();
-
-            return Json(new
-            {
-                message = $"{approvedCount} recipe(s) approved successfully.",
-                success = true,
-                approvedCount = approvedCount
-            });
-        }
-        catch (Exception ex)
-        {
-            _logger.LogError(ex, "Error bulk approving recipes");
-            return Json(new { success = false, message = "An error occurred while approving recipes." });
-        }
-    }
-
-    public async Task<IActionResult> DeclineReasonModel(int? id)
-    {
-        try
-        {
-            if (id == null)
-            {
-                return NotFound();
-            }
-
-            var recipe = await _context.Recipes
-                .Include(r => r.User)
-                .Include(r => r.RecipeIngredients)
-                .ThenInclude(ri => ri.Ingredient)
-                .FirstOrDefaultAsync(m => m.Id == id);
-
-            if (recipe == null)
-            {
-                return NotFound();
-            }
-
-            return PartialView("_RecipeDeclineAdminPartial", recipe);
-        }
-        catch (Exception ex)
-        {
-            _logger.LogError(ex, "Error loading decline reason model");
-            return StatusCode(500, "An error occurred while loading the decline form.");
-        }
-    }
-
-    [HttpGet]
-    public async Task<IActionResult> GetIngredientReview(int id)
-    {
-        try
-        {
-            var ingredient = await _context.Ingredients
+        private readonly AppDbContext _context;
+        private readonly ILogger<AdminController> _logger;
+        private readonly IRecipeApprovalService _recipeApprovalService;
+        private readonly IRestaurantService _restaurantService;
+        private readonly IMealKeywordService _mealKeywordService;
+        private readonly IFileUploadService _fileUploadService;
+
+        public AdminController(
+            AppDbContext context,
+            ILogger<AdminController> logger,
+            IRecipeApprovalService recipeApprovalService,
+            IRestaurantService restaurantService,
+            IMealKeywordService mealKeywordService,
+            IFileUploadService fileUploadService)
+        {
+            _context = context;
+            _logger = logger;
+            _recipeApprovalService = recipeApprovalService;
+            _restaurantService = restaurantService;
+            _mealKeywordService = mealKeywordService;
+            _fileUploadService = fileUploadService;
+        }
+
+        public async Task<IActionResult> Index()
+        {
+            var pendingRecipes = await _recipeApprovalService.GetPendingRecipesAsync();
+            return View(pendingRecipes);
+        }
+
+        #region Recipe Approval
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> ApproveRecipe([FromBody] JsonElement request)
+        {
+            try
+            {
+                if (!request.TryGetProperty("recipeId", out var recipeIdProp))
+                {
+                    return Json(new { success = false, message = "Recipe ID is required." });
+                }
+
+                int recipeId = recipeIdProp.GetInt32();
+                var (success, message) = await _recipeApprovalService.ApproveRecipeAsync(recipeId);
+
+                return Json(new { message, success });
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error approving recipe");
+                return Json(new { success = false, message = "An error occurred while approving the recipe." });
+            }
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> DeclineRecipe([FromBody] JsonElement request)
+        {
+            try
+            {
+                if (!request.TryGetProperty("recipeId", out var recipeIdProp))
+                {
+                    return Json(new { success = false, message = "Recipe ID is required." });
+                }
+
+                int recipeId = recipeIdProp.GetInt32();
+                string reason = request.TryGetProperty("reason", out var reasonProp) ? reasonProp.GetString() ?? "No reason provided." : "No reason provided.";
+                string notes = request.TryGetProperty("notes", out var notesProp) ? notesProp.GetString() ?? "No notes provided." : "No notes provided.";
+
+                var (success, message) = await _recipeApprovalService.DeclineRecipeAsync(recipeId, reason, notes);
+
+                return Json(new { message, success });
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error declining recipe");
+                return Json(new { success = false, message = "An error occurred while declining the recipe." });
+            }
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> BulkApproveRecipes([FromBody] JsonElement request)
+        {
+            try
+            {
+                if (!request.TryGetProperty("recipeIds", out var recipeIdsProp))
+                {
+                    return Json(new { success = false, message = "Recipe IDs are required." });
+                }
+
+                List<int> recipeIds = recipeIdsProp.EnumerateArray()
+                    .Select(x => x.GetInt32())
+                    .ToList();
+
+                var (success, message, approvedCount) = await _recipeApprovalService.BulkApproveRecipesAsync(recipeIds);
+
+                return Json(new { message, success, approvedCount });
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error bulk approving recipes");
+                return Json(new { success = false, message = "An error occurred while approving recipes." });
+            }
+        }
+
+        public async Task<IActionResult> DeclineReasonModel(int? id)
+        {
+            try
+            {
+                if (id == null)
+                {
+                    return NotFound();
+                }
+
+                var recipe = await _recipeApprovalService.GetRecipeForDeclineAsync(id.Value);
+
+                if (recipe == null)
+                {
+                    return NotFound();
+                }
+
+                return PartialView("_RecipeDeclineAdminPartial", recipe);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error loading decline reason model");
+                return StatusCode(500, "An error occurred while loading the decline form.");
+            }
+        }
+
+        #endregion
+
+        #region Ingredient Review
+
+        [HttpGet]
+        public async Task<IActionResult> GetIngredientReview(int id)
+        {
+            try
+            {
+                var ingredient = await _context.Ingredients
                 .Where(i => i.Id == id && i.Status == "Pending")
                 .FirstOrDefaultAsync();
 
-            if (ingredient == null)
-            {
-                return NotFound("Ingredient not found or not pending review.");
-            }
-
-            return PartialView("_IngredientReviewPartial", ingredient);
-        }
-        catch (Exception ex)
-        {
-            _logger.LogError(ex, "Error loading ingredient review for ID: {IngredientId}", id);
-            return StatusCode(500, "An error occurred while loading ingredient details.");
-        }
+                if (ingredient == null)
+                {
+                    return NotFound("Ingredient not found or not pending review.");
+                }
+
+                return PartialView("_IngredientReviewPartial", ingredient);
+            }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, "Error loading ingredient review for ID: {IngredientId}", id);
+                return StatusCode(500, "An error occurred while loading ingredient details.");
+            }
+        }
+
+        #endregion
+
+        #region Meal Keywords
+
+        [HttpGet]
+        public IActionResult GetMealTagsPartial()
+        {
+            return PartialView("_MealTagsPartial");
+        }
+
+        [HttpGet]
+        public async Task<IActionResult> GetMealKeywords()
+        {
+            var keywords = await _mealKeywordService.GetMealKeywordsAsync();
+            return Json(keywords);
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> AddMealKeyword([FromBody] MealKeyword keyword)
+        {
+            try
+            {
+                var (success, message) = await _mealKeywordService.AddMealKeywordAsync(keyword);
+                return Json(new { success, message });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error adding keyword: " + ex.Message });
+            }
+        }
+
+        [HttpDelete]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> DeleteMealKeyword(int id)
+        {
+            try
+            {
+                var (success, message) = await _mealKeywordService.DeleteMealKeywordAsync(id);
+                return Json(new { success, message });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error deleting keyword: " + ex.Message });
+            }
+        }
+
+        #endregion
+
+        #region Restaurant Management
+
+        [HttpGet]
+        public IActionResult GetRestaurantMealsPartial()
+        {
+            return PartialView("_RestaurantMealsManagementPartial");
+        }
+
+        [HttpGet]
+        public async Task<IActionResult> GetRestaurants()
+        {
+            var restaurants = await _restaurantService.GetRestaurantsAsync();
+            return Json(restaurants);
+        }
+
+        [HttpGet]
+        public async Task<IActionResult> GetRestaurant(int id)
+        {
+            try
+            {
+                var restaurant = await _restaurantService.GetRestaurantAsync(id);
+                if (restaurant == null)
+                {
+                    return Json(new { success = false, message = "Restaurant not found" });
+                }
+
+                return Json(restaurant);
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error loading restaurant: " + ex.Message });
+            }
+        }
+
+        [HttpGet]
+        public async Task<IActionResult> GetRestaurantMeals(int id)
+        {
+            try
+            {
+                var meals = await _restaurantService.GetRestaurantMealsAsync(id);
+                return Json(meals);
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error loading meals: " + ex.Message });
+            }
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> AddRestaurantMeal([FromBody] RestaurantMeal meal)
+        {
+            try
+            {
+                var (success, message) = await _restaurantService.AddRestaurantMealAsync(meal);
+                return Json(new { success, message });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error adding meal: " + ex.Message });
+            }
+        }
+
+        [HttpDelete]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> DeleteRestaurantMeal(int id)
+        {
+            try
+            {
+                var (success, message) = await _restaurantService.DeleteRestaurantMealAsync(id);
+                return Json(new { success, message });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error deleting meal: " + ex.Message });
+            }
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> EditRestaurantMeal([FromBody] RestaurantMeal meal)
+        {
+            try
+            {
+                var (success, message) = await _restaurantService.EditRestaurantMealAsync(meal);
+                return Json(new { success, message });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error updating meal: " + ex.Message });
+            }
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> AddRestaurant([FromForm] string name, [FromForm] string description, [FromForm] IFormFile image)
+        {
+            try
+            {
+                var filePath = await _fileUploadService.UploadImageAsync(image);
+
+                if (string.IsNullOrWhiteSpace(filePath))
+                {
+                    return Json(new { success = false, message = "Image upload failed." });
+                }
+
+                var (success, message, restaurantId) = await _restaurantService.AddRestaurantAsync(name, description, filePath);
+
+                return Json(new { success, message, restaurantId });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error adding restaurant: " + ex.Message });
+            }
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> EditRestaurant([FromForm] int id, [FromForm] string name, [FromForm] string description, [FromForm] IFormFile? image)
+        {
+            try
+            {
+                string? filePath = null;
+
+                if (image != null && image.Length > 0)
+                {
+                    filePath = await _fileUploadService.UploadImageAsync(image);
+
+                    if (string.IsNullOrWhiteSpace(filePath))
+                    {
+                        return Json(new { success = false, message = "Image upload failed." });
+                    }
+                }
+
+                var (success, message) = await _restaurantService.EditRestaurantAsync(id, name, description, filePath);
+
+                return Json(new { success, message });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error updating restaurant: " + ex.Message });
+            }
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> DeleteRestaurant(int id)
+        {
+            try
+            {
+                var (success, message) = await _restaurantService.DeleteRestaurantAsync(id);
+                return Json(new { success, message });
+            }
+            catch (Exception ex)
+            {
+                return Json(new { success = false, message = "Error deleting restaurant: " + ex.Message });
+            }
+        }
+
+        #endregion
     }
 }
Index: NutriMatch/Controllers/HomeController.cs
===================================================================
--- NutriMatch/Controllers/HomeController.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Controllers/HomeController.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -10,7 +10,7 @@
     public class Home : Controller
     {
-
         private readonly AppDbContext _context;
         private readonly UserManager<User> _userManager;
+
         public Home(AppDbContext context, UserManager<User> userManager)
         {
@@ -22,29 +22,45 @@
         {
             var recipes = await _context.Recipes
-                            .Where(r => r.RecipeStatus == "Accepted")
-                            .Include(r => r.User)
-                            .Include(r => r.Ratings)
-                            .Select(r => new
-                            {
-                                Recipe = r,
-                                AverageRating = r.Ratings.Any() ? r.Ratings.Average(rating => rating.Rating) : 0
-                            })
-                            .OrderByDescending(x => x.AverageRating)
-                            .Take(6)
-                            .Select(x => x.Recipe)
-                            .ToListAsync(); foreach (var recipe in recipes)
+                .Where(r => r.RecipeStatus == "Accepted")
+                .Include(r => r.User)
+                .Include(r => r.Ratings)
+                .Select(r => new
+                {
+                    Recipe = r,
+                    AverageRating = r.Ratings.Any() ? r.Ratings.Average(rating => rating.Rating) : 0
+                })
+                .OrderByDescending(x => x.AverageRating)
+                .Take(6)
+                .Select(x => x.Recipe)
+                .ToListAsync();
+
+            foreach (var recipe in recipes)
             {
                 recipe.Rating = recipe.Ratings.Any() ? recipe.Ratings.Average(r => r.Rating) : 0;
             }
+
+            var topRestaurants = await _context.Restaurants
+                .Include(r => r.Followers)
+                .OrderByDescending(r => r.Followers.Count)
+                .Take(5)
+                .ToListAsync();
+
             var model = new HomeViewModel
             {
                 Recipes = recipes,
-                Restaurants = await _context.Restaurants.ToListAsync()
+                Restaurants = topRestaurants
             };
 
             var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-            var userRecipes = _context.Recipes.Where(r => r.UserId == userId).Include(r => r.User).Include(r => r.Ratings).ToList();
+            var userRecipes = _context.Recipes
+                .Where(r => r.UserId == userId)
+                .Include(r => r.User)
+                .Include(r => r.Ratings)
+                .ToList();
+
             var recipeIds = userRecipes.Select(r => r.Id).ToList();
-            var ratings = _context.RecipeRatings.Where(r => recipeIds.Contains(r.RecipeId)).GroupBy(r => r.RecipeId);
+            var ratings = _context.RecipeRatings
+                .Where(r => recipeIds.Contains(r.RecipeId))
+                .GroupBy(r => r.RecipeId);
 
             foreach (var recipe in userRecipes)
@@ -54,7 +70,7 @@
 
             double averageRating = 0;
-            foreach (var groop in ratings)
+            foreach (var group in ratings)
             {
-                averageRating += groop.Average(r => r.Rating);
+                averageRating += group.Average(r => r.Rating);
             }
 
@@ -70,8 +86,6 @@
             ViewBag.UserRecipesCount = userRecipes.Count;
 
-
             if (User.Identity.IsAuthenticated && !string.IsNullOrEmpty(userId))
             {
-
                 var currentUser = await _userManager.GetUserAsync(User);
                 ViewBag.UserPicture = currentUser?.ProfilePictureUrl;
@@ -80,6 +94,4 @@
             return View(model);
         }
-
-
     }
 }
Index: NutriMatch/Controllers/MealPlanController.cs
===================================================================
--- NutriMatch/Controllers/MealPlanController.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Controllers/MealPlanController.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -2,20 +2,27 @@
 using Microsoft.AspNetCore.Identity;
 using Microsoft.AspNetCore.Mvc;
+using NutriMatch.Data;
 using NutriMatch.Models;
 using NutriMatch.Services;
 using System.ComponentModel.DataAnnotations;
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
 
 namespace NutriMatch.Controllers
 {
-    [Authorize]
+     [Authorize]
     public class MealPlanController : Controller
     {
         private readonly IMealPlanService _mealPlanService;
         private readonly UserManager<User> _userManager;
+        private readonly AppDbContext _context;
 
-        public MealPlanController(IMealPlanService mealPlanService, UserManager<User> userManager)
+        public MealPlanController(IMealPlanService mealPlanService, UserManager<User> userManager, AppDbContext context)
         {
             _mealPlanService = mealPlanService;
             _userManager = userManager;
+            _context = context;
         }
 
@@ -110,5 +117,65 @@
         }
 
-        
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> RegenerateMeal(int mealSlotId, int mealPlanId)
+        {
+            var user = await _userManager.GetUserAsync(User);
+            if (user == null)
+            {
+                return Json(new { success = false, message = "User not authenticated" });
+            }
+
+            var result = await _mealPlanService.RegenerateMealSlotAsync(mealSlotId, user.Id);
+
+            if (result)
+            {
+                return Json(new { success = true, message = "Meal regenerated successfully!" });
+            }
+            else
+            {
+                return Json(new { success = false, message = "Failed to regenerate meal. Please try again." });
+            }
+        }
+
+
+        [HttpPost]
+        public async Task<JsonResult> MarkMealsAsViewed([FromQuery] int mealId)
+        {
+            try
+            {
+                var user = await _userManager.GetUserAsync(User);
+                if (user == null)
+                {
+                    return Json(new { success = false, message = "User not authenticated" });
+                }
+
+                var mealSlot = await _context.MealSlots
+                    .FirstOrDefaultAsync(ms => ms.Id == mealId);
+
+                if (mealSlot == null)
+                {
+                    return Json(new { success = false, message = "Meal not found" });
+                }
+
+                if (mealSlot.IsRegenerated == true && mealSlot.isViewed == false)
+                {
+                    mealSlot.isViewed = true;
+                    await _context.SaveChangesAsync();
+                }
+
+                return Json(new { success = true, message = "Meal marked as viewed" });
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"Error in MarkMealsAsViewed: {ex.Message}");
+                return Json(new { success = false, message = $"Error marking meal as viewed: {ex.Message}" });
+            }
+        }
+
+
+
+
+
     }
 }
Index: NutriMatch/Controllers/NotificationsController.cs
===================================================================
--- NutriMatch/Controllers/NotificationsController.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Controllers/NotificationsController.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,135 @@
+using System.Security.Claims;
+using Microsoft.AspNetCore.Mvc;
+using NutriMatch.Models;
+using NutriMatch.Services;
+
+namespace NutriMatch.Controllers
+{
+    public class NotificationsController : Controller
+    {
+        private readonly INotificationService _notificationService;
+
+        public NotificationsController(INotificationService notificationService)
+        {
+            _notificationService = notificationService;
+        }
+
+        [HttpGet]
+        public async Task<JsonResult> GetNotifications()
+        {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            if (userId == null)
+                return Json(new { notifications = new List<Notification>(), unreadCount = 0 });
+
+            var (notifications, unreadCount) = await _notificationService.GetNotificationsAsync(userId);
+
+            return Json(new
+            {
+                notifications = notifications,
+                unreadCount = unreadCount
+            });
+        }
+
+        public async Task<ActionResult> NotificationPanel()
+        {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            if (userId == null)
+                return PartialView("_NotificationPanel", new List<Notification>());
+
+            var notifications = await _notificationService.GetAllNotificationsAsync(userId);
+
+            return PartialView("_NotificationPanel", notifications);
+        }
+
+        [HttpPost]
+        public async Task<JsonResult> MarkAsRead(int notificationId)
+        {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            if (userId == null)
+                return Json(new { success = false });
+
+            var (success, unreadCount) = await _notificationService.MarkAsReadAsync(notificationId, userId);
+
+            return Json(new { success = success, unreadCount = unreadCount });
+        }
+
+        [HttpPost]
+        public async Task<JsonResult> MarkAllAsRead()
+        {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            if (userId == null)
+                return Json(new { success = false });
+
+            var success = await _notificationService.MarkAllAsReadAsync(userId);
+
+            return Json(new { success = success, unreadCount = 0 });
+        }
+
+        [HttpPost]
+        public async Task<JsonResult> Delete(int notificationId)
+        {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            if (userId == null)
+                return Json(new { success = false });
+
+            var (success, unreadCount) = await _notificationService.DeleteAsync(notificationId, userId);
+
+            return Json(new { success = success, unreadCount = unreadCount });
+        }
+
+        [HttpPost]
+        public async Task<JsonResult> DeleteAll()
+        {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+
+            var (success, message) = await _notificationService.DeleteAllAsync(userId);
+
+            return Json(new { success = success, message = message });
+        }
+
+        [HttpGet("/Notifications/Stream")]
+        public async Task Stream()
+        {
+            Response.Headers.Add("Content-Type", "text/event-stream");
+            Response.Headers.Add("Cache-Control", "no-cache");
+            Response.Headers.Add("Connection", "keep-alive");
+
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            if (userId == null)
+                return;
+
+            var lastUnreadCount = await _notificationService.GetUnreadCountAsync(userId);
+
+            while (!HttpContext.RequestAborted.IsCancellationRequested)
+            {
+                var unreadCount = await _notificationService.GetUnreadCountAsync(userId);
+
+                if (unreadCount != lastUnreadCount)
+                {
+                    lastUnreadCount = unreadCount;
+
+                    var newNotification = await _notificationService.GetLatestNotificationAsync(userId);
+
+                    var payload = new
+                    {
+                        unreadCount,
+                        latestMessage = newNotification?.Message,
+                        createdAt = newNotification?.CreatedAt
+                    };
+
+                    var json = System.Text.Json.JsonSerializer.Serialize(payload);
+                    await Response.WriteAsync($"data: {json}\n\n");
+                    await Response.Body.FlushAsync();
+                }
+
+                await Task.Delay(3000);
+            }
+        }
+
+        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
+        public IActionResult Error()
+        {
+            return View("Error!");
+        }
+    }
+}
Index: NutriMatch/Controllers/RecipesController.cs
===================================================================
--- NutriMatch/Controllers/RecipesController.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Controllers/RecipesController.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -1,16 +1,11 @@
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.EntityFrameworkCore;
-using NutriMatch.Data;
-using NutriMatch.Models;
-using System.Text.Json;
 using Microsoft.AspNetCore.Authorization;
 using System.Security.Claims;
-using Microsoft.AspNet.Identity;
-
-
+using System.Text.Json;
+using NutriMatch.Models;
+using NutriMatch.Services;
 
 namespace NutriMatch.Controllers
 {
-
     public class MealKeywords
     {
@@ -20,246 +15,25 @@
     }
 
-
     public class RecipesController : Controller
     {
-
-
-
-
-        private MealKeywords LoadKeywordsFromJson()
-        {
-            var filePath = "Data/meal_keywords.json";
-            if (!System.IO.File.Exists(filePath))
-            {
-                return new MealKeywords
-                {
-                    Breakfast = new List<string>(),
-                    Main = new List<string>(),
-                    Snack = new List<string>()
-                };
-            }
-
-            var jsonString = System.IO.File.ReadAllText(filePath);
-            var options = new JsonSerializerOptions
-            {
-                PropertyNameCaseInsensitive = true
-            };
-
-            return JsonSerializer.Deserialize<MealKeywords>(jsonString, options) ?? new MealKeywords
-            {
-                Breakfast = new List<string>(),
-                Main = new List<string>(),
-                Snack = new List<string>()
-            };
-        }
-
-        public List<string> GenerateRecipeTags(Recipe recipe, List<SelectedIngredient> ingredients)
-        {
-            var keywords = LoadKeywordsFromJson();
-
-            var tags = new HashSet<string>();
-
-            string NormalizeWord(string word)
-            {
-                word = word.ToLower().Trim();
-                if (word.EndsWith("ies") && word.Length > 4)
-                    return word.Substring(0, word.Length - 3) + "y";
-                if (word.EndsWith("es") && word.Length > 3)
-                    return word.Substring(0, word.Length - 2);
-                if (word.EndsWith("s") && word.Length > 3 && !word.EndsWith("ss"))
-                    return word.Substring(0, word.Length - 1);
-                return word;
-            }
-
-            int CountKeywordMatches(IEnumerable<string> words, HashSet<string> keywords, bool isTitle = false)
-            {
-                int count = 0;
-                foreach (var word in words)
-                {
-                    bool matches = keywords.Contains(word) || keywords.Contains(NormalizeWord(word));
-                    if (matches)
-                        count += isTitle ? 3 : 1;
-                }
-                return count;
-            }
-
-            bool ContainsKeyword(IEnumerable<string> words, HashSet<string> keywords)
-            {
-                return words.Any(word =>
-                    keywords.Contains(word) ||
-                    keywords.Contains(NormalizeWord(word)) ||
-                    keywords.Any(k => NormalizeWord(k) == NormalizeWord(word))
-                );
-            }
-
-            var breakfastKeywords = new HashSet<string>(keywords.Breakfast ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
-            var mainKeywords = new HashSet<string>(keywords.Main ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
-            var snackKeywords = new HashSet<string>(keywords.Snack ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
-
-            var titleWords = recipe.Title.ToLower()
-                .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
-
-            var ingredientWords = new HashSet<string>();
-            foreach (var ing in ingredients)
-            {
-                var words = ing.Name.ToLower()
-                    .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
-                foreach (var w in words) ingredientWords.Add(w);
-            }
-
-            var allWords = titleWords.Concat(ingredientWords).ToList();
-
-            int breakfastScore = CountKeywordMatches(titleWords, breakfastKeywords, true) +
-                                 CountKeywordMatches(ingredientWords, breakfastKeywords, false);
-
-            int mainScore = CountKeywordMatches(titleWords, mainKeywords, true) +
-                            CountKeywordMatches(ingredientWords, mainKeywords, false);
-
-            int snackScore = CountKeywordMatches(titleWords, snackKeywords, true) +
-                             CountKeywordMatches(ingredientWords, snackKeywords, false);
-
-            int lunchScore = mainScore;
-            int dinnerScore = mainScore;
-
-            float calories = Math.Max(recipe.Calories, 1);
-            float proteinRatio = (recipe.Protein * 4) / calories * 100;
-            float carbRatio = (recipe.Carbs * 4) / calories * 100;
-            float fatRatio = (recipe.Fat * 9) / calories * 100;
-
-            if (calories < 150)
-            {
-                snackScore += 5;
-                breakfastScore -= 2;
-                lunchScore -= 3;
-                dinnerScore -= 4;
-            }
-            else if (calories < 300)
-            {
-                snackScore += 3;
-                breakfastScore += 2;
-                lunchScore -= 1;
-                dinnerScore -= 2;
-            }
-            else if (calories < 450)
-            {
-                breakfastScore += 3;
-                lunchScore += 2;
-                snackScore -= 1;
-                dinnerScore -= 1;
-            }
-            else if (calories < 650)
-            {
-                lunchScore += 3;
-                dinnerScore += 2;
-                breakfastScore -= 1;
-                snackScore -= 3;
-            }
-            else
-            {
-                dinnerScore += 4;
-                lunchScore += 1;
-                breakfastScore -= 3;
-                snackScore -= 4;
-            }
-
-
-            if (proteinRatio > 30)
-            {
-                dinnerScore += 3;
-                lunchScore += 2;
-                breakfastScore += 1;
-                snackScore -= 1;
-            }
-            else if (proteinRatio > 20)
-            {
-                dinnerScore += 2;
-                lunchScore += 1;
-            }
-            else if (proteinRatio < 10)
-            {
-                snackScore += 2;
-                dinnerScore -= 1;
-                lunchScore -= 1;
-            }
-
-
-            if (carbRatio > 60)
-            {
-                breakfastScore += 2;
-                snackScore += 2;
-                dinnerScore -= 1;
-            }
-            else if (carbRatio < 20)
-            {
-                dinnerScore += 1;
-                lunchScore += 1;
-            }
-
-
-            if (fatRatio > 40)
-            {
-                dinnerScore += 2;
-                snackScore += 1;
-                breakfastScore -= 1;
-            }
-
-
-            var results = new List<(string tag, int score)>
-        {
-            ("breakfast", breakfastScore),
-            ("lunch", lunchScore),
-            ("dinner", dinnerScore),
-            ("snack", snackScore)
-        }.OrderByDescending(x => x.score).ToList();
-
-            tags.Add(results[0].tag);
-
-            for (int i = 1; i < results.Count; i++)
-            {
-                if (results[i].score > 0 && results[i].score >= results[0].score * 0.6)
-                    tags.Add(results[i].tag);
-            }
-
-            return tags.ToList();
-        }
-
-
-        float ConvertType(float number, string unit)
-        {
-            float result;
-            switch (unit.ToLower())
-            {
-                case "g":
-                case "ml":
-                    result = number / 100;
-                    break;
-                case "oz":
-                    result = (float)(number * 28.3495 / 100);
-                    break;
-                case "tbsp":
-                    result = (float)(number * 15 / 100);
-                    break;
-                case "tsp":
-                    result = (float)(number * 5 / 100);
-                    break;
-                case "cup":
-                    result = (float)(number * 240 / 100);
-                    break;
-                default:
-                    return 0;
-            }
-
-            return result;
-        }
-
-        private readonly AppDbContext _context;
-        private readonly ILogger<RecipesController> _logger;
-
-        public RecipesController(AppDbContext context, ILogger<RecipesController> logger)
-        {
-            _context = context;
-            _logger = logger;
-        }
-
+        private readonly IMealPlanService _mealPlanService;
+        private readonly IRecipeService _recipeService;
+        private readonly IRatingService _ratingService;
+        private readonly IIngredientService _ingredientService;
+        private readonly IFileUploadService _fileUploadService;
+
+        public RecipesController(
+            IMealPlanService mealPlanService,
+            IRecipeService recipeService,
+            IRatingService ratingService,
+            IIngredientService ingredientService,
+            IFileUploadService fileUploadService)
+        {
+            _mealPlanService = mealPlanService;
+            _recipeService = recipeService;
+            _ratingService = ratingService;
+            _ingredientService = ingredientService;
+            _fileUploadService = fileUploadService;
+        }
 
         public async Task<IActionResult> Index(int page = 1, int pageSize = 6)
@@ -267,30 +41,6 @@
             var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
 
-            var totalRecipes = await _context.Recipes
-                .Where(r => r.RecipeStatus == "Accepted")
-                .CountAsync();
-
-            var recipes = await _context.Recipes
-                .Where(r => r.RecipeStatus == "Accepted")
-                .Include(r => r.User)
-                .Include(r => r.Ratings)
-                .OrderByDescending(r => r.CreatedAt)
-                .Skip((page - 1) * pageSize)
-                .Take(pageSize)
-                .ToListAsync();
-
-            foreach (var recipe in recipes)
-            {
-                recipe.Rating = recipe.Ratings.Any() ? recipe.Ratings.Average(r => r.Rating) : 0;
-            }
-
-            List<int> favoriteRecipeIds = new List<int>();
-            if (!string.IsNullOrEmpty(userId))
-            {
-                favoriteRecipeIds = await _context.FavoriteRecipes
-                    .Where(fr => fr.UserId == userId)
-                    .Select(fr => fr.RecipeId)
-                    .ToListAsync();
-            }
+            var (recipes, totalRecipes) = await _recipeService.GetPaginatedRecipesAsync(page, pageSize);
+            var favoriteRecipeIds = await _recipeService.GetUserFavoriteRecipeIdsAsync(userId);
 
             if (Request.Headers["X-Requested-With"] == "XMLHttpRequest")
@@ -331,5 +81,5 @@
 
         [Route("Recipes/Details/{id}")]
-        public async Task<IActionResult> Details(int? id, bool isOwner = false, String recipeDetailsDisplayContorol = "")
+        public async Task<IActionResult> Details(int? id, bool isOwner = false, string recipeDetailsDisplayContorol = "")
         {
             if (id == null)
@@ -338,10 +88,5 @@
             }
 
-
-            var recipe = await _context.Recipes.Include(r => r.User)
-            .Include(r => r.RecipeIngredients)
-            .ThenInclude(ri => ri.Ingredient)
-            .FirstOrDefaultAsync(m => m.Id == id);
-
+            var recipe = await _recipeService.GetRecipeByIdAsync(id.Value);
 
             if (recipe == null)
@@ -354,37 +99,30 @@
                 return PartialView("_RecipeDeclinePartial", recipe);
             }
-            else
-            {
-                var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-                bool actualIsOwner = !string.IsNullOrEmpty(userId) && recipe.UserId == userId;
-
-                var (averageRating, totalRatings, userRating, hasUserRated) =
-                    await GetRatingDataAsync(id.Value, userId);
-
-                bool isFavorited = false;
-                if (!string.IsNullOrEmpty(userId))
-                {
-                    isFavorited = await _context.FavoriteRecipes
-                        .AnyAsync(fr => fr.UserId == userId && fr.RecipeId == id.Value);
-                }
-
-                if (recipeDetailsDisplayContorol == "Buttons")
-                {
-                    ViewBag.AddAdminButtons = true;
-                }
-                else if (recipeDetailsDisplayContorol == "Index")
-                {
-                    ViewBag.InIndex = true;
-                }
-
-                ViewBag.IsOwner = actualIsOwner;
-                ViewBag.AverageRating = averageRating;
-                ViewBag.TotalRatings = totalRatings;
-                ViewBag.UserRating = userRating;
-                ViewBag.HasUserRated = hasUserRated;
-                ViewBag.IsFavorited = isFavorited;
-
-                return PartialView("_RecipeDetailsPartial", recipe);
-            }
+
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            bool actualIsOwner = !string.IsNullOrEmpty(userId) && recipe.UserId == userId;
+
+            var (averageRating, totalRatings, userRating, hasUserRated) =
+                await _recipeService.GetRatingDataAsync(id.Value, userId);
+
+            bool isFavorited = await _recipeService.IsRecipeFavoritedAsync(userId, id.Value);
+
+            if (recipeDetailsDisplayContorol == "Buttons")
+            {
+                ViewBag.AddAdminButtons = true;
+            }
+            else if (recipeDetailsDisplayContorol == "Index")
+            {
+                ViewBag.InIndex = true;
+            }
+
+            ViewBag.IsOwner = actualIsOwner;
+            ViewBag.AverageRating = averageRating;
+            ViewBag.TotalRatings = totalRatings;
+            ViewBag.UserRating = userRating;
+            ViewBag.HasUserRated = hasUserRated;
+            ViewBag.IsFavorited = isFavorited;
+
+            return PartialView("_RecipeDetailsPartial", recipe);
         }
 
@@ -395,108 +133,24 @@
         }
 
-
         [HttpPost]
         [ValidateAntiForgeryToken]
         public async Task<IActionResult> Create([Bind("Title,Instructions")] Recipe recipe)
         {
-
-
-
-            if (ModelState.IsValid)
-            {
-
-                var file = Request.Form.Files.GetFile("RecipeImage");
-                if (file != null && file.Length > 0)
-                {
-                    var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images");
-                    var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
-                    var filePath = Path.Combine(uploadsFolder, uniqueFileName);
-
-                    using (var stream = new FileStream(filePath, FileMode.Create))
-                    {
-                        await file.CopyToAsync(stream);
-                    }
-
-                    recipe.ImageUrl = "/images/" + uniqueFileName;
-                }
-                else
-                {
-                    Console.WriteLine("No file uploaded or file is empty.");
-                }
-
-                recipe.UserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-                recipe.Type = new List<string> { " " };
-                _context.Add(recipe);
-                await _context.SaveChangesAsync();
-                string selectedIngredients = Request.Form["Ingredients"];
-                List<SelectedIngredient> ingredients = JsonSerializer.Deserialize<List<SelectedIngredient>>(selectedIngredients);
-                float totalCalories = 0;
-                float totalProtein = 0;
-                float totalCarbs = 0;
-                float totalFat = 0;
-
-
-                bool hasPendingIngredients = false;
-                foreach (var i in ingredients)
-                {
-                    _context.RecipeIngredients.Add(new RecipeIngredient
-                    {
-                        RecipeId = recipe.Id,
-                        IngredientId = i.Id,
-                        Unit = i.Unit,
-                        Quantity = i.Quantity
-                    });
-
-                    Ingredient tempIngredient = _context.Ingredients.Find(i.Id);
-
-
-
-                    totalCalories += ConvertType(tempIngredient.Calories, i.Unit) * i.Quantity;
-                    totalProtein += ConvertType(tempIngredient.Protein, i.Unit) * i.Quantity;
-                    totalCarbs += ConvertType(tempIngredient.Carbs, i.Unit) * i.Quantity;
-                    totalFat += ConvertType(tempIngredient.Fat, i.Unit) * i.Quantity;
-
-                    if (tempIngredient.Status == "Pending")
-                    {
-                        hasPendingIngredients = true;
-                    }
-                }
-
-                recipe.Calories = MathF.Round(totalCalories, MidpointRounding.AwayFromZero);
-                recipe.Protein = MathF.Round(totalProtein, MidpointRounding.AwayFromZero);
-                recipe.Carbs = MathF.Round(totalCarbs, MidpointRounding.AwayFromZero);
-                recipe.Fat = MathF.Round(totalFat, MidpointRounding.AwayFromZero);
-
-                if (hasPendingIngredients)
-                {
-                    recipe.HasPendingIngredients = true;
-                }
-
-                recipe.Type = GenerateRecipeTags(recipe, ingredients);
-
-                _context.Update(recipe);
-
-
-                await _context.SaveChangesAsync();
-                return RedirectToAction(nameof(Index));
-
-
-
-            }
-            else
-            {
-                foreach (var key in ModelState.Keys)
-                {
-                    var errors = ModelState[key].Errors;
-                    foreach (var error in errors)
-                    {
-                        Console.WriteLine($"Key: {key} - Error: {error.ErrorMessage}");
-                    }
-                }
-
-
-                Console.WriteLine("Model state is invalid. Please check the input data.");
-            }
-            return View(recipe);
+            if (!ModelState.IsValid)
+            {
+                return View(recipe);
+            }
+
+            var file = Request.Form.Files.GetFile("RecipeImage");
+            var imageUrl = await _fileUploadService.UploadImageAsync(file);
+
+            recipe.UserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+
+            string selectedIngredients = Request.Form["Ingredients"];
+            List<SelectedIngredient> ingredients = JsonSerializer.Deserialize<List<SelectedIngredient>>(selectedIngredients);
+
+            await _recipeService.CreateRecipeAsync(recipe, ingredients, imageUrl);
+
+            return RedirectToAction("MyRecipes");
         }
 
@@ -504,14 +158,59 @@
         public async Task<IActionResult> Edit(int? id, bool requiresChange = false)
         {
-
-            if (requiresChange)
-            {
-                ViewBag.RequireChange = true;
+            if (id == null)
+            {
+                return NotFound();
+            }
+
+            var recipe = await _recipeService.GetRecipeByIdAsync(id.Value);
+
+            if (recipe == null)
+            {
+                return NotFound();
+            }
+
+            if (recipe.UserId != User.FindFirstValue(ClaimTypes.NameIdentifier))
+            {
+                return Forbid();
+            }
+
+            ViewBag.RequireChange = requiresChange;
+
+            return View(recipe);
+        }
+
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> Edit([Bind("Id,Title,Instructions")] Recipe recipe)
+        {
+            if (!ModelState.IsValid)
+            {
+                return View(recipe);
+            }
+
+            var file = Request.Form.Files.GetFile("RecipeImage");
+            string imageUrl;
+
+            if (file != null && file.Length > 0)
+            {
+                imageUrl = await _fileUploadService.UploadImageAsync(file);
             }
             else
             {
-                ViewBag.RequireChange = false;
-            }
-
+                imageUrl = Request.Form["ExistingImageUrl"].ToString();
+            }
+
+            recipe.UserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+
+            string selectedIngredients = Request.Form["Ingredients"];
+            List<SelectedIngredient> ingredients = JsonSerializer.Deserialize<List<SelectedIngredient>>(selectedIngredients);
+
+            await _recipeService.UpdateRecipeAsync(recipe, ingredients, imageUrl);
+
+            return RedirectToAction(nameof(MyRecipes));
+        }
+
+        public async Task<IActionResult> Delete(int? id)
+        {
             if (id == null)
             {
@@ -519,10 +218,6 @@
             }
 
-
-
-            var recipe = await _context.Recipes
-        .Include(r => r.RecipeIngredients)
-            .ThenInclude(ri => ri.Ingredient)
-        .FirstOrDefaultAsync(r => r.Id == id);
+            var recipe = await _recipeService.GetRecipeByIdAsync(id.Value);
+
             if (recipe == null)
             {
@@ -530,183 +225,36 @@
             }
 
-            if (recipe.UserId != User.FindFirstValue(System.Security.Claims.ClaimTypes.NameIdentifier))
-            {
-                return Forbid();
-            }
-
-            return View(recipe);
-        }
-
-
-        [HttpPost]
-        [ValidateAntiForgeryToken]
-        public async Task<IActionResult> Edit([Bind("Id,Title,Instructions")] Recipe recipe)
-        {
-
-
-            if (ModelState.IsValid)
-            {
-                var file = Request.Form.Files.GetFile("RecipeImage");
-                if (file != null && file.Length > 0)
-                {
-                    var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images");
-                    var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
-                    var filePath = Path.Combine(uploadsFolder, uniqueFileName);
-
-                    using (var stream = new FileStream(filePath, FileMode.Create))
-                    {
-                        await file.CopyToAsync(stream);
-                    }
-
-                    recipe.ImageUrl = "/images/" + uniqueFileName;
-                }
-                else
-                {
-
-                    var existing = Request.Form["ExistingImageUrl"].ToString();
-                    if (existing != null)
-                    {
-                        recipe.ImageUrl = existing;
-                    }
-                }
-
-                await _context.RecipeIngredients.Where(ri => ri.RecipeId == recipe.Id).ExecuteDeleteAsync();
-
-                string selectedIngredients = Request.Form["Ingredients"];
-                List<SelectedIngredient> ingredients = JsonSerializer.Deserialize<List<SelectedIngredient>>(selectedIngredients);
-                float totalCalories = 0;
-                float totalProtein = 0;
-                float totalCarbs = 0;
-                float totalFat = 0;
-
-                foreach (var i in ingredients)
-                {
-                    _context.RecipeIngredients.Add(new RecipeIngredient
-                    {
-                        RecipeId = recipe.Id,
-                        IngredientId = i.Id,
-                        Unit = i.Unit,
-                        Quantity = i.Quantity
-                    });
-
-                    Ingredient tempIngredient = _context.Ingredients.Find(i.Id);
-
-                    totalCalories += ConvertType(tempIngredient.Calories, i.Unit) * i.Quantity;
-                    totalProtein += ConvertType(tempIngredient.Protein, i.Unit) * i.Quantity;
-                    totalCarbs += ConvertType(tempIngredient.Carbs, i.Unit) * i.Quantity;
-                    totalFat += ConvertType(tempIngredient.Fat, i.Unit) * i.Quantity;
-                }
-
-                recipe.Calories = MathF.Round(totalCalories, MidpointRounding.AwayFromZero);
-                recipe.Protein = MathF.Round(totalProtein, MidpointRounding.AwayFromZero);
-                recipe.Carbs = MathF.Round(totalCarbs, MidpointRounding.AwayFromZero);
-                recipe.Fat = MathF.Round(totalFat, MidpointRounding.AwayFromZero);
-                recipe.UserId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-
-                recipe.Type = GenerateRecipeTags(recipe, ingredients);
-
-                _context.Update(recipe);
-
-                await _context.SaveChangesAsync();
-                return RedirectToAction(nameof(MyRecipes));
-            }
-            else
-            {
-                foreach (var key in ModelState.Keys)
-                {
-                    var errors = ModelState[key].Errors;
-                    foreach (var error in errors)
-                    {
-                        Console.WriteLine($"Key: {key} - Error: {error.ErrorMessage}");
-                    }
-                }
-
-                Console.WriteLine("Model state is invalid. Please check the input data.");
-            }
-
-            return View(recipe);
-        }
-
-
-
-        public async Task<IActionResult> Delete(int? id)
-        {
-            if (id == null)
-            {
-                return NotFound();
-            }
-
-            var recipe = await _context.Recipes.Include(r => r.RecipeIngredients)
-                .FirstOrDefaultAsync(m => m.Id == id);
-            if (recipe == null)
-            {
-                return NotFound();
-            }
-
             return PartialView("_RecipeDeletePartial", recipe);
         }
 
-
         [HttpPost, ActionName("Delete")]
         [ValidateAntiForgeryToken]
         public async Task<IActionResult> DeleteConfirmed(int id)
         {
-            var recipe = await _context.Recipes.FindAsync(id);
+            var recipe = await _recipeService.GetRecipeByIdAsync(id);
+
             if (recipe != null)
             {
-                _context.Recipes.Remove(recipe);
-            }
-
-            await _context.SaveChangesAsync();
+                await _fileUploadService.DeleteImageAsync(recipe.ImageUrl);
+                await _mealPlanService.HandleDeletedRecipeAsync(id);
+                await _recipeService.DeleteRecipeAsync(id);
+            }
+
             return RedirectToAction(nameof(Index));
         }
 
-        private bool RecipeExists(int id)
-        {
-            return _context.Recipes.Any(e => e.Id == id);
-        }
-
-
-        public async Task<ActionResult<List<Ingredient>>> getSuggestions([FromQuery] String query)
-        {
-            List<Ingredient> suggestions = await _context.Ingredients
-            .Where(i => EF.Functions.ILike(i.Name, $"%{query}%") && i.Status == null)
-            .OrderBy(i => i.Name)
-            .Take(5)
-            .ToListAsync();
-
+        public async Task<ActionResult<List<Ingredient>>> getSuggestions([FromQuery] string query)
+        {
+            var suggestions = await _ingredientService.GetIngredientSuggestionsAsync(query);
             return suggestions;
         }
 
-
-        public ActionResult MyRecipes()
-        {
-
-            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-            var userRecipes = _context.Recipes.Where(r => r.UserId == userId).Include(r => r.User).Include(r => r.Ratings).ToList();
-            var recipeIds = userRecipes.Select(r => r.Id).ToList();
-            var ratings = _context.RecipeRatings.Where(r => recipeIds.Contains(r.RecipeId)).GroupBy(r => r.RecipeId);
-            foreach (var recipe in userRecipes)
-            {
-                recipe.Rating = recipe.Ratings.Any() ? recipe.Ratings.Average(r => r.Rating) : 0;
-            }
-
-            double averageRating = 0;
-            foreach (var groop in ratings)
-            {
-                averageRating += groop.Average(r => r.Rating);
-
-            }
-
-            if (ratings.Count() > 0)
-            {
-                ViewBag.AverageRating = Math.Round(averageRating / ratings.Count(), 1);
-            }
-            else
-            {
-                ViewBag.AverageRating = 0;
-            }
-
-
+        public async Task<ActionResult> MyRecipes()
+        {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            var userRecipes = await _recipeService.GetUserRecipesAsync(userId);
+            var averageRating = await _recipeService.GetUserAverageRatingAsync(userId);
+
+            ViewBag.AverageRating = averageRating;
 
             return View(userRecipes);
@@ -717,71 +265,23 @@
         public async Task<IActionResult> Rate([FromBody] JsonElement body)
         {
-
             int recipeId = body.GetProperty("recipeId").GetInt32();
             double rating = body.GetProperty("rating").GetDouble();
-
-            try
-            {
-                var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-
-                if (string.IsNullOrEmpty(userId))
-                {
-                    return Json(new { success = false, message = "User not authenticated" });
-                }
-
-                if (rating < 1 || rating > 5)
-                {
-                    Console.WriteLine(rating);
-                    Console.WriteLine(recipeId);
-                    return Json(new { success = false, message = "Rating must be between 1 and 5" });
-                }
-
-                var recipe = await _context.Recipes.FindAsync(recipeId);
-                if (recipe == null)
-                {
-                    return Json(new { success = false, message = "Recipe not found" });
-                }
-
-                var existingRating = await _context.RecipeRatings
-                    .FirstOrDefaultAsync(r => r.UserId == userId && r.RecipeId == recipeId);
-
-                if (existingRating != null)
-                {
-                    existingRating.Rating = rating;
-                    _context.RecipeRatings.Update(existingRating);
-                }
-                else
-                {
-                    var newRating = new RecipeRating
-                    {
-                        UserId = userId,
-                        RecipeId = recipeId,
-                        Rating = rating
-                    };
-                    _context.RecipeRatings.Add(newRating);
-                }
-
-                await _context.SaveChangesAsync();
-
-                var ratings = await _context.RecipeRatings
-                    .Where(r => r.RecipeId == recipeId)
-                    .Select(r => r.Rating)
-                    .ToListAsync();
-
-                var averageRating = ratings.Any() ? Math.Round(ratings.Average(), 1) : 0;
-                var totalRatings = ratings.Count;
-
-                return Json(new
-                {
-                    success = true,
-                    averageRating = averageRating,
-                    totalRatings = totalRatings,
-                    message = "Rating submitted successfully"
-                });
-            }
-            catch (Exception ex)
-            {
-                return Json(new { success = false, message = "An error occurred while submitting your rating" });
-            }
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+
+            var (success, message, averageRating, totalRatings) = 
+                await _ratingService.AddOrUpdateRatingAsync(userId, recipeId, rating);
+
+            if (!success)
+            {
+                return Json(new { success = false, message });
+            }
+
+            return Json(new
+            {
+                success = true,
+                averageRating,
+                totalRatings,
+                message
+            });
         }
 
@@ -791,75 +291,22 @@
         public async Task<IActionResult> RemoveRating([FromBody] JsonElement body)
         {
-
             int recipeId = body.GetProperty("recipeId").GetInt32();
-            try
-            {
-                var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-
-                if (string.IsNullOrEmpty(userId))
-                {
-                    return Json(new { success = false, message = "User not authenticated" });
-                }
-
-                var existingRating = await _context.RecipeRatings
-                    .FirstOrDefaultAsync(r => r.UserId == userId && r.RecipeId == recipeId);
-
-                if (existingRating == null)
-                {
-                    return Json(new { success = false, message = "No rating found to remove" });
-                }
-
-                _context.RecipeRatings.Remove(existingRating);
-                await _context.SaveChangesAsync();
-
-                var ratings = await _context.RecipeRatings
-                    .Where(r => r.RecipeId == recipeId)
-                    .Select(r => r.Rating)
-                    .ToListAsync();
-
-                var averageRating = ratings.Any() ? Math.Round(ratings.Average(), 1) : 0;
-                var totalRatings = ratings.Count;
-
-                return Json(new
-                {
-                    success = true,
-                    averageRating = averageRating,
-                    totalRatings = totalRatings,
-                    message = "Rating removed successfully"
-                });
-            }
-            catch (Exception ex)
-            {
-
-
-                return Json(new { success = false, message = "An error occurred while removing your rating" });
-            }
-        }
-
-        private async Task<(double averageRating, int totalRatings, double userRating, bool hasUserRated)>
-            GetRatingDataAsync(int recipeId, string userId = null)
-        {
-            var ratings = await _context.RecipeRatings
-                .Where(r => r.RecipeId == recipeId)
-                .Select(r => new { r.Rating, r.UserId })
-                .ToListAsync();
-
-            var averageRating = ratings.Any() ? Math.Round(ratings.Average(r => r.Rating), 1) : 0;
-            var totalRatings = ratings.Count;
-
-            double userRating = 0;
-            bool hasUserRated = false;
-
-            if (!string.IsNullOrEmpty(userId))
-            {
-                var userRatingData = ratings.FirstOrDefault(r => r.UserId == userId);
-                if (userRatingData != null)
-                {
-                    userRating = userRatingData.Rating;
-                    hasUserRated = true;
-                }
-            }
-
-            return (averageRating, totalRatings, userRating, hasUserRated);
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+
+            var (success, message, averageRating, totalRatings) = 
+                await _ratingService.RemoveRatingAsync(userId, recipeId);
+
+            if (!success)
+            {
+                return Json(new { success = false, message });
+            }
+
+            return Json(new
+            {
+                success = true,
+                averageRating,
+                totalRatings,
+                message
+            });
         }
 
@@ -868,71 +315,32 @@
         public async Task<IActionResult> ToggleFavorite([FromBody] JsonElement request)
         {
-            try
-            {
-                var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
-                if (string.IsNullOrEmpty(userId))
-                {
-                    return Json(new { success = false, message = "User not authenticated" });
-                }
-
-                int recipeId = request.GetProperty("recipeId").GetInt32();
-
-                var recipe = await _context.Recipes.FindAsync(recipeId);
-                if (recipe == null)
-                {
-                    return Json(new { success = false, message = "Recipe not found" });
-                }
-
-                var existingFavorite = await _context.FavoriteRecipes
-                    .FirstOrDefaultAsync(fr => fr.UserId == userId && fr.RecipeId == recipeId);
-
-                bool isFavorited;
-
-                if (existingFavorite != null)
-                {
-                    _context.FavoriteRecipes.Remove(existingFavorite);
-                    isFavorited = false;
-                }
-                else
-                {
-                    var favoriteRecipe = new FavoriteRecipe
-                    {
-                        UserId = userId,
-                        RecipeId = recipeId
-                    };
-                    _context.FavoriteRecipes.Add(favoriteRecipe);
-                    isFavorited = true;
-                }
-
-                await _context.SaveChangesAsync();
-
-                return Json(new
-                {
-                    success = true,
-                    isFavorited = isFavorited,
-                    message = isFavorited ? "Added to favorites" : "Removed from favorites"
-                });
-            }
-            catch (Exception _)
-            {
-                return Json(new
-                {
-                    success = false,
-                    message = "An error occurred while updating favorites"
-                });
-            }
-        }
-
-
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            int recipeId = request.GetProperty("recipeId").GetInt32();
+
+            var (success, message, isFavorited) = 
+                await _recipeService.ToggleFavoriteAsync(userId, recipeId);
+
+            if (!success)
+            {
+                return Json(new { success = false, message });
+            }
+
+            return Json(new
+            {
+                success = true,
+                isFavorited,
+                message
+            });
+        }
 
         [HttpPost]
         public async Task<IActionResult> AddIngredient([FromBody] JsonElement request)
         {
-
-            String Name = request.GetProperty("Name").GetString();
-            float Calories = request.GetProperty("Calories").GetSingle();
-            float Protein = request.GetProperty("Protein").GetSingle();
-            float Carbs = request.GetProperty("Carbs").GetSingle();
-            float Fat = request.GetProperty("Fat").GetSingle();
+            string name = request.GetProperty("Name").GetString();
+            float calories = request.GetProperty("Calories").GetSingle();
+            float protein = request.GetProperty("Protein").GetSingle();
+            float carbs = request.GetProperty("Carbs").GetSingle();
+            float fat = request.GetProperty("Fat").GetSingle();
+
             var token = Request.Headers["RequestVerificationToken"].FirstOrDefault();
             if (string.IsNullOrEmpty(token))
@@ -946,56 +354,23 @@
             }
 
-            if (string.IsNullOrWhiteSpace(Name))
-            {
-                return BadRequest("Ingredient name is required.");
-            }
-
-            try
-            {
-                var existingIngredient = await _context.Ingredients
-                    .FirstOrDefaultAsync(i => i.Name.ToLower() == Name.ToLower());
-
-                if (existingIngredient != null)
-                {
-                    return BadRequest("An ingredient with this name already exists.");
-                }
-
-                var ingredient = new Ingredient
-                {
-                    Name = Name.Trim(),
-                    Calories = Calories,
-                    Protein = Protein,
-                    Carbs = Carbs,
-                    Fat = Fat,
-                    Status = "Pending"
-                };
-
-                _context.Ingredients.Add(ingredient);
-                await _context.SaveChangesAsync();
-
-                return Json(new
-                {
-                    id = ingredient.Id,
-                    name = ingredient.Name,
-                    calories = ingredient.Calories,
-                    protein = ingredient.Protein,
-                    carbs = ingredient.Carbs,
-                    fat = ingredient.Fat,
-                    sucess = true
-                });
-            }
-            catch (Exception ex)
-            {
-                return StatusCode(500, "An error occurred while adding the ingredient.");
-            }
-        }
-
-
-
-
-
+            var (success, message, ingredient) = 
+                await _ingredientService.AddIngredientAsync(name, calories, protein, carbs, fat);
+
+            if (!success)
+            {
+                return BadRequest(message);
+            }
+
+            return Json(new
+            {
+                id = ingredient.Id,
+                name = ingredient.Name,
+                calories = ingredient.Calories,
+                protein = ingredient.Protein,
+                carbs = ingredient.Carbs,
+                fat = ingredient.Fat,
+                success = true
+            });
+        }
     }
-
-
 }
-
Index: NutriMatch/Controllers/RestaurantsController.cs
===================================================================
--- NutriMatch/Controllers/RestaurantsController.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Controllers/RestaurantsController.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -1,37 +1,44 @@
-using System;
 using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
+using System.Security.Claims;
 using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-using Microsoft.EntityFrameworkCore;
-using NutriMatch.Data;
-using System.Text.Json;
 using NutriMatch.Models;
+using NutriMatch.Services;
 
 namespace NutriMatch.Controllers
 {
-
     public class RestaurantsController : Controller
     {
-        private readonly AppDbContext _context;
+        private readonly IRestaurantService _restaurantService;
+        private readonly IMealClassificationService _mealClassificationService;
+        private readonly IUserPreferenceService _userPreferenceService;
 
-
-        public RestaurantsController(AppDbContext context)
+        public RestaurantsController(
+            IRestaurantService restaurantService,
+            IMealClassificationService mealClassificationService,
+            IUserPreferenceService userPreferenceService)
         {
-
-            _context = context;
+            _restaurantService = restaurantService;
+            _mealClassificationService = mealClassificationService;
+            _userPreferenceService = userPreferenceService;
         }
-
 
         public async Task<IActionResult> Index()
         {
-            var restaurants = await _context.Restaurants.ToListAsync();
+            var restaurants = await _restaurantService.GetAllRestaurantsAsync();
             return View(restaurants);
         }
 
-
-        public async Task<IActionResult> GetRestaurantMeals(int? id, int? minCalories, int? maxCalories, int? minProtein, int? maxProtein, int? minCarbs, int? maxCarbs, int? minFat, int? maxFat)
+        public async Task<IActionResult> GetRestaurantMeals(
+            int? id,
+            int? minCalories,
+            int? maxCalories,
+            int? minProtein,
+            int? maxProtein,
+            int? minCarbs,
+            int? maxCarbs,
+            int? minFat,
+            int? maxFat)
         {
             if (id == null)
@@ -40,6 +47,15 @@
             }
 
-            var restaurant = await _context.Restaurants.Include(r => r.RestaurantMeals)
-                .FirstOrDefaultAsync(m => m.Id == id);
+            var (restaurant, filteredMeals) = await _restaurantService.GetRestaurantWithFilteredMealsAsync(
+                id.Value,
+                minCalories,
+                maxCalories,
+                minProtein,
+                maxProtein,
+                minCarbs,
+                maxCarbs,
+                minFat,
+                maxFat);
+
             if (restaurant == null)
             {
@@ -47,211 +63,41 @@
             }
 
-
-
-            var filteredMeals = restaurant.RestaurantMeals
-        .Where(r =>
-            (minCalories == null || r.Calories >= minCalories) &&
-            (maxCalories == null || r.Calories <= maxCalories) &&
-            (minProtein == null || r.Protein >= minProtein) &&
-
-            (maxProtein == null || r.Protein <= maxProtein) &&
-            (minFat == null || r.Fat >= minFat) &&
-            (maxFat == null || r.Fat <= maxFat) &&
-            (minCarbs == null || r.Carbs >= minCarbs) &&
-            (maxCarbs == null || r.Carbs <= maxCarbs)
-        )
-        .ToList();
-
-            Console.WriteLine($"Total meals for restaurant {id}: {filteredMeals.Count}");
-
-
+            ViewBag.RestaurantName = restaurant.Name;
             return PartialView("_RestaurantMealsPartial", filteredMeals);
         }
 
-        public async Task ClassifyAllRestaurantMeals()
+        
+
+        [Authorize]
+        [HttpGet]
+        public async Task<IActionResult> GetUserPreferences()
         {
-            var meals = await GetUnclassifiedMealsFromDatabase();
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            var (preferences, followedRestaurants) = await _userPreferenceService.GetUserPreferencesAsync(userId);
 
-            foreach (var meal in meals)
-            {
-                var mealTypes = GenerateMealTypes(meal);
-                await UpdateMealTypesInDatabase(meal.Id, mealTypes);
-            }
+            return Json(new { preferences, followedRestaurants });
         }
 
-        private MealKeywords LoadKeywordsFromJson()
+        [Authorize]
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> UpdateTagPreferences([FromBody] List<UserMealPreference> preferences)
         {
-            var filePath = "Data/meal_keywords.json";
-            if (!System.IO.File.Exists(filePath))
-            {
-                return new MealKeywords
-                {
-                    Breakfast = new List<string>(),
-                    Main = new List<string>(),
-                    Snack = new List<string>()
-                };
-            }
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            await _userPreferenceService.UpdateTagPreferencesAsync(userId, preferences);
 
-            var jsonString = System.IO.File.ReadAllText(filePath);
-            var options = new JsonSerializerOptions
-            {
-                PropertyNameCaseInsensitive = true
-            };
-
-            return JsonSerializer.Deserialize<MealKeywords>(jsonString, options) ?? new MealKeywords
-            {
-                Breakfast = new List<string>(),
-                Main = new List<string>(),
-                Snack = new List<string>()
-            };
+            return Json(new { success = true });
         }
 
-        public List<string> GenerateMealTypes(RestaurantMeal meal)
+        [Authorize]
+        [HttpPost]
+        [ValidateAntiForgeryToken]
+        public async Task<IActionResult> ToggleFollowRestaurant([FromBody] int restaurantId)
         {
+            var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
+            var (success, following) = await _userPreferenceService.ToggleFollowRestaurantAsync(userId, restaurantId);
 
-            if (meal.Calories == 0 ||
-                (!string.IsNullOrEmpty(meal.ItemDescription) &&
-                 (meal.ItemDescription.ToLower().Contains("wine") ||
-                  meal.ItemDescription.ToLower().Contains("beer") ||
-                  meal.ItemDescription.ToLower().Contains("spirits") ||
-                  meal.ItemDescription.ToLower().Contains("beverages")
-                  )))
-            {
-                return new List<string> { "drink" };
-            }
-
-            var keywords = LoadKeywordsFromJson();
-
-            var tags = new HashSet<string>();
-
-            string NormalizeWord(string word)
-            {
-                word = word.ToLower().Trim();
-                if (word.EndsWith("ies") && word.Length > 4)
-                    return word.Substring(0, word.Length - 3) + "y";
-                if (word.EndsWith("es") && word.Length > 3)
-                    return word.Substring(0, word.Length - 2);
-                if (word.EndsWith("s") && word.Length > 3 && !word.EndsWith("ss"))
-                    return word.Substring(0, word.Length - 1);
-                return word;
-            }
-
-            int CountKeywordMatches(IEnumerable<string> words, HashSet<string> keywords, bool isTitle = false)
-            {
-                int count = 0;
-                foreach (var word in words)
-                {
-                    bool matches = keywords.Contains(word) || keywords.Contains(NormalizeWord(word));
-                    if (matches)
-                        count += isTitle ? 3 : 1;
-                }
-                return count;
-            }
-
-            var breakfastKeywords = new HashSet<string>(keywords.Breakfast ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
-            var mainKeywords = new HashSet<string>(keywords.Main ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
-            var snackKeywords = new HashSet<string>(keywords.Snack ?? new List<string>(), StringComparer.OrdinalIgnoreCase);
-
-            var titleWords = meal.ItemName.ToLower()
-                .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
-
-            var descriptionWords = new HashSet<string>();
-            if (!string.IsNullOrEmpty(meal.ItemDescription))
-            {
-                var words = meal.ItemDescription.ToLower()
-                    .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')', ';', ':' }, StringSplitOptions.RemoveEmptyEntries);
-                foreach (var w in words) descriptionWords.Add(w);
-            }
-
-            var allWords = titleWords.Concat(descriptionWords).ToList();
-
-            int breakfastScore = CountKeywordMatches(titleWords, breakfastKeywords, true) +
-                                CountKeywordMatches(descriptionWords, breakfastKeywords, false);
-
-            int mainScore = CountKeywordMatches(titleWords, mainKeywords, true) +
-                            CountKeywordMatches(descriptionWords, mainKeywords, false);
-
-            int snackScore = CountKeywordMatches(titleWords, snackKeywords, true) +
-                            CountKeywordMatches(descriptionWords, snackKeywords, false);
-
-            int lunchScore = mainScore;
-            int dinnerScore = mainScore;
-
-            float calories = meal.Calories;
-            float proteinRatio = (meal.Protein * 4) / calories * 100;
-            float carbRatio = (meal.Carbs * 4) / calories * 100;
-            float fatRatio = (meal.Fat * 9) / calories * 100;
-
-            if (calories < 250)
-            {
-                snackScore += 2;
-                breakfastScore += 1;
-                dinnerScore -= 2;
-                lunchScore -= 2;
-            }
-            else if (calories <= 500)
-            {
-                lunchScore += 1;
-                dinnerScore += 1;
-                breakfastScore += 2;
-            }
-            else
-            {
-                dinnerScore += 2;
-                lunchScore += 2;
-                breakfastScore -= 1;
-                snackScore -= 2;
-            }
-
-
-            if (proteinRatio >= 25)
-            {
-                dinnerScore += 2;
-                lunchScore += 2;
-            }
-            else if (carbRatio >= 50)
-            {
-                breakfastScore += 1;
-                snackScore += 1;
-            }
-
-            if (fatRatio > 30)
-            {
-                dinnerScore += 1;
-                snackScore += 1;
-            }
-
-            var results = new List<(string tag, int score)>
-            {
-                ("breakfast", breakfastScore),
-                ("lunch", lunchScore),
-                ("dinner", dinnerScore),
-                ("snack", snackScore)
-            }.OrderByDescending(x => x.score).ToList();
-
-            tags.Add(results[0].tag);
-
-            for (int i = 1; i < results.Count; i++)
-            {
-                if (results[i].score > 0 && results[i].score >= results[0].score * 0.6)
-                    tags.Add(results[i].tag);
-            }
-
-            return tags.ToList();
+            return Json(new { success, following });
         }
-
-        private async Task<List<RestaurantMeal>> GetUnclassifiedMealsFromDatabase()
-        {
-            return await _context.RestaurantMeals.ToListAsync();
-        }
-
-        private async Task UpdateMealTypesInDatabase(int mealId, List<string> mealTypes)
-        {
-            var meal = await _context.RestaurantMeals.FindAsync(mealId);
-            meal.Type = mealTypes;
-            await _context.SaveChangesAsync();
-
-        }
-
     }
 }
Index: NutriMatch/Data/AppDbContext.cs
===================================================================
--- NutriMatch/Data/AppDbContext.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Data/AppDbContext.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -25,8 +25,15 @@
         public DbSet<WeeklyMealPlan> WeeklyMealPlans { get; set; }
         public DbSet<MealSlot> MealSlots { get; set; }
+        
+        public DbSet<MealKeyword> MealKeywords { get; set; }
+
+        public DbSet<Notification> Notifications { get; set; }
+
+        public DbSet<UserMealPreference> UserMealPreferences { get; set; }
+        public DbSet<RestaurantFollowing> RestaurantFollowings { get; set; }
 
         protected override void OnModelCreating(ModelBuilder modelBuilder)
         {
-            base.OnModelCreating(modelBuilder); 
+            base.OnModelCreating(modelBuilder);
 
             modelBuilder.Entity<Recipe>()
@@ -63,4 +70,12 @@
                 .HasForeignKey(rr => rr.RecipeId);
 
+            modelBuilder.Entity<UserMealPreference>()
+                .HasIndex(u => new { u.UserId, u.Tag })
+                .IsUnique();
+    
+            modelBuilder.Entity<RestaurantFollowing>()
+                .HasIndex(r => new { r.UserId, r.RestaurantId })
+                .IsUnique();
+
         }
     }
Index: triMatch/Data/meal_keywords.json
===================================================================
--- NutriMatch/Data/meal_keywords.json	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ 	(revision )
@@ -1,67 +1,0 @@
-{
-  "breakfast": [
-    "oatmeal", "pancake", "scramble", "smoothie", "toast",
-    "cereal", "granola", "yogurt", "bagel", "croissant", "waffle", "french toast",
-    "eggs", "omelet", "omelette", "frittata", "hash brown", "bacon", "sausage", "ham",
-    "breakfast", "sandwich", "muffin", "biscuit", "scone",
-    "porridge", "grits", "bowl", "acai", "chia", "oats",
-    "danish", "donut", "pastry", "fruit" , "salad", "melon", "berries",
-    "banana", "apple", "granola bar", "protein shake", "quinoa", "avocado", "toast", 
-    "crepes",  "quiche", "wrap",
-    "oats", "breakfast cereal", "corn flakes", "cheerios",
-    "smoothie", "pancakes"
-  ],
-"main": [
-    "sandwich", "burger", "wrap", "salad", "soup",
-    "grilled", "panini", "sub", "hoagie",
-    "blt", "turkey", "ham", "tuna", "chicken",
-    "cheeseburger", "hamburger", "slider",
-    "tortilla", "pasta", "potato", "coleslaw", "spinach",
-    "tomato", "vegetable", "minestrone", "clam",
-    "broth", "ramen", "noodle",
-    "quesadilla", "taco", "burrito", "bowl", "enchilada",
-    "sushi", "sashimi", "rice", "stir fry",
-    "mac and cheese", "lasagna", "spaghetti", "fettuccine", "ravioli",
-    "pizza slice", "calzone", "flatbread", "focaccia", "breadstick",
-    "fish", "chips", "nuggets", "tenders", "wings", "drumsticks",
-    "meat", "antipasto", "charcuterie", "plate",
-    "casserole", "shepherd's", "pie", "meatloaf", "leftovers", "curry",
-    "steak", "roast", "ribeye", "sirloin", "filet", "mignon", "t-bone",
-    "porterhouse", "strip", "beef", "rib", "brisket", "stew",
-    "linguine", "penne", "rigatoni", "alfredo", "carbonara",
-    "bolognese", "marinara", "pesto", "manicotti", "shells",
-    "margherita", "pepperoni", "bbq",
-    "tikka masala", "vindaloo", "korma", "pad thai",
-    "pork", "lamb", "duck", "fried",
-    "salmon", "cod", "halibut", "mahi", "bass", "sea", "seafood",
-    "shrimp", "lobster", "crab", "scallops", "mussels", "clams", "oyster",
-    "chop", "tenderloin", "bacon", "pulled", "ribs",
-    "leg", "gyros", "kebab",
-    "meatballs", "fajitas", "mein",
-    "risotto", "paella", "jambalaya", "gumbo", "chili", "stuffed peppers",
-    "eggplant", "ratatouille", "roasted",
-    "mashed", "baked", "quinoa", "couscous",
-    "shawarma", "falafel", "poutine", "pho", "dumpling", "spring roll",
-    "gnocchi", "beef stew", "teriyaki", "shish", "biryani",
-    "goulash", "cevapi", "moussaka"
-],
-  "snack": [
-    "chips", "crackers", "pretzels", "popcorn", "nuts", "trail mix", "granola bar",
-    "fruit", "apple", "banana", "bites",
-    "hummus", "guacamole", "salsa","dip",
-    "slices","grapes", "berries", "strawberries", "blueberries",
-    "raspberries", "blackberries", "melon", "watermelon", "cantaloupe", "pineapple",
-    "dried", "raisins", "apricots", "dates", "snacks",
-    "cookies", "biscotti", "shortbread","cookies", 
-    "truffles",
-    "chocolate","fudge",
-    "ice cream", "popsicle", "sorbet", "gelato", "milkshake",
-    "yogurt", "yoghurt", "pudding", "jello", "custard", "mousse",
-    "platter", "string cheese", "cubes", "cream", "spread",
-    "pickles", "olives", "jerky",
-    "smoothie", "protein shake", "juice", "vegetable",
-    "muesli", "overnight", "oats",
-    "sticks", "carrots", "celery", "cucumber", "cherry", "tomatoes", "peppers",
-    "peas", "broccoli", "florets", "cauliflower", "radish"
-]
-}   
Index: NutriMatch/Migrations/20250930183527_AddMealKeywordsTable.Designer.cs
===================================================================
--- NutriMatch/Migrations/20250930183527_AddMealKeywordsTable.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20250930183527_AddMealKeywordsTable.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,728 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20250930183527_AddMealKeywordsTable")]
+    partial class AddMealKeywordsTable
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20250930183527_AddMealKeywordsTable.cs
===================================================================
--- NutriMatch/Migrations/20250930183527_AddMealKeywordsTable.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20250930183527_AddMealKeywordsTable.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,36 @@
+﻿using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class AddMealKeywordsTable : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "MealKeywords",
+                columns: table => new
+                {
+                    Id = table.Column<int>(type: "integer", nullable: false)
+                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+                    Name = table.Column<string>(type: "text", nullable: false),
+                    Tag = table.Column<string>(type: "text", nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_MealKeywords", x => x.Id);
+                });
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "MealKeywords");
+        }
+    }
+}
Index: NutriMatch/Migrations/20251001131313_Notifications.Designer.cs
===================================================================
--- NutriMatch/Migrations/20251001131313_Notifications.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251001131313_Notifications.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,765 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20251001131313_Notifications")]
+    partial class Notifications
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RelatedUserId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20251001131313_Notifications.cs
===================================================================
--- NutriMatch/Migrations/20251001131313_Notifications.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251001131313_Notifications.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,42 @@
+﻿using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class Notifications : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "Notifications",
+                columns: table => new
+                {
+                    Id = table.Column<int>(type: "integer", nullable: false)
+                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+                    UserId = table.Column<string>(type: "text", nullable: false),
+                    Type = table.Column<string>(type: "text", nullable: false),
+                    Message = table.Column<string>(type: "text", nullable: false),
+                    RecipeId = table.Column<int>(type: "integer", nullable: true),
+                    RelatedUserId = table.Column<int>(type: "integer", nullable: true),
+                    IsRead = table.Column<bool>(type: "boolean", nullable: false),
+                    CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Notifications", x => x.Id);
+                });
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "Notifications");
+        }
+    }
+}
Index: NutriMatch/Migrations/20251001141545_Notification.Designer.cs
===================================================================
--- NutriMatch/Migrations/20251001141545_Notification.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251001141545_Notification.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,765 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20251001141545_Notification")]
+    partial class Notification
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RelatedUserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20251001141545_Notification.cs
===================================================================
--- NutriMatch/Migrations/20251001141545_Notification.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251001141545_Notification.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,36 @@
+﻿using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class Notification : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AlterColumn<string>(
+                name: "RelatedUserId",
+                table: "Notifications",
+                type: "text",
+                nullable: true,
+                oldClrType: typeof(int),
+                oldType: "integer",
+                oldNullable: true);
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AlterColumn<int>(
+                name: "RelatedUserId",
+                table: "Notifications",
+                type: "integer",
+                nullable: true,
+                oldClrType: typeof(string),
+                oldType: "text",
+                oldNullable: true);
+        }
+    }
+}
Index: NutriMatch/Migrations/20251003132037_AddRestaurantFollowingAndMealPreferences.Designer.cs
===================================================================
--- NutriMatch/Migrations/20251003132037_AddRestaurantFollowingAndMealPreferences.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251003132037_AddRestaurantFollowingAndMealPreferences.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,850 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20251003132037_AddRestaurantFollowingAndMealPreferences")]
+    partial class AddRestaurantFollowingAndMealPreferences
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RelatedUserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.HasIndex("UserId", "RestaurantId")
+                        .IsUnique();
+
+                    b.ToTable("RestaurantFollowings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "Tag")
+                        .IsUnique();
+
+                    b.ToTable("UserMealPreferences");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("Followers")
+                        .HasForeignKey("RestaurantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FollowedRestaurants")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Restaurant");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("MealTagPreferences")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("Followers");
+
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("FollowedRestaurants");
+
+                    b.Navigation("MealTagPreferences");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20251003132037_AddRestaurantFollowingAndMealPreferences.cs
===================================================================
--- NutriMatch/Migrations/20251003132037_AddRestaurantFollowingAndMealPreferences.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251003132037_AddRestaurantFollowingAndMealPreferences.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,88 @@
+﻿using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class AddRestaurantFollowingAndMealPreferences : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "RestaurantFollowings",
+                columns: table => new
+                {
+                    Id = table.Column<int>(type: "integer", nullable: false)
+                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+                    UserId = table.Column<string>(type: "text", nullable: false),
+                    RestaurantId = table.Column<int>(type: "integer", nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_RestaurantFollowings", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_RestaurantFollowings_AspNetUsers_UserId",
+                        column: x => x.UserId,
+                        principalTable: "AspNetUsers",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                    table.ForeignKey(
+                        name: "FK_RestaurantFollowings_Restaurants_RestaurantId",
+                        column: x => x.RestaurantId,
+                        principalTable: "Restaurants",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "UserMealPreferences",
+                columns: table => new
+                {
+                    Id = table.Column<int>(type: "integer", nullable: false)
+                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+                    UserId = table.Column<string>(type: "text", nullable: false),
+                    Tag = table.Column<string>(type: "text", nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_UserMealPreferences", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_UserMealPreferences_AspNetUsers_UserId",
+                        column: x => x.UserId,
+                        principalTable: "AspNetUsers",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_RestaurantFollowings_RestaurantId",
+                table: "RestaurantFollowings",
+                column: "RestaurantId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_RestaurantFollowings_UserId_RestaurantId",
+                table: "RestaurantFollowings",
+                columns: new[] { "UserId", "RestaurantId" },
+                unique: true);
+
+            migrationBuilder.CreateIndex(
+                name: "IX_UserMealPreferences_UserId_Tag",
+                table: "UserMealPreferences",
+                columns: new[] { "UserId", "Tag" },
+                unique: true);
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "RestaurantFollowings");
+
+            migrationBuilder.DropTable(
+                name: "UserMealPreferences");
+        }
+    }
+}
Index: NutriMatch/Migrations/20251004144331_AddThresholdValuesForPreferences.Designer.cs
===================================================================
--- NutriMatch/Migrations/20251004144331_AddThresholdValuesForPreferences.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251004144331_AddThresholdValuesForPreferences.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,853 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20251004144331_AddThresholdValuesForPreferences")]
+    partial class AddThresholdValuesForPreferences
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RelatedUserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.HasIndex("UserId", "RestaurantId")
+                        .IsUnique();
+
+                    b.ToTable("RestaurantFollowings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("ThresholdValue")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "Tag")
+                        .IsUnique();
+
+                    b.ToTable("UserMealPreferences");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("Followers")
+                        .HasForeignKey("RestaurantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FollowedRestaurants")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Restaurant");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("MealTagPreferences")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("Followers");
+
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("FollowedRestaurants");
+
+                    b.Navigation("MealTagPreferences");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20251004144331_AddThresholdValuesForPreferences.cs
===================================================================
--- NutriMatch/Migrations/20251004144331_AddThresholdValuesForPreferences.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251004144331_AddThresholdValuesForPreferences.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,28 @@
+﻿using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class AddThresholdValuesForPreferences : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<int>(
+                name: "ThresholdValue",
+                table: "UserMealPreferences",
+                type: "integer",
+                nullable: true);
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "ThresholdValue",
+                table: "UserMealPreferences");
+        }
+    }
+}
Index: NutriMatch/Migrations/20251004145314_AddRegeneratedRecipeIndicator.Designer.cs
===================================================================
--- NutriMatch/Migrations/20251004145314_AddRegeneratedRecipeIndicator.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251004145314_AddRegeneratedRecipeIndicator.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,856 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20251004145314_AddRegeneratedRecipeIndicator")]
+    partial class AddRegeneratedRecipeIndicator
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool?>("IsRegenerated")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RelatedUserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.HasIndex("UserId", "RestaurantId")
+                        .IsUnique();
+
+                    b.ToTable("RestaurantFollowings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("ThresholdValue")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "Tag")
+                        .IsUnique();
+
+                    b.ToTable("UserMealPreferences");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("Followers")
+                        .HasForeignKey("RestaurantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FollowedRestaurants")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Restaurant");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("MealTagPreferences")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("Followers");
+
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("FollowedRestaurants");
+
+                    b.Navigation("MealTagPreferences");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20251004145314_AddRegeneratedRecipeIndicator.cs
===================================================================
--- NutriMatch/Migrations/20251004145314_AddRegeneratedRecipeIndicator.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251004145314_AddRegeneratedRecipeIndicator.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,28 @@
+﻿using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class AddRegeneratedRecipeIndicator : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<bool>(
+                name: "IsRegenerated",
+                table: "MealSlots",
+                type: "boolean",
+                nullable: true);
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "IsRegenerated",
+                table: "MealSlots");
+        }
+    }
+}
Index: NutriMatch/Migrations/20251004145939_AddRegeneratedRecipeIndicator2.Designer.cs
===================================================================
--- NutriMatch/Migrations/20251004145939_AddRegeneratedRecipeIndicator2.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251004145939_AddRegeneratedRecipeIndicator2.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,859 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20251004145939_AddRegeneratedRecipeIndicator2")]
+    partial class AddRegeneratedRecipeIndicator2
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool?>("IsRegenerated")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.Property<bool?>("isViewed")
+                        .HasColumnType("boolean");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RelatedUserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.HasIndex("UserId", "RestaurantId")
+                        .IsUnique();
+
+                    b.ToTable("RestaurantFollowings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("ThresholdValue")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "Tag")
+                        .IsUnique();
+
+                    b.ToTable("UserMealPreferences");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("Followers")
+                        .HasForeignKey("RestaurantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FollowedRestaurants")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Restaurant");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("MealTagPreferences")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("Followers");
+
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("FollowedRestaurants");
+
+                    b.Navigation("MealTagPreferences");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20251004145939_AddRegeneratedRecipeIndicator2.cs
===================================================================
--- NutriMatch/Migrations/20251004145939_AddRegeneratedRecipeIndicator2.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251004145939_AddRegeneratedRecipeIndicator2.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,28 @@
+﻿using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class AddRegeneratedRecipeIndicator2 : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<bool>(
+                name: "isViewed",
+                table: "MealSlots",
+                type: "boolean",
+                nullable: true);
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "isViewed",
+                table: "MealSlots");
+        }
+    }
+}
Index: NutriMatch/Migrations/20251006204552_AddNotificationPreferences.Designer.cs
===================================================================
--- NutriMatch/Migrations/20251006204552_AddNotificationPreferences.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251006204552_AddNotificationPreferences.Designer.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,883 @@
+﻿// <auto-generated />
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using NutriMatch.Data;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    [DbContext(typeof(AppDbContext))]
+    [Migration("20251006204552_AddNotificationPreferences")]
+    partial class AddNotificationPreferences
+    {
+        /// <inheritdoc />
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "9.0.7")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedName")
+                        .IsUnique()
+                        .HasDatabaseName("RoleNameIndex");
+
+                    b.ToTable("AspNetRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetRoleClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("ClaimType")
+                        .HasColumnType("text");
+
+                    b.Property<string>("ClaimValue")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserClaims", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderKey")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("ProviderDisplayName")
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("LoginProvider", "ProviderKey");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("AspNetUserLogins", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("RoleId")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "RoleId");
+
+                    b.HasIndex("RoleId");
+
+                    b.ToTable("AspNetUserRoles", (string)null);
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("LoginProvider")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Name")
+                        .HasMaxLength(128)
+                        .HasColumnType("character varying(128)");
+
+                    b.Property<string>("Value")
+                        .HasColumnType("text");
+
+                    b.HasKey("UserId", "LoginProvider", "Name");
+
+                    b.ToTable("AspNetUserTokens", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.Property<string>("UserId")
+                        .HasColumnType("text");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("UserId", "RecipeId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("FavoriteRecipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("Status")
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Ingredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Day")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<bool?>("IsRegenerated")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("IsRestaurantMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("MealType")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("RestaurantMealId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("WeeklyMealPlanId")
+                        .HasColumnType("integer");
+
+                    b.Property<bool?>("isViewed")
+                        .HasColumnType("boolean");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("RestaurantMealId");
+
+                    b.HasIndex("WeeklyMealPlanId");
+
+                    b.ToTable("MealSlots");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RelatedUserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("DeclineReason")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<bool?>("HasPendingIngredients")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<string[]>("Instructions")
+                        .HasColumnType("text[]");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<string>("RecipeStatus")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("IngredientId")
+                        .HasColumnType("integer");
+
+                    b.Property<float>("Quantity")
+                        .HasColumnType("real");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Unit")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IngredientId");
+
+                    b.HasIndex("RecipeId");
+
+                    b.ToTable("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<double>("Rating")
+                        .HasColumnType("double precision");
+
+                    b.Property<int>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RecipeId");
+
+                    b.HasIndex("UserId", "RecipeId")
+                        .IsUnique();
+
+                    b.ToTable("RecipeRatings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Description")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ImageUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Restaurants");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.HasIndex("UserId", "RestaurantId")
+                        .IsUnique();
+
+                    b.ToTable("RestaurantFollowings");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Fat")
+                        .HasColumnType("real");
+
+                    b.Property<string>("ItemDescription")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("ItemName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Protein")
+                        .HasColumnType("real");
+
+                    b.Property<int?>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RestaurantName")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.PrimitiveCollection<List<string>>("Type")
+                        .IsRequired()
+                        .HasColumnType("text[]");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.ToTable("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Property<string>("Id")
+                        .HasColumnType("text");
+
+                    b.Property<int>("AccessFailedCount")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("ConcurrencyStamp")
+                        .IsConcurrencyToken()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("EmailConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("LockoutEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<DateTimeOffset?>("LockoutEnd")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("NormalizedEmail")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<string>("NormalizedUserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("NotifyMealMatchesTags")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyMealPlanUpdated")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyNewRestaurant")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeAccepted")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeDeclined")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeMatchesTags")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeRated")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRestaurantNewMeal")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("PasswordHash")
+                        .HasColumnType("text");
+
+                    b.Property<string>("PhoneNumber")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("PhoneNumberConfirmed")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("ProfilePictureUrl")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("SecurityStamp")
+                        .HasColumnType("text");
+
+                    b.Property<bool>("TwoFactorEnabled")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("UserName")
+                        .HasMaxLength(256)
+                        .HasColumnType("character varying(256)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("NormalizedEmail")
+                        .HasDatabaseName("EmailIndex");
+
+                    b.HasIndex("NormalizedUserName")
+                        .IsUnique()
+                        .HasDatabaseName("UserNameIndex");
+
+                    b.ToTable("AspNetUsers", (string)null);
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("ThresholdValue")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "Tag")
+                        .IsUnique();
+
+                    b.ToTable("UserMealPreferences");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<DateTime>("GeneratedAt")
+                        .HasColumnType("timestamp with time zone");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("WeeklyMealPlans");
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
+                {
+                    b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
+                        .WithMany()
+                        .HasForeignKey("RoleId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", null)
+                        .WithMany()
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("FavoritedBy")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FavoriteRecipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany()
+                        .HasForeignKey("RecipeId");
+
+                    b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
+                        .WithMany()
+                        .HasForeignKey("RestaurantMealId");
+
+                    b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
+                        .WithMany("MealSlots")
+                        .HasForeignKey("WeeklyMealPlanId");
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("RestaurantMeal");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Recipes")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Ingredient", "Ingredient")
+                        .WithMany()
+                        .HasForeignKey("IngredientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.Recipe", null)
+                        .WithMany("RecipeIngredients")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Ingredient");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Recipe", "Recipe")
+                        .WithMany("Ratings")
+                        .HasForeignKey("RecipeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("Ratings")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Recipe");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("Followers")
+                        .HasForeignKey("RestaurantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FollowedRestaurants")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Restaurant");
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("RestaurantMeals")
+                        .HasForeignKey("RestaurantId");
+
+                    b.Navigation("Restaurant");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("MealTagPreferences")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Navigation("FavoritedBy");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("RecipeIngredients");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
+                {
+                    b.Navigation("Followers");
+
+                    b.Navigation("RestaurantMeals");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.User", b =>
+                {
+                    b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("FollowedRestaurants");
+
+                    b.Navigation("MealTagPreferences");
+
+                    b.Navigation("Ratings");
+
+                    b.Navigation("Recipes");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
+                {
+                    b.Navigation("MealSlots");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
Index: NutriMatch/Migrations/20251006204552_AddNotificationPreferences.cs
===================================================================
--- NutriMatch/Migrations/20251006204552_AddNotificationPreferences.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Migrations/20251006204552_AddNotificationPreferences.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,106 @@
+﻿using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace NutriMatch.Migrations
+{
+    /// <inheritdoc />
+    public partial class AddNotificationPreferences : Migration
+    {
+        /// <inheritdoc />
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyMealMatchesTags",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyMealPlanUpdated",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyNewRestaurant",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyRecipeAccepted",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyRecipeDeclined",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyRecipeMatchesTags",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyRecipeRated",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+
+            migrationBuilder.AddColumn<bool>(
+                name: "NotifyRestaurantNewMeal",
+                table: "AspNetUsers",
+                type: "boolean",
+                nullable: false,
+                defaultValue: false);
+        }
+
+        /// <inheritdoc />
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "NotifyMealMatchesTags",
+                table: "AspNetUsers");
+
+            migrationBuilder.DropColumn(
+                name: "NotifyMealPlanUpdated",
+                table: "AspNetUsers");
+
+            migrationBuilder.DropColumn(
+                name: "NotifyNewRestaurant",
+                table: "AspNetUsers");
+
+            migrationBuilder.DropColumn(
+                name: "NotifyRecipeAccepted",
+                table: "AspNetUsers");
+
+            migrationBuilder.DropColumn(
+                name: "NotifyRecipeDeclined",
+                table: "AspNetUsers");
+
+            migrationBuilder.DropColumn(
+                name: "NotifyRecipeMatchesTags",
+                table: "AspNetUsers");
+
+            migrationBuilder.DropColumn(
+                name: "NotifyRecipeRated",
+                table: "AspNetUsers");
+
+            migrationBuilder.DropColumn(
+                name: "NotifyRestaurantNewMeal",
+                table: "AspNetUsers");
+        }
+    }
+}
Index: NutriMatch/Migrations/AppDbContextModelSnapshot.cs
===================================================================
--- NutriMatch/Migrations/AppDbContextModelSnapshot.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Migrations/AppDbContextModelSnapshot.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -7,5 +7,7 @@
 using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
 using NutriMatch.Data;
+
 #nullable disable
+
 namespace NutriMatch.Migrations
 {
@@ -19,24 +21,33 @@
                 .HasAnnotation("ProductVersion", "9.0.7")
                 .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
             NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
                 {
                     b.Property<string>("Id")
                         .HasColumnType("text");
+
                     b.Property<string>("ConcurrencyStamp")
                         .IsConcurrencyToken()
                         .HasColumnType("text");
+
                     b.Property<string>("Name")
                         .HasMaxLength(256)
                         .HasColumnType("character varying(256)");
+
                     b.Property<string>("NormalizedName")
                         .HasMaxLength(256)
                         .HasColumnType("character varying(256)");
-                    b.HasKey("Id");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("NormalizedName")
                         .IsUnique()
                         .HasDatabaseName("RoleNameIndex");
+
                     b.ToTable("AspNetRoles", (string)null);
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
                 {
@@ -44,16 +55,24 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<string>("ClaimType")
                         .HasColumnType("text");
+
                     b.Property<string>("ClaimValue")
                         .HasColumnType("text");
+
                     b.Property<string>("RoleId")
                         .IsRequired()
                         .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("RoleId");
+
                     b.ToTable("AspNetRoleClaims", (string)null);
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
                 {
@@ -61,16 +80,24 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<string>("ClaimType")
                         .HasColumnType("text");
+
                     b.Property<string>("ClaimValue")
                         .HasColumnType("text");
-                    b.Property<string>("UserId")
-                        .IsRequired()
-                        .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("UserId");
+
                     b.ToTable("AspNetUserClaims", (string)null);
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
                 {
@@ -78,51 +105,74 @@
                         .HasMaxLength(128)
                         .HasColumnType("character varying(128)");
+
                     b.Property<string>("ProviderKey")
                         .HasMaxLength(128)
                         .HasColumnType("character varying(128)");
+
                     b.Property<string>("ProviderDisplayName")
                         .HasColumnType("text");
-                    b.Property<string>("UserId")
-                        .IsRequired()
-                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
                     b.HasKey("LoginProvider", "ProviderKey");
+
                     b.HasIndex("UserId");
+
                     b.ToTable("AspNetUserLogins", (string)null);
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
                 {
                     b.Property<string>("UserId")
                         .HasColumnType("text");
+
                     b.Property<string>("RoleId")
                         .HasColumnType("text");
+
                     b.HasKey("UserId", "RoleId");
+
                     b.HasIndex("RoleId");
+
                     b.ToTable("AspNetUserRoles", (string)null);
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
                 {
                     b.Property<string>("UserId")
                         .HasColumnType("text");
+
                     b.Property<string>("LoginProvider")
                         .HasMaxLength(128)
                         .HasColumnType("character varying(128)");
+
                     b.Property<string>("Name")
                         .HasMaxLength(128)
                         .HasColumnType("character varying(128)");
+
                     b.Property<string>("Value")
                         .HasColumnType("text");
+
                     b.HasKey("UserId", "LoginProvider", "Name");
+
                     b.ToTable("AspNetUserTokens", (string)null);
                 });
+
             modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
                 {
                     b.Property<string>("UserId")
                         .HasColumnType("text");
+
                     b.Property<int>("RecipeId")
                         .HasColumnType("integer");
+
                     b.HasKey("UserId", "RecipeId");
+
                     b.HasIndex("RecipeId");
+
                     b.ToTable("FavoriteRecipes");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.Ingredient", b =>
                 {
@@ -130,21 +180,52 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<float>("Calories")
                         .HasColumnType("real");
+
                     b.Property<float>("Carbs")
                         .HasColumnType("real");
+
                     b.Property<float>("Fat")
                         .HasColumnType("real");
+
                     b.Property<string>("Name")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<float>("Protein")
                         .HasColumnType("real");
+
                     b.Property<string>("Status")
                         .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.HasKey("Id");
+
                     b.ToTable("Ingredients");
                 });
+
+            modelBuilder.Entity("NutriMatch.Models.MealKeyword", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("MealKeywords");
+                });
+
             modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
                 {
@@ -152,70 +233,145 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<string>("Day")
                         .IsRequired()
                         .HasColumnType("text");
+
+                    b.Property<bool?>("IsRegenerated")
+                        .HasColumnType("boolean");
+
                     b.Property<bool>("IsRestaurantMeal")
                         .HasColumnType("boolean");
+
                     b.Property<string>("MealType")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<int?>("RecipeId")
                         .HasColumnType("integer");
+
                     b.Property<int?>("RestaurantMealId")
                         .HasColumnType("integer");
+
                     b.Property<int?>("WeeklyMealPlanId")
                         .HasColumnType("integer");
-                    b.HasKey("Id");
+
+                    b.Property<bool?>("isViewed")
+                        .HasColumnType("boolean");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("RecipeId");
+
                     b.HasIndex("RestaurantMealId");
+
                     b.HasIndex("WeeklyMealPlanId");
+
                     b.ToTable("MealSlots");
                 });
-            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
-                {
-                    b.Property<int>("Id")
-                        .ValueGeneratedOnAdd()
-                        .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
-                    b.Property<string>("AdminComment")
-                        .IsRequired()
-                        .HasColumnType("text");
-                    b.Property<float>("Calories")
-                        .HasColumnType("real");
-                    b.Property<float>("Carbs")
-                        .HasColumnType("real");
+
+            modelBuilder.Entity("NutriMatch.Models.Notification", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<DateTime>("CreatedAt")
                         .HasColumnType("timestamp with time zone");
+
+                    b.Property<bool>("IsRead")
+                        .HasColumnType("boolean");
+
+                    b.Property<string>("Message")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("RecipeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("RelatedUserId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Notifications");
+                });
+
+            modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("AdminComment")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<float>("Calories")
+                        .HasColumnType("real");
+
+                    b.Property<float>("Carbs")
+                        .HasColumnType("real");
+
+                    b.Property<DateTime>("CreatedAt")
+                        .HasColumnType("timestamp with time zone");
+
                     b.Property<string>("DeclineReason")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<float>("Fat")
                         .HasColumnType("real");
+
                     b.Property<bool?>("HasPendingIngredients")
                         .HasColumnType("boolean");
+
                     b.Property<string>("ImageUrl")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.PrimitiveCollection<string[]>("Instructions")
                         .HasColumnType("text[]");
+
                     b.Property<float>("Protein")
                         .HasColumnType("real");
+
                     b.Property<string>("RecipeStatus")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<string>("Title")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.PrimitiveCollection<List<string>>("Type")
                         .IsRequired()
                         .HasColumnType("text[]");
-                    b.Property<string>("UserId")
-                        .IsRequired()
-                        .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("UserId");
+
                     b.ToTable("Recipes");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
                 {
@@ -223,19 +379,29 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<int>("IngredientId")
                         .HasColumnType("integer");
+
                     b.Property<float>("Quantity")
                         .HasColumnType("real");
+
                     b.Property<int>("RecipeId")
                         .HasColumnType("integer");
+
                     b.Property<string>("Unit")
                         .IsRequired()
                         .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("IngredientId");
+
                     b.HasIndex("RecipeId");
+
                     b.ToTable("RecipeIngredients");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
                 {
@@ -243,18 +409,27 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<double>("Rating")
                         .HasColumnType("double precision");
+
                     b.Property<int>("RecipeId")
                         .HasColumnType("integer");
-                    b.Property<string>("UserId")
-                        .IsRequired()
-                        .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("RecipeId");
+
                     b.HasIndex("UserId", "RecipeId")
                         .IsUnique();
+
                     b.ToTable("RecipeRatings");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
                 {
@@ -262,17 +437,49 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<string>("Description")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<string>("ImageUrl")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<string>("Name")
                         .IsRequired()
                         .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.HasKey("Id");
+
                     b.ToTable("Restaurants");
                 });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<int>("RestaurantId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("RestaurantId");
+
+                    b.HasIndex("UserId", "RestaurantId")
+                        .IsUnique();
+
+                    b.ToTable("RestaurantFollowings");
+                });
+
             modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
                 {
@@ -280,79 +487,164 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<float>("Calories")
                         .HasColumnType("real");
+
                     b.Property<float>("Carbs")
                         .HasColumnType("real");
+
                     b.Property<float>("Fat")
                         .HasColumnType("real");
+
                     b.Property<string>("ItemDescription")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<string>("ItemName")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<float>("Protein")
                         .HasColumnType("real");
+
                     b.Property<int?>("RestaurantId")
                         .HasColumnType("integer");
+
                     b.Property<string>("RestaurantName")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.PrimitiveCollection<List<string>>("Type")
                         .IsRequired()
                         .HasColumnType("text[]");
-                    b.HasKey("Id");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("RestaurantId");
+
                     b.ToTable("RestaurantMeals");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.User", b =>
                 {
                     b.Property<string>("Id")
                         .HasColumnType("text");
+
                     b.Property<int>("AccessFailedCount")
                         .HasColumnType("integer");
+
                     b.Property<string>("ConcurrencyStamp")
                         .IsConcurrencyToken()
                         .HasColumnType("text");
+
                     b.Property<string>("Email")
                         .HasMaxLength(256)
                         .HasColumnType("character varying(256)");
+
                     b.Property<bool>("EmailConfirmed")
                         .HasColumnType("boolean");
+
                     b.Property<bool>("LockoutEnabled")
                         .HasColumnType("boolean");
+
                     b.Property<DateTimeOffset?>("LockoutEnd")
                         .HasColumnType("timestamp with time zone");
+
                     b.Property<string>("NormalizedEmail")
                         .HasMaxLength(256)
                         .HasColumnType("character varying(256)");
+
                     b.Property<string>("NormalizedUserName")
                         .HasMaxLength(256)
                         .HasColumnType("character varying(256)");
+
+                    b.Property<bool>("NotifyMealMatchesTags")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyMealPlanUpdated")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyNewRestaurant")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeAccepted")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeDeclined")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeMatchesTags")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRecipeRated")
+                        .HasColumnType("boolean");
+
+                    b.Property<bool>("NotifyRestaurantNewMeal")
+                        .HasColumnType("boolean");
+
                     b.Property<string>("PasswordHash")
                         .HasColumnType("text");
+
                     b.Property<string>("PhoneNumber")
                         .HasColumnType("text");
+
                     b.Property<bool>("PhoneNumberConfirmed")
                         .HasColumnType("boolean");
+
                     b.Property<string>("ProfilePictureUrl")
                         .IsRequired()
                         .HasColumnType("text");
+
                     b.Property<string>("SecurityStamp")
                         .HasColumnType("text");
+
                     b.Property<bool>("TwoFactorEnabled")
                         .HasColumnType("boolean");
+
                     b.Property<string>("UserName")
                         .HasMaxLength(256)
                         .HasColumnType("character varying(256)");
-                    b.HasKey("Id");
+
+                    b.HasKey("Id");
+
                     b.HasIndex("NormalizedEmail")
                         .HasDatabaseName("EmailIndex");
+
                     b.HasIndex("NormalizedUserName")
                         .IsUnique()
                         .HasDatabaseName("UserNameIndex");
+
                     b.ToTable("AspNetUsers", (string)null);
                 });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer");
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    b.Property<string>("Tag")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.Property<int?>("ThresholdValue")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "Tag")
+                        .IsUnique();
+
+                    b.ToTable("UserMealPreferences");
+                });
+
             modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
                 {
@@ -360,13 +652,19 @@
                         .ValueGeneratedOnAdd()
                         .HasColumnType("integer");
-                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
+                    NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
+
                     b.Property<DateTime>("GeneratedAt")
                         .HasColumnType("timestamp with time zone");
-                    b.Property<string>("UserId")
-                        .IsRequired()
-                        .HasColumnType("text");
-                    b.HasKey("Id");
+
+                    b.Property<string>("UserId")
+                        .IsRequired()
+                        .HasColumnType("text");
+
+                    b.HasKey("Id");
+
                     b.ToTable("WeeklyMealPlans");
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
                 {
@@ -377,4 +675,5 @@
                         .IsRequired();
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
                 {
@@ -385,4 +684,5 @@
                         .IsRequired();
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
                 {
@@ -393,4 +693,5 @@
                         .IsRequired();
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
                 {
@@ -400,4 +701,5 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.HasOne("NutriMatch.Models.User", null)
                         .WithMany()
@@ -406,4 +708,5 @@
                         .IsRequired();
                 });
+
             modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
                 {
@@ -414,4 +717,5 @@
                         .IsRequired();
                 });
+
             modelBuilder.Entity("NutriMatch.Models.FavoriteRecipe", b =>
                 {
@@ -421,4 +725,5 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.HasOne("NutriMatch.Models.User", "User")
                         .WithMany("FavoriteRecipes")
@@ -426,7 +731,10 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.Navigation("Recipe");
+
                     b.Navigation("User");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.MealSlot", b =>
                 {
@@ -434,13 +742,18 @@
                         .WithMany()
                         .HasForeignKey("RecipeId");
+
                     b.HasOne("NutriMatch.Models.RestaurantMeal", "RestaurantMeal")
                         .WithMany()
                         .HasForeignKey("RestaurantMealId");
+
                     b.HasOne("NutriMatch.Models.WeeklyMealPlan", null)
                         .WithMany("MealSlots")
                         .HasForeignKey("WeeklyMealPlanId");
+
                     b.Navigation("Recipe");
+
                     b.Navigation("RestaurantMeal");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
                 {
@@ -450,6 +763,8 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.Navigation("User");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.RecipeIngredient", b =>
                 {
@@ -459,4 +774,5 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.HasOne("NutriMatch.Models.Recipe", null)
                         .WithMany("RecipeIngredients")
@@ -464,6 +780,8 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.Navigation("Ingredient");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.RecipeRating", b =>
                 {
@@ -473,4 +791,5 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.HasOne("NutriMatch.Models.User", "User")
                         .WithMany("Ratings")
@@ -478,7 +797,29 @@
                         .OnDelete(DeleteBehavior.Cascade)
                         .IsRequired();
+
                     b.Navigation("Recipe");
+
                     b.Navigation("User");
                 });
+
+            modelBuilder.Entity("NutriMatch.Models.RestaurantFollowing", b =>
+                {
+                    b.HasOne("NutriMatch.Models.Restaurant", "Restaurant")
+                        .WithMany("Followers")
+                        .HasForeignKey("RestaurantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("FollowedRestaurants")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("Restaurant");
+
+                    b.Navigation("User");
+                });
+
             modelBuilder.Entity("NutriMatch.Models.RestaurantMeal", b =>
                 {
@@ -486,22 +827,48 @@
                         .WithMany("RestaurantMeals")
                         .HasForeignKey("RestaurantId");
+
                     b.Navigation("Restaurant");
                 });
+
+            modelBuilder.Entity("NutriMatch.Models.UserMealPreference", b =>
+                {
+                    b.HasOne("NutriMatch.Models.User", "User")
+                        .WithMany("MealTagPreferences")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.Navigation("User");
+                });
+
             modelBuilder.Entity("NutriMatch.Models.Recipe", b =>
                 {
                     b.Navigation("FavoritedBy");
+
                     b.Navigation("Ratings");
+
                     b.Navigation("RecipeIngredients");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.Restaurant", b =>
                 {
+                    b.Navigation("Followers");
+
                     b.Navigation("RestaurantMeals");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.User", b =>
                 {
                     b.Navigation("FavoriteRecipes");
+
+                    b.Navigation("FollowedRestaurants");
+
+                    b.Navigation("MealTagPreferences");
+
                     b.Navigation("Ratings");
+
                     b.Navigation("Recipes");
                 });
+
             modelBuilder.Entity("NutriMatch.Models.WeeklyMealPlan", b =>
                 {
Index: NutriMatch/Models/MealKeyword.cs
===================================================================
--- NutriMatch/Models/MealKeyword.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Models/MealKeyword.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,9 @@
+namespace NutriMatch.Models
+{
+    public class MealKeyword
+    {
+        public int Id { get; set; }
+        public string Name { get; set; } = string.Empty;
+        public string Tag { get; set; } = string.Empty;
+    }
+}
Index: NutriMatch/Models/MealSlot.cs
===================================================================
--- NutriMatch/Models/MealSlot.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Models/MealSlot.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -12,4 +12,8 @@
         public RestaurantMeal? RestaurantMeal { get; set; }
         public bool IsRestaurantMeal { get; set; }
+
+        public bool? IsRegenerated { get; set; } = false;
+        
+        public bool? isViewed { get; set; } = false;
     }
 }
Index: NutriMatch/Models/Notification.cs
===================================================================
--- NutriMatch/Models/Notification.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Models/Notification.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,14 @@
+namespace NutriMatch.Models
+{
+    public class Notification
+    {
+        public int Id { get; set; }
+        public string UserId { get; set; }
+        public string Type { get; set; }
+        public string Message { get; set; }
+        public int? RecipeId { get; set; }
+        public string? RelatedUserId { get; set; }
+        public bool IsRead { get; set; }
+        public DateTime CreatedAt { get; set; }
+    }
+}
Index: NutriMatch/Models/Restaurant.cs
===================================================================
--- NutriMatch/Models/Restaurant.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Models/Restaurant.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -15,4 +15,6 @@
 
         virtual public List<RestaurantMeal> RestaurantMeals { get; set; }
+
+        public virtual ICollection<RestaurantFollowing> Followers { get; set; }
     }
 }
Index: NutriMatch/Models/RestaurantFollowing.cs
===================================================================
--- NutriMatch/Models/RestaurantFollowing.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Models/RestaurantFollowing.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,12 @@
+
+namespace NutriMatch.Models
+{
+    public class RestaurantFollowing
+    {
+        public int Id { get; set; }
+        public string UserId { get; set; }
+        public virtual User User { get; set; }
+        public int RestaurantId { get; set; }
+        public virtual Restaurant Restaurant { get; set; }
+    }
+}
Index: NutriMatch/Models/User.cs
===================================================================
--- NutriMatch/Models/User.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Models/User.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -14,5 +14,15 @@
         public ICollection<FavoriteRecipe> FavoriteRecipes { get; set; }
         public ICollection<RecipeRating> Ratings { get; set; }
-        
+        public ICollection<UserMealPreference> MealTagPreferences { get; set; }
+        public ICollection<RestaurantFollowing> FollowedRestaurants { get; set; }
+
+        public bool NotifyRecipeRated { get; set; } = true;
+        public bool NotifyRecipeAccepted { get; set; } = true;
+        public bool NotifyRecipeDeclined { get; set; } = true;
+        public bool NotifyRestaurantNewMeal { get; set; } = true;
+        public bool NotifyMealMatchesTags { get; set; } = true;
+        public bool NotifyRecipeMatchesTags { get; set; } = true;
+        public bool NotifyNewRestaurant { get; set; } = true;
+        public bool NotifyMealPlanUpdated { get; set; } = true;
     }
 }
Index: NutriMatch/Models/UserMealPreference.cs
===================================================================
--- NutriMatch/Models/UserMealPreference.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Models/UserMealPreference.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,12 @@
+
+namespace NutriMatch.Models
+{
+    public class UserMealPreference
+    {
+        public int Id { get; set; }
+        public string UserId { get; set; }
+        public virtual User User { get; set; }
+        public string Tag { get; set; }
+        public int? ThresholdValue { get; set; }
+    }
+}
Index: NutriMatch/NutriMatch.csproj
===================================================================
--- NutriMatch/NutriMatch.csproj	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/NutriMatch.csproj	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -9,4 +9,6 @@
   <ItemGroup>
     <PackageReference Include="Microsoft.AspNet.Identity.EntityFramework" Version="2.2.4" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="9.0.9" />
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.9" />
     <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.7" />
     <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="9.0.7" />
Index: NutriMatch/Program.cs
===================================================================
--- NutriMatch/Program.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Program.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -4,4 +4,5 @@
 using Microsoft.AspNetCore.Identity;
 using NutriMatch.Services;
+
 
 var builder = WebApplication.CreateBuilder(args);
@@ -11,7 +12,36 @@
 builder.Services.AddRazorPages();
 builder.Services.AddScoped<IMealPlanService, MealPlanService>();
+builder.Services.AddScoped<IRestaurantService, RestaurantService>();
+builder.Services.AddScoped<IMealClassificationService, MealClassificationService>();
+builder.Services.AddScoped<IUserPreferenceService, UserPreferenceService>();
+builder.Services.AddScoped<INotificationService, NotificationService>();
+builder.Services.AddScoped<IRecipeService, RecipeService>();
+builder.Services.AddScoped<IRecipeTagService, RecipeTagService>();
+builder.Services.AddScoped<IRatingService, RatingService>();
+builder.Services.AddScoped<IIngredientService, IngredientService>();
+builder.Services.AddScoped<IFileUploadService, FileUploadService>();
+builder.Services.AddScoped<IRecipeApprovalService, RecipeApprovalService>();
+builder.Services.AddScoped<IMealKeywordService, MealKeywordService>();
+
+
+
+
 
 builder.Services.AddDbContext<AppDbContext>(options =>
     options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
+
+builder.Services.AddAuthentication()
+    .AddGoogle(options =>
+    {
+        options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
+        options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
+        options.SaveTokens = true;
+    })
+    .AddFacebook(options =>
+    {
+        options.AppId = builder.Configuration["Authentication:Facebook:AppId"];
+        options.AppSecret = builder.Configuration["Authentication:Facebook:AppSecret"];
+        options.SaveTokens = true;
+    });
 
 builder.Services.AddDefaultIdentity<User>(options =>
Index: NutriMatch/Services/FileUploadService.cs
===================================================================
--- NutriMatch/Services/FileUploadService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/FileUploadService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,69 @@
+    using System;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+
+namespace NutriMatch.Services
+{
+    public class FileUploadService : IFileUploadService
+    {
+        private readonly ILogger<FileUploadService> _logger;
+
+        public FileUploadService(ILogger<FileUploadService> logger)
+        {
+            _logger = logger;
+        }
+
+        public async Task<string> UploadImageAsync(IFormFile file)
+        {
+            if (file == null || file.Length == 0)
+            {
+                return null;
+            }
+
+            var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images");
+            
+            // Ensure directory exists
+            if (!Directory.Exists(uploadsFolder))
+            {
+                Directory.CreateDirectory(uploadsFolder);
+            }
+
+            var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
+            var filePath = Path.Combine(uploadsFolder, uniqueFileName);
+
+            using (var stream = new FileStream(filePath, FileMode.Create))
+            {
+                await file.CopyToAsync(stream);
+            }
+
+            return "/images/" + uniqueFileName;
+        }
+
+        public async Task DeleteImageAsync(string imageUrl)
+        {
+            if (string.IsNullOrEmpty(imageUrl))
+            {
+                return;
+            }
+
+            var imagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", imageUrl.TrimStart('/'));
+            
+            if (File.Exists(imagePath))
+            {
+                try
+                {
+                    await Task.Run(() => File.Delete(imagePath));
+                }
+                catch (Exception ex)
+                {
+                    _logger.LogError(ex, $"Failed to delete image file: {imagePath}");
+                }
+            }
+        }
+
+
+
+    }
+}
Index: triMatch/Services/IMealPlanService.cs
===================================================================
--- NutriMatch/Services/IMealPlanService.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ 	(revision )
@@ -1,12 +1,0 @@
-using NutriMatch.Models;
-
-namespace NutriMatch.Services
-{
-    public interface IMealPlanService
-    {
-        Task<MealPlanResult> GenerateWeeklyMealPlanAsync(string userId, MealPlanRequest request);
-        Task<WeeklyMealPlan> GetMealPlanByIdAsync(int id, string userId);
-        Task<List<WeeklyMealPlan>> GetUserMealPlansAsync(string userId);
-        Task<bool> DeleteMealPlanAsync(int id, string userId);
-    }
-}
Index: NutriMatch/Services/IngredientService.cs
===================================================================
--- NutriMatch/Services/IngredientService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/IngredientService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using NutriMatch.Data;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public class IngredientService : IIngredientService
+    {
+        private readonly AppDbContext _context;
+
+        public IngredientService(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        public async Task<List<Ingredient>> GetIngredientSuggestionsAsync(string query)
+        {
+            return await _context.Ingredients
+                .Where(i => EF.Functions.ILike(i.Name, $"%{query}%") && i.Status == null)
+                .OrderBy(i => i.Name)
+                .Take(5)
+                .ToListAsync();
+        }
+
+        public async Task<(bool success, string message, Ingredient ingredient)> AddIngredientAsync(string name, float calories, float protein, float carbs, float fat)
+        {
+            if (string.IsNullOrWhiteSpace(name))
+            {
+                return (false, "Ingredient name is required.", null);
+            }
+
+            var existingIngredient = await _context.Ingredients
+                .FirstOrDefaultAsync(i => i.Name.ToLower() == name.ToLower());
+
+            if (existingIngredient != null)
+            {
+                return (false, "An ingredient with this name already exists.", null);
+            }
+
+            var ingredient = new Ingredient
+            {
+                Name = name.Trim(),
+                Calories = calories,
+                Protein = protein,
+                Carbs = carbs,
+                Fat = fat,
+                Status = "Pending"
+            };
+
+            _context.Ingredients.Add(ingredient);
+            await _context.SaveChangesAsync();
+
+            return (true, "Ingredient added successfully", ingredient);
+        }
+    }
+}
Index: NutriMatch/Services/Interfaces/IFileUploadService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IFileUploadService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IFileUploadService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,11 @@
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+
+namespace NutriMatch.Services
+{
+    public interface IFileUploadService
+    {
+        Task<string> UploadImageAsync(IFormFile file);
+        Task DeleteImageAsync(string imageUrl);
+    }
+}
Index: NutriMatch/Services/Interfaces/IIngredientService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IIngredientService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IIngredientService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IIngredientService
+    {
+        Task<List<Ingredient>> GetIngredientSuggestionsAsync(string query);
+        Task<(bool success, string message, Ingredient ingredient)> AddIngredientAsync(string name, float calories, float protein, float carbs, float fat);
+    }
+}
Index: NutriMatch/Services/Interfaces/IMealClassificationService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IMealClassificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IMealClassificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IMealClassificationService
+    {
+        
+        Task<List<string>> GenerateMealTypes(RestaurantMeal meal);
+    }
+}
Index: NutriMatch/Services/Interfaces/IMealKeywordService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IMealKeywordService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IMealKeywordService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,12 @@
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IMealKeywordService
+    {
+        Task<List<MealKeyword>> GetMealKeywordsAsync();
+        Task<Dictionary<string, List<string>>> GetKeywordsByTagAsync();
+        Task<(bool success, string message)> AddMealKeywordAsync(MealKeyword keyword);
+        Task<(bool success, string message)> DeleteMealKeywordAsync(int id);
+    }
+}
Index: NutriMatch/Services/Interfaces/IMealPlanService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IMealPlanService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IMealPlanService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,16 @@
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IMealPlanService
+    {
+        Task<MealPlanResult> GenerateWeeklyMealPlanAsync(string userId, MealPlanRequest request);
+        Task<WeeklyMealPlan> GetMealPlanByIdAsync(int id, string userId);
+        Task<List<WeeklyMealPlan>> GetUserMealPlansAsync(string userId);
+        Task<bool> DeleteMealPlanAsync(int id, string userId);
+
+         Task<bool> RegenerateMealSlotAsync(int mealSlotId, string userId);
+        Task HandleDeletedRecipeAsync(int recipeId);
+        Task HandleDeletedRestaurantMealAsync(int restaurantMealId);
+    }
+}
Index: NutriMatch/Services/Interfaces/INotificationService.cs
===================================================================
--- NutriMatch/Services/Interfaces/INotificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/INotificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,17 @@
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface INotificationService
+    {
+        Task<(List<Notification> notifications, int unreadCount)> GetNotificationsAsync(string userId);
+        Task<List<Notification>> GetAllNotificationsAsync(string userId);
+        Task<(bool success, int unreadCount)> MarkAsReadAsync(int notificationId, string userId);
+        Task<bool> MarkAllAsReadAsync(string userId);
+        Task<(bool success, int unreadCount)> DeleteAsync(int notificationId, string userId);
+        Task<(bool success, string message)> DeleteAllAsync(string userId);
+        Task<int> GetUnreadCountAsync(string userId);
+        Task<Notification?> GetLatestNotificationAsync(string userId);
+        Task SendEmailAsync(string toEmail, string subject, string message);
+    }
+}
Index: NutriMatch/Services/Interfaces/IRatingService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IRatingService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IRatingService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+
+namespace NutriMatch.Services
+{
+    public interface IRatingService
+    {
+        Task<(bool success, string message, double averageRating, int totalRatings)> AddOrUpdateRatingAsync(string userId, int recipeId, double rating);
+        Task<(bool success, string message, double averageRating, int totalRatings)> RemoveRatingAsync(string userId, int recipeId);
+    }
+}
Index: NutriMatch/Services/Interfaces/IRecipeApprovalService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IRecipeApprovalService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IRecipeApprovalService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,13 @@
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IRecipeApprovalService
+    {
+        Task<List<Recipe>> GetPendingRecipesAsync();
+        Task<(bool success, string message)> ApproveRecipeAsync(int recipeId);
+        Task<(bool success, string message)> DeclineRecipeAsync(int recipeId, string reason, string notes);
+        Task<(bool success, string message, int approvedCount)> BulkApproveRecipesAsync(List<int> recipeIds);
+        Task<Recipe?> GetRecipeForDeclineAsync(int recipeId);
+    }
+}
Index: NutriMatch/Services/Interfaces/IRecipeService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IRecipeService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IRecipeService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IRecipeService
+    {
+        Task<(List<Recipe> recipes, int totalRecipes)> GetPaginatedRecipesAsync(int page, int pageSize);
+        Task<List<int>> GetUserFavoriteRecipeIdsAsync(string userId);
+        Task<Recipe> GetRecipeByIdAsync(int id);
+        Task<(double averageRating, int totalRatings, double userRating, bool hasUserRated)> GetRatingDataAsync(int recipeId, string userId = null);
+        Task<bool> IsRecipeFavoritedAsync(string userId, int recipeId);
+        Task<List<Recipe>> GetUserRecipesAsync(string userId);
+        Task<double> GetUserAverageRatingAsync(string userId);
+        Task<(Recipe recipe, float totalCalories, float totalProtein, float totalCarbs, float totalFat, bool hasPendingIngredients)> CalculateRecipeNutritionAsync(Recipe recipe, List<SelectedIngredient> ingredients);
+        Task<Recipe> CreateRecipeAsync(Recipe recipe, List<SelectedIngredient> ingredients, string imageUrl);
+        Task<Recipe> UpdateRecipeAsync(Recipe recipe, List<SelectedIngredient> ingredients, string imageUrl);
+        Task DeleteRecipeAsync(int recipeId);
+        float ConvertUnit(float number, string unit);
+        Task<(bool success, string message, bool isFavorited)> ToggleFavoriteAsync(string userId, int recipeId);
+    }
+}
Index: NutriMatch/Services/Interfaces/IRecipeTagService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IRecipeTagService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IRecipeTagService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IRecipeTagService
+    {
+        List<string> GenerateRecipeTags(Recipe recipe, List<SelectedIngredient> ingredients);
+    }
+}
Index: NutriMatch/Services/Interfaces/IRestaurantService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IRestaurantService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IRestaurantService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IRestaurantService
+    {
+        Task<List<Restaurant>> GetAllRestaurantsAsync();
+        Task<(Restaurant restaurant, List<RestaurantMeal> filteredMeals)> GetRestaurantWithFilteredMealsAsync(
+            int id, 
+            int? minCalories, 
+            int? maxCalories, 
+            int? minProtein, 
+            int? maxProtein, 
+            int? minCarbs, 
+            int? maxCarbs, 
+            int? minFat, 
+            int? maxFat);
+        Task<List<object>> GetRestaurantsAsync();
+        Task<object?> GetRestaurantAsync(int id);
+        Task<List<RestaurantMeal>> GetRestaurantMealsAsync(int restaurantId);
+        Task<(bool success, string message, int? restaurantId)> AddRestaurantAsync(string name, string description, string imagePath);
+        Task<(bool success, string message)> EditRestaurantAsync(int id, string name, string description, string? imagePath);
+        Task<(bool success, string message)> DeleteRestaurantAsync(int id);
+        Task<(bool success, string message)> AddRestaurantMealAsync(RestaurantMeal meal);
+        Task<(bool success, string message)> EditRestaurantMealAsync(RestaurantMeal meal);
+        Task<(bool success, string message)> DeleteRestaurantMealAsync(int id);
+    }
+}
Index: NutriMatch/Services/Interfaces/IUserPreferenceService.cs
===================================================================
--- NutriMatch/Services/Interfaces/IUserPreferenceService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/Interfaces/IUserPreferenceService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public interface IUserPreferenceService
+    {
+        Task<(List<object> preferences, List<int> followedRestaurants)> GetUserPreferencesAsync(string userId);
+        Task UpdateTagPreferencesAsync(string userId, List<UserMealPreference> preferences);
+        Task<(bool success, bool following)> ToggleFollowRestaurantAsync(string userId, int restaurantId);
+    }
+}
Index: NutriMatch/Services/MealClassificationService.cs
===================================================================
--- NutriMatch/Services/MealClassificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/MealClassificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,176 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using NutriMatch.Controllers;
+using NutriMatch.Data;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public class MealClassificationService : IMealClassificationService
+    {
+
+        private readonly IMealKeywordService _mealKeywordService;
+        private readonly AppDbContext _context;
+
+        public MealClassificationService(AppDbContext context, IMealKeywordService mealKeywordService)
+        {
+            _context = context;
+            _mealKeywordService = mealKeywordService;
+        }
+
+       
+
+        public async Task<List<string>> GenerateMealTypes(RestaurantMeal meal)
+        {
+            if (meal.Calories == 0 ||
+                (!string.IsNullOrEmpty(meal.ItemDescription) &&
+                (meal.ItemDescription.ToLower().Contains("wine") ||
+                meal.ItemDescription.ToLower().Contains("beer") ||
+                meal.ItemDescription.ToLower().Contains("spirits") ||
+                meal.ItemDescription.ToLower().Contains("beverages"))))
+            {
+                return new List<string> { "drink" };
+            }
+
+            var keywords = await _mealKeywordService.GetKeywordsByTagAsync();
+            var tags = new HashSet<string>();
+
+            var breakfastKeywords = new HashSet<string>(
+                keywords.ContainsKey("breakfast") ? keywords["breakfast"] : new List<string>(), 
+                StringComparer.OrdinalIgnoreCase);
+            var mainKeywords = new HashSet<string>(
+                keywords.ContainsKey("main") ? keywords["main"] : new List<string>(), 
+                StringComparer.OrdinalIgnoreCase);
+            var snackKeywords = new HashSet<string>(
+                keywords.ContainsKey("snack") ? keywords["snack"] : new List<string>(), 
+                StringComparer.OrdinalIgnoreCase);
+
+            var titleWords = meal.ItemName.ToLower()
+                .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
+
+            var descriptionWords = new HashSet<string>();
+            if (!string.IsNullOrEmpty(meal.ItemDescription))
+            {
+                var words = meal.ItemDescription.ToLower()
+                    .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')', ';', ':' }, StringSplitOptions.RemoveEmptyEntries);
+                foreach (var w in words) descriptionWords.Add(w);
+            }
+
+            int breakfastScore = CountKeywordMatches(titleWords, breakfastKeywords, true) +
+                                CountKeywordMatches(descriptionWords, breakfastKeywords, false);
+
+            int mainScore = CountKeywordMatches(titleWords, mainKeywords, true) +
+                            CountKeywordMatches(descriptionWords, mainKeywords, false);
+
+            int snackScore = CountKeywordMatches(titleWords, snackKeywords, true) +
+                            CountKeywordMatches(descriptionWords, snackKeywords, false);
+
+            int lunchScore = mainScore;
+            int dinnerScore = mainScore;
+
+            float calories = meal.Calories;
+            float proteinRatio = (meal.Protein * 4) / calories * 100;
+            float carbRatio = (meal.Carbs * 4) / calories * 100;
+            float fatRatio = (meal.Fat * 9) / calories * 100;
+
+            if (calories < 250)
+            {
+                snackScore += 2;
+                breakfastScore += 1;
+                dinnerScore -= 2;
+                lunchScore -= 2;
+            }
+            else if (calories <= 500)
+            {
+                lunchScore += 1;
+                dinnerScore += 1;
+                breakfastScore += 2;
+            }
+            else
+            {
+                dinnerScore += 2;
+                lunchScore += 2;
+                breakfastScore -= 1;
+                snackScore -= 2;
+            }
+
+            if (proteinRatio >= 25)
+            {
+                dinnerScore += 2;
+                lunchScore += 2;
+            }
+            else if (carbRatio >= 50)
+            {
+                breakfastScore += 1;
+                snackScore += 1;
+            }
+
+            if (fatRatio > 30)
+            {
+                dinnerScore += 1;
+                snackScore += 1;
+            }
+
+            var results = new List<(string tag, int score)>
+            {
+                ("breakfast", breakfastScore),
+                ("lunch", lunchScore),
+                ("dinner", dinnerScore),
+                ("snack", snackScore)
+            }.OrderByDescending(x => x.score).ToList();
+
+            tags.Add(results[0].tag);
+
+            for (int i = 1; i < results.Count; i++)
+            {
+                if (results[i].score > 0 && results[i].score >= results[0].score * 0.6)
+                    tags.Add(results[i].tag);
+            }
+
+            return tags.ToList();
+        }
+
+        private string NormalizeWord(string word)
+        {
+            word = word.ToLower().Trim();
+            if (word.EndsWith("ies") && word.Length > 4)
+                return word.Substring(0, word.Length - 3) + "y";
+            if (word.EndsWith("es") && word.Length > 3)
+                return word.Substring(0, word.Length - 2);
+            if (word.EndsWith("s") && word.Length > 3 && !word.EndsWith("ss"))
+                return word.Substring(0, word.Length - 1);
+            return word;
+        }
+
+        private int CountKeywordMatches(IEnumerable<string> words, HashSet<string> keywords, bool isTitle = false)
+        {
+            int count = 0;
+            foreach (var word in words)
+            {
+                bool matches = keywords.Contains(word) || keywords.Contains(NormalizeWord(word));
+                if (matches)
+                    count += isTitle ? 3 : 1;
+            }
+            return count;
+        }
+
+        private async Task<List<RestaurantMeal>> GetUnclassifiedMealsFromDatabaseAsync()
+        {
+            return await _context.RestaurantMeals.ToListAsync();
+        }
+
+        private async Task UpdateMealTypesInDatabaseAsync(int mealId, List<string> mealTypes)
+        {
+            var meal = await _context.RestaurantMeals.FindAsync(mealId);
+            if (meal != null)
+            {
+                meal.Type = mealTypes;
+                await _context.SaveChangesAsync();
+            }
+        }
+    }
+}
Index: NutriMatch/Services/MealKeywordService.cs
===================================================================
--- NutriMatch/Services/MealKeywordService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/MealKeywordService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,71 @@
+using NutriMatch.Data;
+using NutriMatch.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace NutriMatch.Services
+{
+    public class MealKeywordService : IMealKeywordService
+    {
+        private readonly AppDbContext _context;
+
+        public MealKeywordService(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        public async Task<List<MealKeyword>> GetMealKeywordsAsync()
+        {
+            return await _context.MealKeywords
+                .OrderBy(k => k.Tag)
+                .ThenBy(k => k.Name)
+                .ToListAsync();
+        }
+
+        public async Task<Dictionary<string, List<string>>> GetKeywordsByTagAsync()
+        {
+            var keywords = await _context.MealKeywords.ToListAsync();
+            
+            return keywords
+                .GroupBy(k => k.Tag.ToLower())
+                .ToDictionary(
+                    g => g.Key,
+                    g => g.Select(k => k.Name).ToList()
+                );
+        }
+
+        public async Task<(bool success, string message)> AddMealKeywordAsync(MealKeyword keyword)
+        {
+            if (string.IsNullOrWhiteSpace(keyword.Name))
+            {
+                return (false, "Keyword name is required");
+            }
+
+            var exists = await _context.MealKeywords
+                .AnyAsync(k => k.Name.ToLower() == keyword.Name.ToLower() && k.Tag == keyword.Tag);
+
+            if (exists)
+            {
+                return (false, "This keyword already exists for this meal type");
+            }
+
+            _context.MealKeywords.Add(keyword);
+            await _context.SaveChangesAsync();
+
+            return (true, "Keyword added successfully");
+        }
+
+        public async Task<(bool success, string message)> DeleteMealKeywordAsync(int id)
+        {
+            var keyword = await _context.MealKeywords.FindAsync(id);
+            if (keyword == null)
+            {
+                return (false, "Keyword not found");
+            }
+
+            _context.MealKeywords.Remove(keyword);
+            await _context.SaveChangesAsync();
+
+            return (true, "Keyword deleted successfully");
+        }
+    }
+}
Index: NutriMatch/Services/MealPlanService.cs
===================================================================
--- NutriMatch/Services/MealPlanService.cs	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Services/MealPlanService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -44,4 +44,7 @@
                 foreach (var day in days)
                 {
+                    var usedRecipeIds = new HashSet<int>();
+                    var usedRestaurantMealIds = new HashSet<int>();
+
                     var dailyMacros = new DailyMacros
                     {
@@ -65,24 +68,30 @@
                         if (isRestaurantMeal)
                         {
-                            var restaurantMeal = await SelectRestaurantMealAsync(mealType, targetMacros);
+                            var restaurantMeal = await SelectRestaurantMealAsync(mealType, targetMacros, usedRestaurantMealIds);
                             if (restaurantMeal != null)
                             {
                                 mealSlot.RestaurantMeal = restaurantMeal;
                                 mealSlot.IsRestaurantMeal = true;
+                                usedRestaurantMealIds.Add(restaurantMeal.Id);
                             }
                             else
                             {
-                                var recipe = await SelectRecipeAsync(mealType, targetMacros);
-                                mealSlot.Recipe = recipe;
-                                mealSlot.IsRestaurantMeal = false;
+                                var recipe = await SelectRecipeAsync(mealType, targetMacros, usedRecipeIds);
+                                if (recipe != null)
+                                {
+                                    mealSlot.Recipe = recipe;
+                                    mealSlot.IsRestaurantMeal = false;
+                                    usedRecipeIds.Add(recipe.Id);
+                                }
                             }
                         }
                         else
                         {
-                            var recipe = await SelectRecipeAsync(mealType, targetMacros);
+                            var recipe = await SelectRecipeAsync(mealType, targetMacros, usedRecipeIds);
                             if (recipe != null)
                             {
                                 mealSlot.Recipe = recipe;
                                 mealSlot.IsRestaurantMeal = false;
+                                usedRecipeIds.Add(recipe.Id);
                             }
                         }
@@ -108,5 +117,5 @@
                         };
 
-                        var snackRecipe = await SelectRecipeAsync("snack", snackMacros);
+                        var snackRecipe = await SelectRecipeAsync("snack", snackMacros, usedRecipeIds);
                         if (snackRecipe != null)
                         {
@@ -147,5 +156,4 @@
 
                 _context.MealSlots.RemoveRange(mealPlan.MealSlots);
-
                 _context.WeeklyMealPlans.Remove(mealPlan);
 
@@ -199,5 +207,5 @@
         }
 
-        private async Task<Recipe> SelectRecipeAsync(string mealType, DailyMacros targetMacros)
+        private async Task<Recipe> SelectRecipeAsync(string mealType, DailyMacros targetMacros, HashSet<int> excludeRecipeIds = null)
         {
             var query = _context.Recipes
@@ -205,4 +213,9 @@
                 .Where(r => r.RecipeStatus == "Accepted");
 
+            if (excludeRecipeIds != null && excludeRecipeIds.Any())
+            {
+                query = query.Where(r => !excludeRecipeIds.Contains(r.Id));
+            }
+
             if (!string.IsNullOrEmpty(mealType))
             {
@@ -217,4 +230,9 @@
                     .Where(r => r.RecipeStatus == "Accepted")
                     .ToListAsync();
+
+                if (excludeRecipeIds != null && excludeRecipeIds.Any())
+                {
+                    recipes = recipes.Where(r => !excludeRecipeIds.Contains(r.Id)).ToList();
+                }
             }
 
@@ -235,7 +253,12 @@
         }
 
-        private async Task<RestaurantMeal> SelectRestaurantMealAsync(string mealType, DailyMacros targetMacros)
+        private async Task<RestaurantMeal> SelectRestaurantMealAsync(string mealType, DailyMacros targetMacros, HashSet<int> excludeMealIds = null)
         {
             var query = _context.RestaurantMeals.AsQueryable();
+
+            if (excludeMealIds != null && excludeMealIds.Any())
+            {
+                query = query.Where(rm => !excludeMealIds.Contains(rm.Id));
+            }
 
             if (!string.IsNullOrEmpty(mealType))
@@ -311,5 +334,5 @@
         public async Task<WeeklyMealPlan> GetMealPlanByIdAsync(int id, string userId)
         {
-#pragma warning disable CS8603 
+#pragma warning disable CS8603
             return await _context.WeeklyMealPlans
                 .Include(wmp => wmp.MealSlots)
@@ -330,4 +353,283 @@
                 .ToListAsync();
         }
+
+        public async Task<bool> RegenerateMealSlotAsync(int mealSlotId, string userId)
+        {
+            try
+            {
+                var mealSlot = await _context.MealSlots
+                    .Include(ms => ms.Recipe)
+                    .Include(ms => ms.RestaurantMeal)
+                    .FirstOrDefaultAsync(ms => ms.Id == mealSlotId);
+
+                if (mealSlot == null)
+                    return false;
+
+                var weeklyPlan = await _context.WeeklyMealPlans
+                    .FirstOrDefaultAsync(wmp => wmp.UserId == userId && wmp.MealSlots.Any(ms => ms.Id == mealSlotId));
+
+                if (weeklyPlan == null)
+                    return false;
+
+                var currentRecipeId = mealSlot.Recipe?.Id;
+                var currentRestaurantMealId = mealSlot.RestaurantMeal?.Id;
+
+                var targetMacros = new DailyMacros
+                {
+                    Calories = mealSlot.IsRestaurantMeal ? (mealSlot.RestaurantMeal?.Calories ?? 500) : (mealSlot.Recipe?.Calories ?? 500),
+                    Protein = mealSlot.IsRestaurantMeal ? (mealSlot.RestaurantMeal?.Protein ?? 30) : (mealSlot.Recipe?.Protein ?? 30),
+                    Carbs = mealSlot.IsRestaurantMeal ? (mealSlot.RestaurantMeal?.Carbs ?? 50) : (mealSlot.Recipe?.Carbs ?? 50),
+                    Fat = mealSlot.IsRestaurantMeal ? (mealSlot.RestaurantMeal?.Fat ?? 15) : (mealSlot.Recipe?.Fat ?? 15)
+                };
+
+                if (mealSlot.IsRestaurantMeal)
+                {
+                    var newRestaurantMeal = await SelectBestRestaurantMealAsync(mealSlot.MealType, targetMacros, currentRestaurantMealId);
+                    if (newRestaurantMeal != null)
+                    {
+                        mealSlot.RestaurantMeal = newRestaurantMeal;
+                        mealSlot.Recipe = null;
+                    }
+                    else
+                    {
+                        return false;
+                    }
+                }
+                else
+                {
+                    var newRecipe = await SelectBestRecipeAsync(mealSlot.MealType, targetMacros, currentRecipeId);
+                    if (newRecipe != null)
+                    {
+                        mealSlot.Recipe = newRecipe;
+                        mealSlot.RestaurantMeal = null;
+                    }
+                    else
+                    {
+                        return false;
+                    }
+                }
+
+                await _context.SaveChangesAsync();
+                return true;
+            }
+            catch (Exception ex)
+            {
+                return false;
+            }
+        }
+
+        private async Task<Recipe> SelectBestRecipeAsync(string mealType, DailyMacros targetMacros, int? excludeRecipeId = null)
+        {
+            var query = _context.Recipes
+                .Include(r => r.RecipeIngredients)
+                .Where(r => r.RecipeStatus == "Accepted");
+
+            if (excludeRecipeId.HasValue)
+            {
+                query = query.Where(r => r.Id != excludeRecipeId.Value);
+            }
+
+            if (!string.IsNullOrEmpty(mealType))
+            {
+                query = query.Where(r => r.Type.Contains(mealType));
+            }
+
+            var recipes = await query.ToListAsync();
+
+            if (!recipes.Any())
+            {
+                recipes = await _context.Recipes
+                    .Where(r => r.RecipeStatus == "Accepted" && r.Id != excludeRecipeId)
+                    .ToListAsync();
+            }
+
+            if (!recipes.Any()) return null;
+
+            var closestRecipe = recipes
+                .Select(recipe => new
+                {
+                    Recipe = recipe,
+                    Score = CalculateMacroMatchScore(recipe, targetMacros)
+                })
+                .OrderByDescending(x => x.Score)
+                .First()
+                .Recipe;
+
+            return closestRecipe;
+        }
+
+        private async Task<RestaurantMeal> SelectBestRestaurantMealAsync(string mealType, DailyMacros targetMacros, int? excludeMealId = null)
+        {
+            var query = _context.RestaurantMeals.AsQueryable();
+
+            if (excludeMealId.HasValue)
+            {
+                query = query.Where(rm => rm.Id != excludeMealId.Value);
+            }
+
+            if (!string.IsNullOrEmpty(mealType))
+            {
+                query = query.Where(rm => rm.Type.Contains(mealType));
+            }
+
+            var restaurantMeals = await query.ToListAsync();
+
+            if (!restaurantMeals.Any())
+            {
+                restaurantMeals = await _context.RestaurantMeals
+                    .Where(rm => rm.Id != excludeMealId)
+                    .ToListAsync();
+            }
+
+            if (!restaurantMeals.Any()) return null;
+
+            var closestMeal = restaurantMeals
+                .Select(meal => new
+                {
+                    Meal = meal,
+                    Score = CalculateMacroMatchScore(meal, targetMacros)
+                })
+                .OrderByDescending(x => x.Score)
+                .First()
+                .Meal;
+
+            return closestMeal;
+        }
+
+        public async Task HandleDeletedRecipeAsync(int recipeId)
+        {
+            try
+            {
+                var affectedMealSlots = await _context.MealSlots
+                    .Include(ms => ms.Recipe)
+                    .Where(ms => ms.Recipe != null && ms.Recipe.Id == recipeId && !ms.IsRestaurantMeal)
+                    .ToListAsync();
+
+                if (!affectedMealSlots.Any())
+                    return;
+
+                var affectedUserIds = await _context.WeeklyMealPlans
+                    .Where(wmp => wmp.MealSlots.Any(ms => affectedMealSlots.Select(ams => ams.Id).Contains(ms.Id)))
+                    .Select(wmp => wmp.UserId)
+                    .Distinct()
+                    .ToListAsync();
+
+                foreach (var mealSlot in affectedMealSlots)
+                {
+                    var targetMacros = new DailyMacros
+                    {
+                        Calories = mealSlot.Recipe?.Calories ?? 500,
+                        Protein = mealSlot.Recipe?.Protein ?? 30,
+                        Carbs = mealSlot.Recipe?.Carbs ?? 50,
+                        Fat = mealSlot.Recipe?.Fat ?? 15
+                    };
+
+                    var replacementRecipe = await SelectBestRecipeAsync(mealSlot.MealType, targetMacros, recipeId);
+
+                    if (replacementRecipe != null)
+                    {
+                        mealSlot.Recipe = replacementRecipe;
+                        mealSlot.IsRegenerated = true;
+                        mealSlot.isViewed = false;
+                    }
+                    else
+                    {
+                        mealSlot.Recipe = null;
+                    }
+                }
+
+                await _context.SaveChangesAsync();
+
+                foreach (var userId in affectedUserIds)
+                {
+                    var UserNotification = await _context.Users.FindAsync(userId);
+                    if (UserNotification.NotifyMealPlanUpdated)
+                    {
+
+                        var notification = new Notification
+                        {
+                            UserId = userId,
+                            Type = "MealPlanUpdated",
+                            Message = $"A recipe in your meal plan was removed and has been automatically replaced with a similar recipe.",
+                            CreatedAt = DateTime.Now.ToUniversalTime(),
+
+                            IsRead = false
+                        };
+
+                        _context.Notifications.Add(notification);
+                    }
+                }
+
+                await _context.SaveChangesAsync();
+            }
+            catch (Exception ex)
+            {
+            }
+        }
+
+        public async Task HandleDeletedRestaurantMealAsync(int restaurantMealId)
+        {
+            try
+            {
+                var affectedMealSlots = await _context.MealSlots
+                    .Include(ms => ms.RestaurantMeal)
+                    .Where(ms => ms.RestaurantMeal != null && ms.RestaurantMeal.Id == restaurantMealId && ms.IsRestaurantMeal)
+                    .ToListAsync();
+
+                if (!affectedMealSlots.Any())
+                    return;
+
+                var affectedUserIds = await _context.WeeklyMealPlans
+                    .Where(wmp => wmp.MealSlots.Any(ms => affectedMealSlots.Select(ams => ams.Id).Contains(ms.Id)))
+                    .Select(wmp => wmp.UserId)
+                    .Distinct()
+                    .ToListAsync();
+
+                foreach (var mealSlot in affectedMealSlots)
+                {
+                    var targetMacros = new DailyMacros
+                    {
+                        Calories = mealSlot.RestaurantMeal?.Calories ?? 500,
+                        Protein = mealSlot.RestaurantMeal?.Protein ?? 30,
+                        Carbs = mealSlot.RestaurantMeal?.Carbs ?? 50,
+                        Fat = mealSlot.RestaurantMeal?.Fat ?? 15
+                    };
+
+                    var replacementMeal = await SelectBestRestaurantMealAsync(mealSlot.MealType, targetMacros, restaurantMealId);
+
+                    if (replacementMeal != null)
+                    {
+                        mealSlot.RestaurantMeal = replacementMeal;
+                        mealSlot.IsRegenerated = true;
+                        mealSlot.isViewed = false;
+                    }
+                    else
+                    {
+                        mealSlot.RestaurantMeal = null;
+                    }
+                }
+
+                await _context.SaveChangesAsync();
+
+                foreach (var userId in affectedUserIds)
+                {
+                    var notification = new Notification
+                    {
+                        UserId = userId,
+                        Type = "MealPlanUpdated",
+                        Message = $"A restaurant meal in your meal plan was removed and has been automatically replaced with a similar restaurant meal.",
+                        CreatedAt = DateTime.Now.ToUniversalTime(),
+                        IsRead = false
+                    };
+
+                    _context.Notifications.Add(notification);
+                }
+
+                await _context.SaveChangesAsync();
+            }
+            catch (Exception ex)
+            {
+            }
+        }
     }
 }
Index: NutriMatch/Services/NotificationService.cs
===================================================================
--- NutriMatch/Services/NotificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/NotificationService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,157 @@
+
+using NutriMatch.Data;
+using NutriMatch.Models;
+using Microsoft.EntityFrameworkCore;
+using System.Net.Mail;
+using System.Net;
+
+namespace NutriMatch.Services
+{
+    public class NotificationService : INotificationService
+    {
+        private readonly AppDbContext _context;
+        
+        private readonly IConfiguration _config;
+
+        public NotificationService(AppDbContext context, IConfiguration config)
+        {
+            _context = context;
+            _config = config;
+        }
+
+        public async Task<(List<Notification> notifications, int unreadCount)> GetNotificationsAsync(string userId)
+        {
+            var notifications = await _context.Notifications
+                .Where(n => n.UserId == userId)
+                .OrderByDescending(n => n.CreatedAt)
+                .Take(10)
+                .ToListAsync();
+
+            var unreadCount = await _context.Notifications
+                .CountAsync(n => n.UserId == userId && !n.IsRead);
+
+            return (notifications, unreadCount);
+        }
+
+        public async Task<List<Notification>> GetAllNotificationsAsync(string userId)
+        {
+            return await _context.Notifications
+                .Where(n => n.UserId == userId)
+                .OrderByDescending(n => n.CreatedAt)
+                .ToListAsync();
+        }
+
+        public async Task<(bool success, int unreadCount)> MarkAsReadAsync(int notificationId, string userId)
+        {
+            var notification = await _context.Notifications
+                .FirstOrDefaultAsync(n => n.Id == notificationId && n.UserId == userId);
+
+            if (notification == null)
+            {
+                return (false, 0);
+            }
+
+            notification.IsRead = true;
+            await _context.SaveChangesAsync();
+
+            var unreadCount = await _context.Notifications
+                .CountAsync(n => n.UserId == userId && !n.IsRead);
+
+            return (true, unreadCount);
+        }
+
+        public async Task<bool> MarkAllAsReadAsync(string userId)
+        {
+            var notifications = await _context.Notifications
+                .Where(n => n.UserId == userId && !n.IsRead)
+                .ToListAsync();
+
+            foreach (var notification in notifications)
+            {
+                notification.IsRead = true;
+            }
+
+            await _context.SaveChangesAsync();
+            return true;
+        }
+
+        public async Task<(bool success, int unreadCount)> DeleteAsync(int notificationId, string userId)
+        {
+            var notification = await _context.Notifications
+                .FirstOrDefaultAsync(n => n.Id == notificationId && n.UserId == userId);
+
+            if (notification == null)
+            {
+                return (false, 0);
+            }
+
+            _context.Notifications.Remove(notification);
+            await _context.SaveChangesAsync();
+
+            var unreadCount = await _context.Notifications
+                .CountAsync(n => n.UserId == userId && !n.IsRead);
+
+            return (true, unreadCount);
+        }
+
+        public async Task<(bool success, string message)> DeleteAllAsync(string userId)
+        {
+            try
+            {
+                if (string.IsNullOrEmpty(userId))
+                {
+                    return (false, "User not found");
+                }
+
+                var userNotifications = await _context.Notifications
+                    .Where(n => n.UserId == userId)
+                    .ToListAsync();
+
+                _context.Notifications.RemoveRange(userNotifications);
+                await _context.SaveChangesAsync();
+
+                return (true, "All notifications deleted");
+            }
+            catch (Exception)
+            {
+                return (false, "Error deleting notifications");
+            }
+        }
+
+        public async Task<int> GetUnreadCountAsync(string userId)
+        {
+            return await _context.Notifications
+                .CountAsync(n => n.UserId == userId && !n.IsRead);
+        }
+
+        public async Task<Notification?> GetLatestNotificationAsync(string userId)
+        {
+            return await _context.Notifications
+                .Where(n => n.UserId == userId)
+                .OrderByDescending(n => n.CreatedAt)
+                .FirstOrDefaultAsync();
+        }
+
+        public async Task SendEmailAsync(string toEmail, string subject, string message)
+        {
+            var fromEmail = _config["EmailSettings:FromEmail"];
+            var password = _config["EmailSettings:Password"];
+            var smtpServer = _config["EmailSettings:SmtpServer"];
+            var port = int.Parse(_config["EmailSettings:Port"]);
+
+            using (var client = new SmtpClient(smtpServer, port))
+            {
+                client.EnableSsl = true;
+                client.Credentials = new NetworkCredential(fromEmail, password);
+
+                var mailMessage = new MailMessage(fromEmail, toEmail, subject, message)
+                {
+                    IsBodyHtml = true
+                };
+
+                await client.SendMailAsync(mailMessage);
+            }
+        }
+
+    }
+}
Index: NutriMatch/Services/RatingService.cs
===================================================================
--- NutriMatch/Services/RatingService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/RatingService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,126 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using NutriMatch.Data;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public class RatingService : IRatingService
+    {
+        private readonly AppDbContext _context;
+        private readonly INotificationService _notificationService;
+
+        public RatingService(AppDbContext context, INotificationService notificationService)
+        {
+            _context = context;
+            _notificationService = notificationService;
+        }
+
+        public async Task<(bool success, string message, double averageRating, int totalRatings)> AddOrUpdateRatingAsync(string userId, int recipeId, double rating)
+        {
+            if (string.IsNullOrEmpty(userId))
+            {
+                return (false, "User not authenticated", 0, 0);
+            }
+
+            if (rating < 1 || rating > 5)
+            {
+                return (false, "Rating must be between 1 and 5", 0, 0);
+            }
+
+            var recipe = await _context.Recipes.FindAsync(recipeId);
+            if (recipe == null)
+            {
+                return (false, "Recipe not found", 0, 0);
+            }
+
+            var existingRating = await _context.RecipeRatings
+                .FirstOrDefaultAsync(r => r.UserId == userId && r.RecipeId == recipeId);
+
+            if (existingRating != null)
+            {
+                existingRating.Rating = rating;
+                _context.RecipeRatings.Update(existingRating);
+            }
+            else
+            {
+                var newRating = new RecipeRating
+                {
+                    UserId = userId,
+                    RecipeId = recipeId,
+                    Rating = rating
+                };
+                _context.RecipeRatings.Add(newRating);
+            }
+
+            // Send notification
+            var userNotification = await _context.Users.FindAsync(recipe.UserId);
+            if (userNotification?.NotifyRecipeRated == true)
+            {
+                var notification = new Notification
+                {
+                    UserId = recipe.UserId,
+                    Type = "RecipeRated",
+                    Message = $"Your recipe '{recipe.Title}' received a new rating of {rating} stars.",
+                    RecipeId = recipe.Id,
+                    RelatedUserId = userId,
+                    CreatedAt = DateTime.UtcNow,
+                    IsRead = false
+                };
+
+                _context.Notifications.Add(notification);
+
+                await _notificationService.SendEmailAsync(
+                    userNotification.Email,
+                    "Your recipe was rated!",
+                    $"<p>Hi {userNotification.UserName},</p><p>{notification.Message}</p>"
+                );
+            }
+
+            await _context.SaveChangesAsync();
+
+            var ratings = await _context.RecipeRatings
+                .Where(r => r.RecipeId == recipeId)
+                .Select(r => r.Rating)
+                .ToListAsync();
+
+            var averageRating = ratings.Any() ? Math.Round(ratings.Average(), 1) : 0;
+            var totalRatings = ratings.Count;
+
+            return (true, "Rating submitted successfully", averageRating, totalRatings);
+        }
+
+        public async Task<(bool success, string message, double averageRating, int totalRatings)> RemoveRatingAsync(string userId, int recipeId)
+        {
+            if (string.IsNullOrEmpty(userId))
+            {
+                return (false, "User not authenticated", 0, 0);
+            }
+
+            var existingRating = await _context.RecipeRatings
+                .FirstOrDefaultAsync(r => r.UserId == userId && r.RecipeId == recipeId);
+
+            if (existingRating == null)
+            {
+                return (false, "No rating found to remove", 0, 0);
+            }
+
+            _context.RecipeRatings.Remove(existingRating);
+            await _context.SaveChangesAsync();
+
+            var ratings = await _context.RecipeRatings
+                .Where(r => r.RecipeId == recipeId)
+                .Select(r => r.Rating)
+                .ToListAsync();
+
+            var averageRating = ratings.Any() ? Math.Round(ratings.Average(), 1) : 0;
+            var totalRatings = ratings.Count;
+
+            return (true, "Rating removed successfully", averageRating, totalRatings);
+        }
+    }
+
+    
+}
Index: NutriMatch/Services/RecipeApprovalService.cs
===================================================================
--- NutriMatch/Services/RecipeApprovalService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/RecipeApprovalService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,303 @@
+
+using NutriMatch.Data;
+using NutriMatch.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace NutriMatch.Services
+{
+    public class RecipeApprovalService : IRecipeApprovalService
+    {
+        private readonly AppDbContext _context;
+        private readonly INotificationService _notificationService;
+
+        public RecipeApprovalService(
+            AppDbContext context,
+            INotificationService notificationService)
+        {
+            _context = context;
+            _notificationService = notificationService;
+        }
+
+        public async Task<List<Recipe>> GetPendingRecipesAsync()
+        {
+            return await _context.Recipes
+                .Where(r => r.RecipeStatus == "Pending")
+                .Include(r => r.User)
+                .ToListAsync();
+        }
+
+        public async Task<(bool success, string message)> ApproveRecipeAsync(int recipeId)
+        {
+            var recipe = await _context.Recipes
+                .Include(r => r.RecipeIngredients)
+                .ThenInclude(ri => ri.Ingredient)
+                .FirstOrDefaultAsync(r => r.Id == recipeId);
+
+            if (recipe == null)
+            {
+                return (false, "Recipe not found.");
+            }
+
+            recipe.RecipeStatus = "Accepted";
+
+            if (recipe.HasPendingIngredients == true)
+            {
+                var pendingIngredients = recipe.RecipeIngredients
+                    .Where(ri => ri.Ingredient.Status == "Pending")
+                    .Select(ri => ri.Ingredient);
+
+                foreach (var ingredient in pendingIngredients)
+                {
+                    ingredient.Status = null;
+                }
+
+                recipe.HasPendingIngredients = false;
+            }
+
+            var userNotification = await _context.Users.FindAsync(recipe.UserId);
+
+            if (userNotification?.NotifyRecipeAccepted == true)
+            {
+                var notification = new Notification
+                {
+                    UserId = recipe.UserId,
+                    Type = "RecipeAccepted",
+                    Message = $"Great news! Your recipe '{recipe.Title}' has been approved and is now live!",
+                    RecipeId = recipeId,
+                    CreatedAt = DateTime.UtcNow,
+                    IsRead = false
+                };
+
+                _context.Notifications.Add(notification);
+
+                await _notificationService.SendEmailAsync(
+                    userNotification.Email,
+                    "Your recipe has been approved!",
+                    $"<p>Hi {userNotification.UserName},</p><p>{notification.Message}</p>"
+                );
+            }
+
+            await _context.SaveChangesAsync();
+            await CreateRecipeNotificationsAsync(recipe);
+
+            return (true, "Recipe approved successfully.");
+        }
+
+        public async Task<(bool success, string message)> DeclineRecipeAsync(int recipeId, string reason, string notes)
+        {
+            var recipe = await _context.Recipes
+                .Include(r => r.RecipeIngredients)
+                .ThenInclude(ri => ri.Ingredient)
+                .FirstOrDefaultAsync(r => r.Id == recipeId);
+
+            if (recipe == null)
+            {
+                return (false, "Recipe not found.");
+            }
+
+            recipe.RecipeStatus = "Declined";
+            recipe.DeclineReason = reason ?? string.Empty;
+            recipe.AdminComment = notes ?? string.Empty;
+
+            string notificationMessage = string.IsNullOrEmpty(reason) || reason == "No reason provided."
+                ? $"Your recipe '{recipe.Title}' was declined."
+                : $"Your recipe '{recipe.Title}' was declined. Reason: {reason}";
+
+            var userNotification = await _context.Users.FindAsync(recipe.UserId);
+
+            if (userNotification?.NotifyRecipeDeclined == true)
+            {
+                var notification = new Notification
+                {
+                    UserId = recipe.UserId,
+                    Type = "RecipeDeclined",
+                    Message = notificationMessage,
+                    RecipeId = recipeId,
+                    CreatedAt = DateTime.UtcNow,
+                    IsRead = false
+                };
+
+                _context.Notifications.Add(notification);
+
+                await _notificationService.SendEmailAsync(
+                    userNotification.Email,
+                    "Your recipe was declined",
+                    $"<p>Hi {userNotification.UserName},</p><p>{notification.Message}</p>"
+                );
+            }
+
+            await _context.SaveChangesAsync();
+
+            return (true, "Recipe declined successfully.");
+        }
+
+        public async Task<(bool success, string message, int approvedCount)> BulkApproveRecipesAsync(List<int> recipeIds)
+        {
+            if (!recipeIds.Any())
+            {
+                return (false, "No recipe IDs provided.", 0);
+            }
+
+            var recipes = await _context.Recipes
+                .Include(r => r.RecipeIngredients)
+                .ThenInclude(ri => ri.Ingredient)
+                .Where(r => recipeIds.Contains(r.Id))
+                .ToListAsync();
+
+            if (!recipes.Any())
+            {
+                return (false, "No recipes found.", 0);
+            }
+
+            int approvedCount = 0;
+            foreach (var recipe in recipes)
+            {
+                recipe.RecipeStatus = "Accepted";
+
+                if (recipe.HasPendingIngredients == true)
+                {
+                    var pendingIngredients = recipe.RecipeIngredients
+                        .Where(ri => ri.Ingredient.Status == "Pending")
+                        .Select(ri => ri.Ingredient);
+
+                    foreach (var ingredient in pendingIngredients)
+                    {
+                        ingredient.Status = null;
+                    }
+
+                    recipe.HasPendingIngredients = false;
+                }
+
+                var userNotification = await _context.Users.FindAsync(recipe.UserId);
+                if (userNotification?.NotifyRecipeAccepted == true)
+                {
+                    var notification = new Notification
+                    {
+                        UserId = recipe.UserId,
+                        Type = "RecipeAccepted",
+                        Message = $"Great news! Your recipe '{recipe.Title}' has been approved and is now live!",
+                        RecipeId = recipe.Id,
+                        CreatedAt = DateTime.UtcNow,
+                        IsRead = false
+                    };
+
+                    _context.Notifications.Add(notification);
+
+                    await _notificationService.SendEmailAsync(
+                        userNotification.Email,
+                        "Your recipe has been approved!",
+                        $"<p>Hi {userNotification.UserName},</p><p>{notification.Message}</p>"
+                    );
+                }
+                approvedCount++;
+            }
+
+            await _context.SaveChangesAsync();
+
+            foreach (var recipe in recipes)
+            {
+                await CreateRecipeNotificationsAsync(recipe);
+            }
+
+            return (true, $"{approvedCount} recipe(s) approved successfully.", approvedCount);
+        }
+
+        public async Task<Recipe?> GetRecipeForDeclineAsync(int recipeId)
+        {
+            return await _context.Recipes
+                .Include(r => r.User)
+                .Include(r => r.RecipeIngredients)
+                .ThenInclude(ri => ri.Ingredient)
+                .FirstOrDefaultAsync(m => m.Id == recipeId);
+        }
+
+        private async Task CreateRecipeNotificationsAsync(Recipe recipe)
+        {
+            var allPrefs = await _context.UserMealPreferences
+                .Include(p => p.User)
+                .ToListAsync();
+
+            var userPreferences = allPrefs
+                .GroupBy(p => p.UserId)
+                .Select(g => new
+                {
+                    UserId = g.Key,
+                    Preferences = g.ToList(),
+                    User = g.First().User
+                })
+                .Where(u => u.UserId != recipe.UserId && u.User.NotifyRecipeMatchesTags)
+                .ToList();
+
+            foreach (var userPref in userPreferences)
+            {
+                var matchingTags = GetMatchingTags(userPref.Preferences, recipe.Protein, recipe.Carbs, recipe.Fat, recipe.Calories);
+
+                if (matchingTags.Any())
+                {
+                    var tagsText = string.Join(", ", matchingTags);
+
+                    var notification = new Notification
+                    {
+                        UserId = userPref.UserId,
+                        Type = "RecipeMatchesTags",
+                        Message = $"New recipe matches your preferences ({tagsText}): {recipe.Title}",
+                        RecipeId = recipe.Id,
+                        CreatedAt = DateTime.UtcNow,
+                        IsRead = false
+                    };
+
+                    _context.Notifications.Add(notification);
+
+                    await _notificationService.SendEmailAsync(
+                        userPref.User.Email,
+                        "New recipe matches your preferences",
+                        $"<p>Hi {userPref.User.UserName},</p><p>{notification.Message}</p>"
+                    );
+                }
+            }
+
+            await _context.SaveChangesAsync();
+        }
+
+        private List<string> GetMatchingTags(List<UserMealPreference> preferences, float protein, float carbs, float fat, float calories)
+        {
+            var matchingTags = new List<string>();
+
+            foreach (var pref in preferences)
+            {
+                bool matches = pref.Tag switch
+                {
+                    "high-protein" => pref.ThresholdValue.HasValue ? protein >= pref.ThresholdValue.Value : protein >= 30,
+                    "low-carb" => pref.ThresholdValue.HasValue ? carbs <= pref.ThresholdValue.Value : carbs <= 20,
+                    "high-carb" => pref.ThresholdValue.HasValue ? carbs >= pref.ThresholdValue.Value : carbs >= 50,
+                    "low-fat" => pref.ThresholdValue.HasValue ? fat <= pref.ThresholdValue.Value : fat <= 15,
+                    "high-fat" => pref.ThresholdValue.HasValue ? fat >= pref.ThresholdValue.Value : fat >= 30,
+                    "low-calorie" => pref.ThresholdValue.HasValue ? calories <= pref.ThresholdValue.Value : calories <= 300,
+                    "high-calorie" => pref.ThresholdValue.HasValue ? calories >= pref.ThresholdValue.Value : calories >= 600,
+                    "balanced" => IsBalanced(protein, carbs, fat, calories),
+                    _ => false
+                };
+
+                if (matches)
+                {
+                    matchingTags.Add(pref.Tag);
+                }
+            }
+
+            return matchingTags;
+        }
+
+        private bool IsBalanced(float protein, float carbs, float fat, float calories)
+        {
+            if (calories <= 0) return false;
+
+            float proteinRatio = (protein * 4) / calories * 100;
+            float carbRatio = (carbs * 4) / calories * 100;
+            float fatRatio = (fat * 9) / calories * 100;
+
+            return proteinRatio >= 20 && proteinRatio <= 35 &&
+                carbRatio >= 30 && carbRatio <= 50 &&
+                fatRatio >= 20 && fatRatio <= 35;
+        }
+    }
+}
Index: NutriMatch/Services/RecipeService.cs
===================================================================
--- NutriMatch/Services/RecipeService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/RecipeService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,319 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using NutriMatch.Data;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public class RecipeService : IRecipeService
+    {
+        private readonly AppDbContext _context;
+        private readonly IRecipeTagService _recipeTagService;
+
+        public RecipeService(AppDbContext context, IRecipeTagService recipeTagService)
+        {
+            _context = context;
+            _recipeTagService = recipeTagService;
+        }
+
+        public async Task<(List<Recipe> recipes, int totalRecipes)> GetPaginatedRecipesAsync(int page, int pageSize)
+        {
+            var totalRecipes = await _context.Recipes
+                .Where(r => r.RecipeStatus == "Accepted")
+                .CountAsync();
+
+            var recipes = await _context.Recipes
+                .Where(r => r.RecipeStatus == "Accepted")
+                .Include(r => r.User)
+                .Include(r => r.Ratings)
+                .OrderByDescending(r => r.CreatedAt)
+                .Skip((page - 1) * pageSize)
+                .Take(pageSize)
+                .ToListAsync();
+
+            foreach (var recipe in recipes)
+            {
+                recipe.Rating = recipe.Ratings.Any() ? recipe.Ratings.Average(r => r.Rating) : 0;
+            }
+
+            return (recipes, totalRecipes);
+        }
+
+        public async Task<List<int>> GetUserFavoriteRecipeIdsAsync(string userId)
+        {
+            if (string.IsNullOrEmpty(userId))
+            {
+                return new List<int>();
+            }
+
+            return await _context.FavoriteRecipes
+                .Where(fr => fr.UserId == userId)
+                .Select(fr => fr.RecipeId)
+                .ToListAsync();
+        }
+
+        public async Task<Recipe> GetRecipeByIdAsync(int id)
+        {
+            return await _context.Recipes
+                .Include(r => r.User)
+                .Include(r => r.RecipeIngredients)
+                .ThenInclude(ri => ri.Ingredient)
+                .FirstOrDefaultAsync(m => m.Id == id);
+        }
+
+        public async Task<(double averageRating, int totalRatings, double userRating, bool hasUserRated)> GetRatingDataAsync(int recipeId, string userId = null)
+        {
+            var ratings = await _context.RecipeRatings
+                .Where(r => r.RecipeId == recipeId)
+                .Select(r => new { r.Rating, r.UserId })
+                .ToListAsync();
+
+            var averageRating = ratings.Any() ? Math.Round(ratings.Average(r => r.Rating), 1) : 0;
+            var totalRatings = ratings.Count;
+
+            double userRating = 0;
+            bool hasUserRated = false;
+
+            if (!string.IsNullOrEmpty(userId))
+            {
+                var userRatingData = ratings.FirstOrDefault(r => r.UserId == userId);
+                if (userRatingData != null)
+                {
+                    userRating = userRatingData.Rating;
+                    hasUserRated = true;
+                }
+            }
+
+            return (averageRating, totalRatings, userRating, hasUserRated);
+        }
+
+        public async Task<bool> IsRecipeFavoritedAsync(string userId, int recipeId)
+        {
+            if (string.IsNullOrEmpty(userId))
+            {
+                return false;
+            }
+
+            return await _context.FavoriteRecipes
+                .AnyAsync(fr => fr.UserId == userId && fr.RecipeId == recipeId);
+        }
+
+        public async Task<List<Recipe>> GetUserRecipesAsync(string userId)
+        {
+            var userRecipes = await _context.Recipes
+                .Where(r => r.UserId == userId)
+                .Include(r => r.User)
+                .Include(r => r.Ratings)
+                .ToListAsync();
+
+            foreach (var recipe in userRecipes)
+            {
+                recipe.Rating = recipe.Ratings.Any() ? recipe.Ratings.Average(r => r.Rating) : 0;
+            }
+
+            return userRecipes;
+        }
+
+        public async Task<double> GetUserAverageRatingAsync(string userId)
+        {
+            var userRecipes = await _context.Recipes
+                .Where(r => r.UserId == userId)
+                .Select(r => r.Id)
+                .ToListAsync();
+
+            var ratings = await _context.RecipeRatings
+                .Where(r => userRecipes.Contains(r.RecipeId))
+                .GroupBy(r => r.RecipeId)
+                .Select(g => g.Average(r => r.Rating))
+                .ToListAsync();
+
+            if (ratings.Any())
+            {
+                return Math.Round(ratings.Average(), 1);
+            }
+
+            return 0;
+        }
+
+        public async Task<(Recipe recipe, float totalCalories, float totalProtein, float totalCarbs, float totalFat, bool hasPendingIngredients)> CalculateRecipeNutritionAsync(Recipe recipe, List<SelectedIngredient> ingredients)
+        {
+            float totalCalories = 0;
+            float totalProtein = 0;
+            float totalCarbs = 0;
+            float totalFat = 0;
+            bool hasPendingIngredients = false;
+
+            foreach (var i in ingredients)
+            {
+                var tempIngredient = await _context.Ingredients.FindAsync(i.Id);
+
+                if (tempIngredient != null)
+                {
+                    totalCalories += ConvertUnit(tempIngredient.Calories, i.Unit) * i.Quantity;
+                    totalProtein += ConvertUnit(tempIngredient.Protein, i.Unit) * i.Quantity;
+                    totalCarbs += ConvertUnit(tempIngredient.Carbs, i.Unit) * i.Quantity;
+                    totalFat += ConvertUnit(tempIngredient.Fat, i.Unit) * i.Quantity;
+
+                    if (tempIngredient.Status == "Pending")
+                    {
+                        hasPendingIngredients = true;
+                    }
+                }
+            }
+
+            return (recipe, totalCalories, totalProtein, totalCarbs, totalFat, hasPendingIngredients);
+        }
+
+        public async Task<Recipe> CreateRecipeAsync(Recipe recipe, List<SelectedIngredient> ingredients, string imageUrl)
+        {
+            recipe.ImageUrl = imageUrl;
+            recipe.Type = new List<string> { " " };
+            
+            _context.Add(recipe);
+            await _context.SaveChangesAsync();
+
+            var (_, totalCalories, totalProtein, totalCarbs, totalFat, hasPendingIngredients) = 
+                await CalculateRecipeNutritionAsync(recipe, ingredients);
+
+            foreach (var i in ingredients)
+            {
+                _context.RecipeIngredients.Add(new RecipeIngredient
+                {
+                    RecipeId = recipe.Id,
+                    IngredientId = i.Id,
+                    Unit = i.Unit,
+                    Quantity = i.Quantity
+                });
+            }
+
+            recipe.Calories = MathF.Round(totalCalories, MidpointRounding.AwayFromZero);
+            recipe.Protein = MathF.Round(totalProtein, MidpointRounding.AwayFromZero);
+            recipe.Carbs = MathF.Round(totalCarbs, MidpointRounding.AwayFromZero);
+            recipe.Fat = MathF.Round(totalFat, MidpointRounding.AwayFromZero);
+            recipe.HasPendingIngredients = hasPendingIngredients;
+            recipe.Type = _recipeTagService.GenerateRecipeTags(recipe, ingredients);
+
+            _context.Update(recipe);
+            await _context.SaveChangesAsync();
+
+            return recipe;
+        }
+
+        public async Task<Recipe> UpdateRecipeAsync(Recipe recipe, List<SelectedIngredient> ingredients, string imageUrl)
+        {
+            recipe.ImageUrl = imageUrl;
+
+            await _context.RecipeIngredients
+                .Where(ri => ri.RecipeId == recipe.Id)
+                .ExecuteDeleteAsync();
+
+            var (_, totalCalories, totalProtein, totalCarbs, totalFat, _) = 
+                await CalculateRecipeNutritionAsync(recipe, ingredients);
+
+            foreach (var i in ingredients)
+            {
+                _context.RecipeIngredients.Add(new RecipeIngredient
+                {
+                    RecipeId = recipe.Id,
+                    IngredientId = i.Id,
+                    Unit = i.Unit,
+                    Quantity = i.Quantity
+                });
+            }
+
+            recipe.Calories = MathF.Round(totalCalories, MidpointRounding.AwayFromZero);
+            recipe.Protein = MathF.Round(totalProtein, MidpointRounding.AwayFromZero);
+            recipe.Carbs = MathF.Round(totalCarbs, MidpointRounding.AwayFromZero);
+            recipe.Fat = MathF.Round(totalFat, MidpointRounding.AwayFromZero);
+            recipe.Type = _recipeTagService.GenerateRecipeTags(recipe, ingredients);
+
+            _context.Update(recipe);
+            await _context.SaveChangesAsync();
+
+            return recipe;
+        }
+
+        public async Task DeleteRecipeAsync(int recipeId)
+        {
+            var recipe = await _context.Recipes.FindAsync(recipeId);
+            if (recipe != null)
+            {
+                _context.Recipes.Remove(recipe);
+                await _context.SaveChangesAsync();
+            }
+        }
+
+        public float ConvertUnit(float number, string unit)
+        {
+            float result;
+            switch (unit.ToLower())
+            {
+                case "g":
+                case "ml":
+                    result = number / 100;
+                    break;
+                case "oz":
+                    result = (float)(number * 28.3495 / 100);
+                    break;
+                case "tbsp":
+                    result = (float)(number * 15 / 100);
+                    break;
+                case "tsp":
+                    result = (float)(number * 5 / 100);
+                    break;
+                case "cup":
+                    result = (float)(number * 240 / 100);
+                    break;
+                default:
+                    return 0;
+            }
+
+            return result;
+        }
+
+        public async Task<(bool success, string message, bool isFavorited)> ToggleFavoriteAsync(string userId, int recipeId)
+        {
+            if (string.IsNullOrEmpty(userId))
+            {
+                return (false, "User not authenticated", false);
+            }
+
+            var recipe = await _context.Recipes.FindAsync(recipeId);
+            if (recipe == null)
+            {
+                return (false, "Recipe not found", false);
+            }
+
+            var existingFavorite = await _context.FavoriteRecipes
+                .FirstOrDefaultAsync(fr => fr.UserId == userId && fr.RecipeId == recipeId);
+
+            bool isFavorited;
+            string message;
+
+            if (existingFavorite != null)
+            {
+                _context.FavoriteRecipes.Remove(existingFavorite);
+                isFavorited = false;
+                message = "Removed from favorites";
+            }
+            else
+            {
+                var favoriteRecipe = new FavoriteRecipe
+                {
+                    UserId = userId,
+                    RecipeId = recipeId
+                };
+                _context.FavoriteRecipes.Add(favoriteRecipe);
+                isFavorited = true;
+                message = "Added to favorites";
+            }
+
+            await _context.SaveChangesAsync();
+
+            return (true, message, isFavorited);
+        }
+    }
+}
Index: NutriMatch/Services/RecipeTagService.cs
===================================================================
--- NutriMatch/Services/RecipeTagService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/RecipeTagService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NutriMatch.Data;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public class RecipeTagService : IRecipeTagService
+    {
+        private readonly AppDbContext _context;
+
+        public RecipeTagService(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        public List<string> GenerateRecipeTags(Recipe recipe, List<SelectedIngredient> ingredients)
+        {
+            var breakfastKeywords = new HashSet<string>(
+                _context.MealKeywords.Where(k => k.Tag == "breakfast").Select(k => k.Name),
+                StringComparer.OrdinalIgnoreCase
+            );
+
+            var mainKeywords = new HashSet<string>(
+                _context.MealKeywords.Where(k => k.Tag == "main").Select(k => k.Name),
+                StringComparer.OrdinalIgnoreCase
+            );
+
+            var snackKeywords = new HashSet<string>(
+                _context.MealKeywords.Where(k => k.Tag == "snack").Select(k => k.Name),
+                StringComparer.OrdinalIgnoreCase
+            );
+
+            var tags = new HashSet<string>();
+
+            var titleWords = recipe.Title.ToLower()
+                .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
+
+            var ingredientWords = new HashSet<string>();
+            foreach (var ing in ingredients)
+            {
+                var words = ing.Name.ToLower()
+                    .Split(new char[] { ' ', '-', '_', ',', '.', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
+                foreach (var w in words) ingredientWords.Add(w);
+            }
+
+            int breakfastScore = CountKeywordMatches(titleWords, breakfastKeywords, true) +
+                                CountKeywordMatches(ingredientWords, breakfastKeywords, false);
+
+            int mainScore = CountKeywordMatches(titleWords, mainKeywords, true) +
+                            CountKeywordMatches(ingredientWords, mainKeywords, false);
+
+            int snackScore = CountKeywordMatches(titleWords, snackKeywords, true) +
+                            CountKeywordMatches(ingredientWords, snackKeywords, false);
+
+            int lunchScore = mainScore;
+            int dinnerScore = mainScore;
+
+            float calories = Math.Max(recipe.Calories, 1);
+            float proteinRatio = (recipe.Protein * 4) / calories * 100;
+            float carbRatio = (recipe.Carbs * 4) / calories * 100;
+            float fatRatio = (recipe.Fat * 9) / calories * 100;
+
+            if (calories < 150)
+            {
+                snackScore += 5;
+                breakfastScore -= 2;
+                lunchScore -= 3;
+                dinnerScore -= 4;
+            }
+            else if (calories < 300)
+            {
+                snackScore += 3;
+                breakfastScore += 2;
+                lunchScore -= 1;
+                dinnerScore -= 2;
+            }
+            else if (calories < 450)
+            {
+                breakfastScore += 3;
+                lunchScore += 2;
+                snackScore -= 1;
+                dinnerScore -= 1;
+            }
+            else if (calories < 650)
+            {
+                lunchScore += 3;
+                dinnerScore += 2;
+                breakfastScore -= 1;
+                snackScore -= 3;
+            }
+            else
+            {
+                dinnerScore += 4;
+                lunchScore += 1;
+                breakfastScore -= 3;
+                snackScore -= 4;
+            }
+
+            // Protein ratio scoring
+            if (proteinRatio > 30)
+            {
+                dinnerScore += 3;
+                lunchScore += 2;
+                breakfastScore += 1;
+                snackScore -= 1;
+            }
+            else if (proteinRatio > 20)
+            {
+                dinnerScore += 2;
+                lunchScore += 1;
+            }
+            else if (proteinRatio < 10)
+            {
+                snackScore += 2;
+                dinnerScore -= 1;
+                lunchScore -= 1;
+            }
+
+            // Carb ratio scoring
+            if (carbRatio > 60)
+            {
+                breakfastScore += 2;
+                snackScore += 2;
+                dinnerScore -= 1;
+            }
+            else if (carbRatio < 20)
+            {
+                dinnerScore += 1;
+                lunchScore += 1;
+            }
+
+            // Fat ratio scoring
+            if (fatRatio > 40)
+            {
+                dinnerScore += 2;
+                snackScore += 1;
+                breakfastScore -= 1;
+            }
+
+            var results = new List<(string tag, int score)>
+            {
+                ("breakfast", breakfastScore),
+                ("lunch", lunchScore),
+                ("dinner", dinnerScore),
+                ("snack", snackScore)
+            }.OrderByDescending(x => x.score).ToList();
+
+            tags.Add(results[0].tag);
+
+            for (int i = 1; i < results.Count; i++)
+            {
+                if (results[i].score > 0 && results[i].score >= results[0].score * 0.6)
+                    tags.Add(results[i].tag);
+            }
+
+            return tags.ToList();
+        }
+
+        private string NormalizeWord(string word)
+        {
+            word = word.ToLower().Trim();
+            if (word.EndsWith("ies") && word.Length > 4)
+                return word.Substring(0, word.Length - 3) + "y";
+            if (word.EndsWith("es") && word.Length > 3)
+                return word.Substring(0, word.Length - 2);
+            if (word.EndsWith("s") && word.Length > 3 && !word.EndsWith("ss"))
+                return word.Substring(0, word.Length - 1);
+            return word;
+        }
+
+        private int CountKeywordMatches(IEnumerable<string> words, HashSet<string> keywords, bool isTitle = false)
+        {
+            int count = 0;
+            foreach (var word in words)
+            {
+                bool matches = keywords.Contains(word) || keywords.Contains(NormalizeWord(word));
+                if (matches)
+                    count += isTitle ? 3 : 1;
+            }
+            return count;
+        }
+    }
+}
Index: NutriMatch/Services/RestaurantService.cs
===================================================================
--- NutriMatch/Services/RestaurantService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/RestaurantService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,436 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using NutriMatch.Data;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public class RestaurantService : IRestaurantService
+    {
+        private readonly AppDbContext _context;
+        private readonly IWebHostEnvironment _env;
+        private readonly IMealPlanService _mealPlanService;
+
+        private readonly IMealClassificationService _mealClassificationService;
+        private readonly INotificationService _notificationService;
+
+        public RestaurantService(
+            AppDbContext context,
+            IWebHostEnvironment env,
+            IMealPlanService mealPlanService,
+            INotificationService notificationService,
+            IMealClassificationService mealClassificationService
+          )
+        {
+            _context = context;
+            _env = env;
+            _mealPlanService = mealPlanService;
+            _notificationService = notificationService;
+          
+            _mealClassificationService = mealClassificationService;
+        }
+
+        public async Task<List<Restaurant>> GetAllRestaurantsAsync()
+        {
+            return await _context.Restaurants.ToListAsync();
+        }
+
+        public async Task<(Restaurant restaurant, List<RestaurantMeal> filteredMeals)> GetRestaurantWithFilteredMealsAsync(
+            int id,
+            int? minCalories,
+            int? maxCalories,
+            int? minProtein,
+            int? maxProtein,
+            int? minCarbs,
+            int? maxCarbs,
+            int? minFat,
+            int? maxFat)
+        {
+            var restaurant = await _context.Restaurants
+                .Include(r => r.RestaurantMeals)
+                .FirstOrDefaultAsync(m => m.Id == id);
+
+            if (restaurant == null)
+            {
+                return (null, null);
+            }
+
+            var filteredMeals = restaurant.RestaurantMeals
+                .Where(r =>
+                    (minCalories == null || r.Calories >= minCalories) &&
+                    (maxCalories == null || r.Calories <= maxCalories) &&
+                    (minProtein == null || r.Protein >= minProtein) &&
+                    (maxProtein == null || r.Protein <= maxProtein) &&
+                    (minFat == null || r.Fat >= minFat) &&
+                    (maxFat == null || r.Fat <= maxFat) &&
+                    (minCarbs == null || r.Carbs >= minCarbs) &&
+                    (maxCarbs == null || r.Carbs <= maxCarbs)
+                )
+                .ToList();
+
+            Console.WriteLine($"Total meals for restaurant {id}: {filteredMeals.Count}");
+
+            return (restaurant, filteredMeals);
+        }
+
+        public async Task<List<object>> GetRestaurantsAsync()
+        {
+            return await _context.Restaurants
+                .OrderBy(r => r.Name)
+                .Select(r => new { id = r.Id, name = r.Name })
+                .Cast<object>()
+                .ToListAsync();
+        }
+
+        public async Task<object?> GetRestaurantAsync(int id)
+        {
+            var restaurant = await _context.Restaurants.FindAsync(id);
+            if (restaurant == null)
+            {
+                return null;
+            }
+
+            return new
+            {
+                id = restaurant.Id,
+                name = restaurant.Name,
+                imageUrl = restaurant.ImageUrl,
+                description = restaurant.Description
+            };
+        }
+
+        public async Task<List<RestaurantMeal>> GetRestaurantMealsAsync(int restaurantId)
+        {
+            return await _context.RestaurantMeals
+                .Where(m => m.RestaurantId == restaurantId)
+                .OrderBy(m => m.ItemName)
+                .ToListAsync();
+        }
+
+        public async Task<(bool success, string message, int? restaurantId)> AddRestaurantAsync(string name, string description, string imagePath)
+        {
+            if (string.IsNullOrWhiteSpace(name))
+            {
+                return (false, "Restaurant name is required", null);
+            }
+
+            var restaurant = new Restaurant
+            {
+                Name = name,
+                Description = description,
+                ImageUrl = imagePath
+            };
+
+            _context.Restaurants.Add(restaurant);
+            await _context.SaveChangesAsync();
+
+            await CreateRestaurantNotificationsAsync(restaurant);
+
+            return (true, "Restaurant added successfully", restaurant.Id);
+        }
+
+        public async Task<(bool success, string message)> EditRestaurantAsync(int id, string name, string description, string? imagePath)
+        {
+            var restaurant = await _context.Restaurants.FindAsync(id);
+            if (restaurant == null)
+            {
+                return (false, "Restaurant not found");
+            }
+
+            if (string.IsNullOrWhiteSpace(name))
+            {
+                return (false, "Restaurant name is required");
+            }
+
+            restaurant.Name = name;
+            restaurant.Description = description;
+
+            if (!string.IsNullOrEmpty(imagePath))
+            {
+                if (!string.IsNullOrEmpty(restaurant.ImageUrl))
+                {
+                    var oldImagePath = Path.Combine(_env.WebRootPath, restaurant.ImageUrl.TrimStart('/'));
+                    if (File.Exists(oldImagePath))
+                    {
+                        File.Delete(oldImagePath);
+                    }
+                }
+
+                restaurant.ImageUrl = imagePath;
+            }
+
+            await _context.SaveChangesAsync();
+
+            return (true, "Restaurant updated successfully");
+        }
+
+        public async Task<(bool success, string message)> DeleteRestaurantAsync(int id)
+        {
+            if (id == 0)
+                return (false, "Invalid restaurant ID");
+
+            var restaurant = await _context.Restaurants
+                .Include(r => r.RestaurantMeals)
+                .Include(r => r.Followers)
+                .FirstOrDefaultAsync(r => r.Id == id);
+
+            if (restaurant == null)
+                return (false, "Restaurant not found");
+
+            if (restaurant.Followers != null && restaurant.Followers.Any())
+            {
+                _context.RestaurantFollowings.RemoveRange(restaurant.Followers);
+            }
+
+            if (restaurant.RestaurantMeals != null && restaurant.RestaurantMeals.Any())
+            {
+                foreach (var meal in restaurant.RestaurantMeals)
+                {
+                    await _mealPlanService.HandleDeletedRestaurantMealAsync(meal.Id);
+                }
+                _context.RestaurantMeals.RemoveRange(restaurant.RestaurantMeals);
+            }
+
+            if (!string.IsNullOrEmpty(restaurant.ImageUrl))
+            {
+                var imagePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", restaurant.ImageUrl.TrimStart('/'));
+                if (File.Exists(imagePath))
+                {
+                    try
+                    {
+                        File.Delete(imagePath);
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine($"Failed to delete image file: {imagePath}. Error: {ex.Message}");
+                    }
+                }
+            }
+
+            _context.Restaurants.Remove(restaurant);
+            await _context.SaveChangesAsync();
+
+            return (true, $"Restaurant '{restaurant.Name}' and all related data deleted successfully");
+        }
+
+        public async Task<(bool success, string message)> AddRestaurantMealAsync(RestaurantMeal meal)
+        {
+            if (string.IsNullOrWhiteSpace(meal.ItemName))
+            {
+                return (false, "Meal name is required");
+            }
+
+            if (meal.RestaurantId == null || meal.RestaurantId == 0)
+            {
+                return (false, "Restaurant is required");
+            }
+
+            var restaurant = await _context.Restaurants.FindAsync(meal.RestaurantId);
+            if (restaurant == null)
+            {
+                return (false, "Restaurant not found");
+            }
+
+            meal.RestaurantName = restaurant.Name;
+
+            meal.Type = await _mealClassificationService.GenerateMealTypes(meal);
+
+            _context.RestaurantMeals.Add(meal);
+            await _context.SaveChangesAsync();
+
+            await CreateMealNotificationsAsync(meal, restaurant);
+
+            return (true, "Meal added successfully");
+        }
+
+        public async Task<(bool success, string message)> EditRestaurantMealAsync(RestaurantMeal meal)
+        {
+            if (meal == null || meal.Id == 0)
+                return (false, "Invalid meal");
+
+            var existing = await _context.RestaurantMeals.FindAsync(meal.Id);
+            if (existing == null)
+                return (false, "Meal not found");
+
+            existing.ItemName = meal.ItemName;
+            existing.ItemDescription = meal.ItemDescription;
+            existing.Type = await _mealClassificationService.GenerateMealTypes(meal);
+            existing.Calories = meal.Calories;
+            existing.Protein = meal.Protein;
+            existing.Carbs = meal.Carbs;
+            existing.Fat = meal.Fat;
+
+            await _context.SaveChangesAsync();
+
+            return (true, "Meal updated successfully");
+        }
+
+        public async Task<(bool success, string message)> DeleteRestaurantMealAsync(int id)
+        {
+            var meal = await _context.RestaurantMeals.FindAsync(id);
+            if (meal == null)
+            {
+                return (false, "Meal not found");
+            }
+
+            await _mealPlanService.HandleDeletedRestaurantMealAsync(id);
+
+            _context.RestaurantMeals.Remove(meal);
+            await _context.SaveChangesAsync();
+
+            return (true, "Meal deleted successfully");
+        }
+
+        private async Task CreateRestaurantNotificationsAsync(Restaurant restaurant)
+        {
+            var users = await _context.Users
+                .Where(u => u.NotifyNewRestaurant)
+                .ToListAsync();
+
+            foreach (var user in users)
+            {
+                var notification = new Notification
+                {
+                    UserId = user.Id,
+                    Type = "NewRestaurant",
+                    Message = "New restaurant added: " + restaurant.Name,
+                    RecipeId = restaurant.Id,
+                    CreatedAt = DateTime.UtcNow,
+                    IsRead = false
+                };
+
+                _context.Notifications.Add(notification);
+
+                await _notificationService.SendEmailAsync(
+                    user.Email,
+                    "New restaurant added!",
+                    $"<p>Hi {user.UserName},</p><p>New restaurant added: <b>{restaurant.Name}</b>.</p>"
+                );
+            }
+
+            await _context.SaveChangesAsync();
+        }
+
+        private async Task CreateMealNotificationsAsync(RestaurantMeal meal, Restaurant restaurant)
+        {
+            var followers = await _context.RestaurantFollowings
+                .Include(f => f.User)
+                .Where(f => f.RestaurantId == meal.RestaurantId && f.User.NotifyRestaurantNewMeal)
+                .Select(f => f.UserId)
+                .ToListAsync();
+
+            foreach (var userId in followers)
+            {
+                var notification = new Notification
+                {
+                    UserId = userId,
+                    Type = "RestaurantNewMeal",
+                    Message = $"{restaurant.Name} added a new meal: {meal.ItemName}",
+                    RecipeId = restaurant.Id,
+                    CreatedAt = DateTime.UtcNow,
+                    IsRead = false
+                };
+                _context.Notifications.Add(notification);
+
+                var follower = await _context.Users.FindAsync(userId);
+                if (follower != null)
+                {
+                    await _notificationService.SendEmailAsync(
+                        follower.Email,
+                        "New meal added",
+                        $"<p>Hi {follower.UserName},</p><p>{restaurant.Name} added a new meal: <b>{meal.ItemName}</b>.</p>"
+                    );
+                }
+            }
+
+            var allPrefs = await _context.UserMealPreferences
+                .Include(p => p.User)
+                .ToListAsync();
+
+            var userPreferences = allPrefs
+                .GroupBy(p => p.UserId)
+                .Select(g => new
+                {
+                    UserId = g.Key,
+                    Preferences = g.ToList(),
+                    User = g.First().User
+                })
+                .Where(u => !followers.Contains(u.UserId) && u.User.NotifyMealMatchesTags)
+                .ToList();
+
+            foreach (var userPref in userPreferences)
+            {
+                var matchingTags = GetMatchingTags(userPref.Preferences, meal.Protein, meal.Carbs, meal.Fat, meal.Calories);
+
+                if (matchingTags.Any())
+                {
+                    var tagsText = string.Join(", ", matchingTags);
+
+                    var notification = new Notification
+                    {
+                        UserId = userPref.UserId,
+                        Type = "MealMatchesTags",
+                        Message = $"New meal matches your preferences ({tagsText}): {meal.ItemName} at {restaurant.Name}",
+                        RecipeId = restaurant.Id,
+                        CreatedAt = DateTime.UtcNow,
+                        IsRead = false
+                    };
+                    _context.Notifications.Add(notification);
+
+                    await _notificationService.SendEmailAsync(
+                        userPref.User.Email,
+                        "New meal matches your preferences",
+                        $"<p>Hi {userPref.User.UserName},</p><p>{notification.Message}</p>"
+                    );
+                }
+            }
+
+            await _context.SaveChangesAsync();
+        }
+
+        private List<string> GetMatchingTags(List<UserMealPreference> preferences, float protein, float carbs, float fat, float calories)
+        {
+            var matchingTags = new List<string>();
+
+            foreach (var pref in preferences)
+            {
+                bool matches = pref.Tag switch
+                {
+                    "high-protein" => pref.ThresholdValue.HasValue ? protein >= pref.ThresholdValue.Value : protein >= 30,
+                    "low-carb" => pref.ThresholdValue.HasValue ? carbs <= pref.ThresholdValue.Value : carbs <= 20,
+                    "high-carb" => pref.ThresholdValue.HasValue ? carbs >= pref.ThresholdValue.Value : carbs >= 50,
+                    "low-fat" => pref.ThresholdValue.HasValue ? fat <= pref.ThresholdValue.Value : fat <= 15,
+                    "high-fat" => pref.ThresholdValue.HasValue ? fat >= pref.ThresholdValue.Value : fat >= 30,
+                    "low-calorie" => pref.ThresholdValue.HasValue ? calories <= pref.ThresholdValue.Value : calories <= 300,
+                    "high-calorie" => pref.ThresholdValue.HasValue ? calories >= pref.ThresholdValue.Value : calories >= 600,
+                    "balanced" => IsBalanced(protein, carbs, fat, calories),
+                    _ => false
+                };
+
+                if (matches)
+                {
+                    matchingTags.Add(pref.Tag);
+                }
+            }
+
+            return matchingTags;
+        }
+
+        private bool IsBalanced(float protein, float carbs, float fat, float calories)
+        {
+            if (calories <= 0) return false;
+
+            float proteinRatio = (protein * 4) / calories * 100;
+            float carbRatio = (carbs * 4) / calories * 100;
+            float fatRatio = (fat * 9) / calories * 100;
+
+            return proteinRatio >= 20 && proteinRatio <= 35 &&
+                   carbRatio >= 30 && carbRatio <= 50 &&
+                   fatRatio >= 20 && fatRatio <= 35;
+        }
+    }
+
+}
Index: NutriMatch/Services/UserPreferenceService.cs
===================================================================
--- NutriMatch/Services/UserPreferenceService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Services/UserPreferenceService.cs	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,82 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using NutriMatch.Data;
+using NutriMatch.Models;
+
+namespace NutriMatch.Services
+{
+    public class UserPreferenceService : IUserPreferenceService
+    {
+        private readonly AppDbContext _context;
+
+        public UserPreferenceService(AppDbContext context)
+        {
+            _context = context;
+        }
+
+        public async Task<(List<object> preferences, List<int> followedRestaurants)> GetUserPreferencesAsync(string userId)
+        {
+            var preferences = await _context.UserMealPreferences
+                .Where(p => p.UserId == userId)
+                .Select(p => new
+                {
+                    tag = p.Tag,
+                    thresholdValue = p.ThresholdValue
+                })
+                .ToListAsync<object>();
+
+            var followedRestaurants = await _context.RestaurantFollowings
+                .Where(f => f.UserId == userId)
+                .Select(f => f.RestaurantId)
+                .ToListAsync();
+
+            return (preferences, followedRestaurants);
+        }
+
+        public async Task UpdateTagPreferencesAsync(string userId, List<UserMealPreference> preferences)
+        {
+            var existing = await _context.UserMealPreferences
+                .Where(p => p.UserId == userId)
+                .ToListAsync();
+            
+            _context.UserMealPreferences.RemoveRange(existing);
+
+            foreach (var pref in preferences)
+            {
+                _context.UserMealPreferences.Add(new UserMealPreference
+                {
+                    UserId = userId,
+                    Tag = pref.Tag,
+                    ThresholdValue = pref.ThresholdValue
+                });
+            }
+
+            await _context.SaveChangesAsync();
+        }
+
+        public async Task<(bool success, bool following)> ToggleFollowRestaurantAsync(string userId, int restaurantId)
+        {
+            var existing = await _context.RestaurantFollowings
+                .FirstOrDefaultAsync(f => f.UserId == userId && f.RestaurantId == restaurantId);
+
+            if (existing != null)
+            {
+                _context.RestaurantFollowings.Remove(existing);
+                await _context.SaveChangesAsync();
+                return (true, false);
+            }
+            else
+            {
+                _context.RestaurantFollowings.Add(new RestaurantFollowing
+                {
+                    UserId = userId,
+                    RestaurantId = restaurantId,
+                });
+                await _context.SaveChangesAsync();
+                return (true, true);
+            }
+        }
+    }
+}
Index: NutriMatch/Views/Admin/Index.cshtml
===================================================================
--- NutriMatch/Views/Admin/Index.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/Admin/Index.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -12,4 +12,63 @@
     <title>NutriMatch - Admin Panel</title>
 </head>
+
+<style>
+/* Admin Management Section Styles */
+
+.admin-management-section {
+    padding: 15px 0;
+}
+
+.admin-management-section .btn {
+    background: white;
+    border: 1px solid #e0e0e0;
+    border-radius: 8px;
+    padding: 20px 24px;
+    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
+    position: relative;
+    overflow: hidden;
+}
+
+.admin-management-section .btn:hover {
+    transform: translateY(-1px);
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+    border-color: #d0d0d0;
+}
+
+.admin-management-section .btn-outline-primary:hover {
+    background: #f8f9ff;
+    border-color: #4a6fa5;
+    color: #4a6fa5;
+}
+
+.admin-management-section .btn-outline-success:hover {
+    background: #f6fef9;
+    border-color: #198754;
+    color: #198754;
+}
+
+.admin-management-section .btn i {
+    font-size: 1.3rem;
+    display: inline-block;
+    vertical-align: middle;
+    margin-right: 8px;
+}
+
+.admin-management-section .btn strong {
+    font-size: 1rem;
+    font-weight: 600;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.admin-management-section .btn .small {
+    font-size: 0.8rem;
+    opacity: 0.65;
+    display: block;
+    margin-top: 4px;
+    font-weight: 400;
+}
+</style>
 <body>
     @Html.AntiForgeryToken()
@@ -20,7 +79,6 @@
                     <h2 class="admin-title">
                         <i class="fas fa-shield-alt me-2" style="color: var(--nutri-green);"></i>
-                        Recipe Approval Panel
+                        Admin Panel
                     </h2>
-                    <p class="admin-subtitle text-muted">Review and manage pending recipe submissions</p>
                 </div>
                 <div class="col-md-4 text-end">
@@ -34,4 +92,25 @@
             </div>
         </div>
+
+        <!-- NEW ADMIN MANAGEMENT BUTTONS -->
+        <div class="admin-management-section mb-4">
+            <div class="row g-3">
+                <div class="col-md-6">
+                    <button class="btn btn-outline-primary w-100 py-3" onclick="openMealTagsModal()">
+                        <i class="fas fa-tags me-2"></i>
+                        <strong>Manage Meal Tags</strong>
+                        <div class="small text-muted">Add or remove meal type keywords</div>
+                    </button>
+                </div>
+                <div class="col-md-6">
+                    <button class="btn btn-outline-success w-100 py-3" onclick="openRestaurantMealsModal()">
+                        <i class="fas fa-utensils me-2"></i>
+                        <strong>Manage Restaurants And Meals</strong>
+                        <div class="small text-muted">Add or remove meals from restaurants</div>
+                    </button>
+                </div>
+            </div>
+        </div>
+
         <div class="search-container">
             <div class="row align-items-center">
@@ -147,4 +226,11 @@
     <div id="toast-container" class="toast-container"></div>
     <div id="declineModalContainer"></div>
+
+    <!-- Meal Tags Management Modal Container -->
+    <div id="mealTagsModalContainer"></div>
+
+    <!-- Restaurant Meals Management Modal Container -->
+    <div id="restaurantMealsModalContainer"></div>
+
     <div class="modal fade" id="ingredientReviewModal" tabindex="-1" aria-labelledby="ingredientReviewModalLabel"
         aria-hidden="true">
Index: NutriMatch/Views/Admin/_MealTagsPartial.cshtml
===================================================================
--- NutriMatch/Views/Admin/_MealTagsPartial.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Views/Admin/_MealTagsPartial.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,127 @@
+<div class="modal fade" id="mealTagsModal" tabindex="-1" aria-labelledby="mealTagsModalLabel" aria-hidden="true">
+    <div class="modal-dialog modal-lg">
+        <div class="modal-content">
+            <div class="modal-header bg-primary text-white">
+                <h5 class="modal-title" id="mealTagsModalLabel">
+                    <i class="fas fa-tags me-2"></i>Manage Meal Tags
+                </h5>
+                <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"
+                    aria-label="Close"></button>
+            </div>
+            <div class="modal-body">
+                <!-- Add New Keyword Section -->
+                <div class="add-keyword-section mb-4 p-3 bg-light rounded">
+                    <h6 class="mb-3">
+                        <i class="fas fa-plus-circle me-2"></i>Add New Keyword
+                    </h6>
+                    <div class="row g-3">
+                        <div class="col-md-8">
+                            <label for="newKeywordName" class="form-label">Keyword Name</label>
+                            <input type="text" class="form-control" id="newKeywordName"
+                                placeholder="e.g., pancakes, cereal, pizza">
+                        </div>
+                        <div class="col-md-4">
+                            <label for="newKeywordTag" class="form-label">Meal Type</label>
+                            <select class="form-select" id="newKeywordTag">
+                                <option value="breakfast">Breakfast</option>
+                                <option value="main">Main</option>
+                                <option value="snack">Snack</option>
+                            </select>
+                        </div>
+                        <div class="col-12">
+                            <button class="btn btn-primary w-100" onclick="addMealKeyword()">
+                                <i class="fas fa-plus me-2"></i>Add Keyword
+                            </button>
+                        </div>
+                    </div>
+                </div>
+
+                <hr>
+
+                <!-- Existing Keywords Section -->
+                <div class="existing-keywords-section">
+                    <h6 class="mb-3">
+                        <i class="fas fa-list me-2"></i>Existing Keywords
+                    </h6>
+                    <div id="mealKeywordsList">
+                        <div class="text-center py-4">
+                            <div class="spinner-border text-primary" role="status">
+                                <span class="visually-hidden">Loading...</span>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<style>
+    .tag-group {
+        border: 1px solid #e0e0e0;
+        border-radius: 8px;
+        padding: 15px;
+        background-color: #f8f9fa;
+    }
+
+    .tag-header {
+        margin-bottom: 15px;
+        padding-bottom: 10px;
+        border-bottom: 2px solid #dee2e6;
+    }
+
+    .keyword-list {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 10px;
+    }
+
+    .keyword-item {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+        background-color: white;
+        padding: 8px 12px;
+        border-radius: 6px;
+        border: 1px solid #dee2e6;
+    }
+
+    .keyword-name {
+        font-weight: 500;
+        color: #333;
+    }
+
+    .add-keyword-section {
+        border: 2px dashed #0d6efd;
+    }
+</style>
+
+<script>
+    (function () {
+        const modalElement = document.getElementById('mealTagsModal');
+        if (modalElement) {
+            modalElement.addEventListener('shown.bs.modal', function () {
+                console.log('Meal Tags Modal shown, loading keywords...');
+                loadMealKeywords();
+            });
+
+            if (modalElement.classList.contains('show')) {
+                console.log('Modal already shown, loading keywords...');
+                loadMealKeywords();
+            }
+        }
+    })();
+
+    const keywordInput = document.getElementById('newKeywordName');
+    if (keywordInput) {
+        keywordInput.addEventListener('keypress', function (e) {
+            if (e.key === 'Enter') {
+                e.preventDefault();
+                addMealKeyword();
+            }
+        });
+    }
+</script>
Index: NutriMatch/Views/Admin/_RestaurantMealsManagementPartial.cshtml
===================================================================
--- NutriMatch/Views/Admin/_RestaurantMealsManagementPartial.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Views/Admin/_RestaurantMealsManagementPartial.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,199 @@
+<div class="modal fade" id="restaurantMealsModal" tabindex="-1" aria-labelledby="restaurantMealsModalLabel" aria-hidden="true">
+    <div class="modal-dialog modal-xl">
+        <div class="modal-content">
+            <div class="modal-header bg-success text-white">
+                <h5 class="modal-title" id="restaurantMealsModalLabel">
+                    <i class="fas fa-utensils me-2"></i>Manage Restaurant Meals
+                </h5>
+                <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
+            </div>
+            <div class="modal-body">
+                <!-- Restaurant Selection -->
+                <div class="restaurant-select-section mb-4">
+                    <div class="d-flex justify-content-between align-items-end mb-2">
+                        <label for="restaurantSelect" class="form-label fw-bold mb-0">
+                            <i class="fas fa-store me-2"></i>Select Restaurant
+                        </label>
+                        <div class="d-flex gap-2">
+
+                        <button class="btn btn-sm btn-outline-danger" id="deleteRestaurantBtn" style="display: none;" onclick="deleteRestaurant()">
+                            <i class="fas fa-trash me-1"></i>Delete Restaurant
+                        </button>
+                            <button class="btn btn-sm btn-outline-primary" id="editRestaurantBtn" style="display: none;" onclick="showEditRestaurantForm()">
+                                <i class="fas fa-edit me-1"></i>Edit Restaurant
+                            </button>
+                            <button class="btn btn-sm btn-outline-success" onclick="showAddRestaurantForm()">
+                                <i class="fas fa-plus me-1"></i>Add New Restaurant
+                            </button>
+                        </div>
+                    </div>
+                    <select class="form-select form-select-lg" id="restaurantSelect" onchange="loadRestaurantMeals(this.value)">
+                        <option value="">Loading restaurants...</option>
+                    </select>
+                </div>
+
+                <!-- Add/Edit Restaurant Form Section -->
+                <div id="addRestaurantFormSection" class="add-restaurant-section mb-4 p-4 bg-light rounded" style="display: none;">
+                    <h6 class="mb-3" id="restaurantFormTitle">
+                        <i class="fas fa-store-alt me-2"></i>Add New Restaurant
+                    </h6>
+                    <form id="addRestaurantForm">
+                        <input type="hidden" id="editRestaurantId" value="">
+                        <div class="row g-3">
+                            <div class="col-md-6">
+                                <label for="restaurantName" class="form-label">Restaurant Name *</label>
+                                <input type="text" class="form-control" id="restaurantName" placeholder="e.g., Healthy Bites Cafe" required>
+                            </div>
+                            <div class="col-md-6">
+                                <label for="restaurantImage" class="form-label">Restaurant Image *</label>
+                                <input type="file" class="form-control" id="restaurantImage" accept="image/*" onchange="previewImage()">
+                                <small class="text-muted">Accepted formats: JPG, PNG, GIF (Max 5MB)</small>
+                            </div>
+                            <div class="col-12" id="imagePreview" style="display: none;">
+                                <label class="form-label">Image Preview</label>
+                                <div class="border rounded p-2 text-center bg-white">
+                                    <img id="previewImg" src="" alt="Preview" style="max-width: 300px; max-height: 200px; object-fit: contain;">
+                                </div>
+                            </div>
+                            <div class="col-12">
+                                <label for="restaurantDescription" class="form-label">Description</label>
+                                <textarea class="form-control" id="restaurantDescription" rows="2" placeholder="Brief description of the restaurant"></textarea>
+                            </div>
+                            <div class="col-12">
+                                <div class="d-flex gap-2">
+                                    <button type="button" class="btn btn-success flex-grow-1" onclick="addRestaurant()">
+                                        <i class="fas fa-check me-2"></i>Add Restaurant
+                                    </button>
+                                    <button type="button" class="btn btn-secondary" onclick="cancelAddRestaurant()">
+                                        <i class="fas fa-times me-2"></i>Cancel
+                                    </button>
+                                </div>
+                            </div>
+                        </div>
+                    </form>
+                </div>
+
+                <hr>
+
+                <!-- Add New Meal Button -->
+                <div class="text-end mb-3" id="showAddMealBtn" style="display: none;">
+                    <button class="btn btn-success" onclick="showAddMealForm()">
+                        <i class="fas fa-plus me-2"></i>Add New Meal
+                    </button>
+                </div>
+
+                <!-- Add Meal Form Section -->
+                <div id="addMealFormSection" class="add-meal-section mb-4 p-4 bg-light rounded" style="display: none;">
+                    <h6 class="mb-3" id="addMealFormTitle">
+                        <i class="fas fa-plus-circle me-2"></i>Add New Meal
+                    </h6>
+                    <form id="addMealForm">
+                        <input type="hidden" id="editMealId" value="">
+                        <div class="row g-3">
+                            <div class="col-md-8">
+                                <label for="mealItemName" class="form-label">Meal Name *</label>
+                                <input type="text" class="form-control" id="mealItemName" placeholder="e.g., Grilled Chicken Salad" required>
+                            </div>
+                            <div class="col-12">
+                                <label for="mealItemDescription" class="form-label">Description</label>
+                                <textarea class="form-control" id="mealItemDescription" rows="2" placeholder="Brief description of the meal"></textarea>
+                            </div>
+                            <div class="col-md-3">
+                                <label for="mealCalories" class="form-label">Calories</label>
+                                <input type="number" class="form-control" id="mealCalories" step="0.1" min="0" placeholder="0" required>
+                            </div>
+                            <div class="col-md-3">
+                                <label for="mealProtein" class="form-label">Protein (g)</label>
+                                <input type="number" class="form-control" id="mealProtein" step="0.1" min="0" placeholder="0" required>
+                            </div>
+                            <div class="col-md-3">
+                                <label for="mealCarbs" class="form-label">Carbs (g)</label>
+                                <input type="number" class="form-control" id="mealCarbs" step="0.1" min="0" placeholder="0" required>
+                            </div>
+                            <div class="col-md-3">
+                                <label for="mealFat" class="form-label">Fat (g)</label>
+                                <input type="number" class="form-control" id="mealFat" step="0.1" min="0" placeholder="0" required>
+                            </div>
+                            <div class="col-12">
+                                <div class="d-flex gap-2">
+                                    <button type="button" class="btn btn-success flex-grow-1" onclick="addRestaurantMeal()">
+                                        <i class="fas fa-check me-2"></i>Add Meal
+                                    </button>
+                                    <button type="button" class="btn btn-secondary" onclick="cancelAddMeal()">
+                                        <i class="fas fa-times me-2"></i>Cancel
+                                    </button>
+                                </div>
+                            </div>
+                        </div>
+                    </form>
+                </div>
+
+                <!-- Existing Meals List -->
+                <div class="existing-meals-section">
+                    <h6 class="mb-3">
+                        <i class="fas fa-list me-2"></i>Existing Meals
+                    </h6>
+                    <div id="restaurantMealsList">
+                        <p class="text-muted text-center py-4">Please select a restaurant to view meals</p>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
+            </div>
+        </div>
+    </div>
+</div>
+
+<style>
+.add-meal-section {
+    border: 2px dashed #198754;
+}
+
+.add-restaurant-section {
+    border: 2px dashed #0d6efd;
+}
+
+.meals-grid {
+    display: grid;
+    gap: 15px;
+    max-height: 400px;
+    overflow-y: auto;
+}
+
+.meal-card {
+    background-color: white;
+    border: 1px solid #dee2e6;
+    border-radius: 8px;
+    padding: 15px;
+    transition: box-shadow 0.3s ease;
+}
+
+.meal-card:hover {
+    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+}
+
+.meal-name {
+    color: #333;
+    font-weight: 600;
+    margin-bottom: 5px;
+}
+
+.meal-description {
+    margin-bottom: 8px;
+}
+
+.meal-types {
+    margin-bottom: 8px;
+}
+
+.meal-macros {
+    padding-top: 8px;
+    border-top: 1px solid #e9ecef;
+    color: #666;
+}
+
+#imagePreview img {
+    border-radius: 8px;
+}
+</style>
Index: NutriMatch/Views/Home/Index.cshtml
===================================================================
--- NutriMatch/Views/Home/Index.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/Home/Index.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -32,8 +32,9 @@
                             filter recipes by macronutrient profiles that align with your dietary needs
                         </p>
-                        <button class="btn btn-primary-custom">
+                       <a href="/Identity/Account/Register"> <button class="btn btn-primary-custom">
                             Sign up
                         </button>
-                        <p class="mt-3 text-muted">Already have an account? <a href="#"
+                        </a>
+                        <p class="mt-3 text-muted">Already have an account? <a href="/Identity/Account/Login"
                                 style="color: var(--primary-green); text-decoration: none;">Log in</a></p>
                     </div>
@@ -161,4 +162,5 @@
         </section>
     }
+
     <section class="share-recipe-section">
         <div class="container">
@@ -190,5 +192,5 @@
                     <p class="share-description">
                         Have a recipe that fits your nutrition goals? Share it with the community and help others
-                        discover meals that balance flavor and function. Whether it’s high-protein, low-carb, or
+                        discover meals that balance flavor and function. Whether it's high-protein, low-carb, or
                         macro-balanced — your creations make a difference.
                     </p>
@@ -200,4 +202,5 @@
         </div>
     </section>
+
     <section class="trending-section">
         <div class="container">
@@ -276,4 +279,5 @@
         </div>
     </section>
+
     <section class="restaurants-section">
         <div class="container">
@@ -284,9 +288,10 @@
             <div class="restaurants-container" onclick="window.location.href='@Url.Action("Index", "Restaurants")'"
                 style="cursor: pointer;">
-                @foreach (var restaurant in Model.Restaurants)
+                @for (int i = 0; i < Model.Restaurants.Count; i++)
                 {
-                    <div class="restaurant-card">
+                    var restaurant = Model.Restaurants[i];
+                    <div class="restaurant-card" style="animation-delay: @(i * -4)s; top: 20px;">
                         <div class="restaurant-logo"
-                            style="background: display: flex; align-items: center; justify-content: center; font-size: 1.5rem; color: white; font-weight: bold;">
+                            style="display: flex; align-items: center; justify-content: center; font-size: 1.5rem; color: white; font-weight: bold;">
                             <img src="@restaurant.ImageUrl" style="width: 70px;">
                         </div>
@@ -299,2 +304,3 @@
     </section>
 </body>
+</html>
Index: NutriMatch/Views/MealPlan/Details.cshtml
===================================================================
--- NutriMatch/Views/MealPlan/Details.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/MealPlan/Details.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -4,4 +4,5 @@
     Layout = "~/Views/Shared/_Layout.cshtml";
 }
+
 <head>
     <meta charset="UTF-8">
@@ -9,5 +10,106 @@
     <title>Create Meal Plan</title>
     <link href="~/css/MealPlanDetails.css" rel="stylesheet">
+    <style>
+        .regenerate-btn {
+            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
+            color: white;
+            border: none;
+            padding: 6px 10px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.75rem;
+            font-weight: 600;
+            display: flex;
+            align-items: center;
+            gap: 4px;
+            transition: all 0.3s ease;
+            box-shadow: 0 2px 6px rgba(16, 185, 129, 0.25);
+            margin-top: 8px;
+            width: fit-content;
+        }
+
+        .regenerate-btn:hover {
+            transform: translateY(-1px);
+            box-shadow: 0 3px 10px rgba(16, 185, 129, 0.35);
+        }
+
+        .regenerate-btn:active {
+            transform: translateY(0);
+        }
+
+        .regenerate-btn i {
+            animation: none;
+        }
+
+        .regenerate-btn.loading i {
+            animation: spin 1s linear infinite;
+        }
+
+        @@keyframes spin {
+            from {
+                transform: rotate(0deg);
+            }
+
+            to {
+                transform: rotate(360deg);
+            }
+        }
+
+        .regenerated-indicator {
+            position: absolute;
+            top: -0.5rem;
+            right: -0.5rem;
+            background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
+            color: white;
+            padding: 6px;
+            border-radius: 50%;
+            font-size: 0.875rem;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            z-index: 5;
+            animation: fadeIn 0.5s ease;
+            transition: opacity 0.3s ease, transform 0.3s ease;
+            width: 28px;
+            height: 28px;
+        }
+
+        .regenerated-indicator.fade-out {
+            opacity: 0;
+            transform: scale(0.8);
+        }
+
+        @@keyframes fadeIn {
+            from {
+                opacity: 0;
+                transform: scale(0.8);
+            }
+
+            to {
+                opacity: 1;
+                transform: scale(1);
+            }
+        }
+
+
+
+        .notification-icon {
+            font-size: 1.5rem;
+        }
+
+        .notification-icon.success {
+            color: #10b981;
+        }
+
+        .notification-icon.error {
+            color: #ef4444;
+        }
+
+        .meal-card {
+            position: relative;
+        }
+    </style>
 </head>
+
 <body>
     <div class="container">
@@ -19,4 +121,5 @@
             </div>
         </div>
+
         <div class="navigation-bar">
             <a href="@Url.Action("Index", "MealPlan")" class="nav-btn">
@@ -29,4 +132,5 @@
             </button>
         </div>
+
         <div class="days-container">
             @{
@@ -34,10 +138,11 @@
                 var dayMeals = Model.MealSlots.GroupBy(ms => ms.Day).ToDictionary(g => g.Key, g => g.ToList());
             }
+
             @foreach (var day in days)
             {
                 var meals = dayMeals.ContainsKey(day) ? dayMeals[day] : new List<NutriMatch.Models.MealSlot>();
                 var dailyCalories = meals.Sum(m => m.IsRestaurantMeal ? (m.RestaurantMeal?.Calories ?? 0) :
-                (m.Recipe?.Calories
-                ?? 0));
+                (m.Recipe?.Calories ?? 0));
+
                 <div class="day-card">
                     <div class="day-header">
@@ -45,4 +150,5 @@
                         <div class="day-calories">@((int)dailyCalories) cal</div>
                     </div>
+
                     @if (meals.Any())
                     {
@@ -52,8 +158,23 @@
                                 @if (meal.IsRestaurantMeal && meal.RestaurantMeal != null)
                                 {
-                                    <div class="meal-card @meal.MealType">
+                                    <div class="meal-card @meal.MealType" data-meal-id="@meal.Id"
+                                        data-is-regenerated="@(meal.IsRegenerated == true ? "true" : "false")"
+                                        data-is-viewed="@(meal.isViewed == true ? "true" : "false")"
+                                        onclick="SetIsViewed(event, true, @meal.Id)">
+
+                                        @if (meal.IsRegenerated == true && meal.isViewed == false)
+                                        {
+                                            <div class="regenerated-indicator">
+                                                <i class="fas fa-sync-alt"></i>
+                                            </div>
+                                        }
+
                                         <div class="meal-header">
                                             <span class="meal-type @meal.MealType">@meal.MealType</span>
                                             <span class="restaurant-badge">Restaurant</span>
+                                            <button class="regenerate-btn" onclick="regenerateMeal(event, @meal.Id, @Model.Id)">
+                                                <i class="fas fa-sync-alt"></i>
+                                                Regenerate
+                                            </button>
                                         </div>
                                         <div class="meal-name">@meal.RestaurantMeal.ItemName</div>
@@ -69,9 +190,23 @@
                                 else if (meal.Recipe != null)
                                 {
-                                    <div class="meal-card @meal.MealType clickable"
-                                        onclick="handleMealCardClick(event, @meal.Recipe.Id)">
+                                    <div class="meal-card @meal.MealType clickable" data-meal-id="@meal.Id"
+                                        data-is-regenerated="@(meal.IsRegenerated == true ? "true" : "false")"
+                                        data-is-viewed="@(meal.isViewed == true ? "true" : "false")"
+                                        onclick="handleMealCardClick(event, @meal.Recipe.Id, @meal.Id)">
+
+                                        @if (meal.IsRegenerated == true && meal.isViewed == false)
+                                        {
+                                            <div class="regenerated-indicator">
+                                                <i class="fas fa-sync-alt"></i>
+                                            </div>
+                                        }
+
                                         <div class="meal-header">
                                             <span class="meal-type @meal.MealType">@meal.MealType</span>
                                             <span class="recipe-badge">Recipe</span>
+                                            <button class="regenerate-btn" onclick="regenerateMeal(event, @meal.Id, @Model.Id)">
+                                                <i class="fas fa-sync-alt"></i>
+                                                Regenerate
+                                            </button>
                                         </div>
                                         <div class="meal-name">@meal.Recipe.Title</div>
@@ -94,4 +229,5 @@
             }
         </div>
+
         <div class="summary-card">
             <div class="summary-header">
@@ -99,4 +235,5 @@
                 <p>Your nutritional breakdown for the entire week</p>
             </div>
+
             @{
                 var totalCalories = Model.MealSlots.Sum(ms => ms.IsRestaurantMeal ? (ms.RestaurantMeal?.Calories ?? 0) :
@@ -107,8 +244,8 @@
                 (ms.Recipe?.Carbs ?? 0));
                 var totalFat = Model.MealSlots.Sum(ms => ms.IsRestaurantMeal ? (ms.RestaurantMeal?.Fat ?? 0) :
-                (ms.Recipe?.Fat
-                ?? 0));
+                (ms.Recipe?.Fat ?? 0));
                 var restaurantMeals = Model.MealSlots.Count(ms => ms.IsRestaurantMeal);
             }
+
             <div class="summary-grid">
                 <div class="summary-item">
@@ -139,5 +276,7 @@
         </div>
     </div>
+
     <div id="modalWindow"></div>
+
     <div id="deleteModal" class="modal">
         <div class="delete-modal-content modal-content">
@@ -156,4 +295,5 @@
         </div>
     </div>
+
     <form id="deleteForm" method="post" action="@Url.Action("Delete", "MealPlan")" style="display: none;">
         @Html.AntiForgeryToken()
@@ -161,84 +301,7 @@
     </form>
 </body>
-<script>
-    function showRecipeDetailsFromMealPlan(recipeId) {
-        const clickedCard = event.currentTarget;
-        clickedCard.classList.add('loading');
-        fetch(`/Recipes/Details/${recipeId}`)
-            .then(response => {
-                if (!response.ok) {
-                    throw new Error('Network response was not ok');
-                }
-                return response.text();
-            })
-            .then(html => {
-                const modalContainer = document.getElementById('modalWindow');
-                modalContainer.innerHTML = html;
-                const scripts = modalContainer.querySelectorAll("script");
-                scripts.forEach(script => {
-                    const newScript = document.createElement("script");
-                    if (script.src) {
-                        newScript.src = script.src;
-                    } else {
-                        newScript.textContent = script.textContent;
-                    }
-                    document.body.appendChild(newScript);
-                    document.body.removeChild(newScript);
-                });
-                const modalElement = modalContainer.querySelector('.modal');
-                if (modalElement) {
-                    const modal = new bootstrap.Modal(modalElement);
-                    modal.show();
-                    modalElement.addEventListener('hidden.bs.modal', function () {
-                        modalContainer.innerHTML = '';
-                        clickedCard.classList.remove('loading');
-                    });
-                    modalElement.addEventListener('shown.bs.modal', function () {
-                        clickedCard.classList.remove('loading');
-                    });
-                } else {
-                    clickedCard.classList.remove('loading');
-                }
-            })
-            .catch(err => {
-                console.error("Failed to fetch recipe details", err);
-                alert("Failed to load recipe details. Please try again.");
-                clickedCard.classList.remove('loading');
-            });
-    }
-    function handleMealCardClick(event, recipeId) {
-        if (recipeId && recipeId > 0) {
-            showRecipeDetailsFromMealPlan(recipeId);
-        }
-    }
-    function showDeleteModal() {
-        document.getElementById('deleteModal').style.display = 'block';
-        document.body.style.overflow = 'hidden';
-    }
-    function hideDeleteModal() {
-        document.getElementById('deleteModal').style.display = 'none';
-        document.body.style.overflow = 'auto';
-    }
-    function confirmDelete() {
-        document.getElementById('deleteForm').submit();
-    }
-    window.onclick = function (event) {
-        const modal = document.getElementById('deleteModal');
-        if (event.target === modal) {
-            hideDeleteModal();
-        }
-    }
-    document.addEventListener('keydown', function (event) {
-        if (event.key === 'Escape') {
-            hideDeleteModal();
-        }
-    });
-    document.addEventListener('DOMContentLoaded', function () {
-        const cards = document.querySelectorAll('.day-card');
-        cards.forEach((card, index) => {
-            card.style.animationDelay = `${index * 0.1}s`;
-        });
-    });
-</script>
+
+<script src="~/js/MealPlanDetails.js"></script>
+
 @functions {
     private int GetMealOrder(string mealType)
Index: NutriMatch/Views/MealPlan/Index.cshtml
===================================================================
--- NutriMatch/Views/MealPlan/Index.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/MealPlan/Index.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -11,4 +11,68 @@
     <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
     <link href="~/css/MealPlanIndex.css" rel="stylesheet">
+    <style>
+        @@keyframes pulse {
+            0%, 100% { 
+                transform: scale(1);
+                box-shadow: 0 0 0 0 rgba(251, 191, 36, 0.7);
+            }
+            50% { 
+                transform: scale(1.05);
+                box-shadow: 0 0 0 10px rgba(251, 191, 36, 0);
+            }
+        }
+
+        @@keyframes bounce {
+            0%, 100% { transform: translateY(0); }
+            50% { transform: translateY(-5px); }
+        }
+
+        .plan-status {
+            display: flex;
+            flex-direction: column;
+            gap: 8px;
+            margin-top: 12px;
+        }
+
+        .notification-badge-number {
+            position: absolute;
+            top: -12px;
+            right: -12px;
+            background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
+            color: white;
+            min-width: 32px;
+            height: 32px;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 0.85rem;
+            font-weight: 700;
+            box-shadow: 0 6px 20px rgba(251, 191, 36, 0.5);
+            animation: pulse 2s infinite, bounce 1s ease-in-out infinite;
+            z-index: 10;
+            border: 3px solid white;
+            padding: 0 8px;
+        }
+
+        .notification-badge-number i {
+            font-size: 0.9rem;
+            margin-right: 2px;
+        }
+
+        .plan-card {
+            position: relative;
+            overflow: visible;
+            
+        }
+
+        .plans-grid {
+            display: grid;
+            grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
+            gap: 24px;
+            margin-top: 32px;
+        }
+    
+    </style>
 </head>
 <body>
@@ -21,4 +85,5 @@
             <p>Manage and view your personalized weekly meal plans</p>
         </div>
+
         @if (TempData["Success"] != null)
         {
@@ -28,4 +93,5 @@
             </div>
         }
+
         @if (TempData["Error"] != null)
         {
@@ -35,4 +101,5 @@
             </div>
         }
+
         @if (Model == null || !Model.Any())
         {
@@ -58,8 +125,23 @@
                     </div>
                 </a>
+
                 @foreach (var mealPlan in Model.OrderByDescending(m => m.GeneratedAt))
                 {
+                    var unviewedRegeneratedCount = 0;
+                    if (mealPlan.MealSlots != null)
+                    {
+                        unviewedRegeneratedCount = mealPlan.MealSlots.Count(ms => ms.IsRegenerated == true && ms.isViewed == false);
+                    }
+                    
                     <div class="plan-card"
                         onclick="location.href='@Url.Action("Details", "MealPlan", new { id = mealPlan.Id })'">
+                        
+                        @if (unviewedRegeneratedCount > 0)
+                        {
+                            <div class="notification-badge-number">
+                                <i ></i>@unviewedRegeneratedCount
+                            </div>
+                        }
+
                         <div class="plan-card-header">
                             <div class="plan-title">
@@ -72,4 +154,5 @@
                             </div>
                         </div>
+
                         <div class="plan-card-body">
                             <div class="plan-stats">
@@ -83,4 +166,5 @@
                                 </div>
                             </div>
+
                             <a href="@Url.Action("Details", "MealPlan", new { id = mealPlan.Id })" class="view-plan-btn">
                                 <i class="fas fa-arrow-right"></i>
@@ -93,4 +177,5 @@
         }
     </div>
+
     <script>
         document.addEventListener('DOMContentLoaded', function () {
Index: NutriMatch/Views/Notifications/_NotificationPanel.cshtml
===================================================================
--- NutriMatch/Views/Notifications/_NotificationPanel.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/Views/Notifications/_NotificationPanel.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,111 @@
+@model IEnumerable<NutriMatch.Models.Notification>
+
+<div class="notification-header">
+    <h4>Notifications</h4>
+    <div class="notification-actions">
+    @if (Model.Any(n => !n.IsRead))
+        {
+            <button id="mark-all-read" class="btn-link">Mark all as read</button>
+        }
+        @if (Model.Any())
+        {
+            <button id="delete-all-notifications" class="btn-link text-danger" title="Delete all notifications" onclick="deleteAllNotifications()">
+                <i class="fas fa-trash-alt"></i>
+            </button>
+        }
+        
+        <a asp-area="Identity" asp-page="/Account/MyAccount" asp-route-activeTab="Notifications" class="btn-link" title="Notification settings">
+            <i class="fas fa-cog"></i>
+        </a>
+    </div>
+</div>
+<div class="notification-list" id="notification-list">
+    @if (Model.Any())
+    {
+        foreach (var notification in Model)
+        {
+            var unreadClass = notification.IsRead ? "" : "unread";
+            var timeAgo = GetTimeAgo(notification.CreatedAt);
+            
+            <div class="notification-item @unreadClass" data-id="@notification.Id" data-recipe-id="@notification.RecipeId">
+                @if (notification.Type == "RecipeRated")
+                {
+                    <div class="notification-icon-wrapper">
+                        <i class="fas fa-star notification-type-icon" style="color: #ffc107;"></i>
+                    </div>
+                }
+                else if (notification.Type == "RecipeAccepted")
+                {
+                    <div class="notification-icon-wrapper">
+                        <i class="fas fa-check-circle notification-type-icon" style="color: #4caf50;"></i>
+                    </div>
+                }
+                else if (notification.Type == "RecipeDeclined")
+                {
+                    <div class="notification-icon-wrapper">
+                        <i class="fas fa-times-circle notification-type-icon" style="color: #f44336;"></i>
+                    </div>
+                }
+                else if (notification.Type == "RestaurantNewMeal")
+                {
+                    <div class="notification-icon-wrapper">
+                        <i class="fas fa-utensils notification-type-icon" style="color: #ff6b6b;"></i>
+                    </div>
+                }
+                else if (notification.Type == "MealMatchesTags" || notification.Type == "RecipeMatchesTags")
+                {
+                    <div class="notification-icon-wrapper">
+                        <i class="fas fa-tags notification-type-icon" style="color: #4ecdc4;"></i>
+                    </div>
+                }
+                else if (notification.Type == "NewRestaurant")
+                {
+                    <div class="notification-icon-wrapper">
+                        <i class="fas fa-store notification-type-icon" style="color: #007bff;"></i>
+                    </div>
+                }else if (notification.Type == "MealPlanUpdated")
+                    {
+                        <div class="notification-icon-wrapper">
+                            <i class="fas fa-calendar-check notification-type-icon" style="color: #9c27b0;"></i>
+                        </div>
+                    }
+                
+                <div class="notification-content">
+                    <div class="notification-message">@notification.Message</div>
+                    <div class="notification-time">@timeAgo</div>
+                </div>
+
+                <button class="notification-delete-btn" data-notification-id="@notification.Id" title="Delete notification">
+                    <i class="fas fa-times"></i>
+                </button>
+            </div>
+        }
+    }
+    else
+    {
+        <div class="notification-item no-notifications">
+            <i class="fas fa-bell-slash"></i>
+            <p>No notifications yet</p>
+        </div>
+    }
+</div>
+
+@functions {
+    private string GetTimeAgo(DateTime dateTime)
+    {
+        var timeSpan = DateTime.Now.ToUniversalTime() - dateTime.ToUniversalTime();
+        
+        if (timeSpan.TotalSeconds < 60)
+            return "Just now";
+        else if (timeSpan.TotalMinutes < 60)
+            return $"{(int)timeSpan.TotalMinutes} minute{((int)timeSpan.TotalMinutes != 1 ? "s" : "")} ago";
+        else if (timeSpan.TotalHours < 24)
+            return $"{(int)timeSpan.TotalHours} hour{((int)timeSpan.TotalHours != 1 ? "s" : "")} ago";
+        else if (timeSpan.TotalDays < 7)
+            return $"{(int)timeSpan.TotalDays} day{((int)timeSpan.TotalDays != 1 ? "s" : "")} ago";
+        else
+            return dateTime.ToString("MMM dd, yyyy");
+    }
+}
+
+
Index: NutriMatch/Views/Recipes/Create.cshtml
===================================================================
--- NutriMatch/Views/Recipes/Create.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/Recipes/Create.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -92,6 +92,6 @@
             </div>
         </div>
-        <a href="/Recipes" class="back-link">
-            ← Back to Recipes
+        <a href="/Recipes/MyRecipes" class="back-link">
+            ← Back to My Recipes
         </a>
     </div>
Index: NutriMatch/Views/Recipes/Index.cshtml
===================================================================
--- NutriMatch/Views/Recipes/Index.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/Recipes/Index.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -28,4 +28,11 @@
                 <button class="btn btn-outline-secondary btn-sm ms-3" onclick="resetFilters()"><i
                         class="fas fa-undo me-1"></i>Reset Filters</button>
+                @if (User.Identity.IsAuthenticated)
+                {
+                    <button style="float: right;" class="btn btn-success" onclick="openPreferencesModal()">
+                        <i class="fas fa-sliders-h me-2"></i>Recipe Preferences & Notifications
+                    </button>
+                }
+            </h4>
             </h4>
             <div class="row">
@@ -170,4 +177,151 @@
         </div>
     </div>
+    <!-- Preferences Modal -->
+        <div class="modal fade" id="preferencesModal" tabindex="-1">
+            <div class="modal-dialog modal-lg">
+                <div class="modal-content modal-content-preferences">
+                    <div class="modal-header modal-header-preferences">
+                        <h5 class="modal-title">Recipe Preferences & Notifications</h5>
+                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
+                    </div>
+                    <div class="modal-body">
+                        <p class="text-muted small mb-3">
+                            <i class="fas fa-bell me-1"></i>
+                            Get notified when new recipes matching your preferences are added
+                        </p>
+                        
+                        <div class="tag-selection">
+                            <!-- High Protein -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-protein')">
+                                    <input type="checkbox" id="tag-high-protein" value="high-protein">
+                                    <label for="tag-high-protein">
+                                        <i class="fas fa-drumstick-bite"></i> High Protein
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-protein">
+                                    <label class="small text-muted">Minimum protein (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-protein" min="10" max="150" value="30" step="5">
+                                </div>
+                            </div>
+
+                            <!-- Low Carb -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('low-carb')">
+                                    <input type="checkbox" id="tag-low-carb" value="low-carb">
+                                    <label for="tag-low-carb">
+                                        <i class="fas fa-bread-slice"></i> Low Carb
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-low-carb">
+                                    <label class="small text-muted">Maximum carbs (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-low-carb" min="5" max="100" value="20" step="5">
+                                </div>
+                            </div>
+
+                            <!-- High Carb -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-carb')">
+                                    <input type="checkbox" id="tag-high-carb" value="high-carb">
+                                    <label for="tag-high-carb">
+                                        <i class="fas fa-bread-slice"></i> High Carb
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-carb">
+                                    <label class="small text-muted">Minimum carbs (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-carb" min="30" max="150" value="50" step="5">
+                                </div>
+                            </div>
+
+                            <!-- Low Fat -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('low-fat')">
+                                    <input type="checkbox" id="tag-low-fat" value="low-fat">
+                                    <label for="tag-low-fat">
+                                        <i class="fas fa-tint"></i> Low Fat
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-low-fat">
+                                    <label class="small text-muted">Maximum fat (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-low-fat" min="5" max="50" value="15" step="5">
+                                </div>
+                            </div>
+
+                            <!-- High Fat -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-fat')">
+                                    <input type="checkbox" id="tag-high-fat" value="high-fat">
+                                    <label for="tag-high-fat">
+                                        <i class="fas fa-tint"></i> High Fat
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-fat">
+                                    <label class="small text-muted">Minimum fat (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-fat" min="15" max="100" value="30" step="5">
+                                </div>
+                            </div>
+
+                            <!-- Balanced -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item">
+                                    <input type="checkbox" id="tag-balanced" value="balanced">
+                                    <label for="tag-balanced">
+                                        <i class="fas fa-balance-scale"></i> Balanced
+                                    </label>
+                                </div>
+                            </div>
+
+                            <!-- Low Calorie -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('low-calorie')">
+                                    <input type="checkbox" id="tag-low-calorie" value="low-calorie">
+                                    <label for="tag-low-calorie">
+                                        <i class="fas fa-fire"></i> Low Calorie
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-low-calorie">
+                                    <label class="small text-muted">Maximum calories:</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-low-calorie" min="100" max="500" value="300" step="50">
+                                </div>
+                            </div>
+
+                            <!-- High Calorie -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-calorie')">
+                                    <input type="checkbox" id="tag-high-calorie" value="high-calorie">
+                                    <label for="tag-high-calorie">
+                                        <i class="fas fa-fire"></i> High Calorie
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-calorie">
+                                    <label class="small text-muted">Minimum calories:</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-calorie" min="400" max="1500" value="600" step="50">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
+                        <button type="button" class="btn btn-success" onclick="savePreferences()">
+                            <i class="fas fa-save me-2"></i>Save Preferences
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
     <div id="modalWindow"></div>
     <script>
Index: NutriMatch/Views/Restaurants/Index.cshtml
===================================================================
--- NutriMatch/Views/Restaurants/Index.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/Restaurants/Index.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -12,15 +12,20 @@
 </head>
 <body>
-    <div class="container">
-        <div class="page-header">
-            <h1 class="display-5 fw-bold mb-3">Find Your Perfect Restaurant</h1>
-            <p class="lead text-muted">Discover restaurants with detailed nutritional information for every dish</p>
-        </div>
+    <div class="container ct-main">
+    
+        
         <div class="filter-section">
             <h4 class="mb-4" style="color: #1f2937; font-weight: 700;">
                 <i class="fas fa-sliders-h me-2" style="color: var(--nutri-green);"></i>
                 Filter by Macronutrients
-                <button class="btn btn-outline-secondary btn-sm ms-3" onclick="resetFilters()"><i
-                        class="fas fa-undo me-1"></i>Reset Filters</button>
+                <button class="btn btn-outline-secondary btn-sm ms-3" onclick="resetFilters()">
+                    <i class="fas fa-undo me-1"></i>Reset Filters
+                </button>
+                @if (User.Identity.IsAuthenticated)
+                {
+                    <button style="float: right;" class="btn btn-success" onclick="openPreferencesModal()">
+                        <i class="fas fa-sliders-h me-2"></i>Meal Preferences & Notifications
+                    </button>
+                }
             </h4>
             <div class="row">
@@ -87,4 +92,5 @@
             </div>
         </div>
+        
         <div class="row" id="restaurantsGrid">
             @foreach (var r in Model)
@@ -92,4 +98,13 @@
                 <div class="col-md-6 col-lg-4 mb-2">
                     <div class="restaurant-card" onclick="openMenu(@r.Id)">
+                        @if (User.Identity.IsAuthenticated)
+                        {
+                            <button class="notification-bell" 
+                                    data-restaurant-id="@r.Id"
+                                    onclick="toggleFollow(@r.Id, event)"
+                                    title="Get notified about new meals">
+                                <i class="far fa-bell"></i>
+                            </button>
+                        }
                         <div class="restaurant-info">
                             <img style="width: 200px;" src="@r.ImageUrl">
@@ -102,21 +117,163 @@
         </div>
     </div>
+    
+    <!-- Menu Modal -->
     <div class="modal fade" id="menuModal" tabindex="-1">
         <div class="modal-dialog modal-lg">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h5 class="modal-title" id="modalRestaurantName"></h5>
-                    <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
-                </div>
-                <div class="modal-body">
-                    <div id="filterInfo" class="filter-info" style="display: none;">
-                        <small><i class="fas fa-info-circle me-1"></i>Showing items matching your macro filters</small>
-                    </div>
-                    <div id="menuItems">
-                    </div>
-                </div>
+            <div class="modal-content" id="modal-content">
+                
             </div>
         </div>
     </div>
+    
+    <!-- Preferences Modal -->
+        <div class="modal fade" id="preferencesModal" tabindex="-1">
+            <div class="modal-dialog modal-lg">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h5 class="modal-title">Meal Preferences & Notifications</h5>
+                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
+                    </div>
+                    <div class="modal-body">
+                        <p class="text-muted small mb-3">
+                            <i class="fas fa-bell me-1"></i>
+                            Get notified when new meals matching your preferences are added
+                        </p>
+                        
+                        <div class="tag-selection">
+                            <!-- High Protein -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-protein')">
+                                    <input type="checkbox" id="tag-high-protein" value="high-protein">
+                                    <label for="tag-high-protein">
+                                        <i class="fas fa-drumstick-bite"></i> High Protein
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-protein">
+                                    <label class="small text-muted">Minimum protein (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-protein" min="10" max="150" value="30" step="5">
+                                </div>
+                            </div>
+
+                            <!-- Low Carb -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('low-carb')">
+                                    <input type="checkbox" id="tag-low-carb" value="low-carb">
+                                    <label for="tag-low-carb">
+                                        <i class="fas fa-bread-slice"></i> Low Carb
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-low-carb">
+                                    <label class="small text-muted">Maximum carbs (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-low-carb" min="5" max="100" value="20" step="5">
+                                </div>
+                            </div>
+
+                            <!-- High Carb -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-carb')">
+                                    <input type="checkbox" id="tag-high-carb" value="high-carb">
+                                    <label for="tag-high-carb">
+                                        <i class="fas fa-bread-slice"></i> High Carb
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-carb">
+                                    <label class="small text-muted">Minimum carbs (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-carb" min="30" max="150" value="50" step="5">
+                                </div>
+                            </div>
+
+                            <!-- Low Fat -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('low-fat')">
+                                    <input type="checkbox" id="tag-low-fat" value="low-fat">
+                                    <label for="tag-low-fat">
+                                        <i class="fas fa-tint"></i> Low Fat
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-low-fat">
+                                    <label class="small text-muted">Maximum fat (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-low-fat" min="5" max="50" value="15" step="5">
+                                </div>
+                            </div>
+
+                            <!-- High Fat -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-fat')">
+                                    <input type="checkbox" id="tag-high-fat" value="high-fat">
+                                    <label for="tag-high-fat">
+                                        <i class="fas fa-tint"></i> High Fat
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-fat">
+                                    <label class="small text-muted">Minimum fat (g):</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-fat" min="15" max="100" value="30" step="5">
+                                </div>
+                            </div>
+
+                            <!-- Balanced -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item">
+                                    <input type="checkbox" id="tag-balanced" value="balanced">
+                                    <label for="tag-balanced">
+                                        <i class="fas fa-balance-scale"></i> Balanced
+                                    </label>
+                                </div>
+                            </div>
+
+                            <!-- Low Calorie -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('low-calorie')">
+                                    <input type="checkbox" id="tag-low-calorie" value="low-calorie">
+                                    <label for="tag-low-calorie">
+                                        <i class="fas fa-fire"></i> Low Calorie
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-low-calorie">
+                                    <label class="small text-muted">Maximum calories:</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-low-calorie" min="100" max="500" value="300" step="50">
+                                </div>
+                            </div>
+
+                            <!-- High Calorie -->
+                            <div class="tag-item-wrapper">
+                                <div class="tag-item" onclick="toggleTagExpansion('high-calorie')">
+                                    <input type="checkbox" id="tag-high-calorie" value="high-calorie">
+                                    <label for="tag-high-calorie">
+                                        <i class="fas fa-fire"></i> High Calorie
+                                    </label>
+                                    <i class="fas fa-chevron-down expand-icon"></i>
+                                </div>
+                                <div class="tag-threshold" id="threshold-high-calorie">
+                                    <label class="small text-muted">Minimum calories:</label>
+                                    <input type="number" class="form-control form-control-sm" 
+                                        id="value-high-calorie" min="400" max="1500" value="600" step="50">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
+                        <button type="button" class="btn btn-success" onclick="savePreferences()">
+                            <i class="fas fa-save me-2"></i>Save Preferences
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    
+    @Html.AntiForgeryToken()
     <script src="~/js/RestaurantIndex.js"></script>
 </body>
Index: NutriMatch/Views/Restaurants/_RestaurantMealsPartial.cshtml
===================================================================
--- NutriMatch/Views/Restaurants/_RestaurantMealsPartial.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/Restaurants/_RestaurantMealsPartial.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -1,50 +1,153 @@
 @model List<NutriMatch.Models.RestaurantMeal>
 
-@if (Model.Count == 0)
-{
-    <div class="no-items-message">
-        <i class="fas fa-filter fa-2x mb-3"></i>
-        <h5>No items match your filters</h5>
-        <p>Try adjusting your macro filters to see more menu items</p>
+<div class="modal-header">
+    <h5 class="modal-title" id="modalRestaurantName">@ViewBag.RestaurantName</h5>
+    <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
+</div>
+<div class="modal-body">
+    <div id="filterInfo" class="filter-info" style="display: none;">
+        <small><i class="fas fa-info-circle me-1"></i>Showing items matching your macro filters</small>
     </div>
-}
-else
-{
-    @foreach (var meal in Model)
-    {
-        <div class="col-md-5">
-            <div class="menu-item">
-                <div class="menu-item-header" onclick="toggleItemDetails(this)">
-                    <div class="d-flex justify-content-between align-items-center">
-                        <div>
-                            <h6 class="mb-1 fs-6">@meal.ItemName</h6>
+    <div id="menuItems">
+        <div class="col-12">
+            <div class="row mb-3">
+                <div class="position-relative">
+                    <input type="text" id="menuSearchInput" class="form-control" placeholder="Search menu items..."
+                        autocomplete="off">
+                    <i class="fas fa-search position-absolute"
+                        style="right: 20px; top: 50%; transform: translateY(-50%); color: #6c757d;"></i>
+                </div>
+                <small class="text-muted" id="searchResultCount"></small>
+            </div>
+        </div>
+
+        <div class="row g-3">
+            <div class="col-12">
+                <div id="menuItemsContainer" class="row g-3">
+                    @if (Model.Count == 0)
+                    {
+                        <div class="col-12">
+                            <div class="no-items-message">
+                                <i class="fas fa-filter fa-2x mb-3"></i>
+                                <h5>No items match your filters</h5>
+                                <p>Try adjusting your macro filters to see more menu items</p>
+                            </div>
                         </div>
-                        <div class="text-end">
-                            <small class="text-muted">
-                                <i class="fas fa-chevron-down chevron-icon"></i>
-                            </small>
+                    }
+                    else
+                    {
+                        @foreach (var meal in Model)
+                        {
+                            <div class="col-md-6 menu-item-wrapper" data-meal-name="@meal.ItemName.ToLower()"
+                                data-meal-description="@meal.ItemDescription?.ToLower()">
+                                <div class="menu-item">
+                                    <div class="menu-item-header" onclick="toggleItemDetails(this)">
+                                        <div class="d-flex justify-content-between align-items-center">
+                                            <div>
+                                                <h6 class="mb-1 fs-6">@meal.ItemName</h6>
+                                            </div>
+                                            <div class="text-end">
+                                                <small class="text-muted">
+                                                    <i class="fas fa-chevron-down chevron-icon"></i>
+                                                </small>
+                                            </div>
+                                        </div>
+                                    </div>
+                                    <div class="collapse menu-item-details">
+                                        <p class="mb-2 small">@meal.ItemDescription</p>
+                                        <div class="macros">
+                                            <span class="macro-badge calories">
+                                                <i class="fas fa-fire me-1"></i>@meal.Calories cal
+                                            </span>
+                                            <span class="macro-badge protein">
+                                                <i class="fas fa-drumstick-bite me-1"></i>@meal.Protein g protein
+                                            </span>
+                                            <span class="macro-badge carbs">
+                                                <i class="fas fa-bread-slice me-1"></i>@meal.Carbs g carbs
+                                            </span>
+                                            <span class="macro-badge fats">
+                                                <i class="fas fa-tint me-1"></i>@meal.Fat g fats
+                                            </span>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        }
+                    }
+                </div>
+
+                <div id="noSearchResults" class="row" style="display: none;">
+                    <div class="col-12">
+                        <div class="no-items-message">
+                            <i class="fas fa-search fa-2x mb-3"></i>
+                            <h5>No items found</h5>
+                            <p>No menu items match your search</p>
                         </div>
-                    </div>
-                </div>
-                <div class="collapse menu-item-details">
-                    <p class="mb-2 small">@meal.ItemDescription</p>
-                    <div class="macros">
-                        <span class="macro-badge calories">
-                            <i class="fas fa-fire me-1"></i>@meal.Calories cal
-                        </span>
-                        <span class="macro-badge protein">
-                            <i class="fas fa-drumstick-bite me-1"></i>@meal.Protein g protein
-                        </span>
-                        <span class="macro-badge carbs">
-                            <i class="fas fa-bread-slice me-1"></i>@meal.Carbs g carbs
-                        </span>
-                        <span class="macro-badge fats">
-                            <i class="fas fa-tint me-1 "></i>@meal.Fat g fats
-                        </span>
                     </div>
                 </div>
             </div>
         </div>
-    }
 
-}
+
+
+
+
+        <script>
+            filterInfo = document.getElementById("filterInfo");
+            if (!areFiltersDefault()) {
+                filterInfo.style.display = "block";
+            } else {
+                filterInfo.style.display = "none";
+            }
+
+            (function () {
+                const searchInput = document.getElementById('menuSearchInput');
+                const itemsContainer = document.getElementById('menuItemsContainer');
+                const noResultsMessage = document.getElementById('noSearchResults');
+                const resultCount = document.getElementById('searchResultCount');
+
+                if (!searchInput) return;
+
+                function performSearch() {
+                    const searchTerm = searchInput.value.toLowerCase().trim();
+                    const menuItems = itemsContainer.querySelectorAll('.menu-item-wrapper');
+                    let visibleCount = 0;
+
+                    menuItems.forEach(item => {
+                        const mealName = item.dataset.mealName || '';
+                        const mealDescription = item.dataset.mealDescription || '';
+
+                        const matches = mealName.includes(searchTerm) || mealDescription.includes(searchTerm);
+
+                        if (matches) {
+                            item.style.display = '';
+                            visibleCount++;
+                        } else {
+                            item.style.display = 'none';
+                        }
+                    });
+
+                    if (searchTerm) {
+                        resultCount.textContent = `Showing ${visibleCount} of ${menuItems.length} items`;
+                    } else {
+                        resultCount.textContent = '';
+                    }
+
+                    if (visibleCount === 0 && searchTerm) {
+                        itemsContainer.style.display = 'none';
+                        noResultsMessage.style.display = 'block';
+                    } else {
+                        itemsContainer.style.display = 'flex';
+                        noResultsMessage.style.display = 'none';
+                    }
+                }
+
+                let searchTimeout;
+                searchInput.addEventListener('input', function () {
+                    clearTimeout(searchTimeout);
+                    searchTimeout = setTimeout(performSearch, 200);
+                });
+
+                searchInput.focus();
+            })();
+        </script>
Index: NutriMatch/Views/Shared/_Layout.cshtml
===================================================================
--- NutriMatch/Views/Shared/_Layout.cshtml	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/Views/Shared/_Layout.cshtml	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -1,3 +1,6 @@
-﻿<!DOCTYPE html>
+﻿@using Microsoft.AspNetCore.Identity
+@inject UserManager<User> UserManager
+
+<!DOCTYPE html>
 <html lang="en">
 <head>
@@ -9,4 +12,6 @@
     <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
     <link rel="stylesheet" href="~/css/_Layout.css" />
+    <link rel="stylesheet" href="~/css/Notifications.css" />
+
 </head>
 @{
@@ -26,5 +31,5 @@
                 </button>
                 <div class="collapse navbar-collapse" id="navbarNav">
-                    <ul class="navbar-nav ms-auto">
+                    <ul class="navbar-nav mx-auto">
                         <li class="nav-item">
                             <a class="nav-link @(currentController == "Home" && currentAction == "Index" ? "active-glow" : "")"
@@ -49,8 +54,4 @@
                                     href="/MealPlan">Meal Plans</a>
                             </li>
-                            <a class="nav-link @(currentPage == "/Account/MyAccount" ? "active-glow" : "")"
-                                href="/Identity/Account/MyAccount">
-                                My Account
-                            </a>
                             @if (User.IsInRole("Admin"))
                             {
@@ -61,12 +62,41 @@
                             }
                         }
-                        else
+                        
+                    </ul>
+                    
+                    @if (User.Identity.IsAuthenticated)
+                    {
+                        var user = await UserManager.GetUserAsync(User);
+                        var profilePicUrl = user?.ProfilePictureUrl ?? "~/images/default-profile.png";
+                        
+                        <ul class="navbar-nav ms-auto align-items-center">
+                            <li class="nav-item">
+                                <div id="notification-bell">
+                                    <div class="notification-icon">
+                                        <i class="fas fa-bell"></i>
+                                        <span class="notification-badge hidden" id="notification-count">0</span>
+                                    </div>
+                                    <div class="notification-panel" id="notification-panel">
+                                        <div id="notification-panel-content">
+                                            <!-- Partial view will load here -->
+                                        </div>
+                                    </div>
+                                </div>
+                            </li>
+                            <li class="nav-item">
+                                <a class="user-profile-link @(currentPage == "/Account/MyAccount" ? "active-glow-border" : "")"
+                                    href="/Identity/Account/MyAccount" title="My Account">
+                                    <img src="@profilePicUrl" alt="Profile" class="user-profile-pic" />
+                                </a>
+                            </li>
+                        </ul>
+                    }else
                         {
                             <partial name="_LoginPartial" />
                         }
-                    </ul>
                 </div>
             </div>
         </nav>
+        
     </header>
     <div class="container">
@@ -75,4 +105,7 @@
         </main>
     </div>
+
+
+
 <footer class="text-light py-5">
     <div class="container">
@@ -120,4 +153,5 @@
         </div>
         <hr class="my-4">
+    
         <div class="text-center">
             <p>&copy; 2025 NutriMatch. All rights reserved.</p>
@@ -126,4 +160,5 @@
 </footer>
     <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
+    <script src="~/js/Notifications.js"></script>
     @await RenderSectionAsync("Scripts", required: false)
 </body>
Index: NutriMatch/appsettings.json
===================================================================
--- NutriMatch/appsettings.json	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/appsettings.json	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -10,4 +10,21 @@
     }
   },
-  "AllowedHosts": "*"
+  "AllowedHosts": "*",
+  "Authentication": {
+    "Google": {
+      "ClientId": "186490876175-v5m2b9v2pkt5efo59idgf6f8570e81e4.apps.googleusercontent.com",
+      "ClientSecret": "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"
+    },
+    "Facebook": {
+      "AppId": "1298079728131772",
+      "AppSecret": "4d94b12c9a7d938150394aed4b4f3b20"
+    }
+  },
+  "EmailSettings": {
+    "FromEmail": "nutrimatch.finki@gmail.com",
+    "Password": "wyvy bypc fyvl mbrg",
+    "SmtpServer": "smtp.gmail.com",
+    "Port": "587"
+  }
+
 }
Index: NutriMatch/wwwroot/css/AdminIndex.css
===================================================================
--- NutriMatch/wwwroot/css/AdminIndex.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/AdminIndex.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -1,2 +1,7 @@
+ body {
+   
+    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+}
+
 .admin-header {
     background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
@@ -6,4 +11,7 @@
     box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
 }
+
+
+
 
 .admin-subtitle {
@@ -256,2 +264,3 @@
     margin-bottom: 1rem;
 }
+
Index: NutriMatch/wwwroot/css/HomeIndex.css
===================================================================
--- NutriMatch/wwwroot/css/HomeIndex.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/HomeIndex.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -419,9 +419,6 @@
 
 
-.restaurant-card:nth-child(1) { animation-delay: 0s; top: 20px; }
-.restaurant-card:nth-child(2) { animation-delay: -4s; top: 20px; }
-.restaurant-card:nth-child(3) { animation-delay: -8s; top: 20px; }
-.restaurant-card:nth-child(4) { animation-delay: -12s; top: 20px; }
-.restaurant-card:nth-child(5) { animation-delay: -16s; top: 20px; }
+
+
 
 .daily-dish {
Index: NutriMatch/wwwroot/css/MealPlanCreate.css
===================================================================
--- NutriMatch/wwwroot/css/MealPlanCreate.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/MealPlanCreate.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -2,9 +2,10 @@
 body {
     background: #c3d5c4;
-    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+     font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
     margin: 0;
     padding: 0;
     min-height: 100vh;
 }
+
 
 .container {
Index: NutriMatch/wwwroot/css/MealPlanDetails.css
===================================================================
--- NutriMatch/wwwroot/css/MealPlanDetails.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/MealPlanDetails.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -19,5 +19,4 @@
 
 .container {
-    max-width: 1200px;
     margin: 0 auto;
     padding: 40px 20px;
@@ -149,4 +148,5 @@
     transition: all 0.2s ease;
     position: relative;
+    min-height: 10rem;
 }
 
@@ -228,4 +228,7 @@
 
 .restaurant-badge {
+    position:absolute;
+    top: 1.5rem;
+    left: 6rem;
     background: #ef4444;
     color: white;
@@ -239,4 +242,7 @@
 
 .recipe-badge {
+    position:absolute;
+    top: 1.5rem;
+    left: 6rem;
     background: #4ade80;
     color: white;
@@ -255,4 +261,5 @@
     margin-bottom: 4px;
     line-height: 1.3;
+    margin-top: 5px;
 }
 
Index: NutriMatch/wwwroot/css/MealPlanIndex.css
===================================================================
--- NutriMatch/wwwroot/css/MealPlanIndex.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/MealPlanIndex.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -17,5 +17,4 @@
 
 .container {
-    max-width: 1200px;
     margin: 0 auto;
     padding: 40px 20px;
@@ -94,4 +93,6 @@
     position: relative;
     overflow: hidden;
+    border-top-left-radius:12px;
+    border-top-right-radius: 12px;
 }
 
@@ -219,4 +220,5 @@
     gap: 8px;
     font-size: 0.9rem;
+    margin-top: 2rem;
 }
 
Index: NutriMatch/wwwroot/css/Notifications.css
===================================================================
--- NutriMatch/wwwroot/css/Notifications.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/wwwroot/css/Notifications.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,295 @@
+#notification-bell {
+    position: fixed;
+    bottom: 20px;
+    right: 20px;
+    z-index: 1000;
+}
+
+.notification-icon {
+    background: #4CAF50;
+    width: 60px;
+    height: 60px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    box-shadow: 0 4px 8px rgba(0,0,0,0.3);
+    transition: all 0.3s ease;
+    position: relative;
+}
+
+.notification-icon:hover {
+    transform: scale(1.1);
+    box-shadow: 0 6px 12px rgba(0,0,0,0.4);
+}
+
+.notification-icon i {
+    color: white;
+    font-size: 24px;
+}
+
+.notification-badge {
+    position: absolute;
+    top: -5px;
+    right: -5px;
+    background: #f44336 ;
+    color: white;
+    border-radius: 50%;
+    width: 24px;
+    height: 24px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 12px;
+    font-weight: bold;
+}
+
+.notification-badge.hidden {
+    display: none;
+}
+
+.notification-panel {
+    position: absolute;
+    bottom: 70px;
+    right: 0;
+    width: 350px;
+    max-height: 500px;
+    background: white;
+    border-radius: 8px;
+    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
+    display: none;
+    flex-direction: column;
+}
+
+.notification-panel.show {
+    display: flex;
+}
+
+.notification-header {
+    padding: 15px;
+    border-bottom: 1px solid #eee;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.notification-header h4 {
+    margin: 0;
+    font-size: 18px;
+}
+
+.notification-list {
+    overflow-y: auto;
+    max-height: 400px;
+}
+
+.notification-item {
+    padding: 15px;
+    border-bottom: 1px solid #f0f0f0;
+    cursor: pointer;
+    transition: background 0.2s;
+}
+
+.notification-item:hover {
+    background: #f9f9f9;
+}
+
+.notification-item.unread {
+    background: #e3f2fd;
+}
+
+.notification-item .notification-message {
+    font-size: 14px;
+    margin-bottom: 5px;
+    color: #333;
+}
+
+.notification-item .notification-time {
+    font-size: 12px;
+    color: #999;
+}
+
+.btn-link {
+    background: none;
+    border: none;
+    color: #4CAF50;
+    cursor: pointer;
+    font-size: 14px;
+}
+
+.btn-link:hover {
+    text-decoration: underline;
+}
+
+
+
+.notification-item {
+    display: flex;
+    align-items: flex-start;
+    padding: 15px;
+    border-bottom: 1px solid #f0f0f0;
+    cursor: pointer;
+    transition: background 0.2s;
+}
+
+.notification-item:last-child {
+    border-bottom: none;
+}
+
+.notification-item:hover {
+    background: #f9f9f9;
+}
+
+.notification-item.unread {
+    background: #e3f2fd;
+}
+
+.notification-item.unread:hover {
+    background: #d1e7fd;
+}
+
+.notification-icon-wrapper {
+    flex-shrink: 0;
+    margin-right: 12px;
+    margin-top: 2px;
+}
+
+.notification-type-icon {
+    font-size: 20px;
+}
+
+.notification-content {
+    flex: 1;
+}
+
+.notification-message {
+    font-size: 14px;
+    margin-bottom: 5px;
+    color: #333;
+    line-height: 1.4;
+}
+
+.notification-time {
+    font-size: 12px;
+    color: #999;
+}
+
+.no-notifications {
+    text-align: center;
+    padding: 40px 20px;
+    color: #999;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    cursor: default;
+}
+
+.no-notifications:hover {
+    background: white;
+}
+
+.no-notifications i {
+    font-size: 48px;
+    margin-bottom: 15px;
+    opacity: 0.5;
+}
+
+.no-notifications p {
+    margin: 0;
+    font-size: 14px;
+}
+
+.notification-error {
+    padding: 20px;
+    text-align: center;
+    color: #f44336;
+}
+
+#notification-panel-content {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+}
+
+.notification-item {
+    display: flex;
+    align-items: flex-start;
+    padding: 15px;
+    border-bottom: 1px solid #f0f0f0;
+    cursor: pointer;
+    transition: background 0.2s;
+    position: relative;
+}
+
+.notification-delete-btn {
+    position: absolute;
+    right: 10px;
+    top: 50%;
+    transform: translateY(-50%);
+    background: none;
+    border: none;
+    color: #999;
+    cursor: pointer;
+    padding: 5px 8px;
+    border-radius: 4px;
+    opacity: 0;
+    transition: all 0.2s ease;
+    font-size: 16px;
+}
+
+.notification-item:hover .notification-delete-btn {
+    opacity: 1;
+}
+
+
+.notification-item {
+    transition: all 0.3s ease;
+}
+
+.notification-delete-btn {
+    position: absolute;
+    right: 10px;
+    top: 50%;
+    transform: translateY(-50%);
+    background: none;
+    border: none;
+    color: #ccc;
+    cursor: pointer;
+    padding: 5px 8px;
+    opacity: 0;
+    transition: all 0.2s ease;
+    font-size: 14px;
+    font-weight: normal;
+}
+
+.notification-item:hover .notification-delete-btn {
+    opacity: 1;
+}
+
+.notification-delete-btn:hover {
+    color: #f44336;
+    font-weight: bold;
+    transform: translateY(-50%) scale(1.2);
+}
+
+.notification-delete-btn i {
+    pointer-events: none;
+    transition: all 0.2s ease;
+}
+
+
+.text-danger {
+    color: #dc3545 !important;
+}
+
+.text-danger:hover {
+    color: #c82333 !important;
+    background-color: rgba(220, 53, 69, 0.1);
+}
+
+.notification-actions {
+    display: flex;
+    align-items: center;
+    gap: 0.75rem;
+}
Index: NutriMatch/wwwroot/css/RecipeCreate.css
===================================================================
--- NutriMatch/wwwroot/css/RecipeCreate.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/RecipeCreate.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -5,6 +5,7 @@
 }
 
+
 body {
-    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
     background: #fafbfc;
     color: #1a1a1a;
Index: NutriMatch/wwwroot/css/RecipeIndex.css
===================================================================
--- NutriMatch/wwwroot/css/RecipeIndex.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/RecipeIndex.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -409,2 +409,153 @@
     position: relative;
 }
+
+.tag-selection {
+            display: grid;
+            grid-template-columns: repeat(2, 1fr);
+            gap: 12px;
+        }
+
+        .tag-item-wrapper {
+            display: flex;
+            flex-direction: column;
+            background: #f8f9fa;
+            border-radius: 8px;
+            overflow: hidden;
+            transition: all 0.3s ease;
+            align-self: start;
+        }
+
+        .tag-item {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            padding: 12px;
+            cursor: pointer;
+            transition: all 0.2s;
+            position: relative;
+        }
+
+        .tag-item:hover {
+            background: #e9ecef;
+        }
+
+        .tag-item input[type="checkbox"] {
+            display: none;
+        }
+
+        .tag-item label {
+            cursor: pointer;
+            margin: 0;
+            font-weight: 500;
+            flex-grow: 1;
+        }
+
+        .tag-item input[type="checkbox"]:checked + label {
+            color: #31cf6b;
+        }
+
+        .tag-item input[type="checkbox"]:checked ~ label::before {
+            content: '✓ ';
+            margin-right: 4px;
+        }
+
+        .expand-icon {
+            font-size: 0.8rem;
+            color: #6c757d;
+            transition: transform 0.3s ease;
+            margin-left: 8px;
+        }
+
+        .tag-item.expanded .expand-icon {
+            transform: rotate(180deg);
+        }
+
+        .tag-threshold {
+            max-height: 0;
+            overflow: hidden;
+            padding: 0 12px;
+            transition: all 0.3s ease;
+            background: white;
+            border-top: 1px solid transparent;
+        }
+
+        .tag-threshold.show {
+            max-height: 100px;
+            padding: 12px;
+            border-top-color: #e9ecef;
+        }
+
+        .tag-threshold label {
+            display: block;
+            margin-bottom: 6px;
+            font-weight: 500;
+        }
+
+        .tag-threshold input[type="number"] {
+            width: 100%;
+        }
+
+        .modal-dialog.modal-lg {
+            max-width: 700px;
+        }
+
+        .tag-item-wrapper:has(#tag-balanced) .tag-item {
+            cursor: default;
+        }
+
+        .tag-item-wrapper:has(#tag-balanced) .expand-icon {
+            display: none;
+        }
+
+        .tag-selection {
+            display: grid;
+            grid-template-columns: repeat(2, 1fr);
+            gap: 12px;
+        }
+
+        .tag-item {
+            display: flex;
+            align-items: center;
+            padding: 12px;
+            background: #f8f9fa;
+            border-radius: 8px;
+            cursor: pointer;
+            transition: all 0.2s;
+        }
+
+        .tag-item:hover {
+            background: #e9ecef;
+        }
+
+        .tag-item input[type="checkbox"] {
+            display: none;
+        }
+
+        .tag-item label {
+            cursor: pointer;
+            margin: 0;
+            width: 100%;
+            font-weight: 500;
+        }
+
+        .tag-item input[type="checkbox"]:checked + label {
+            color: #31cf6b;
+        }
+
+        .tag-item input[type="checkbox"]:checked ~ label::before {
+            content: '✓ ';
+            margin-right: 4px;
+        }
+
+        .modal-header-preferences {
+            background: linear-gradient(135deg, #4ade80, #22c55e);
+            color: white;
+            border-radius: 20px 20px 0 0;
+            border: none;
+        }
+
+        .modal-content-preferences {
+            border-radius: 20px;
+            border: none;
+            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
+        }
Index: NutriMatch/wwwroot/css/RestaurantIndex.css
===================================================================
--- NutriMatch/wwwroot/css/RestaurantIndex.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/RestaurantIndex.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -30,4 +30,5 @@
             cursor: pointer;
             height: 100%;
+            position: relative;
 
         }
@@ -66,11 +67,4 @@
         }
 
-        #menuItems{
-            display: flex;
-            flex-wrap: wrap;
-            
-            justify-content: space-around;
-            
-        }
         
         .menu-item:hover {
@@ -228,2 +222,200 @@
             justify-content: center;
         }
+
+        .tag-selection {
+            display: grid;
+            grid-template-columns: repeat(2, 1fr);
+            gap: 12px;
+        }
+
+        .tag-item {
+            display: flex;
+            align-items: center;
+            padding: 12px;
+            background: #f8f9fa;
+            border-radius: 8px;
+            cursor: pointer;
+            transition: all 0.2s;
+        }
+
+        .tag-item:hover {
+            background: #e9ecef;
+        }
+
+        .tag-item input[type="checkbox"] {
+            display: none;
+        }
+
+        .tag-item label {
+            cursor: pointer;
+            margin: 0;
+            width: 100%;
+            font-weight: 500;
+        }
+
+        .tag-item input[type="checkbox"]:checked + label {
+            color: #31cf6b;
+        }
+
+        .tag-item input[type="checkbox"]:checked ~ label::before {
+            content: '✓ ';
+            margin-right: 4px;
+        }
+
+        .follow-btn {
+            margin-top: 10px;
+            width: 100%;
+            transition: all 0.3s;
+        }
+
+        .follow-btn:hover {
+            transform: scale(1.05);
+        }
+
+        .notification-bell {
+            position: absolute;
+            top: 15px;
+            right: 15px;
+            width: 40px;
+            height: 40px;
+            border-radius: 50%;
+            border: none;
+            background: white;
+            color: var(--nutri-green);
+            font-size: 1.2rem;
+            cursor: pointer;
+            transition: all 0.3s ease;
+            z-index: 10;
+            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+
+        .notification-bell:hover {
+            transform: scale(1.1);
+            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
+        }
+
+        .notification-bell.active {
+            background: var(--nutri-green);
+            color: white;
+        }
+
+        .notification-bell i {
+            transition: all 0.3s ease;
+        }
+
+        @keyframes bellRing {
+            0%, 100% { transform: rotate(0deg); }
+            10%, 30%, 50%, 70%, 90% { transform: rotate(-10deg); }
+            20%, 40%, 60%, 80% { transform: rotate(10deg); }
+        }
+
+        .notification-bell.just-activated {
+            animation: bellRing 0.5s ease-in-out;
+        }
+        
+
+        .tag-selection {
+            display: grid;
+            grid-template-columns: repeat(2, 1fr);
+            gap: 12px;
+        }
+
+        .tag-item-wrapper {
+            display: flex;
+            flex-direction: column;
+            background: #f8f9fa;
+            border-radius: 8px;
+            overflow: hidden;
+            transition: all 0.3s ease;
+            align-self: start;
+        }
+
+        .tag-item {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            padding: 12px;
+            cursor: pointer;
+            transition: all 0.2s;
+            position: relative;
+        }
+
+        .tag-item:hover {
+            background: #e9ecef;
+        }
+
+        .tag-item input[type="checkbox"] {
+            display: none;
+        }
+
+        .tag-item label {
+            cursor: pointer;
+            margin: 0;
+            font-weight: 500;
+            flex-grow: 1;
+        }
+
+        .tag-item input[type="checkbox"]:checked + label {
+            color: #31cf6b;
+        }
+
+        .tag-item input[type="checkbox"]:checked ~ label::before {
+            content: '✓ ';
+            margin-right: 4px;
+        }
+
+        .expand-icon {
+            font-size: 0.8rem;
+            color: #6c757d;
+            transition: transform 0.3s ease;
+            margin-left: 8px;
+        }
+
+        .tag-item.expanded .expand-icon {
+            transform: rotate(180deg);
+        }
+
+        .tag-threshold {
+            max-height: 0;
+            overflow: hidden;
+            padding: 0 12px;
+            transition: all 0.3s ease;
+            background: white;
+            border-top: 1px solid transparent;
+        }
+
+        .tag-threshold.show {
+            max-height: 100px;
+            padding: 12px;
+            border-top-color: #e9ecef;
+        }
+
+        .tag-threshold label {
+            display: block;
+            margin-bottom: 6px;
+            font-weight: 500;
+        }
+
+        .tag-threshold input[type="number"] {
+            width: 100%;
+        }
+
+        .modal-dialog.modal-lg {
+            max-width: 700px;
+        }
+
+        .tag-item-wrapper:has(#tag-balanced) .tag-item {
+            cursor: default;
+        }
+
+        .tag-item-wrapper:has(#tag-balanced) .expand-icon {
+            display: none;
+        }
+
+        .ct-main {
+            margin-top: 40px;
+        }
+    
Index: NutriMatch/wwwroot/css/_Layout.css
===================================================================
--- NutriMatch/wwwroot/css/_Layout.css	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/css/_Layout.css	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -7,5 +7,4 @@
     --light-gray: #ECF0F1;
 }
-
 
 body {
@@ -18,11 +17,4 @@
 .container:has(main) {
     flex: 1;
-}
-
-footer {
-    margin-top: auto;
-}
-.container:has(main) {
-    flex: 1;
     display: flex;
     flex-direction: column;
@@ -31,4 +23,8 @@
 main {
     flex: 1;
+}
+
+footer {
+    margin-top: auto;
 }
 
@@ -56,9 +52,76 @@
 }
 
-.nav-link{
+.nav-link {
     color: black !important;
     font-size: 18px !important;
     margin-left: 15px;
+    position: relative;
+    transition: color 0.3s ease-in-out;
 }
+
+.nav-link::after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 0;
+    height: 2px;
+    background: #2ECC71;
+    transition: width 0.3s ease-in-out;
+}
+
+.nav-link:hover {
+    color: #2ECC71 !important;
+}
+
+.nav-link:hover::after {
+    width: 80%;
+}
+
+
+.user-profile-pic {
+    width: 50px;
+    height: 50px;
+    border-radius: 50%;
+    object-fit: cover;
+    border: 2px solid #ddd;
+    transition: all 0.3s ease-in-out;
+    cursor: pointer;
+}
+
+.user-profile-link {
+    padding: 0 !important;
+    margin-left: -4.5rem !important;
+}
+
+.user-profile-pic:hover {
+    border-color: #2ECC71;
+    transform: scale(1.1);
+    box-shadow: 0 0 15px rgba(46, 204, 113, 0.4);
+}
+
+.user-profile-link.active-glow-border .user-profile-pic {
+    border-color: #2ECC71;
+    box-shadow: 0 0 10px rgba(46, 204, 113, 0.5);
+}
+
+
+.navbar-collapse {
+    align-items: center;
+}
+
+.navbar-nav.mx-auto {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+
+}
+
+.navbar-nav.mx-auto .nav-item {
+    display: flex;
+    align-items: center;
+}
+
 
 footer {
@@ -93,4 +156,10 @@
 }
 
+.active-glow {
+    color: #2ECC71 !important;
+    font-weight: bold !important;
+    transition: all 0.3s ease-in-out;
+}
+
 @media (max-width: 768px) {
     .signup-title {
@@ -111,9 +180,12 @@
         height: 60px;
     }
+    
+    .user-profile-pic {
+        width: 40px;
+        height: 40px;
+    }
+    
+    .navbar-nav.mx-auto {
+        margin-left: 0; 
+    }
 }
-
-.active-glow{
-    color: #2ECC71 !important;
-    font-weight: bold !important;
-    transition: all 0.3s ease-in-out;
-}
Index: NutriMatch/wwwroot/js/AdminIndex.js
===================================================================
--- NutriMatch/wwwroot/js/AdminIndex.js	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/js/AdminIndex.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -462,4 +462,66 @@
 }
 
+function showConfirmation(message, onConfirm, onCancel = null) {
+  const toastContainer =
+    document.getElementById("toast-container") || createToastContainer();
+
+  const toastId = "toast-confirm-" + Date.now();
+  const toast = document.createElement("div");
+  toast.id = toastId;
+  toast.className = "toast align-items-center text-white bg-warning border-0";
+  toast.setAttribute("role", "alert");
+  toast.setAttribute("aria-live", "assertive");
+  toast.setAttribute("aria-atomic", "true");
+  toast.style.minWidth = "350px";
+
+  toast.innerHTML = `
+    <div class="d-flex flex-column p-2">
+        <div class="toast-body mb-2">
+            <i class="fas fa-question-circle me-2"></i>
+            ${message}
+        </div>
+        <div class="d-flex gap-2 px-2 pb-2">
+            <button type="button" class="btn btn-sm btn-light flex-grow-1" onclick="confirmAction('${toastId}', true)">
+                <i class="fas fa-check me-1"></i>Yes
+            </button>
+            <button type="button" class="btn btn-sm btn-secondary flex-grow-1" onclick="confirmAction('${toastId}', false)">
+                <i class="fas fa-times me-1"></i>No
+            </button>
+        </div>
+    </div>
+  `;
+
+  toastContainer.appendChild(toast);
+
+  toast.style.display = "block";
+  setTimeout(() => {
+    toast.classList.add("show");
+  }, 100);
+
+  window[`confirmCallback_${toastId}`] = { onConfirm, onCancel };
+
+  setTimeout(() => {
+    removeToast(toastId);
+    if (window[`confirmCallback_${toastId}`]) {
+      delete window[`confirmCallback_${toastId}`];
+    }
+  }, 10000);
+}
+
+function confirmAction(toastId, confirmed) {
+  const callbacks = window[`confirmCallback_${toastId}`];
+
+  if (callbacks) {
+    if (confirmed && callbacks.onConfirm) {
+      callbacks.onConfirm();
+    } else if (!confirmed && callbacks.onCancel) {
+      callbacks.onCancel();
+    }
+    delete window[`confirmCallback_${toastId}`];
+  }
+
+  removeToast(toastId);
+}
+
 function refreshPendingRecipes() {
   showLoadingOverlay();
@@ -505,5 +567,5 @@
     if (!modal || !content) {
       console.error("Modal or content container not found");
-      alert("Modal components not found");
+      showError("Modal components not found");
       return;
     }
@@ -563,2 +625,780 @@
   }
 }
+
+function showNotification(message, type) {
+  if (type === "error") {
+    showError(message);
+  } else if (type === "success") {
+    showSuccess(message);
+  } else if (type === "warning") {
+    showWarning(message);
+  } else {
+    showInfo(message);
+  }
+}
+
+function openMealTagsModal() {
+  fetch("/Admin/GetMealTagsPartial")
+    .then((response) => response.text())
+    .then((html) => {
+      document.getElementById("mealTagsModalContainer").innerHTML = html;
+      const modal = new bootstrap.Modal(
+        document.getElementById("mealTagsModal")
+      );
+      modal.show();
+      setTimeout(() => {
+        loadMealKeywords();
+      }, 100);
+    })
+    .catch((error) => {
+      console.error("Error loading meal tags modal:", error);
+      showError("Error loading meal tags");
+    });
+}
+
+function openRestaurantMealsModal() {
+  fetch("/Admin/GetRestaurantMealsPartial")
+    .then((response) => response.text())
+    .then((html) => {
+      document.getElementById("restaurantMealsModalContainer").innerHTML = html;
+      const modal = new bootstrap.Modal(
+        document.getElementById("restaurantMealsModal")
+      );
+      modal.show();
+      setTimeout(() => {
+        loadRestaurants();
+      }, 100);
+    })
+    .catch((error) => {
+      console.error("Error loading restaurant meals modal:", error);
+      showError("Error loading restaurant meals");
+    });
+}
+
+function loadMealKeywords() {
+  const container = document.getElementById("mealKeywordsList");
+  if (!container) {
+    console.error("mealKeywordsList container not found");
+    return;
+  }
+
+  container.innerHTML = `
+        <div class="text-center py-4">
+            <div class="spinner-border text-primary" role="status">
+                <span class="visually-hidden">Loading...</span>
+            </div>
+        </div>
+    `;
+
+  fetch("/Admin/GetMealKeywords")
+    .then((response) => {
+      if (!response.ok) {
+        throw new Error("Network response was not ok");
+      }
+      return response.json();
+    })
+    .then((data) => {
+      console.log("Loaded keywords:", data);
+      displayMealKeywords(data);
+    })
+    .catch((error) => {
+      console.error("Error loading meal keywords:", error);
+      container.innerHTML =
+        '<p class="text-danger text-center">Error loading keywords. Please try again.</p>';
+      showError("Error loading meal keywords");
+    });
+}
+
+function displayMealKeywords(keywords) {
+  const container = document.getElementById("mealKeywordsList");
+  if (!container) return;
+
+  if (!keywords || keywords.length === 0) {
+    container.innerHTML =
+      '<p class="text-muted text-center py-4">No keywords found. Add your first keyword above!</p>';
+    return;
+  }
+
+  const grouped = keywords.reduce((acc, keyword) => {
+    if (!acc[keyword.tag]) {
+      acc[keyword.tag] = [];
+    }
+    acc[keyword.tag].push(keyword);
+    return acc;
+  }, {});
+
+  let html = "";
+  const tagOrder = ["breakfast", "main", "snack"];
+
+  tagOrder.forEach((tag) => {
+    const items = grouped[tag];
+    if (items && items.length > 0) {
+      html += `
+                <div class="tag-group mb-4">
+                    <h5 class="tag-header">
+                        <span class="badge bg-primary">${
+                          tag.charAt(0).toUpperCase() + tag.slice(1)
+                        }</span>
+                    </h5>
+                    <div class="keyword-list">
+                        ${items
+                          .map(
+                            (item) => `
+                            <div class="keyword-item">
+                                <span class="keyword-name">${item.name}</span>
+                                <button class="btn btn-sm btn-outline-danger" onclick="deleteMealKeyword(${
+                                  item.id
+                                }, '${item.name.replace(/'/g, "\\'")}')">
+                                    <i class="fas fa-trash"></i>
+                                </button>
+                            </div>
+                        `
+                          )
+                          .join("")}
+                    </div>
+                </div>
+            `;
+    }
+  });
+
+  if (html === "") {
+    container.innerHTML =
+      '<p class="text-muted text-center py-4">No keywords found. Add your first keyword above!</p>';
+  } else {
+    container.innerHTML = html;
+  }
+}
+
+function addMealKeyword() {
+  const nameInput = document.getElementById("newKeywordName");
+  const tagSelect = document.getElementById("newKeywordTag");
+
+  if (!nameInput || !tagSelect) {
+    console.error("Form elements not found");
+    return;
+  }
+
+  const name = nameInput.value.trim();
+  const tag = tagSelect.value;
+
+  if (!name) {
+    showError("Please enter a keyword name");
+    return;
+  }
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+
+  fetch("/Admin/AddMealKeyword", {
+    method: "POST",
+    headers: {
+      "Content-Type": "application/json",
+      RequestVerificationToken: token,
+    },
+    body: JSON.stringify({ name: name, tag: tag }),
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      if (data.success) {
+        showSuccess("Keyword added successfully");
+        nameInput.value = "";
+        loadMealKeywords();
+      } else {
+        showError(data.message || "Error adding keyword");
+      }
+    })
+    .catch((error) => {
+      console.error("Error adding keyword:", error);
+      showError("Error adding keyword");
+    });
+}
+
+function deleteMealKeyword(id, name) {
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+
+  fetch(`/Admin/DeleteMealKeyword/${id}`, {
+    method: "DELETE",
+    headers: {
+      RequestVerificationToken: token,
+    },
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      if (data.success) {
+        showError("Keyword deleted");
+        loadMealKeywords();
+      } else {
+        showError(data.message || "Error deleting keyword");
+      }
+    })
+    .catch((error) => {
+      console.error("Error deleting keyword:", error);
+      showError("Error deleting keyword");
+    });
+}
+
+function loadRestaurants() {
+  const select = document.getElementById("restaurantSelect");
+  if (!select) {
+    console.error("restaurantSelect not found");
+    return;
+  }
+
+  select.innerHTML = '<option value="">Loading restaurants...</option>';
+
+  fetch("/Admin/GetRestaurants")
+    .then((response) => {
+      if (!response.ok) {
+        throw new Error("Network response was not ok");
+      }
+      return response.json();
+    })
+    .then((data) => {
+      console.log("Loaded restaurants:", data);
+      if (data && data.length > 0) {
+        select.innerHTML =
+          '<option value="">Select a restaurant...</option>' +
+          data
+            .map((r) => `<option value="${r.id}">${r.name}</option>`)
+            .join("");
+      } else {
+        select.innerHTML = '<option value="">No restaurants found</option>';
+      }
+    })
+    .catch((error) => {
+      console.error("Error loading restaurants:", error);
+      select.innerHTML = '<option value="">Error loading restaurants</option>';
+      showError("Error loading restaurants");
+    });
+}
+
+function loadRestaurantMeals(restaurantId) {
+  const container = document.getElementById("restaurantMealsList");
+  const addMealBtn = document.getElementById("showAddMealBtn");
+  const editRestaurantBtn = document.getElementById("editRestaurantBtn");
+  const deleteRestaurantBtn = document.getElementById("deleteRestaurantBtn");
+
+  if (!container) {
+    console.error("restaurantMealsList container not found");
+    return;
+  }
+
+  if (!restaurantId) {
+    container.innerHTML =
+      '<p class="text-muted text-center">Please select a restaurant</p>';
+    if (addMealBtn) addMealBtn.style.display = "none";
+    if (editRestaurantBtn) editRestaurantBtn.style.display = "none";
+    if (deleteRestaurantBtn) deleteRestaurantBtn.style.display = "none";
+    return;
+  }
+
+  if (addMealBtn) addMealBtn.style.display = "block";
+  if (editRestaurantBtn) editRestaurantBtn.style.display = "block";
+  if (deleteRestaurantBtn) deleteRestaurantBtn.style.display = "block";
+
+  container.innerHTML = `
+        <div class="text-center py-4">
+            <div class="spinner-border text-success" role="status">
+                <span class="visually-hidden">Loading...</span>
+            </div>
+        </div>
+    `;
+
+  fetch(`/Admin/GetRestaurantMeals/${restaurantId}`)
+    .then((response) => {
+      if (!response.ok) {
+        throw new Error("Network response was not ok");
+      }
+      return response.json();
+    })
+    .then((data) => {
+      console.log("Loaded meals:", data);
+      displayRestaurantMeals(data);
+    })
+    .catch((error) => {
+      console.error("Error loading meals:", error);
+      container.innerHTML =
+        '<p class="text-danger text-center">Error loading meals. Please try again.</p>';
+      showError("Error loading meals");
+    });
+}
+
+function displayRestaurantMeals(meals) {
+  const container = document.getElementById("restaurantMealsList");
+
+  if (meals.length === 0) {
+    container.innerHTML =
+      '<p class="text-muted text-center">No meals found for this restaurant</p>';
+    return;
+  }
+
+  let html = '<div class="meals-grid">';
+  meals.forEach((meal) => {
+    html += `
+            <div class="meal-card">
+                <div class="d-flex justify-content-between align-items-start">
+                    <div class="flex-grow-1">
+                        <h6 class="meal-name">${meal.itemName}</h6>
+                        <p class="meal-description text-muted small">${
+                          meal.itemDescription || "No description"
+                        }</p>
+                        <div class="meal-macros mt-2">
+                            <small>
+                                <strong>${meal.calories}</strong> cal | 
+                                <strong>${meal.protein}g</strong> protein | 
+                                <strong>${meal.carbs}g</strong> carbs | 
+                                <strong>${meal.fat}g</strong> fat
+                            </small>
+                        </div>
+                    </div>
+                    <button class="btn btn-sm btn-outline-primary me-2" 
+                            onclick="editRestaurantMeal(${meal.id})">
+                        <i class="fas fa-edit"></i>
+                    </button>
+                    <button class="btn btn-sm btn-outline-danger" onclick="deleteRestaurantMeal(${
+                      meal.id
+                    }, '${meal.itemName.replace(/'/g, "\\'")}')">
+                        <i class="fas fa-trash"></i>
+                    </button>
+                </div>
+            </div>
+        `;
+  });
+  html += "</div>";
+
+  container.innerHTML = html;
+}
+
+function showAddMealForm() {
+  document.getElementById("addMealFormSection").style.display = "block";
+  document.getElementById("showAddMealBtn").style.display = "none";
+  document.getElementById("addMealFormTitle").innerHTML =
+    '<i class="fas fa-plus-circle me-2"></i>Add New Meal';
+
+  const btn = document.querySelector("#addMealForm button.btn-success");
+  btn.innerHTML = '<i class="fas fa-check me-2"></i>Add Meal';
+  btn.setAttribute("onclick", "addRestaurantMeal()");
+}
+
+function cancelAddMeal() {
+  document.getElementById("addMealFormSection").style.display = "none";
+  document.getElementById("showAddMealBtn").style.display = "block";
+  document.getElementById("addMealForm").reset();
+  document.getElementById("editMealId").value = "";
+}
+
+function addRestaurantMeal() {
+  const restaurantId = document.getElementById("restaurantSelect").value;
+
+  if (!restaurantId) {
+    showError("Please select a restaurant first");
+    return;
+  }
+
+  const mealData = {
+    restaurantId: parseInt(restaurantId),
+    itemName: document.getElementById("mealItemName").value.trim(),
+    itemDescription: document
+      .getElementById("mealItemDescription")
+      .value.trim(),
+    type: [],
+    calories: parseFloat(document.getElementById("mealCalories").value),
+    protein: parseFloat(document.getElementById("mealProtein").value),
+    carbs: parseFloat(document.getElementById("mealCarbs").value),
+    fat: parseFloat(document.getElementById("mealFat").value),
+  };
+
+  if (!mealData.itemName) {
+    showError("Please enter a meal name");
+    return;
+  }
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+
+  fetch("/Admin/AddRestaurantMeal", {
+    method: "POST",
+    headers: {
+      "Content-Type": "application/json",
+      RequestVerificationToken: token,
+    },
+    body: JSON.stringify(mealData),
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      if (data.success) {
+        showSuccess("Meal added successfully");
+        cancelAddMeal();
+        loadRestaurantMeals(restaurantId);
+      } else {
+        showError(data.message || "Error adding meal");
+      }
+    })
+    .catch((error) => {
+      console.error("Error adding meal:", error);
+      showError("Error adding meal");
+    });
+}
+
+function deleteRestaurantMeal(id, name) {
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+  const restaurantId = document.getElementById("restaurantSelect").value;
+
+  fetch(`/Admin/DeleteRestaurantMeal/${id}`, {
+    method: "DELETE",
+    headers: {
+      RequestVerificationToken: token,
+    },
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      if (data.success) {
+        showError("Meal deleted");
+        loadRestaurantMeals(restaurantId);
+      } else {
+        showError(data.message || "Error deleting meal");
+      }
+    })
+    .catch((error) => {
+      console.error("Error deleting meal:", error);
+      showError("Error deleting meal");
+    });
+}
+
+function editRestaurantMeal(id) {
+  const restaurantId = document.getElementById("restaurantSelect").value;
+
+  fetch(`/Admin/GetRestaurantMeals/${restaurantId}`)
+    .then((res) => res.json())
+    .then((meals) => {
+      const meal = meals.find((m) => m.id === id);
+      if (!meal) {
+        showError("Meal not found");
+        return;
+      }
+
+      document.getElementById("editMealId").value = meal.id;
+      document.getElementById("mealItemName").value = meal.itemName;
+      document.getElementById("mealItemDescription").value =
+        meal.itemDescription || "";
+      document.getElementById("mealCalories").value = meal.calories;
+      document.getElementById("mealProtein").value = meal.protein;
+      document.getElementById("mealCarbs").value = meal.carbs;
+      document.getElementById("mealFat").value = meal.fat;
+
+
+      document.getElementById("addMealFormSection").style.display = "block";
+      document.getElementById("showAddMealBtn").style.display = "none";
+      document.getElementById("addMealFormTitle").innerHTML =
+        '<i class="fas fa-edit me-2"></i>Edit Meal';
+
+      const btn = document.querySelector("#addMealForm button.btn-success");
+      btn.innerHTML = '<i class="fas fa-save me-2"></i>Update Meal';
+      btn.setAttribute("onclick", "updateRestaurantMeal()");
+    })
+    .catch((err) => {
+      console.error("Error fetching meals:", err);
+      showError("Error loading meals");
+    });
+}
+
+function updateRestaurantMeal() {
+  const restaurantId = document.getElementById("restaurantSelect").value;
+  const id = parseInt(document.getElementById("editMealId").value);
+
+  const mealData = {
+    id: id,
+    restaurantId: parseInt(restaurantId),
+    itemName: document.getElementById("mealItemName").value.trim(),
+    itemDescription: document
+      .getElementById("mealItemDescription")
+      .value.trim(),
+    type: [],
+    calories: parseFloat(document.getElementById("mealCalories").value),
+    protein: parseFloat(document.getElementById("mealProtein").value),
+    carbs: parseFloat(document.getElementById("mealCarbs").value),
+    fat: parseFloat(document.getElementById("mealFat").value),
+  };
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+
+  fetch("/Admin/EditRestaurantMeal", {
+    method: "POST",
+    headers: {
+      "Content-Type": "application/json",
+      RequestVerificationToken: token,
+    },
+    body: JSON.stringify(mealData),
+  })
+    .then((res) => res.json())
+    .then((data) => {
+      if (data.success) {
+        showSuccess("Meal updated successfully");
+        cancelAddMeal();
+        loadRestaurantMeals(restaurantId);
+      } else {
+        showError(data.message || "Error updating meal");
+      }
+    })
+    .catch((err) => {
+      console.error("Error updating meal:", err);
+      showError("Error updating meal");
+    });
+}
+
+function showAddRestaurantForm() {
+  document.getElementById("addRestaurantFormSection").style.display = "block";
+  document.getElementById("addMealFormSection").style.display = "none";
+  document.getElementById("showAddMealBtn").style.display = "none";
+  document.getElementById("editRestaurantBtn").style.display = "none";
+  document.getElementById("deleteRestaurantBtn").style.display = "none";
+  document.getElementById("restaurantFormTitle").innerHTML =
+    '<i class="fas fa-store-alt me-2"></i>Add New Restaurant';
+
+  const btn = document.querySelector("#addRestaurantForm button.btn-success");
+  btn.innerHTML = '<i class="fas fa-check me-2"></i>Add Restaurant';
+  btn.setAttribute("onclick", "addRestaurant()");
+
+  document.getElementById("editRestaurantId").value = "";
+  document.getElementById("addRestaurantForm").reset();
+  document.getElementById("imagePreview").style.display = "none";
+}
+
+function cancelAddRestaurant() {
+  document.getElementById("addRestaurantFormSection").style.display = "none";
+  document.getElementById("addRestaurantForm").reset();
+  document.getElementById("editRestaurantId").value = "";
+  document.getElementById("imagePreview").style.display = "none";
+
+  const restaurantId = document.getElementById("restaurantSelect").value;
+  if (restaurantId) {
+    document.getElementById("showAddMealBtn").style.display = "block";
+    document.getElementById("editRestaurantBtn").style.display = "block";
+    document.getElementById("deleteRestaurantBtn").style.display = "block";
+  }
+}
+
+function previewImage() {
+  const fileInput = document.getElementById("restaurantImage");
+  const preview = document.getElementById("imagePreview");
+  const previewImg = document.getElementById("previewImg");
+
+  if (fileInput.files && fileInput.files[0]) {
+    const reader = new FileReader();
+
+    reader.onload = function (e) {
+      previewImg.src = e.target.result;
+      preview.style.display = "block";
+    };
+
+    reader.readAsDataURL(fileInput.files[0]);
+  }
+}
+
+function addRestaurant() {
+  const name = document.getElementById("restaurantName").value.trim();
+  const description = document
+    .getElementById("restaurantDescription")
+    .value.trim();
+  const imageFile = document.getElementById("restaurantImage").files[0];
+
+  if (!name) {
+    showError("Please enter a restaurant name");
+    return;
+  }
+
+  if (!imageFile) {
+    showError("Please select an image");
+    return;
+  }
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+  const formData = new FormData();
+  formData.append("name", name);
+  formData.append("description", description);
+  formData.append("image", imageFile);
+
+  fetch("/Admin/AddRestaurant", {
+    method: "POST",
+    headers: {
+      RequestVerificationToken: token,
+    },
+    body: formData,
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      if (data.success) {
+        showSuccess("Restaurant added successfully");
+
+        cancelAddRestaurant();
+        loadRestaurants();
+
+        setTimeout(() => {
+          showAddMealForm();
+
+          const select = document.getElementById("restaurantSelect");
+          select.value = data.restaurantId;
+        }, 500);
+      } else {
+        showError(data.message || "Error adding restaurant");
+      }
+    })
+    .catch((error) => {
+      console.error("Error adding restaurant:", error);
+      showError("Error adding restaurant");
+    });
+}
+
+function showEditRestaurantForm() {
+  const restaurantId = document.getElementById("restaurantSelect").value;
+  if (!restaurantId) {
+    showError("Please select a restaurant");
+    return;
+  }
+
+  fetch(`/Admin/GetRestaurant/${restaurantId}`)
+    .then((response) => response.json())
+    .then((restaurant) => {
+      document.getElementById("editRestaurantId").value = restaurant.id;
+      document.getElementById("restaurantName").value = restaurant.name;
+      document.getElementById("restaurantDescription").value =
+        restaurant.description || "";
+
+      if (restaurant.imageUrl) {
+        const previewImg = document.getElementById("previewImg");
+        previewImg.src = restaurant.imageUrl;
+        document.getElementById("imagePreview").style.display = "block";
+      }
+
+      document.getElementById("addRestaurantFormSection").style.display =
+        "block";
+      document.getElementById("addMealFormSection").style.display = "none";
+      document.getElementById("showAddMealBtn").style.display = "none";
+      document.getElementById("editRestaurantBtn").style.display = "none";
+      document.getElementById("deleteRestaurantBtn").style.display = "none";
+      document.getElementById("restaurantFormTitle").innerHTML =
+        '<i class="fas fa-edit me-2"></i>Edit Restaurant';
+
+      const btn = document.querySelector(
+        "#addRestaurantForm button.btn-success"
+      );
+      btn.innerHTML = '<i class="fas fa-save me-2"></i>Update Restaurant';
+      btn.setAttribute("onclick", "updateRestaurant()");
+    })
+    .catch((error) => {
+      console.error("Error loading restaurant:", error);
+      showError("Error loading restaurant");
+    });
+}
+
+function updateRestaurant() {
+  const id = parseInt(document.getElementById("editRestaurantId").value);
+  const name = document.getElementById("restaurantName").value.trim();
+  const description = document
+    .getElementById("restaurantDescription")
+    .value.trim();
+  const imageFile = document.getElementById("restaurantImage").files[0];
+
+  if (!name) {
+    showError("Please enter a restaurant name");
+    return;
+  }
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+  const formData = new FormData();
+  formData.append("id", id);
+  formData.append("name", name);
+  formData.append("description", description);
+  if (imageFile) {
+    formData.append("image", imageFile);
+  }
+
+  fetch("/Admin/EditRestaurant", {
+    method: "POST",
+    headers: {
+      RequestVerificationToken: token,
+    },
+    body: formData,
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      if (data.success) {
+        showSuccess("Restaurant updated successfully");
+        cancelAddRestaurant();
+        loadRestaurants();
+
+        setTimeout(() => {
+          const select = document.getElementById("restaurantSelect");
+          select.value = id;
+          loadRestaurantMeals(id);
+        }, 500);
+      } else {
+        showError(data.message || "Error updating restaurant");
+      }
+    })
+    .catch((error) => {
+      console.error("Error updating restaurant:", error);
+      showError("Error updating restaurant");
+    });
+}
+
+function deleteRestaurant() {
+  const restaurantId = document.getElementById("restaurantSelect").value;
+  if (!restaurantId) {
+    showError("Please select a restaurant");
+    return;
+  }
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+
+  fetch(`/Admin/DeleteRestaurant/${restaurantId}`, {
+    method: "POST",
+    headers: {
+      "Content-Type": "application/json",
+      RequestVerificationToken: token,
+    },
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      if (data.success) {
+        showError(data.message || "Restaurant deleted");
+
+        const restaurantSelect = document.getElementById("restaurantSelect");
+        restaurantSelect.remove(restaurantSelect.selectedIndex);
+        restaurantSelect.value = "";
+
+        document.getElementById("addRestaurantFormSection").style.display =
+          "none";
+        document.getElementById("addMealFormSection").style.display = "none";
+        document.getElementById("editRestaurantBtn").style.display = "none";
+        document.getElementById("deleteRestaurantBtn").style.display = "none";
+        document.getElementById("showAddMealBtn").style.display = "none";
+
+        const mealsContainer = document.getElementById("restaurantMealsList");
+        if (mealsContainer) {
+          mealsContainer.innerHTML =
+            '<p class="text-muted text-center">Please select a restaurant</p>';
+        }
+      } else {
+        showError(data.message || "Error deleting restaurant");
+      }
+    })
+    .catch((error) => {
+      console.error("Error deleting restaurant:", error);
+      showError("Error deleting restaurant");
+    });
+}
Index: NutriMatch/wwwroot/js/MealPlanDetails.js
===================================================================
--- NutriMatch/wwwroot/js/MealPlanDetails.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/wwwroot/js/MealPlanDetails.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,216 @@
+document.addEventListener('DOMContentLoaded', function () {
+        const regeneratedMeals = document.querySelectorAll('.meal-card[data-is-regenerated="true"][data-is-viewed="false"]');
+
+        if (regeneratedMeals.length > 0) {
+            const mealIds = Array.from(regeneratedMeals).map(card => parseInt(card.dataset.mealId));
+
+            fetch('@Url.Action("MarkMealsAsViewed", "MealPlan")', {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/json',
+                    'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+                },
+                body: JSON.stringify(mealIds)
+            })
+                .then(response => response.json())
+                .then(data => {
+                    if (data.success) {
+                        console.log('Regenerated meals marked as viewed');
+
+                        regeneratedMeals.forEach(card => {
+                            card.dataset.isViewed = 'true';
+                            const indicator = card.querySelector('.regenerated-indicator');
+                            if (indicator) {
+                                indicator.classList.add('fade-out');
+                                setTimeout(() => {
+                                    indicator.remove();
+                                }, 300);
+                            }
+                        });
+                    }
+                })
+                .catch(error => {
+                    console.error('Error marking meals as viewed:', error);
+                });
+        }
+
+        const cards = document.querySelectorAll('.day-card');
+        cards.forEach((card, index) => {
+            card.style.animationDelay = `${index * 0.1}s`;
+        });
+    });
+
+
+
+
+    function regenerateMeal(event, mealSlotId, mealPlanId) {
+        event.stopPropagation();
+        const btn = event.currentTarget;
+        const card = btn.closest('.meal-card');
+        btn.disabled = true;
+        btn.classList.add('loading');
+        btn.innerHTML = '<i class="fas fa-sync-alt"></i> Regenerating...';
+        
+        const formData = new FormData();
+        formData.append('mealSlotId', mealSlotId);
+        formData.append('mealPlanId', mealPlanId);
+        formData.append('__RequestVerificationToken', document.querySelector('input[name="__RequestVerificationToken"]').value);
+        
+        fetch('/MealPlan/RegenerateMeal', {
+            method: 'POST',
+            body: formData
+        })
+        .then(response => {
+            if (!response.ok) {
+                throw new Error(`HTTP error! status: ${response.status}`);
+            }
+            return response.json();
+        })
+        .then(data => {
+            if (data.success) {
+                const existingIndicator = card.querySelector('.regenerated-indicator');
+                if (!existingIndicator) {
+                    const indicator = document.createElement('div');
+                    indicator.className = 'regenerated-indicator';
+                    indicator.innerHTML = '<i class="fas fa-sync-alt"></i>';
+                    card.appendChild(indicator);
+                }
+                setTimeout(() => {
+                    location.reload();
+                }, 1500);
+            } else {
+                alert(data.message || 'Failed to regenerate meal');
+                btn.disabled = false;
+                btn.classList.remove('loading');
+                btn.innerHTML = '<i class="fas fa-sync-alt"></i> Regenerate';
+            }
+        })
+        .catch(error => {
+            console.error('Error:', error);
+            alert('An error occurred while regenerating the meal');
+            btn.disabled = false;
+            btn.classList.remove('loading');
+            btn.innerHTML = '<i class="fas fa-sync-alt"></i> Regenerate';
+        });
+    }
+
+    function showRecipeDetailsFromMealPlan(recipeId) {
+        const clickedCard = event.currentTarget;
+        clickedCard.classList.add('loading');
+
+        fetch(`/Recipes/Details/${recipeId}`)
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error('Network response was not ok');
+                }
+                return response.text();
+            })
+            .then(html => {
+                const modalContainer = document.getElementById('modalWindow');
+                modalContainer.innerHTML = html;
+
+                const scripts = modalContainer.querySelectorAll("script");
+                scripts.forEach(script => {
+                    const newScript = document.createElement("script");
+                    if (script.src) {
+                        newScript.src = script.src;
+                    } else {
+                        newScript.textContent = script.textContent;
+                    }
+                    document.body.appendChild(newScript);
+                    document.body.removeChild(newScript);
+                });
+
+                const modalElement = modalContainer.querySelector('.modal');
+                if (modalElement) {
+                    const modal = new bootstrap.Modal(modalElement);
+                    modal.show();
+
+                    modalElement.addEventListener('hidden.bs.modal', function () {
+                        modalContainer.innerHTML = '';
+                        clickedCard.classList.remove('loading');
+                    });
+
+                    modalElement.addEventListener('shown.bs.modal', function () {
+                        clickedCard.classList.remove('loading');
+                    });
+                } else {
+                    clickedCard.classList.remove('loading');
+                }
+            })
+            .catch(err => {
+                console.error("Failed to fetch recipe details", err);
+                alert("Failed to load recipe details. Please try again.");
+                clickedCard.classList.remove('loading');
+            });
+    }
+
+    function handleMealCardClick(event, recipeId, mealSlotId) {
+        SetIsViewed(event, true, mealSlotId);
+
+        if (event.target.closest('.regenerate-btn')) {
+            return;
+        }
+
+        if (recipeId && recipeId > 0) {
+            showRecipeDetailsFromMealPlan(recipeId);
+        }
+    }
+
+    function SetIsViewed(event, isViewed, mealSlotId) {
+        console.log('SetIsViewed called with mealSlotId:', mealSlotId);
+        const card = event.currentTarget;
+        const currentlyViewed = card.dataset.isViewed === 'true';
+
+        if (isViewed && !currentlyViewed) {
+            fetch(`/MealPlan/MarkMealsAsViewed?mealId=${mealSlotId}`, {
+                method: 'POST',
+                headers: {
+                    'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
+                }
+            })
+                .then(response => response.json())
+                .then(data => {
+                    if (data.success) {
+                        console.log('Meal marked as viewed');
+                        card.dataset.isViewed = 'true';
+
+                        const indicator = card.querySelector('.regenerated-indicator');
+                        if (indicator) {
+                            indicator.classList.add('fade-out');
+                            setTimeout(() => indicator.remove(), 300);
+                        }
+                    } else {
+                        console.error(data.message);
+                    }
+                })
+                .catch(error => console.error('Error marking meal as viewed:', error));
+        }
+    }
+
+    function showDeleteModal() {
+        document.getElementById('deleteModal').style.display = 'block';
+        document.body.style.overflow = 'hidden';
+    }
+
+    function hideDeleteModal() {
+        document.getElementById('deleteModal').style.display = 'none';
+        document.body.style.overflow = 'auto';
+    }
+
+    function confirmDelete() {
+        document.getElementById('deleteForm').submit();
+    }
+
+    window.onclick = function (event) {
+        const modal = document.getElementById('deleteModal');
+        if (event.target === modal) {
+            hideDeleteModal();
+        }
+    }
+
+    document.addEventListener('keydown', function (event) {
+        if (event.key === 'Escape') {
+            hideDeleteModal();
+        }
+    });
Index: NutriMatch/wwwroot/js/MyRecipes.js
===================================================================
--- NutriMatch/wwwroot/js/MyRecipes.js	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/js/MyRecipes.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -1,5 +1,22 @@
+document.addEventListener("DOMContentLoaded", function () {
+  const urlParams = new URLSearchParams(window.location.search);
+  const openDeclineModalRecipeId = urlParams.get("openDeclineModal");
+
+  if (openDeclineModalRecipeId) {
+    setTimeout(function () {
+      showRecipeDetails(openDeclineModalRecipeId, true, "Declined");
+    }, 300);
+
+    const newUrl = window.location.pathname;
+    window.history.replaceState({}, document.title, newUrl);
+  }
+});
+
 function showRecipeDetails(recipeId, isOwner, recipeStatus) {
-  const clickedCard = event.currentTarget;
-  clickedCard.classList.add("loading");
+  const clickedCard = event && event.currentTarget ? event.currentTarget : null;
+
+  if (clickedCard) {
+    clickedCard.classList.add("loading");
+  }
 
   const params = new URLSearchParams({
@@ -38,12 +55,18 @@
         modalElement.addEventListener("hidden.bs.modal", function () {
           modalContainer.innerHTML = "";
-          clickedCard.classList.remove("loading");
+          if (clickedCard) {
+            clickedCard.classList.remove("loading");
+          }
         });
 
         modalElement.addEventListener("shown.bs.modal", function () {
-          clickedCard.classList.remove("loading");
+          if (clickedCard) {
+            clickedCard.classList.remove("loading");
+          }
         });
       } else {
-        clickedCard.classList.remove("loading");
+        if (clickedCard) {
+          clickedCard.classList.remove("loading");
+        }
       }
     })
@@ -51,5 +74,7 @@
       console.error("Failed to fetch recipe details", err);
       alert("Failed to load recipe details. Please try again.");
-      clickedCard.classList.remove("loading");
+      if (clickedCard) {
+        clickedCard.classList.remove("loading");
+      }
     });
 }
Index: NutriMatch/wwwroot/js/Notifications.js
===================================================================
--- NutriMatch/wwwroot/js/Notifications.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
+++ NutriMatch/wwwroot/js/Notifications.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -0,0 +1,357 @@
+document.addEventListener("DOMContentLoaded", function () {
+  const notificationPanel = document.getElementById("notification-panel");
+  const notificationIcon = document.querySelector(".notification-icon");
+  let isOpen = false;
+
+  notificationIcon.addEventListener("click", function (e) {
+    e.stopPropagation();
+
+    if (isOpen) {
+      closePanel();
+    } else {
+      openPanel();
+    }
+  });
+
+  function openPanel() {
+    loadNotificationPanel();
+    notificationPanel.classList.add("show");
+    isOpen = true;
+  }
+
+  function closePanel() {
+    notificationPanel.classList.remove("show");
+    isOpen = false;
+  }
+
+  document.addEventListener("click", function (e) {
+    if (!e.target.closest("#notification-bell") && isOpen) {
+      closePanel();
+    }
+  });
+
+  function loadNotificationPanel() {
+    fetch("/Notifications/NotificationPanel", {
+      method: "GET",
+      headers: {
+        "Content-Type": "text/html",
+      },
+    })
+      .then((response) => {
+        if (!response.ok) {
+          throw new Error("Network response was not ok");
+        }
+        return response.text();
+      })
+      .then((html) => {
+        document.getElementById("notification-panel-content").innerHTML = html;
+      })
+      .catch((error) => {
+        console.error("Error loading notifications:", error);
+        document.getElementById("notification-panel-content").innerHTML =
+          '<div class="notification-error">Failed to load notifications</div>';
+      });
+  }
+
+  function loadNotificationCount() {
+    fetch("/Notifications/GetNotifications", {
+      method: "GET",
+      headers: {
+        "Content-Type": "application/json",
+      },
+    })
+      .then((response) => response.json())
+      .then((data) => {
+        updateNotificationBadge(data.unreadCount);
+      })
+      .catch((error) => {
+        console.log("Failed to load notification count:", error);
+      });
+  }
+
+  function updateNotificationBadge(count) {
+    const badge = document.getElementById("notification-count");
+    if (count > 0) {
+      badge.textContent = count > 99 ? "99+" : count;
+      badge.classList.remove("hidden");
+    } else {
+      badge.classList.add("hidden");
+    }
+  }
+
+  document.addEventListener("click", function (e) {
+    const notificationItem = e.target.closest(".notification-item");
+
+    if (notificationItem) {
+      const notifId = notificationItem.getAttribute("data-id");
+      const recipeId = notificationItem.getAttribute("data-recipe-id");
+
+      if (e.target.closest(".notification-delete-btn")) return;
+
+      const notificationType = getNotificationType(notificationItem);
+
+      if (!notifId) return;
+
+      const formData = new FormData();
+      formData.append("notificationId", notifId);
+
+      fetch("/Notifications/MarkAsRead", {
+        method: "POST",
+        body: formData,
+      })
+        .then((response) => response.json())
+        .then((data) => {
+          if (data.success) {
+            notificationItem.classList.remove("unread");
+            updateNotificationBadge(data.unreadCount);
+
+            if (recipeId && recipeId !== "" && recipeId !== "null") {
+              if (notificationType === "RecipeDeclined") {
+                window.location.href =
+                  "/Recipes/MyRecipes?openDeclineModal=" + recipeId;
+              } else if (isRestaurantNotification(notificationType)) {
+                window.location.href =
+                  "/Restaurants/Index?restaurantId=" + recipeId;
+              } else if (isRecipeNotification(notificationType)) {
+                window.location.href = "/Recipes/Index?recipeId=" + recipeId;
+              }
+            } else {
+              if (isMealPlanNotification(notificationType)) {
+                window.location.href = "/MealPlan/";
+                console.log("TEST");
+              }
+            }
+          }
+        })
+        .catch((error) => {
+          console.error("Error marking notification as read:", error);
+        });
+    }
+  });
+
+  function getNotificationType(notificationItem) {
+    const iconWrapper = notificationItem.querySelector(
+      ".notification-icon-wrapper i"
+    );
+    if (!iconWrapper) return null;
+
+    if (iconWrapper.classList.contains("fa-star")) return "RecipeRated";
+    if (iconWrapper.classList.contains("fa-check-circle"))
+      return "RecipeAccepted";
+    if (iconWrapper.classList.contains("fa-times-circle"))
+      return "RecipeDeclined";
+    if (iconWrapper.classList.contains("fa-utensils"))
+      return "RestaurantNewMeal";
+    if (iconWrapper.classList.contains("fa-store")) return "NewRestaurant";
+    if (iconWrapper.classList.contains("fa-calendar-check"))
+      return "MealPlanUpdated";
+
+    if (iconWrapper.classList.contains("fa-tags")) {
+      const messageElement = notificationItem.querySelector(
+        ".notification-message"
+      );
+      if (messageElement) {
+        const message = messageElement.textContent;
+        if (message.includes(" at ")) {
+          return "MealMatchesTags";
+        } else {
+          return "RecipeMatchesTags";
+        }
+      }
+      return "MealMatchesTags";
+    }
+
+    return null;
+  }
+
+  function isRestaurantNotification(type) {
+    return ["RestaurantNewMeal", "MealMatchesTags", "NewRestaurant"].includes(
+      type
+    );
+  }
+
+  function isRecipeNotification(type) {
+    return [
+      "RecipeRated",
+      "RecipeAccepted",
+      "RecipeDeclined",
+      "RecipeMatchesTags",
+    ].includes(type);
+  }
+
+  function isMealPlanNotification(type) {
+    return ["MealPlanUpdated"].includes(type);
+  }
+
+  document.addEventListener("click", function (e) {
+    if (e.target.id === "mark-all-read" || e.target.closest("#mark-all-read")) {
+      e.preventDefault();
+
+      fetch("/Notifications/MarkAllAsRead", {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+        },
+      })
+        .then((response) => response.json())
+        .then((data) => {
+          if (data.success) {
+            const allNotifications =
+              document.querySelectorAll(".notification-item");
+            allNotifications.forEach((item) => {
+              item.classList.remove("unread");
+            });
+
+            updateNotificationBadge(0);
+
+            const markAllBtn = document.getElementById("mark-all-read");
+            if (markAllBtn) {
+              markAllBtn.style.display = "none";
+            }
+          }
+        })
+        .catch((error) => {
+          console.error("Error marking all as read:", error);
+        });
+    }
+  });
+
+  if (!window.notificationEventSource) {
+    window.notificationEventSource = new EventSource("/Notifications/Stream");
+
+    window.notificationEventSource.onmessage = function (event) {
+      const data = JSON.parse(event.data);
+      updateNotificationBadge(data.unreadCount);
+
+      if (isOpen) {
+        loadNotificationPanel();
+      }
+    };
+
+    window.notificationEventSource.onerror = function (err) {
+      console.warn("SSE error:", err);
+    };
+  }
+
+  window.addEventListener("beforeunload", function () {
+    if (window.notificationEventSource) {
+      window.notificationEventSource.close();
+      window.notificationEventSource = null;
+    }
+  });
+
+  loadNotificationCount();
+
+  document.addEventListener("click", function (e) {
+    const deleteBtn = e.target.closest(".notification-delete-btn");
+
+    if (deleteBtn) {
+      e.stopPropagation();
+
+      const notifId = deleteBtn.getAttribute("data-notification-id");
+      const notificationItem = deleteBtn.closest(".notification-item");
+
+      if (!notifId) return;
+
+      const formData = new FormData();
+      formData.append("notificationId", notifId);
+
+      fetch("/Notifications/Delete", {
+        method: "POST",
+        body: formData,
+      })
+        .then((response) => response.json())
+        .then((data) => {
+          if (data.success) {
+            notificationItem.style.opacity = "0";
+            notificationItem.style.transform = "translateX(100%)";
+
+            setTimeout(() => {
+              notificationItem.remove();
+              updateNotificationBadge(data.unreadCount);
+
+              const remainingNotifications = document.querySelectorAll(
+                ".notification-item:not(.no-notifications)"
+              );
+              if (remainingNotifications.length === 0) {
+                const notificationList =
+                  document.getElementById("notification-list");
+                notificationList.innerHTML = `
+                                <div class="notification-item no-notifications">
+                                    <i class="fas fa-bell-slash"></i>
+                                    <p>No notifications yet</p>
+                                </div>
+                            `;
+              }
+
+              const unreadNotifications = document.querySelectorAll(
+                ".notification-item.unread"
+              );
+              if (unreadNotifications.length === 0) {
+                const markAllBtn = document.getElementById("mark-all-read");
+                if (markAllBtn) {
+                  markAllBtn.style.display = "none";
+                }
+              }
+            }, 300);
+          }
+        })
+        .catch((error) => {
+          console.error("Error deleting notification:", error);
+        });
+    }
+  });
+});
+
+function deleteAllNotifications() {
+  fetch("/Notifications/DeleteAll", {
+    method: "POST",
+    headers: {
+      "Content-Type": "application/json",
+    },
+  })
+    .then((response) => {
+      if (!response.ok) {
+        throw new Error("Network response was not ok");
+      }
+      return response.json();
+    })
+    .then((data) => {
+      if (data.success) {
+        const notificationList = document.getElementById("notification-list");
+        if (notificationList) {
+          notificationList.innerHTML = `
+                    <div class="notification-item no-notifications">
+                        <i class="fas fa-bell-slash"></i>
+                        <p>No notifications yet</p>
+                    </div>
+                `;
+        }
+
+        if (typeof updateNotificationBadge === "function") {
+          updateNotificationBadge(0);
+        }
+
+        const deleteAllBtn = document.getElementById(
+          "delete-all-notifications"
+        );
+        const markAllReadBtn = document.getElementById("mark-all-read");
+
+        if (deleteAllBtn) deleteAllBtn.style.display = "none";
+        if (markAllReadBtn) markAllReadBtn.style.display = "none";
+      } else {
+        throw new Error(data.message || "Failed to delete notifications");
+      }
+    })
+    .catch((error) => {
+      console.error("Error:", error);
+      if (typeof showNotification === "function") {
+        showNotification(
+          "Error deleting notifications: " + error.message,
+          "error"
+        );
+      } else {
+        alert("Error deleting notifications: " + error.message);
+      }
+    });
+}
Index: NutriMatch/wwwroot/js/RecipeEdit.js
===================================================================
--- NutriMatch/wwwroot/js/RecipeEdit.js	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/js/RecipeEdit.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -5,419 +5,428 @@
 let selectedIngredient = null;
 
-
-const ingredientSearch = document.getElementById('ingredientSearch');
-const ingredientDropdown = document.getElementById('ingredientDropdown');
-const ingredientsList = document.getElementById('ingredientsList');
-const hiddenIngredientsInput = document.getElementById('selectedIngredients');
-const addButton = document.getElementById('addIngredientButton');
-const qtyInput = document.getElementById('ingredientQuantity');
-const unitSelect = document.getElementById('ingredientUnit');
-const instructionInput = document.getElementById('instructionInput');
-const addInstructionButton = document.getElementById('addInstructionButton');
-const instructionsList = document.getElementById('instructionsList');
-const hiddenInstructionsInput = document.getElementById('selectedInstructions');
-const fileUploadArea = document.getElementById('fileUploadArea');
-const fileInput = document.getElementById('RecipeImage');
-const imagePreview = document.getElementById('imagePreview');
-
-
-document.addEventListener('DOMContentLoaded', function() {
-    initializeSearchFunctionality();
-    initializeInstructionsFunctionality();
-    initializeInstructionsAndIngredients();
-    
-    updateIngredientsDisplay();
-    updateIngredientsInput();
-    updateInstructionsDisplay();
-    updateInstructionsInput(); 
+const ingredientSearch = document.getElementById("ingredientSearch");
+const ingredientDropdown = document.getElementById("ingredientDropdown");
+const ingredientsList = document.getElementById("ingredientsList");
+const hiddenIngredientsInput = document.getElementById("selectedIngredients");
+const addButton = document.getElementById("addIngredientButton");
+const qtyInput = document.getElementById("ingredientQuantity");
+const unitSelect = document.getElementById("ingredientUnit");
+const instructionInput = document.getElementById("instructionInput");
+const addInstructionButton = document.getElementById("addInstructionButton");
+const instructionsList = document.getElementById("instructionsList");
+const hiddenInstructionsInput = document.getElementById("selectedInstructions");
+const fileUploadArea = document.getElementById("fileUploadArea");
+const fileInput = document.getElementById("RecipeImage");
+const imagePreview = document.getElementById("imagePreview");
+
+document.addEventListener("DOMContentLoaded", function () {
+  initializeSearchFunctionality();
+  initializeInstructionsFunctionality();
+  initializeInstructionsAndIngredients();
+
+  updateIngredientsDisplay();
+  updateIngredientsInput();
+  updateInstructionsDisplay();
+  updateInstructionsInput();
 });
 
-function initializeInstructionsAndIngredients(){
-    var existingInstructions = JSON.parse((document.getElementById('selectedInstructionsScript').innerText))[0];
-    existingInstructions = JSON.parse(existingInstructions);
-    
-    var existingIngredients = JSON.parse((document.getElementById('selectedIngredientsScript').innerText));
-    console.log(existingIngredients)
-
-    existingIngredients.forEach(element => {
-        selectedIngredients.push({
-            Id: element.IngredientId,
-            Name: element.Ingredient.Name,
-            Quantity: element.Quantity,
-            Unit: element.Unit
-        })
-    }); 
-
-    existingInstructions.forEach(element => {
-        selectedInstructions.push(element);
-    });
+function initializeInstructionsAndIngredients() {
+  var existingInstructions = JSON.parse(
+    document.getElementById("selectedInstructionsScript").innerText
+  )[0];
+  existingInstructions = JSON.parse(existingInstructions);
+
+  var existingIngredients = JSON.parse(
+    document.getElementById("selectedIngredientsScript").innerText
+  );
+  console.log(existingIngredients);
+
+  existingIngredients.forEach((element) => {
+    selectedIngredients.push({
+      Id: element.IngredientId,
+      Name: element.Ingredient.Name,
+      Quantity: element.Quantity,
+      Unit: element.Unit,
+    });
+  });
+
+  existingInstructions.forEach((element) => {
+    selectedInstructions.push(element);
+  });
 }
 
 function initializeSearchFunctionality() {
-    if (addButton) {
-        addButton.addEventListener('click', function() {
-            if (selectedIngredient && qtyInput && unitSelect) {
-                const qty = parseFloat(qtyInput.value);
-                const unit = unitSelect.value;
-                
-                if (qty > 0 && unit && selectedIngredient.name) {
-                    addIngredient(selectedIngredient, qty, unit);
-                } else {
-                    alert('Please enter a valid quantity and select a unit.');
-                }
-            } else {
-                alert('Please search and select an ingredient first.');
-            }
-        });
+  if (addButton) {
+    addButton.addEventListener("click", function () {
+      if (selectedIngredient && qtyInput && unitSelect) {
+        const qty = parseFloat(qtyInput.value);
+        const unit = unitSelect.value;
+
+        if (qty > 0 && unit && selectedIngredient.name) {
+          addIngredient(selectedIngredient, qty, unit);
+        } else {
+          alert("Please enter a valid quantity and select a unit.");
+        }
+      } else {
+        alert("Please search and select an ingredient first.");
+      }
+    });
+  }
+
+  if (ingredientSearch) {
+    ingredientSearch.addEventListener("input", function () {
+      const query = this.value.trim();
+      currentFocus = -1;
+      selectedIngredient = null;
+
+      if (query === "") {
+        hideDropdown(ingredientDropdown);
+        return;
+      }
+
+      clearTimeout(searchTimeout);
+      searchTimeout = setTimeout(() => {
+        searchIngredients(query);
+      }, 300);
+    });
+
+    ingredientSearch.addEventListener("keydown", function (e) {
+      handleKeyNavigation(e, ingredientDropdown);
+    });
+
+    ingredientSearch.addEventListener("focus", function () {
+      if (this.value.trim() !== "") {
+        searchIngredients(this.value.trim());
+      }
+    });
+  }
+
+  document.addEventListener("click", function (e) {
+    if (!e.target.closest(".search-container")) {
+      hideDropdown(ingredientDropdown);
     }
-
-    if (ingredientSearch) {
-        ingredientSearch.addEventListener('input', function() {
-            const query = this.value.trim();
-            currentFocus = -1;
-            selectedIngredient = null; 
-            
-            if (query === '') {
-                hideDropdown(ingredientDropdown);
-                return;
-            }
-
-            clearTimeout(searchTimeout);
-            searchTimeout = setTimeout(() => {
-                searchIngredients(query);
-            }, 300);
-        });
-
-        ingredientSearch.addEventListener('keydown', function(e) {
-            handleKeyNavigation(e, ingredientDropdown);
-        });
-
-        ingredientSearch.addEventListener('focus', function() {
-            if (this.value.trim() !== '') {
-                searchIngredients(this.value.trim());
-            }
-        });
+  });
+}
+
+function initializeInstructionsFunctionality() {
+  if (addInstructionButton) {
+    addInstructionButton.addEventListener("click", function () {
+      addInstruction();
+    });
+  }
+
+  if (instructionInput) {
+    instructionInput.addEventListener("keydown", function (e) {
+      if (e.key === "Enter") {
+        e.preventDefault();
+        addInstruction();
+      }
+    });
+  }
+}
+
+async function searchIngredients(query) {
+  if (!ingredientDropdown) return;
+
+  try {
+    ingredientDropdown.innerHTML = '<div class="loading">Loading...</div>';
+    showDropdown(ingredientDropdown);
+
+    const response = await fetch(
+      `/Recipes/getSuggestions?query=${encodeURIComponent(query)}`,
+      {
+        method: "GET",
+        headers: {
+          "Content-Type": "application/json",
+          "X-Requested-With": "XMLHttpRequest",
+        },
+      }
+    );
+
+    if (!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
     }
 
-    
-    document.addEventListener('click', function(e) {
-        if (!e.target.closest('.search-container')) {
-            hideDropdown(ingredientDropdown);
-        }
-    });
-}
-
-function initializeInstructionsFunctionality() {
-    if (addInstructionButton) {
-        addInstructionButton.addEventListener('click', function() {
-            addInstruction();
-        });
-    }
-
-    if (instructionInput) {
-        instructionInput.addEventListener('keydown', function(e) {
-            if (e.key === 'Enter') {
-                e.preventDefault();
-                addInstruction();
-            }
-        });
-    }
-}
-
-
-async function searchIngredients(query) {
-    if (!ingredientDropdown) return;
-
-    try {
-        ingredientDropdown.innerHTML = '<div class="loading">Loading...</div>';
-        showDropdown(ingredientDropdown);
-
-       
-        const response = await fetch(`/Recipes/getSuggestions?query=${encodeURIComponent(query)}`, {
-            method: 'GET',
-            headers: {
-                'Content-Type': 'application/json',
-                'X-Requested-With': 'XMLHttpRequest'
-            }
-        });
-
-        if (!response.ok) {
-            throw new Error(`HTTP error! status: ${response.status}`);
-        }
-
-        const suggestions = await response.json();
-        displaySuggestions(suggestions, query);
-
-    } catch (error) {
-        console.error('Error fetching suggestions:', error);
-        ingredientDropdown.innerHTML = '<div class="no-results">Error loading suggestions. Please try again.</div>';
-        showDropdown(ingredientDropdown);
-    }
-}
-
+    const suggestions = await response.json();
+    displaySuggestions(suggestions, query);
+  } catch (error) {
+    console.error("Error fetching suggestions:", error);
+    ingredientDropdown.innerHTML =
+      '<div class="no-results">Error loading suggestions. Please try again.</div>';
+    showDropdown(ingredientDropdown);
+  }
+}
 
 function displaySuggestions(suggestions, query) {
-    if (!ingredientDropdown) return;
-
-    ingredientDropdown.innerHTML = '';
-    
-    if (!suggestions || suggestions.length === 0) {
-        ingredientDropdown.innerHTML = '<div class="no-results">No results found</div>';
-        showDropdown(ingredientDropdown);
-        return;
-    }
-
-    suggestions.forEach((suggestion, index) => {
-        const item = document.createElement('div');
-        item.className = 'dropdown-item';
-        item.setAttribute('data-index', index);
-        
-        const name = typeof suggestion === 'string' ? suggestion : suggestion.name;
-        const id = typeof suggestion === 'object' ? suggestion.id : null;
-        
-        const regex = new RegExp(`(${query})`, 'gi');
-        const highlightedText = name.replace(regex, '<strong>$1</strong>');
-        item.innerHTML = highlightedText;
-        
-        item.addEventListener('click', function() {
-            selectedIngredient = {
-                id: id,
-                name: name
-            };
-            ingredientSearch.value = name;
-            hideDropdown(ingredientDropdown);
-        });
-        
-        ingredientDropdown.appendChild(item);
-    });
-
+  if (!ingredientDropdown) return;
+
+  ingredientDropdown.innerHTML = "";
+
+  if (!suggestions || suggestions.length === 0) {
+    ingredientDropdown.innerHTML =
+      '<div class="no-results">No results found</div>';
     showDropdown(ingredientDropdown);
-}
-
+    return;
+  }
+
+  suggestions.forEach((suggestion, index) => {
+    const item = document.createElement("div");
+    item.className = "dropdown-item";
+    item.setAttribute("data-index", index);
+
+    const name = typeof suggestion === "string" ? suggestion : suggestion.name;
+    const id = typeof suggestion === "object" ? suggestion.id : null;
+
+    const regex = new RegExp(`(${query})`, "gi");
+    const highlightedText = name.replace(regex, "<strong>$1</strong>");
+    item.innerHTML = highlightedText;
+
+    item.addEventListener("click", function () {
+      selectedIngredient = {
+        id: id,
+        name: name,
+      };
+      ingredientSearch.value = name;
+      hideDropdown(ingredientDropdown);
+    });
+
+    ingredientDropdown.appendChild(item);
+  });
+
+  showDropdown(ingredientDropdown);
+}
 
 function handleKeyNavigation(e, dropdownElement) {
-    if (!dropdownElement) return;
-
-    const items = dropdownElement.querySelectorAll('.dropdown-item:not(.no-results):not(.loading)');
-    
-    switch(e.key) {
-        case 'ArrowDown':
-            e.preventDefault();
-            currentFocus++;
-            if (currentFocus >= items.length) currentFocus = 0;
-            setActive(items);
-            break;
-            
-        case 'ArrowUp':
-            e.preventDefault();
-            currentFocus--;
-            if (currentFocus < 0) currentFocus = items.length - 1;
-            setActive(items);
-            break;
-            
-        case 'Enter':
-            e.preventDefault();
-            if (currentFocus > -1 && items[currentFocus]) {
-                items[currentFocus].click();
-            }
-            break;
-            
-        case 'Escape':
-            hideDropdown(dropdownElement);
-            e.target.blur();
-            break;
-    }
-}
-
+  if (!dropdownElement) return;
+
+  const items = dropdownElement.querySelectorAll(
+    ".dropdown-item:not(.no-results):not(.loading)"
+  );
+
+  switch (e.key) {
+    case "ArrowDown":
+      e.preventDefault();
+      currentFocus++;
+      if (currentFocus >= items.length) currentFocus = 0;
+      setActive(items);
+      break;
+
+    case "ArrowUp":
+      e.preventDefault();
+      currentFocus--;
+      if (currentFocus < 0) currentFocus = items.length - 1;
+      setActive(items);
+      break;
+
+    case "Enter":
+      e.preventDefault();
+      if (currentFocus > -1 && items[currentFocus]) {
+        items[currentFocus].click();
+      }
+      break;
+
+    case "Escape":
+      hideDropdown(dropdownElement);
+      e.target.blur();
+      break;
+  }
+}
 
 function setActive(items) {
-    
-    items.forEach(item => item.classList.remove('highlighted'));
-    
-    
-    if (currentFocus >= 0 && currentFocus < items.length) {
-        items[currentFocus].classList.add('highlighted');
-        items[currentFocus].scrollIntoView({ block: 'nearest' });
-    }
-}
-
+  items.forEach((item) => item.classList.remove("highlighted"));
+
+  if (currentFocus >= 0 && currentFocus < items.length) {
+    items[currentFocus].classList.add("highlighted");
+    items[currentFocus].scrollIntoView({ block: "nearest" });
+  }
+}
 
 function addIngredient(ingredient, quantity, unit) {
-    if (!ingredient || !ingredient.name) {
-        console.error('Invalid ingredient data');
-        return;
-    }
-
-    
-    const existingIngredient = selectedIngredients.find(item => item.Id === ingredient.id);
-    
-    if (existingIngredient) {
-        alert('This ingredient is already added to the recipe.');
-        return;
-    }
-
-    
-    const newIngredient = {
-        Id: ingredient.id,
-        Name: ingredient.name,
-        Quantity: quantity,
-        Unit: unit
-    };
-
-    selectedIngredients.push(newIngredient);
-    updateIngredientsDisplay();
-    updateIngredientsInput();
-
-    
-    if (ingredientSearch) ingredientSearch.value = '';
-    if (qtyInput) qtyInput.value = '';
-    if (unitSelect) unitSelect.value = '';
-    
-    selectedIngredient = null;
-    hideDropdown(ingredientDropdown);
-    currentFocus = -1;
-}
-
+  if (!ingredient || !ingredient.name) {
+    console.error("Invalid ingredient data");
+    return;
+  }
+
+  const existingIngredient = selectedIngredients.find(
+    (item) => item.Id === ingredient.id
+  );
+
+  if (existingIngredient) {
+    alert("This ingredient is already added to the recipe.");
+    return;
+  }
+
+  const newIngredient = {
+    Id: ingredient.id,
+    Name: ingredient.name,
+    Quantity: quantity,
+    Unit: unit,
+  };
+
+  selectedIngredients.push(newIngredient);
+  updateIngredientsDisplay();
+  updateIngredientsInput();
+
+  if (ingredientSearch) ingredientSearch.value = "";
+  if (qtyInput) qtyInput.value = "";
+  if (unitSelect) unitSelect.value = "";
+
+  selectedIngredient = null;
+  hideDropdown(ingredientDropdown);
+  currentFocus = -1;
+}
 
 function removeIngredient(ingredientName) {
-    selectedIngredients = selectedIngredients.filter(item => item.Name !== ingredientName);
-    updateIngredientsDisplay();
-    updateIngredientsInput();
-}
-
+  selectedIngredients = selectedIngredients.filter(
+    (item) => item.Name !== ingredientName
+  );
+  updateIngredientsDisplay();
+  updateIngredientsInput();
+}
 
 function addInstruction() {
-    if (!instructionInput) return;
-
-    const instruction = instructionInput.value.trim();
-    
-    if (instruction === '') {
-        alert('Please enter an instruction.');
-        return;
-    }
-
-    if (selectedInstructions.includes(instruction)) {
-        alert('This instruction is already added.');
-        return;
-    }
-
-    selectedInstructions.push(instruction);
-    updateInstructionsDisplay();
-    updateInstructionsInput();
-
-    instructionInput.value = '';
+  if (!instructionInput) return;
+
+  const instruction = instructionInput.value.trim();
+
+  if (instruction === "") {
+    alert("Please enter an instruction.");
+    return;
+  }
+
+  if (selectedInstructions.includes(instruction)) {
+    alert("This instruction is already added.");
+    return;
+  }
+
+  selectedInstructions.push(instruction);
+  updateInstructionsDisplay();
+  updateInstructionsInput();
+
+  instructionInput.value = "";
 }
 
 function removeInstruction(instructionIndex) {
-    selectedInstructions.splice(instructionIndex, 1);
-    updateInstructionsDisplay();
-    updateInstructionsInput();
+  selectedInstructions.splice(instructionIndex, 1);
+  updateInstructionsDisplay();
+  updateInstructionsInput();
 }
 
 function updateIngredientsDisplay() {
-    if (!ingredientsList) return;
-
-    if (selectedIngredients.length === 0) {
-        ingredientsList.innerHTML = '<small class="text-muted">Selected ingredients will appear here</small>';
-    } else {
-        ingredientsList.innerHTML = selectedIngredients.map(ingredient => 
-            `<span class="ingredient-tag">
+  if (!ingredientsList) return;
+
+  if (selectedIngredients.length === 0) {
+    ingredientsList.innerHTML =
+      '<small class="text-muted">Selected ingredients will appear here</small>';
+  } else {
+    ingredientsList.innerHTML = selectedIngredients
+      .map(
+        (ingredient) =>
+          `<span class="ingredient-tag">
                 ${ingredient.Quantity} ${ingredient.Unit} of ${ingredient.Name}
                 <span class="remove" onclick="removeIngredient('${ingredient.Name}')" title="Remove ingredient">&times;</span>
             </span>`
-        ).join('');
-    }
+      )
+      .join("");
+  }
 }
 
 function updateInstructionsDisplay() {
-    if (!instructionsList) return;
-
-    if (selectedInstructions.length === 0) {
-        instructionsList.innerHTML = '<small class="text-muted">Added instructions will appear here</small>';
-    } else {
-        instructionsList.innerHTML = selectedInstructions.map((instruction, index) => 
-            `<div class="instruction-item">
+  if (!instructionsList) return;
+
+  if (selectedInstructions.length === 0) {
+    instructionsList.innerHTML =
+      '<small class="text-muted">Added instructions will appear here</small>';
+  } else {
+    instructionsList.innerHTML = selectedInstructions
+      .map(
+        (instruction, index) =>
+          `<div class="instruction-item">
                 <span class="instruction-number" ">${index + 1}</span>
                 <span class="instruction-text">${instruction}</span>
                 <span class="remove" onclick="removeInstruction(${index})" style=font-size: 18px;"title="Remove instruction">&times;</span>
             </div>`
-        ).join('');
-    }
+      )
+      .join("");
+  }
 }
 
 function updateIngredientsInput() {
-    if (hiddenIngredientsInput) {
-        hiddenIngredientsInput.value = JSON.stringify(selectedIngredients);
-        console.log('Updated hidden ingredients input:', hiddenIngredientsInput.value);
-    }
+  if (hiddenIngredientsInput) {
+    hiddenIngredientsInput.value = JSON.stringify(selectedIngredients);
+    console.log(
+      "Updated hidden ingredients input:",
+      hiddenIngredientsInput.value
+    );
+  }
 }
 
 function updateInstructionsInput() {
-    if (hiddenInstructionsInput) {
-        hiddenInstructionsInput.value = JSON.stringify(selectedInstructions);
-        console.log('Updated hidden instructions input:', hiddenInstructionsInput.value);
-    }
+  if (hiddenInstructionsInput) {
+    hiddenInstructionsInput.value = JSON.stringify(selectedInstructions);
+    console.log(
+      "Updated hidden instructions input:",
+      hiddenInstructionsInput.value
+    );
+  }
 }
 
 function showDropdown(dropdownElement) {
-    if (dropdownElement) {
-        dropdownElement.style.display = 'block';
-    }
+  if (dropdownElement) {
+    dropdownElement.style.display = "block";
+  }
 }
 
 function hideDropdown(dropdownElement) {
-    if (dropdownElement) {
-        dropdownElement.style.display = 'none';
-    }
-    currentFocus = -1;
-}
-
-
-
-fileUploadArea.addEventListener('click', () => fileInput.click());
-
-fileUploadArea.addEventListener('dragover', (e) => {
-    e.preventDefault();
-    fileUploadArea.classList.add('dragover');
+  if (dropdownElement) {
+    dropdownElement.style.display = "none";
+  }
+  currentFocus = -1;
+}
+
+fileUploadArea.addEventListener("click", () => fileInput.click());
+
+fileUploadArea.addEventListener("dragover", (e) => {
+  e.preventDefault();
+  fileUploadArea.classList.add("dragover");
 });
 
-fileUploadArea.addEventListener('dragleave', () => {
-    fileUploadArea.classList.remove('dragover');
+fileUploadArea.addEventListener("dragleave", () => {
+  fileUploadArea.classList.remove("dragover");
 });
 
-fileUploadArea.addEventListener('drop', (e) => {
-    e.preventDefault();
-    fileUploadArea.classList.remove('dragover');
-    const files = e.dataTransfer.files;
-    if (files.length > 0) {
-        handleFileSelect(files[0]);
-        setFileToInput(files[0]);
-    }
+fileUploadArea.addEventListener("drop", (e) => {
+  e.preventDefault();
+  fileUploadArea.classList.remove("dragover");
+  const files = e.dataTransfer.files;
+  if (files.length > 0) {
+    handleFileSelect(files[0]);
+    setFileToInput(files[0]);
+  }
 });
 
-fileInput.addEventListener('change', (e) => {
-    if (e.target.files && e.target.files[0]) {
-        handleFileSelect(e.target.files[0]);
-    }
+fileInput.addEventListener("change", (e) => {
+  if (e.target.files && e.target.files[0]) {
+    handleFileSelect(e.target.files[0]);
+  }
 });
 
 function handleFileSelect(file) {
-    if (file.type.startsWith('image/')) {
-        const reader = new FileReader();
-        reader.onload = (e) => {
-            imagePreview.innerHTML = `
+  if (file.type.startsWith("image/")) {
+    const reader = new FileReader();
+    reader.onload = (e) => {
+      imagePreview.innerHTML = `
                 <img id="image-preview" src="${e.target.result}" alt="Recipe preview">
                 <p style="margin-top: 0.5rem; color: #4CAF50; font-weight: 500;">✓ Image uploaded successfully</p>
             `;
-        };
-        reader.readAsDataURL(file);
-    }
+    };
+    reader.readAsDataURL(file);
+  }
 }
 
 function setFileToInput(file) {
-    const dataTransfer = new DataTransfer();
-    dataTransfer.items.add(file);
-    
-    fileInput.files = dataTransfer.files;
-}
-
+  const dataTransfer = new DataTransfer();
+  dataTransfer.items.add(file);
+
+  fileInput.files = dataTransfer.files;
+}
Index: NutriMatch/wwwroot/js/RecipeIndex.js
===================================================================
--- NutriMatch/wwwroot/js/RecipeIndex.js	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/js/RecipeIndex.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -21,4 +21,6 @@
 
   filterRecipes();
+
+  checkForRecipeIdParameter();
 });
 
@@ -327,5 +329,5 @@
   document.getElementById("proteinMax").value = 150;
   document.getElementById("carbsMin").value = 0;
-  document.getElementById("carbsMax").value = 150;
+  document.getElementById("carbsMax").value = 200;
   document.getElementById("fatsMin").value = 0;
   document.getElementById("fatsMax").value = 150;
@@ -494,2 +496,280 @@
   filterRecipes();
 }
+
+let userPreferences = {
+  tags: [],
+  followedRestaurants: [],
+};
+
+window.addEventListener("load", function () {
+  if (document.querySelector(".notification-bell")) {
+    loadUserPreferences();
+  }
+});
+
+async function loadUserPreferences() {
+  try {
+    const response = await fetch("/Restaurants/GetUserPreferences");
+    if (response.ok) {
+      userPreferences = await response.json();
+      updateFollowButtons();
+    }
+  } catch (error) {
+    console.error("Error loading preferences:", error);
+  }
+}
+
+function toggleTagExpansion(tagName) {
+  const threshold = document.getElementById(`threshold-${tagName}`);
+  const tagItem = threshold.previousElementSibling;
+  const checkbox = document.getElementById(`tag-${tagName}`);
+
+  const isExpanded = threshold.classList.contains("show");
+  threshold.classList.toggle("show", !isExpanded);
+  tagItem.classList.toggle("expanded", !isExpanded);
+
+  if (!isExpanded) {
+    checkbox.checked = true;
+  }
+}
+
+document.addEventListener("DOMContentLoaded", function () {
+  const checkboxes = document.querySelectorAll(
+    '.tag-item input[type="checkbox"]'
+  );
+  checkboxes.forEach((checkbox) => {
+    checkbox.addEventListener("click", function (e) {
+      e.stopPropagation();
+
+      const tagName = this.value;
+      const threshold = document.getElementById(`threshold-${tagName}`);
+
+      if (!this.checked && threshold) {
+        threshold.classList.remove("show");
+        threshold.previousElementSibling.classList.remove("expanded");
+      }
+    });
+  });
+});
+
+function openPreferencesModal() {
+  const modal = new bootstrap.Modal(
+    document.getElementById("preferencesModal")
+  );
+
+  loadUserPreferencesForModal();
+
+  modal.show();
+}
+
+async function loadUserPreferencesForModal() {
+  try {
+    const response = await fetch("/Restaurants/GetUserPreferences");
+    if (response.ok) {
+      const data = await response.json();
+
+      document
+        .querySelectorAll('.tag-selection input[type="checkbox"]')
+        .forEach((cb) => {
+          cb.checked = false;
+        });
+      document.querySelectorAll(".tag-threshold").forEach((threshold) => {
+        threshold.classList.remove("show");
+      });
+      document.querySelectorAll(".tag-item").forEach((item) => {
+        item.classList.remove("expanded");
+      });
+
+      data.preferences.forEach((pref) => {
+        const checkbox = document.getElementById(`tag-${pref.tag}`);
+        if (checkbox) {
+          checkbox.checked = true;
+
+          if (
+            pref.thresholdValue !== null &&
+            pref.thresholdValue !== undefined
+          ) {
+            const valueInput = document.getElementById(`value-${pref.tag}`);
+            const threshold = document.getElementById(`threshold-${pref.tag}`);
+
+            if (valueInput && threshold) {
+              valueInput.value = pref.thresholdValue;
+              threshold.classList.add("show");
+              threshold.previousElementSibling.classList.add("expanded");
+            }
+          }
+        }
+      });
+    }
+  } catch (error) {
+    console.error("Error loading preferences:", error);
+  }
+}
+
+async function savePreferences() {
+  const preferences = [];
+
+  document
+    .querySelectorAll('.tag-selection input[type="checkbox"]:checked')
+    .forEach((cb) => {
+      const tagValue = cb.value;
+      const valueInput = document.getElementById(`value-${tagValue}`);
+
+      const preference = {
+        tag: tagValue,
+        thresholdValue: valueInput ? parseInt(valueInput.value) : null,
+      };
+
+      preferences.push(preference);
+    });
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+
+  try {
+    const response = await fetch("/Restaurants/UpdateTagPreferences", {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+        RequestVerificationToken: token,
+      },
+      body: JSON.stringify(preferences),
+    });
+
+    const data = await response.json();
+    if (data.success) {
+      showSuccess(
+        "Preferences saved! You will receive notifications for matching meals."
+      );
+      bootstrap.Modal.getInstance(
+        document.getElementById("preferencesModal")
+      ).hide();
+    } else {
+      showError("Failed to save preferences");
+    }
+  } catch (error) {
+    console.error("Error saving preferences:", error);
+    showError("Error saving preferences");
+  }
+}
+
+function showSuccess(message) {
+  createToast(message, "success");
+}
+
+function showError(message) {
+  createToast(message, "danger");
+}
+
+function showInfo(message) {
+  createToast(message, "info");
+}
+
+function createToast(message, type = "info") {
+  const toastContainer =
+    document.getElementById("toast-container") || createToastContainer();
+
+  const toastId = "toast-" + Date.now();
+  const toast = document.createElement("div");
+  toast.id = toastId;
+  toast.className = `toast align-items-center text-white bg-${type} border-0`;
+  toast.setAttribute("role", "alert");
+
+  const iconMap = {
+    success: "fas fa-check-circle",
+    danger: "fas fa-exclamation-circle",
+    info: "fas fa-info-circle",
+  };
+
+  toast.innerHTML = `
+        <div class="d-flex">
+            <div class="toast-body">
+                <i class="${iconMap[type]} me-2"></i>
+                ${message}
+            </div>
+            <button type="button" class="btn-close btn-close-white me-2 m-auto" onclick="removeToast('${toastId}')"></button>
+        </div>
+    `;
+
+  toastContainer.appendChild(toast);
+  toast.style.display = "block";
+  setTimeout(() => toast.classList.add("show"), 100);
+  setTimeout(() => removeToast(toastId), 5000);
+}
+
+function removeToast(toastId) {
+  const toast = document.getElementById(toastId);
+  if (toast) {
+    toast.classList.remove("show");
+    setTimeout(() => toast.remove(), 300);
+  }
+}
+
+function createToastContainer() {
+  const container = document.createElement("div");
+  container.id = "toast-container";
+  container.className = "toast-container position-fixed top-0 end-0 p-3";
+  container.style.zIndex = "10000";
+  document.body.appendChild(container);
+  return container;
+}
+
+function checkForRecipeIdParameter() {
+  const urlParams = new URLSearchParams(window.location.search);
+  const recipeId = urlParams.get("recipeId");
+
+  if (recipeId) {
+    const newUrl = window.location.pathname;
+    window.history.replaceState({}, document.title, newUrl);
+    al;
+    setTimeout(() => {
+      showRecipeDetailsFromNotification(recipeId);
+    }, 300);
+  }
+}
+
+function showRecipeDetailsFromNotification(recipeId) {
+  const params = new URLSearchParams({
+    isOwner: false,
+    recipeDetailsDisplayContorol: "Index",
+  });
+
+  fetch(`/Recipes/Details/${recipeId}?${params}`)
+    .then((response) => {
+      if (!response.ok) {
+        throw new Error("Network response was not ok");
+      }
+      return response.text();
+    })
+    .then((html) => {
+      const modalContainer = document.getElementById("modalWindow");
+      modalContainer.innerHTML = html;
+
+      const scripts = modalContainer.querySelectorAll("script");
+      scripts.forEach((script) => {
+        const newScript = document.createElement("script");
+        if (script.src) {
+          newScript.src = script.src;
+        } else {
+          newScript.textContent = script.textContent;
+        }
+        document.body.appendChild(newScript);
+        document.body.removeChild(newScript);
+      });
+
+      const modalElement = modalContainer.querySelector(".modal");
+      if (modalElement) {
+        const modal = new bootstrap.Modal(modalElement);
+        modal.show();
+
+        modalElement.addEventListener("hidden.bs.modal", function () {
+          modalContainer.innerHTML = "";
+        });
+      }
+    })
+    .catch((err) => {
+      console.error("Failed to fetch recipe details", err);
+      showToast("Failed to load recipe details. Please try again.", "error");
+    });
+}
Index: NutriMatch/wwwroot/js/RestaurantIndex.js
===================================================================
--- NutriMatch/wwwroot/js/RestaurantIndex.js	(revision 43fd85228cd124d1d74530c2e0b5a9aae73adf35)
+++ NutriMatch/wwwroot/js/RestaurantIndex.js	(revision 7d86a11e63b56e75d10177f1f24be1ddd20f75ee)
@@ -9,4 +9,6 @@
   initializeFilters();
   updateFilterValues();
+
+  checkForRestaurantIdParameter();
 });
 
@@ -91,14 +93,7 @@
   const query = new URLSearchParams(f).toString();
 
-  const menuContainer = document.getElementById("menuItems");
+  const menuContainer = document.getElementById("modal-content");
   menuContainer.innerHTML =
     '<div class="text-center p-4"><i class="fas fa-spinner fa-spin"></i> Loading menu...</div>';
-
-  const filterInfo = document.getElementById("filterInfo");
-  if (!areFiltersDefault()) {
-    filterInfo.style.display = "block";
-  } else {
-    filterInfo.style.display = "none";
-  }
 
   const modal = new bootstrap.Modal(document.getElementById("menuModal"));
@@ -116,4 +111,16 @@
       console.log("Received HTML length:", html.length);
       menuContainer.innerHTML = html;
+
+      const scripts = menuContainer.querySelectorAll("script");
+      scripts.forEach((script) => {
+        const newScript = document.createElement("script");
+        if (script.src) {
+          newScript.src = script.src;
+        } else {
+          newScript.textContent = script.textContent;
+        }
+        document.body.appendChild(newScript);
+        document.body.removeChild(newScript);
+      });
     })
     .catch((err) => {
@@ -227,2 +234,312 @@
   updateSlider("fats");
 }
+
+let userPreferences = {
+  tags: [],
+  followedRestaurants: [],
+};
+
+window.addEventListener("load", function () {
+  if (document.querySelector(".notification-bell")) {
+    loadUserPreferences();
+  }
+});
+
+async function loadUserPreferences() {
+  try {
+    const response = await fetch("/Restaurants/GetUserPreferences");
+    if (response.ok) {
+      userPreferences = await response.json();
+      updateFollowButtons();
+    }
+  } catch (error) {
+    console.error("Error loading preferences:", error);
+  }
+}
+
+function openPreferencesModal() {
+  const modal = new bootstrap.Modal(
+    document.getElementById("preferencesModal")
+  );
+
+  userPreferences.tags.forEach((tag) => {
+    const checkbox = document.getElementById(`tag-${tag}`);
+    if (checkbox) {
+      checkbox.checked = true;
+    }
+  });
+
+  modal.show();
+}
+
+async function toggleFollow(restaurantId, event) {
+  event.stopPropagation();
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+  const btn = event.currentTarget;
+
+  try {
+    const response = await fetch("/Restaurants/ToggleFollowRestaurant", {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+        RequestVerificationToken: token,
+      },
+      body: JSON.stringify(restaurantId),
+    });
+
+    const data = await response.json();
+    if (data.success) {
+      const icon = btn.querySelector("i");
+
+      if (data.following) {
+        btn.classList.add("active");
+        icon.classList.remove("far");
+        icon.classList.add("fas");
+
+        btn.classList.add("just-activated");
+        setTimeout(() => btn.classList.remove("just-activated"), 500);
+
+        showSuccess("You will be notified when this restaurant adds new meals");
+        userPreferences.followedRestaurants.push(restaurantId);
+      } else {
+        btn.classList.remove("active");
+        icon.classList.remove("fas");
+        icon.classList.add("far");
+
+        showInfo("Notifications disabled for this restaurant");
+        userPreferences.followedRestaurants =
+          userPreferences.followedRestaurants.filter(
+            (id) => id !== restaurantId
+          );
+      }
+    }
+  } catch (error) {
+    console.error("Error toggling follow:", error);
+    showError("Error updating notification settings");
+  }
+}
+
+function updateFollowButtons() {
+  document.querySelectorAll(".notification-bell").forEach((btn) => {
+    const restaurantId = parseInt(btn.dataset.restaurantId);
+    if (userPreferences.followedRestaurants.includes(restaurantId)) {
+      btn.classList.add("active");
+      const icon = btn.querySelector("i");
+      icon.classList.remove("far");
+      icon.classList.add("fas");
+    }
+  });
+}
+
+function showSuccess(message) {
+  createToast(message, "success");
+}
+
+function showError(message) {
+  createToast(message, "danger");
+}
+
+function showInfo(message) {
+  createToast(message, "info");
+}
+
+function createToast(message, type = "info") {
+  const toastContainer =
+    document.getElementById("toast-container") || createToastContainer();
+
+  const toastId = "toast-" + Date.now();
+  const toast = document.createElement("div");
+  toast.id = toastId;
+  toast.className = `toast align-items-center text-white bg-${type} border-0`;
+  toast.setAttribute("role", "alert");
+
+  const iconMap = {
+    success: "fas fa-check-circle",
+    danger: "fas fa-exclamation-circle",
+    info: "fas fa-info-circle",
+  };
+
+  toast.innerHTML = `
+        <div class="d-flex">
+            <div class="toast-body">
+                <i class="${iconMap[type]} me-2"></i>
+                ${message}
+            </div>
+            <button type="button" class="btn-close btn-close-white me-2 m-auto" onclick="removeToast('${toastId}')"></button>
+        </div>
+    `;
+
+  toastContainer.appendChild(toast);
+  toast.style.display = "block";
+  setTimeout(() => toast.classList.add("show"), 100);
+  setTimeout(() => removeToast(toastId), 5000);
+}
+
+function removeToast(toastId) {
+  const toast = document.getElementById(toastId);
+  if (toast) {
+    toast.classList.remove("show");
+    setTimeout(() => toast.remove(), 300);
+  }
+}
+
+function createToastContainer() {
+  const container = document.createElement("div");
+  container.id = "toast-container";
+  container.className = "toast-container position-fixed top-0 end-0 p-3";
+  container.style.zIndex = "10000";
+  document.body.appendChild(container);
+  return container;
+}
+
+function toggleTagExpansion(tagName) {
+  const threshold = document.getElementById(`threshold-${tagName}`);
+  const tagItem = threshold.previousElementSibling;
+  const checkbox = document.getElementById(`tag-${tagName}`);
+
+  const isExpanded = threshold.classList.contains("show");
+  threshold.classList.toggle("show", !isExpanded);
+  tagItem.classList.toggle("expanded", !isExpanded);
+
+  if (!isExpanded) {
+    checkbox.checked = true;
+  }
+}
+
+document.addEventListener("DOMContentLoaded", function () {
+  const checkboxes = document.querySelectorAll(
+    '.tag-item input[type="checkbox"]'
+  );
+  checkboxes.forEach((checkbox) => {
+    checkbox.addEventListener("click", function (e) {
+      e.stopPropagation();
+
+      const tagName = this.value;
+      const threshold = document.getElementById(`threshold-${tagName}`);
+
+      if (!this.checked && threshold) {
+        threshold.classList.remove("show");
+        threshold.previousElementSibling.classList.remove("expanded");
+      }
+    });
+  });
+});
+
+function openPreferencesModal() {
+  const modal = new bootstrap.Modal(
+    document.getElementById("preferencesModal")
+  );
+
+  loadUserPreferencesForModal();
+
+  modal.show();
+}
+
+async function loadUserPreferencesForModal() {
+  try {
+    const response = await fetch("/Restaurants/GetUserPreferences");
+    if (response.ok) {
+      const data = await response.json();
+
+      document
+        .querySelectorAll('.tag-selection input[type="checkbox"]')
+        .forEach((cb) => {
+          cb.checked = false;
+        });
+      document.querySelectorAll(".tag-threshold").forEach((threshold) => {
+        threshold.classList.remove("show");
+      });
+      document.querySelectorAll(".tag-item").forEach((item) => {
+        item.classList.remove("expanded");
+      });
+
+      data.preferences.forEach((pref) => {
+        const checkbox = document.getElementById(`tag-${pref.tag}`);
+        if (checkbox) {
+          checkbox.checked = true;
+
+          if (
+            pref.thresholdValue !== null &&
+            pref.thresholdValue !== undefined
+          ) {
+            const valueInput = document.getElementById(`value-${pref.tag}`);
+            const threshold = document.getElementById(`threshold-${pref.tag}`);
+
+            if (valueInput && threshold) {
+              valueInput.value = pref.thresholdValue;
+              threshold.classList.add("show");
+              threshold.previousElementSibling.classList.add("expanded");
+            }
+          }
+        }
+      });
+    }
+  } catch (error) {
+    console.error("Error loading preferences:", error);
+  }
+}
+
+async function savePreferences() {
+  const preferences = [];
+
+  document
+    .querySelectorAll('.tag-selection input[type="checkbox"]:checked')
+    .forEach((cb) => {
+      const tagValue = cb.value;
+      const valueInput = document.getElementById(`value-${tagValue}`);
+
+      const preference = {
+        tag: tagValue,
+        thresholdValue: valueInput ? parseInt(valueInput.value) : null,
+      };
+
+      preferences.push(preference);
+    });
+
+  const token = document.querySelector(
+    'input[name="__RequestVerificationToken"]'
+  ).value;
+
+  try {
+    const response = await fetch("/Restaurants/UpdateTagPreferences", {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+        RequestVerificationToken: token,
+      },
+      body: JSON.stringify(preferences),
+    });
+
+    const data = await response.json();
+    if (data.success) {
+      showSuccess(
+        "Preferences saved! You will receive notifications for matching meals."
+      );
+      bootstrap.Modal.getInstance(
+        document.getElementById("preferencesModal")
+      ).hide();
+    } else {
+      showError("Failed to save preferences");
+    }
+  } catch (error) {
+    console.error("Error saving preferences:", error);
+    showError("Error saving preferences");
+  }
+}
+
+function checkForRestaurantIdParameter() {
+  const urlParams = new URLSearchParams(window.location.search);
+  const restaurantId = urlParams.get("restaurantId");
+
+  if (restaurantId) {
+    const newUrl = window.location.pathname;
+    window.history.replaceState({}, document.title, newUrl);
+
+    setTimeout(() => {
+      openMenu(parseInt(restaurantId));
+    }, 300);
+  }
+}
