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>
6.5 KiB
Pull Request: Database-Backed Ingredient-Instruction Mapping
Summary
This PR implements a comprehensive solution for managing ingredient-to-instruction mappings in cooking mode. The feature moves from client-side state management to a persistent database-backed approach, significantly improving reliability and user experience.
Changes
Database Schema
- New Table:
IngredientInstructionMapping- Many-to-many relationship between ingredients and instructions
- Includes
orderfield for display ordering within instructions - Cascade delete for data integrity
- Migration:
20251031050746_add_ingredient_instruction_mapping
Backend (API)
New Service
packages/api/src/services/ingredientMatcher.service.ts- Automatic ingredient matching algorithm
- Extracts core ingredient names (removes quantities/units)
- Generates name variations (plural/singular)
- Finds ingredient positions in instruction text
- Prevents duplicate mappings (same ingredient appearing multiple times)
- Cross-step tracking (ingredients only appear once across all steps)
API Endpoints
- Updated GET
/api/recipes/:id: Now includes ingredient-instruction mappings in response - Updated POST
/api/recipes: Automatically generates mappings on recipe creation - Updated PUT
/api/recipes/:id: Regenerates mappings on recipe update - New POST
/api/recipes/:id/ingredient-mappings: Manually update mappings - New POST
/api/recipes/:id/regenerate-mappings: Re-run automatic matching
Frontend (Web)
Simplified Cooking Mode
packages/web/src/pages/CookingMode.tsx- Significantly simplified- Removed all client-side matching logic (~200 lines removed)
- Removed localStorage state management
- Removed drag-and-drop functionality
- Now purely read-only, displays database-stored mappings
- Added "⚙️ Manage Ingredients" button for editing
New Management Interface
-
packages/web/src/pages/ManageIngredientMappings.tsx- New dedicated page- Similar layout to cooking mode for familiarity
- Drag-and-drop ingredients to instruction steps
- Remove ingredients with ✕ button
- Real-time preview of changes
- Save to database with "💾 Save Changes" button
- Auto-regenerate with "🔄 Regenerate Auto Mappings" button
- Navigate to cooking mode with "👨🍳 Preview in Cooking Mode" button
- Unsaved changes warning banner
-
packages/web/src/styles/ManageIngredientMappings.css- Dedicated styling
Updated Components
packages/web/src/App.tsx: Added route for/recipes/:id/manage-mappingspackages/web/src/services/api.ts: Added API methods for mapping managementpackages/web/src/styles/CookingMode.css: Removed unused drag-and-drop styles
Shared Types
packages/shared/src/types.ts- Added
IngredientInstructionMappinginterface - Updated
IngredientandInstructionto include optional mapping arrays
- Added
Scripts
packages/api/src/scripts/regenerate-mappings.ts- Utility script to regenerate mappings for all existing recipes
Testing
Test Results
- ✅ API Tests: 24/25 passing (96%)
- ✅ New Ingredient Matcher Service: 11/11 tests passing
- ✅ Recipe Routes: 9/9 tests passing (includes mapping integration)
- ✅ Storage Service: 4/5 passing (1 pre-existing S3 test failure)
- ✅ Shared Tests: 16/16 passing (100%)
- ⚠️ Web Tests: 7/15 passing (8 pre-existing failures in axios mocking setup)
New Test Coverage
Created comprehensive unit tests for ingredientMatcher.service.ts:
- ✅ Simple ingredient matching
- ✅ Ingredients with quantities in names
- ✅ Plural/singular form matching
- ✅ No duplication across steps
- ✅ No duplication of same core ingredient
- ✅ Recipes with sections
- ✅ Ingredient ordering by text position
- ✅ Error handling for missing recipes
- ✅ Save mappings functionality
- ✅ Auto-map integration
Manual Testing Performed
- ✅ Created new test recipe with automatic mapping generation
- ✅ Regenerated mappings for 5 existing recipes (Soft Sourdough, Apple Dutch Baby, Ice Cream, etc.)
- ✅ Verified mappings persist across page refreshes
- ✅ Tested drag-and-drop in management interface
- ✅ Tested remove functionality
- ✅ Tested save persistence to database
- ✅ Verified cooking mode displays stored mappings correctly
Migration Guide
For Existing Recipes
Run the regeneration script to generate mappings for all existing recipes:
cd packages/api
npx tsx src/scripts/regenerate-mappings.ts
This was already executed and successfully generated mappings for all 5 existing recipes.
Database Migration
The migration runs automatically when deploying the API container. No manual intervention needed.
Benefits
- Reliability: Mappings are persisted in database, not client-side localStorage
- Consistency: Same mappings across all clients/devices
- Simplicity: Cooking mode is now read-only with no complex state management
- User Control: Dedicated management interface for editing mappings
- Automatic: Mappings are generated automatically on recipe import/creation
- Flexible: Users can manually adjust mappings if automatic matching is incorrect
Breaking Changes
None. This is a new feature with backward compatibility. Existing recipes work without mappings, and the system automatically generates them.
Future Enhancements
- Add UI to manage mappings during recipe import (for recipes with ambiguous matches)
- Add reordering of ingredients within instructions (drag-and-drop reorder)
- Add bulk mapping tools (e.g., "map all ingredients to step 1")
- Add mapping analytics/suggestions based on common patterns
Screenshots
Cooking Mode (Read-Only)
- Clean, distraction-free interface
- Ingredients listed inline with each step
- No edit controls visible
Manage Ingredient Mappings
- Drag ingredients from top section to instruction steps
- Remove with ✕ button
- Save changes button persists to database
- Regenerate button re-runs automatic matching
Related Issues
Fixes issues with ingredient mapping:
- Ingredients duplicating when dragging
- Remove button not working
- Changes not persisting across clients
- Complex client-side state management
Review Checklist
- Database migration created and tested
- API tests updated and passing
- Frontend tests updated (some pre-existing failures remain)
- Manual testing completed
- Documentation updated
- No breaking changes
- Backward compatible