diff --git a/src/lib/assets/icons/Heart.svelte b/src/lib/assets/icons/Heart.svelte
new file mode 100644
index 0000000..dfd4c1c
--- /dev/null
+++ b/src/lib/assets/icons/Heart.svelte
@@ -0,0 +1,33 @@
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/FavoriteButton.svelte b/src/lib/components/FavoriteButton.svelte
new file mode 100644
index 0000000..9ed997d
--- /dev/null
+++ b/src/lib/components/FavoriteButton.svelte
@@ -0,0 +1,102 @@
+
+
+
+
+{#if isLoggedIn}
+
+{/if}
\ No newline at end of file
diff --git a/src/models/UserFavorites.ts b/src/models/UserFavorites.ts
new file mode 100644
index 0000000..88bd612
--- /dev/null
+++ b/src/models/UserFavorites.ts
@@ -0,0 +1,11 @@
+import mongoose from 'mongoose';
+
+const UserFavoritesSchema = new mongoose.Schema(
+ {
+ username: { type: String, required: true, unique: true },
+ favorites: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' }] // Recipe MongoDB ObjectIds
+ },
+ { timestamps: true }
+);
+
+export const UserFavorites = mongoose.model("UserFavorites", UserFavoritesSchema);
\ No newline at end of file
diff --git a/src/routes/api/rezepte/favorites/+server.ts b/src/routes/api/rezepte/favorites/+server.ts
new file mode 100644
index 0000000..5d62cd2
--- /dev/null
+++ b/src/routes/api/rezepte/favorites/+server.ts
@@ -0,0 +1,112 @@
+import { json, type RequestHandler } from '@sveltejs/kit';
+import { UserFavorites } from '../../../../models/UserFavorites';
+import { Recipe } from '../../../../models/Recipe';
+import { dbConnect, dbDisconnect } from '../../../../utils/db';
+import { error } from '@sveltejs/kit';
+import mongoose from 'mongoose';
+
+export const GET: RequestHandler = async ({ locals }) => {
+ const session = await locals.auth();
+
+ if (!session?.user?.nickname) {
+ throw error(401, 'Authentication required');
+ }
+
+ await dbConnect();
+
+ try {
+ const userFavorites = await UserFavorites.findOne({
+ username: session.user.nickname
+ }).lean();
+
+ await dbDisconnect();
+
+ return json({
+ favorites: userFavorites?.favorites || []
+ });
+ } catch (e) {
+ await dbDisconnect();
+ throw error(500, 'Failed to fetch favorites');
+ }
+};
+
+export const POST: RequestHandler = async ({ request, locals }) => {
+ const session = await locals.auth();
+
+ if (!session?.user?.nickname) {
+ throw error(401, 'Authentication required');
+ }
+
+ const { recipeId } = await request.json();
+
+ if (!recipeId) {
+ throw error(400, 'Recipe ID required');
+ }
+
+ await dbConnect();
+
+ try {
+ // Validate that the recipe exists and get its ObjectId
+ const recipe = await Recipe.findOne({ short_name: recipeId });
+ if (!recipe) {
+ await dbDisconnect();
+ throw error(404, 'Recipe not found');
+ }
+
+ await UserFavorites.findOneAndUpdate(
+ { username: session.user.nickname },
+ { $addToSet: { favorites: recipe._id } },
+ { upsert: true, new: true }
+ );
+
+ await dbDisconnect();
+
+ return json({ success: true });
+ } catch (e) {
+ await dbDisconnect();
+ if (e instanceof Error && e.message.includes('404')) {
+ throw e;
+ }
+ throw error(500, 'Failed to add favorite');
+ }
+};
+
+export const DELETE: RequestHandler = async ({ request, locals }) => {
+ const session = await locals.auth();
+
+ if (!session?.user?.nickname) {
+ throw error(401, 'Authentication required');
+ }
+
+ const { recipeId } = await request.json();
+
+ if (!recipeId) {
+ throw error(400, 'Recipe ID required');
+ }
+
+ await dbConnect();
+
+ try {
+ // Find the recipe's ObjectId
+ const recipe = await Recipe.findOne({ short_name: recipeId });
+ if (!recipe) {
+ await dbDisconnect();
+ throw error(404, 'Recipe not found');
+ }
+
+ await UserFavorites.findOneAndUpdate(
+ { username: session.user.nickname },
+ { $pull: { favorites: recipe._id } }
+ );
+
+ await dbDisconnect();
+
+ return json({ success: true });
+ } catch (e) {
+ await dbDisconnect();
+ if (e instanceof Error && e.message.includes('404')) {
+ throw e;
+ }
+ throw error(500, 'Failed to remove favorite');
+ }
+};
\ No newline at end of file
diff --git a/src/routes/api/rezepte/favorites/check/[shortName]/+server.ts b/src/routes/api/rezepte/favorites/check/[shortName]/+server.ts
new file mode 100644
index 0000000..06afc8d
--- /dev/null
+++ b/src/routes/api/rezepte/favorites/check/[shortName]/+server.ts
@@ -0,0 +1,42 @@
+import { json, type RequestHandler } from '@sveltejs/kit';
+import { UserFavorites } from '../../../../../../models/UserFavorites';
+import { Recipe } from '../../../../../../models/Recipe';
+import { dbConnect, dbDisconnect } from '../../../../../../utils/db';
+import { error } from '@sveltejs/kit';
+
+export const GET: RequestHandler = async ({ locals, params }) => {
+ const session = await locals.auth();
+
+ if (!session?.user?.nickname) {
+ return json({ isFavorite: false });
+ }
+
+ await dbConnect();
+
+ try {
+ // Find the recipe by short_name to get its ObjectId
+ const recipe = await Recipe.findOne({ short_name: params.shortName });
+ if (!recipe) {
+ await dbDisconnect();
+ throw error(404, 'Recipe not found');
+ }
+
+ // Check if this recipe is in the user's favorites
+ const userFavorites = await UserFavorites.findOne({
+ username: session.user.nickname,
+ favorites: recipe._id
+ }).lean();
+
+ await dbDisconnect();
+
+ return json({
+ isFavorite: !!userFavorites
+ });
+ } catch (e) {
+ await dbDisconnect();
+ if (e instanceof Error && e.message.includes('404')) {
+ throw e;
+ }
+ throw error(500, 'Failed to check favorite status');
+ }
+};
\ No newline at end of file
diff --git a/src/routes/api/rezepte/favorites/recipes/+server.ts b/src/routes/api/rezepte/favorites/recipes/+server.ts
new file mode 100644
index 0000000..8e5f0c7
--- /dev/null
+++ b/src/routes/api/rezepte/favorites/recipes/+server.ts
@@ -0,0 +1,40 @@
+import { json, type RequestHandler } from '@sveltejs/kit';
+import { UserFavorites } from '../../../../../models/UserFavorites';
+import { Recipe } from '../../../../../models/Recipe';
+import { dbConnect, dbDisconnect } from '../../../../../utils/db';
+import type { RecipeModelType } from '../../../../../types/types';
+import { error } from '@sveltejs/kit';
+
+export const GET: RequestHandler = async ({ locals }) => {
+ const session = await locals.auth();
+
+ if (!session?.user?.nickname) {
+ throw error(401, 'Authentication required');
+ }
+
+ await dbConnect();
+
+ try {
+ const userFavorites = await UserFavorites.findOne({
+ username: session.user.nickname
+ }).lean();
+
+ if (!userFavorites?.favorites?.length) {
+ await dbDisconnect();
+ return json([]);
+ }
+
+ let recipes = await Recipe.find({
+ _id: { $in: userFavorites.favorites }
+ }).lean() as RecipeModelType[];
+
+ await dbDisconnect();
+
+ recipes = JSON.parse(JSON.stringify(recipes));
+
+ return json(recipes);
+ } catch (e) {
+ await dbDisconnect();
+ throw error(500, 'Failed to fetch favorite recipes');
+ }
+};
\ No newline at end of file
diff --git a/src/routes/rezepte/+layout.svelte b/src/routes/rezepte/+layout.svelte
index 4c154bc..482c8bf 100644
--- a/src/routes/rezepte/+layout.svelte
+++ b/src/routes/rezepte/+layout.svelte
@@ -11,6 +11,9 @@ if(data.session){