generator client { provider = "prisma-client-js" binaryTargets = ["native", "debian-openssl-1.0.x"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") } enum AuthProvider { EMAIL GOOGLE APPLE } enum RecipeOrigin { MANUAL URL_IMPORT INGREDIENTS_AI IMAGE_AI VOICE_AI } enum RecipeDifficulty { EASY MEDIUM DIFFICULT } enum UserPlan { FREE PREMIUM } enum ShoppingListStatus { ACTIVE ARCHIVED } model User { id String @id @default(uuid()) email String @unique emailVerifiedAt DateTime? username String? @unique passwordHash String? displayName String? avatarUrl String? preferredLanguage String @default("en") plan UserPlan @default(FREE) freeAiActionsUsedDate DateTime? freeAiActionsUsedToday Int @default(0) lastOccasionalAdAt DateTime? deletedAt DateTime? anonymizedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt authAccounts AuthAccount[] refreshTokens RefreshToken[] emailVerificationTokens EmailVerificationToken[] passwordResetTokens PasswordResetToken[] preferences UserPreference? recipes Recipe[] savedRecipes FavoriteRecipe[] favoriteRecipes RecipeFavorite[] shoppingLists ShoppingList[] shoppingGroups ShoppingGroup[] shoppingGroupPreferences ShoppingGroupPreference[] following UserFollow[] @relation("UserFollowing") followers UserFollow[] @relation("UserFollowers") recipeComments RecipeComment[] } model EmailVerificationToken { id String @id @default(uuid()) userId String tokenHash String @unique expiresAt DateTime createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([expiresAt]) } model PasswordResetToken { id String @id @default(uuid()) userId String tokenHash String @unique expiresAt DateTime createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([expiresAt]) } model UserFollow { followerId String followedId String createdAt DateTime @default(now()) follower User @relation("UserFollowing", fields: [followerId], references: [id], onDelete: Cascade) followed User @relation("UserFollowers", fields: [followedId], references: [id], onDelete: Cascade) @@id([followerId, followedId]) @@index([followedId]) } model AuthAccount { id String @id @default(uuid()) userId String provider AuthProvider providerAccountId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([provider, providerAccountId]) @@index([userId]) } model RefreshToken { id String @id @default(uuid()) userId String tokenHash String @unique expiresAt DateTime revokedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([expiresAt]) } model UserPreference { userId String @id dietaryPreferences String[] dietaryRestrictions String[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) } model Recipe { id String @id @default(uuid()) userId String cuisineId String? mealTypeId String? difficulty RecipeDifficulty? title String description String? notes String? servings Int @default(1) prepTimeMinutes Int? cookTimeMinutes Int? totalTimeMinutes Int? ingredients String[] steps String[] imageUrl String? origin RecipeOrigin sourceUrl String? sourceLanguage String? adaptedFromRecipeId String? shareSlug String? @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Restrict) adaptedFrom Recipe? @relation("RecipeAdaptations", fields: [adaptedFromRecipeId], references: [id], onDelete: SetNull) adaptations Recipe[] @relation("RecipeAdaptations") cuisine Cuisine? @relation(fields: [cuisineId], references: [id], onDelete: SetNull) mealType MealType? @relation(fields: [mealTypeId], references: [id], onDelete: SetNull) translations RecipeTranslation[] savedBy FavoriteRecipe[] favoritedBy RecipeFavorite[] shoppingListLinks ShoppingListRecipe[] recipeIngredients RecipeIngredient[] dietaryLabels RecipeDietaryLabel[] tags RecipeTagAssignment[] techniques RecipeTechnique[] tools RecipeTool[] comments RecipeComment[] @@index([userId]) @@index([origin]) @@index([adaptedFromRecipeId]) @@index([cuisineId]) @@index([mealTypeId]) } model RecipeComment { id String @id @default(uuid()) recipeId String userId String content String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([recipeId, createdAt]) @@index([userId]) } model RecipeTranslation { id String @id @default(uuid()) recipeId String languageCode String title String description String? servings Int? prepTimeMinutes Int? cookTimeMinutes Int? totalTimeMinutes Int? ingredients String[] steps String[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) @@unique([recipeId, languageCode]) @@index([languageCode]) } model Ingredient { id String @id @default(uuid()) slug String @unique displayName String normalizedName String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipes RecipeIngredient[] @@index([normalizedName]) } model RecipeIngredient { id String @id @default(uuid()) recipeId String ingredientId String? originalText String amount Decimal? @db.Decimal(10, 2) unit String? preparation String? scalable Boolean @default(true) quantityText String? position Int? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) ingredient Ingredient? @relation(fields: [ingredientId], references: [id], onDelete: SetNull) @@index([recipeId]) @@index([ingredientId]) } model Cuisine { id String @id @default(uuid()) slug String @unique name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipes Recipe[] } model MealType { id String @id @default(uuid()) slug String @unique name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipes Recipe[] } model DietaryLabel { id String @id @default(uuid()) slug String @unique name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipes RecipeDietaryLabel[] } model RecipeDietaryLabel { recipeId String dietaryLabelId String createdAt DateTime @default(now()) recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) dietaryLabel DietaryLabel @relation(fields: [dietaryLabelId], references: [id], onDelete: Cascade) @@id([recipeId, dietaryLabelId]) @@index([dietaryLabelId]) } model Tag { id String @id @default(uuid()) slug String @unique name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipes RecipeTagAssignment[] } model RecipeTagAssignment { recipeId String tagId String createdAt DateTime @default(now()) recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade) @@id([recipeId, tagId]) @@index([tagId]) } model Technique { id String @id @default(uuid()) slug String @unique name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipes RecipeTechnique[] } model RecipeTechnique { recipeId String techniqueId String createdAt DateTime @default(now()) recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) technique Technique @relation(fields: [techniqueId], references: [id], onDelete: Cascade) @@id([recipeId, techniqueId]) @@index([techniqueId]) } model Tool { id String @id @default(uuid()) slug String @unique name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt recipes RecipeTool[] } model RecipeTool { recipeId String toolId String createdAt DateTime @default(now()) recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) tool Tool @relation(fields: [toolId], references: [id], onDelete: Cascade) @@id([recipeId, toolId]) @@index([toolId]) } model FavoriteRecipe { userId String recipeId String createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) @@id([userId, recipeId]) @@index([recipeId]) } model RecipeFavorite { userId String recipeId String createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) @@id([userId, recipeId]) @@index([recipeId]) } model ShoppingList { id String @id @default(uuid()) userId String name String status ShoppingListStatus @default(ACTIVE) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) items ShoppingListItem[] recipes ShoppingListRecipe[] @@index([userId]) @@index([status]) } model ShoppingListItem { id String @id @default(uuid()) shoppingListId String groupId String? label String normalizedName String? quantityText String? isPurchased Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt shoppingList ShoppingList @relation(fields: [shoppingListId], references: [id], onDelete: Cascade) group ShoppingGroup? @relation(fields: [groupId], references: [id], onDelete: SetNull) @@index([shoppingListId]) @@index([isPurchased]) @@index([groupId]) } model ShoppingListRecipe { shoppingListId String recipeId String createdAt DateTime @default(now()) shoppingList ShoppingList @relation(fields: [shoppingListId], references: [id], onDelete: Cascade) recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade) @@id([shoppingListId, recipeId]) @@index([recipeId]) } model ShoppingGroup { id String @id @default(uuid()) userId String name String position Int createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) items ShoppingListItem[] preferences ShoppingGroupPreference[] @@unique([userId, name]) @@unique([userId, position]) @@index([userId]) } model ShoppingGroupPreference { id String @id @default(uuid()) userId String groupId String normalizedName String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) group ShoppingGroup @relation(fields: [groupId], references: [id], onDelete: Cascade) @@unique([userId, normalizedName]) @@index([userId]) @@index([groupId]) }