- Persist built recipes to recipes table on /build so they get real DB IDs
and can be bookmarked via saved_recipes (FK was pointing at negative IDs)
- Populate missing_ingredients in build_from_selection() from role_overrides
vs pantry diff -- backend now owns shopping list computation
- Remove client-side cartItems tracking; shopping list derived from
builtRecipe.missing_ingredients instead
- Fix saved_recipes 422: mount saved_recipes router before recipes router in
routes.py so /recipes/saved isn't captured by /recipes/{recipe_id}
- Bump SaveRecipeModal z-index to 500 (above detail-overlay at 400)
- Replace "Add to pantry" primary action with "Grocery list" clipboard copy;
"Add to pantry" demoted to compact secondary button
- Default app landing changed from Pantry to Recipes tab
- Pre-fetch inventory on app mount so Find tab has data immediately
- Reorder recipe sub-tabs: Saved > Build Your Own > Community > Find > Browse
- Default active sub-tab changed to Saved
- Auto-redirect from Saved to Build Your Own when saved list is empty
- Add freeform custom ingredient input: typing a non-pantry item now shows
"Use X anyway" button so users aren't blocked on unknown ingredients
- PublishPayload gains optional slots field; PublishPlanModal maps
plan.slots into the payload so the backend can compute element
snapshot scores (seasoning, richness, etc.) from actual recipes
- plan-forked emit type updated to ForkResult across CommunityFeedPanel
and RecipesView so forked_from is preserved for future navigation
- onUnmounted clears blooperHoldTimer to prevent stale callback after
component teardown
- HallOfChaosView loading state gains aria-live="polite" so state
transitions are announced to screen readers
- CommunityFeedPanel reduced-motion block resets toast translateY offset
to avoid flash-of-offset-position on slow paint cycles
Adds the Hall of Chaos overlay component (recipe blooper gallery with
static CSS tilts, chaos level counter, panel-local overlay) and wires
the 800ms long-press trigger on the Bloopers filter tab in
CommunityFeedPanel. Pairs with the backend /community/hall-of-chaos
endpoint and test added in Task 10.
- update_prep_task: move whitelist guard above filter so invalid column
check runs on raw kwargs (was dead code — set(filtered) - allowed is
always empty); fixes latent SQL injection path for future callers
- main.py: move register_kiwi_programs() into lifespan context manager
so it runs once at startup, not at module import time
- MealPlanView.vue: remove debug console.log stubs from onSlotClick and
onAddMealType (follow-up issue handlers, not ready for production)
- Add migration 021: recipe_browser_fts FTS5 table on category + keywords
columns, eliminating LIKE '%keyword%' full sequential scans on 3.1M rows
- _count_recipes_for_keywords now uses FTS5 MATCH (O(log N) vs O(N))
- browse_recipes reuses cached count, eliminating the second COUNT(*) scan
per page request; ORDER BY r.id replaces the unindexed ORDER BY title sort
- Module-level _COUNT_CACHE keyed by (db_path, keywords) means domain-switch
category counts are computed once per process lifetime
feat(find): dietary preset grid, Big 9 allergen pills, Hard Day Mode surface
- Dietary constraints replaced with toggle-button preset grid (8 options)
+ free-text "Other" field; removes dense freeform text input
- Allergies replaced with Big 9 pill picker (peanuts, tree nuts, shellfish,
fish, milk, eggs, wheat, soy, sesame) + "Other" for custom entries
- Hard Day Mode surfaced as a standalone aria-pressed button above the
dietary collapsible; no longer buried inside a collapsed section
- Active-state dot indicators on both collapsibles show filter engagement
at a glance without expanding
fix(a11y): aria-describedby wiring for wildcard checkbox and tag inputs (#40)
- Persistent hint spans replace placeholder-only instructions for constraint
and allergy fields (WCAG 3.3.2)
fix(browse): auto-select highest-count category on domain switch (#41)
- Eliminates the 3-decision cold start (domain → category → content)
- Surprise Me button added for zero-decision random navigation
- "Use What I Have" / "Allow Swaps" / "Get Creative" / "Surprise Me 🎲"
- Active level shows a one-liner description beneath the selector
- Hover tooltips repeat the description for mouse users
- Label changed from "Creativity Level" to "How far should we stretch?"
- Wildcard confirmation copy updated to match new framing
- feedback.py: add GET /feedback/status endpoint (returns {enabled: bool})
so frontend can probe on mount instead of optimistic-enable; remove
unused get_db import
- FeedbackButton.vue: probe /feedback/status on mount, start hidden;
drop redundant 503-hide path (status probe makes it redundant)
- pyproject.toml: declare requests>=2.31 (used by feedback.py Forgejo calls)
- tests/api/test_feedback.py: 7 tests — status endpoint (no-token, token,
demo mode), POST 503/403, happy path with mocked Forgejo, 502 on error
- index.html: inline anti-FOUC CSS so sidebar stays hidden on mobile
before the JS bundle hydrates (eliminates ~100ms flash of sidebar)
- InventoryList: scan-mode-toggle fills card width on <=480px so buttons
don't overflow; mode button labels hidden on <=360px (icons only)
- Very narrow phones get icon-only mode toggle, all three buttons still
accessible via aria-label
- Style/category filter panel with active chip display
- Dismiss (excluded_ids) support — recipes don't reappear until next fresh search
- Load more appends next batch without full re-fetch
- Prep notes 'Before you start:' section above directions
- Nutrition macro chips (kcal, fat, protein, carbs, fiber, sugar, sodium)
- Composables extracted for reuse
- EditItemModal: replace all hardcoded colors (#eee, #f5f5f5, #2196F3, etc.) with CSS variable tokens; restyle modal header with display font, blur backdrop, and theme-aware form elements
- ReceiptsView: replace emoji headings, hardcoded spinner, and non-theme .button class with themed equivalents; all colors through var(--color-*) tokens
- RecipesView: fix broken --color-warning-rgb / --color-primary-rgb references (not defined in theme); use --color-warning-bg and --color-info-bg instead; apply section-title to heading
- SettingsView: apply section-title display-font class to heading for consistency
- InventoryList: remove three dead functions (formatDate, getDaysUntilExpiry, getExpiryClass) that caused TS6133 build errors
- RecipesView: level selector (1-4), constraints/allergies tag inputs,
hard day mode toggle, max missing input, expiry-first pantry extraction,
recipe cards with collapsible swaps/directions, grocery links, rate
limit banner
- SettingsView: cooking equipment tag input with quick-add chips, save
with confirmation feedback
- stores/recipes.ts: Pinia store for recipe state + suggest() action
- stores/settings.ts: Pinia store for cooking_equipment persistence
- api.ts: RecipeRequest/Result/Suggestion types + recipesAPI + settingsAPI
- App.vue: two new tabs (Recipes, Settings), lazy inventory load on tab switch