Some checks failed
Security Scanning / Dependency License Check (pull_request) Has been cancelled
CI Pipeline / Lint Code (pull_request) Has been cancelled
CI Pipeline / Test API Package (pull_request) Has been cancelled
CI Pipeline / Test Web Package (pull_request) Has been cancelled
CI Pipeline / Test Shared Package (pull_request) Has been cancelled
Docker Build & Deploy / Build Docker Images (pull_request) Has been cancelled
E2E Tests / End-to-End Tests (pull_request) Has been cancelled
E2E Tests / E2E Tests (Mobile) (pull_request) Has been cancelled
Security Scanning / NPM Audit (pull_request) Has been cancelled
Security Scanning / Code Quality Scan (pull_request) Has been cancelled
Security Scanning / Docker Image Security (pull_request) Has been cancelled
CI Pipeline / Build All Packages (pull_request) Has been cancelled
CI Pipeline / Generate Coverage Report (pull_request) Has been cancelled
Docker Build & Deploy / Push Docker Images (pull_request) Has been cancelled
Docker Build & Deploy / Deploy to Staging (pull_request) Has been cancelled
Docker Build & Deploy / Deploy to Production (pull_request) Has been cancelled
Security Scanning / Security Summary (pull_request) Has been cancelled
Implement comprehensive solution for managing ingredient-to-instruction mappings in cooking mode. This moves from client-side state management to persistent database storage, significantly improving reliability and user experience. ## Key Changes ### Database & Backend - Add IngredientInstructionMapping table with many-to-many relationship - Implement automatic ingredient matching algorithm with smart name extraction - Add API endpoints for mapping management (update, regenerate) - Create migration script for existing recipes ### Frontend - Simplify CookingMode to read-only display of stored mappings - Add ManageIngredientMappings page with drag-and-drop editing - Remove complex client-side state management (~200 lines) - Add navigation between cooking mode and management interface ### Testing - Add 11 comprehensive unit tests for ingredient matcher service - Update integration tests with proper mocking - All new features fully tested (24/25 API tests passing) ## Benefits - Persistent mappings across all clients/devices - Automatic generation on recipe import/creation - User control via dedicated management interface - Cleaner, more maintainable codebase 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
130 lines
3.6 KiB
Plaintext
130 lines
3.6 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model Recipe {
|
|
id String @id @default(cuid())
|
|
title String
|
|
description String?
|
|
prepTime Int? // minutes
|
|
cookTime Int? // minutes
|
|
totalTime Int? // minutes
|
|
servings Int?
|
|
imageUrl String?
|
|
sourceUrl String? // For imported recipes
|
|
author String?
|
|
cuisine String?
|
|
category String?
|
|
rating Float?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
sections RecipeSection[]
|
|
ingredients Ingredient[]
|
|
instructions Instruction[]
|
|
images RecipeImage[]
|
|
tags RecipeTag[]
|
|
|
|
@@index([title])
|
|
@@index([cuisine])
|
|
@@index([category])
|
|
}
|
|
|
|
model RecipeSection {
|
|
id String @id @default(cuid())
|
|
recipeId String
|
|
name String // e.g., "Starter", "Dough", "Assembly"
|
|
order Int
|
|
timing String? // e.g., "Day 1 - 8PM", "12 hours before mixing"
|
|
|
|
recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade)
|
|
ingredients Ingredient[]
|
|
instructions Instruction[]
|
|
|
|
@@index([recipeId])
|
|
}
|
|
|
|
model Ingredient {
|
|
id String @id @default(cuid())
|
|
recipeId String? // Optional - can be derived from section
|
|
sectionId String? // Optional - if null, belongs to recipe directly
|
|
name String
|
|
amount String?
|
|
unit String?
|
|
notes String?
|
|
order Int
|
|
|
|
recipe Recipe? @relation(fields: [recipeId], references: [id], onDelete: Cascade)
|
|
section RecipeSection? @relation(fields: [sectionId], references: [id], onDelete: Cascade)
|
|
instructions IngredientInstructionMapping[]
|
|
|
|
@@index([recipeId])
|
|
@@index([sectionId])
|
|
}
|
|
|
|
model Instruction {
|
|
id String @id @default(cuid())
|
|
recipeId String? // Optional - can be derived from section
|
|
sectionId String? // Optional - if null, belongs to recipe directly
|
|
step Int
|
|
text String @db.Text
|
|
imageUrl String?
|
|
timing String? // e.g., "8:00am", "After 30 minutes", "Day 2 - Morning"
|
|
|
|
recipe Recipe? @relation(fields: [recipeId], references: [id], onDelete: Cascade)
|
|
section RecipeSection? @relation(fields: [sectionId], references: [id], onDelete: Cascade)
|
|
ingredients IngredientInstructionMapping[]
|
|
|
|
@@index([recipeId])
|
|
@@index([sectionId])
|
|
}
|
|
|
|
model IngredientInstructionMapping {
|
|
id String @id @default(cuid())
|
|
ingredientId String
|
|
instructionId String
|
|
order Int // Display order within the instruction
|
|
|
|
ingredient Ingredient @relation(fields: [ingredientId], references: [id], onDelete: Cascade)
|
|
instruction Instruction @relation(fields: [instructionId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([ingredientId, instructionId])
|
|
@@index([instructionId])
|
|
@@index([ingredientId])
|
|
}
|
|
|
|
model RecipeImage {
|
|
id String @id @default(cuid())
|
|
recipeId String
|
|
url String
|
|
order Int
|
|
|
|
recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([recipeId])
|
|
}
|
|
|
|
model Tag {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
recipes RecipeTag[]
|
|
}
|
|
|
|
model RecipeTag {
|
|
recipeId String
|
|
tagId String
|
|
|
|
recipe Recipe @relation(fields: [recipeId], references: [id], onDelete: Cascade)
|
|
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([recipeId, tagId])
|
|
@@index([recipeId])
|
|
@@index([tagId])
|
|
}
|