Context
Recipe makeability is computed in backend/src/services/mealie_query_service.py by matching Mealie ingredient names against Pantrie inventory item names: case-insensitive exact match, then an ILIKE '%name%' substring fallback.
Problem
Real-world naming differences cause false "missing" results:
"Corn Starch" in inventory vs "cornstarch" in a recipe → exact fails (space), and ILIKE '%cornstarch%' also fails because "cornstarch" is not a substring of "corn starch".
- Pantry staples a household always has (notably water) are reported as missing and clutter the shopping list.
Proposed behavior
- Fuzzy matching between recipe ingredients and inventory items. Normalize before comparing — lowercase, collapse/remove whitespace and punctuation, singularize simple plurals — and apply a similarity threshold (token-set or Levenshtein/
difflib.SequenceMatcher) so Corn Starch ≈ cornstarch, Tomatoes ≈ tomato, etc. Keep exact match as the highest-confidence tier.
- Per-household assumed staples: a household-configurable allowlist of always-on-hand ingredients, treated as in-stock without an inventory row.
water is seeded automatically for every household; users can add/remove entries.
Implementation notes
- Centralize normalization + matching in one helper so both makeability and the (future) availability endpoints share it.
- Guard the fuzzy threshold to avoid over-matching (e.g.
"oil" matching "olive oil" may be desirable, but "corn" matching "cornstarch" may not — tune with real recipes).
- Staples storage: per-household, so a new model + migration (e.g.
household_staples, or a JSON column on the household/settings) keyed by household. Seed each household with water on creation; backfill existing households in the migration.
- API: CRUD for a household's staples (list/add/remove), admin-or-member gated consistent with other household-scoped resources.
- Frontend: a small manager under Settings → Household (alongside the existing allergen/location managers) to view/add/remove staples, with
water present by default.
- Staples are applied during makeability so a matching ingredient is counted in-stock and excluded from the missing list / shopping-list push.
Acceptance criteria
Decisions
- Staples are per-household configurable, with
water auto-included at the start. ✅ confirmed.
Enhances the (closed) Mealie integration epic #1. Tracked under epic #35. The normalized-matching helper here is reused by #34.
Context
Recipe makeability is computed in
backend/src/services/mealie_query_service.pyby matching Mealie ingredient names against Pantrie inventory item names: case-insensitive exact match, then anILIKE '%name%'substring fallback.Problem
Real-world naming differences cause false "missing" results:
"Corn Starch"in inventory vs"cornstarch"in a recipe → exact fails (space), andILIKE '%cornstarch%'also fails because"cornstarch"is not a substring of"corn starch".Proposed behavior
difflib.SequenceMatcher) soCorn Starch≈cornstarch,Tomatoes≈tomato, etc. Keep exact match as the highest-confidence tier.wateris seeded automatically for every household; users can add/remove entries.Implementation notes
"oil"matching"olive oil"may be desirable, but"corn"matching"cornstarch"may not — tune with real recipes).household_staples, or a JSON column on the household/settings) keyed by household. Seed each household withwateron creation; backfill existing households in the migration.waterpresent by default.Acceptance criteria
Corn Starch(inventory) counts as present for acornstarchingredient.waterin its staples; existing households are backfilled.Decisions
waterauto-included at the start. ✅ confirmed.Enhances the (closed) Mealie integration epic #1. Tracked under epic #35. The normalized-matching helper here is reused by #34.