Skip to content

Warn before deleting entities referenced elsewhere #7

@guplem

Description

@guplem

Context

Deleting an entity that is referenced elsewhere is unguarded across the app. The most severe case: deleting an ingredient used in a recipe crashes at runtime (IngredientsProvider.get() null assertion in ingredients_provider.dart:43). Recipe deletion leaves stale Cooking entries in menus (displays "?" but no crash). Instruction deletion orphans input IDs in sibling instructions.

All three remove methods carry a // TODO: Ask for confirmation comment (ingredients_provider.dart:57, recipes_provider.dart:66, recipes_provider.dart:88).

Entity deleted Referenced by Current behavior
Ingredient IngredientUsage in recipes Runtime crash (null assertion)
Recipe Cooking.recipeId in menu meals Graceful degradation (shows "?")
Instruction inputs list in sibling instructions Orphaned IDs (no crash, no cleanup)

Proposed Solution

Add a pre-delete check and confirmation dialog pattern:

  1. Model-level reference checks (parameterized, per ADRs 0001/0002): pure methods that answer "who references this entity?" without accessing providers. Ingredient.findReferencingRecipes(ingredientId:, recipes:), Recipe.findReferencingMeals(recipeId:, multiWeekMenu:), Recipe.findDependentInstructions(instructionId:, recipe:).

  2. Reusable confirmation dialog (DeleteConfirmationDialog in flutter_essentials/): follows the existing showDialog<bool> + TextButton/FilledButton pattern from play_recipe_page.dart. Shows what references the entity and what will be affected. Skipped entirely when nothing references the entity (existing undo-snackbar UX preserved).

  3. Cascade cleanup on confirmed delete: actively remove dangling references (ingredient usages from recipes, cooking entries from menus, orphaned input IDs from instructions) rather than leaving stale data.

  4. Undo snackbar enhancement: capture and restore both the deleted entity and any cascade-cleaned references.

Key files to modify:

  • lib/ingredients/models/ingredient.dart -- add findReferencingRecipes()
  • lib/recipes/models/recipe.dart -- add findReferencingMeals(), findDependentInstructions()
  • lib/flutter_essentials/widgets/delete_confirmation_dialog.dart -- new reusable dialog
  • lib/ingredients/widgets/ingredients_page.dart -- pre-delete check at call site
  • lib/recipes/widgets/recipes_page.dart -- pre-delete check at call site
  • lib/recipes/widgets/recipe_page.dart -- pre-delete check for instruction deletion

Relevant ADRs: 0001 (model logic), 0002 (provider access restricted to UI), 0005 (instruction I/O chain), 0008 (multi-week menus), 0009 (recipe ID references).

Acceptance Criteria

  • Deleting an ingredient used in recipes shows a dialog listing the affected recipes before proceeding
  • Deleting a recipe assigned in any menu week shows a dialog listing the affected meal slots
  • Deleting an instruction whose outputs are used as inputs by other instructions shows a dialog listing the dependent instructions
  • On confirmed delete, dangling references are cleaned up (no stale IDs left behind)
  • Undo via snackbar restores both the entity and its cleaned references
  • Deleting an entity with no references proceeds immediately with the existing undo-snackbar UX (no dialog)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P: MediumDegraded functionality, workaround existsenhancementNew feature or requestingredientsIngredient managementmenuMenu generation and configurationrecipesRecipe managementwaiting-for-human-checkNo human has verified this yet -- direct AI output

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions