Recipe browser: domain/category navigation with pantry match badges (Free tier) #25

Closed
opened 2026-04-07 21:53:21 -07:00 by pyr0ball · 0 comments
Owner

Summary

Browse the full recipe corpus by pre-baked domain schemas (cuisine, meal type, dietary, main ingredient), with pantry match percentage shown inline. Free tier.

Domain Schemas

New file: app/services/recipe/browser_domains.py

Four domains, each mapping keyword sets to a two-level category hierarchy:

  • Cuisine — Italian, Mexican, Asian, American, Mediterranean, Indian, …
  • Meal Type — Breakfast, Lunch, Dinner, Snack, Dessert, Beverage
  • Dietary — Vegetarian, Vegan, Gluten-Free, Low-Carb, High-Protein
  • Main Ingredient — Chicken, Beef, Pork, Fish, Pasta, Vegetable, Egg, Legumes

Matching is case-insensitive against the category column and keywords JSON array already in the recipes table. A recipe may appear in multiple categories (correct).

Before writing this module: run SELECT category, count(*) FROM recipes GROUP BY category ORDER BY count(*) DESC against the food.com corpus to calibrate keyword mappings.

Store Methods

  • get_browser_categories(domain: str) -> list[dict][{category, recipe_count}]
  • browse_recipes(domain, category, page, page_size, pantry_items) -> dict{recipes, total, page}, each recipe includes match_pct: float | None

match_pct is set intersection of pantry_items vs ingredient_names — deterministic, no LLM (large language model) needed.

API Endpoints

Extend app/api/endpoints/recipes.py:

  • GET /recipes/browse/domains — list domain schemas
  • GET /recipes/browse/{domain} — categories with recipe counts
  • GET /recipes/browse/{domain}/{category}?page=1&page_size=20&pantry_items=item1,item2

Pantry Match Badges

Frontend pulls pantry items from the inventory store automatically (no extra user action). Badge thresholds:

  • 80–100%: green "Great match"
  • 50–79%: yellow "Good match"
  • < 50%: no badge (or faint "Partial")

Nesting Depth Telemetry

Migration 020: browser_telemetry table — (domain, category, page_reached, result_count, recorded_at). Log on each browse request. Review manually: if any category has page > 5 and result_count > 100 consistently, consider adding a third nesting level.

Frontend

  • RecipeBrowserPanel.vue — domain pill picker, category list with count chips, recipe grid/list with pantry match badges, pagination
  • New Browse tab in RecipesView.vue (tab bar: Find / Browse / Saved)
  • Clicking a recipe opens existing RecipeDetailPanel

Spec

circuitforge-plans/kiwi/superpowers/specs/2026-04-07-saved-recipes-browser-design.md section 4

## Summary Browse the full recipe corpus by pre-baked domain schemas (cuisine, meal type, dietary, main ingredient), with pantry match percentage shown inline. Free tier. ## Domain Schemas New file: `app/services/recipe/browser_domains.py` Four domains, each mapping keyword sets to a two-level category hierarchy: - **Cuisine** — Italian, Mexican, Asian, American, Mediterranean, Indian, … - **Meal Type** — Breakfast, Lunch, Dinner, Snack, Dessert, Beverage - **Dietary** — Vegetarian, Vegan, Gluten-Free, Low-Carb, High-Protein - **Main Ingredient** — Chicken, Beef, Pork, Fish, Pasta, Vegetable, Egg, Legumes Matching is case-insensitive against the `category` column and `keywords` JSON array already in the `recipes` table. A recipe may appear in multiple categories (correct). **Before writing this module:** run `SELECT category, count(*) FROM recipes GROUP BY category ORDER BY count(*) DESC` against the food.com corpus to calibrate keyword mappings. ## Store Methods - `get_browser_categories(domain: str) -> list[dict]` — `[{category, recipe_count}]` - `browse_recipes(domain, category, page, page_size, pantry_items) -> dict` — `{recipes, total, page}`, each recipe includes `match_pct: float | None` `match_pct` is set intersection of pantry_items vs `ingredient_names` — deterministic, no LLM (large language model) needed. ## API Endpoints Extend `app/api/endpoints/recipes.py`: - `GET /recipes/browse/domains` — list domain schemas - `GET /recipes/browse/{domain}` — categories with recipe counts - `GET /recipes/browse/{domain}/{category}?page=1&page_size=20&pantry_items=item1,item2` ## Pantry Match Badges Frontend pulls pantry items from the inventory store automatically (no extra user action). Badge thresholds: - 80–100%: green "Great match" - 50–79%: yellow "Good match" - < 50%: no badge (or faint "Partial") ## Nesting Depth Telemetry Migration 020: `browser_telemetry` table — `(domain, category, page_reached, result_count, recorded_at)`. Log on each browse request. Review manually: if any category has page > 5 and result_count > 100 consistently, consider adding a third nesting level. ## Frontend - `RecipeBrowserPanel.vue` — domain pill picker, category list with count chips, recipe grid/list with pantry match badges, pagination - New **Browse** tab in `RecipesView.vue` (tab bar: Find / Browse / Saved) - Clicking a recipe opens existing `RecipeDetailPanel` ## Spec `circuitforge-plans/kiwi/superpowers/specs/2026-04-07-saved-recipes-browser-design.md` section 4
pyr0ball added the
enhancement
label 2026-04-07 21:53:21 -07:00
pyr0ball added this to the Beta — Recipe Suggestions milestone 2026-04-07 22:09:32 -07:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/kiwi#25
No description provided.