Commit graph

88 commits

Author SHA1 Message Date
9941227fae chore: merge main into feature/meal-planner
Resolves three conflicts:
- app/api/routes.py: fixed saved_recipes-before-recipes ordering from main;
  meal_plans and community_router from feature branch
- app/db/store.py: meal plan/prep session methods (feature) + community
  pseudonym methods (main) -- both additive
- app/tiers.py: KIWI_BYOK_UNLOCKABLE includes meal_plan_llm,
  meal_plan_llm_timing (feature) and community_fork_adapt (main)
2026-04-14 14:53:52 -07:00
3933136666 fix: save, shopping list, and route ordering for Build Your Own
- 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
2026-04-14 14:48:30 -07:00
b4f031e87d feat(kiwi): add orch_fallback field to RecipeResult 2026-04-14 14:38:37 -07:00
fbae9ced72 feat(kiwi): add LIFETIME_ORCH_CAPS and LIFETIME_SOURCES constants 2026-04-14 14:38:36 -07:00
144d1dc6c4 chore: commit in-progress work -- tag inferrer, imitate endpoint, hall-of-chaos easter egg, migration files, Dockerfile .env defense
- app/services/recipe/tag_inferrer.py: infer tags from recipe ingredient text
- app/db/migrations/022_recipe_generic_flag.sql, 029_inferred_tags.sql: schema migrations
- app/api/endpoints/imitate.py: recipe imitation endpoint stub
- app/api/endpoints/community.py: hall-of-chaos easter egg endpoint
- scripts/pipeline/infer_recipe_tags.py, backfill_keywords.py: pipeline scripts
- scripts/pipeline/build_recipe_index.py: extended index builder
- Dockerfile: explicit .env removal as defense-in-depth
- frontend/src/components/FeedbackButton.vue: feedback UX improvements
- frontend/src/style.css: minor style tweaks
- app/cloud_session.py: cloud session improvements
- tests/api/test_community_endpoints.py: additional test coverage
2026-04-14 13:23:15 -07:00
8c4965123f feat: add GET /templates, GET /template-candidates, POST /build endpoints
Wires the three Build Your Own API routes into the recipes router,
registered before the catch-all /{recipe_id} route to avoid shadowing.
Adds 5 endpoint tests covering template list count/shape, candidate
response structure, successful recipe build, and 404 on unknown template.
2026-04-14 11:45:43 -07:00
c02e538cb2 feat: remove assembly results from suggest() -- moved to Build Your Own tab 2026-04-14 11:39:57 -07:00
da940ebaec feat: add get_role_candidates() and build_from_selection() to assembly engine
Both functions are DB-free public API additions to assembly_recipes.py.
get_role_candidates() scores pantry candidates against a wizard step using
element-profile overlap with prior picks; build_from_selection() builds a
RecipeSuggestion from explicit role overrides with required-role validation.
2026-04-14 11:06:08 -07:00
4f1570ee6f feat: add Store.get_element_profiles() for wizard role candidate lookup 2026-04-14 10:50:46 -07:00
1a5fb23dfd feat: add slug/icon/descriptor to AssemblyTemplate and get_templates_for_api()
Extends AssemblyTemplate dataclass with slug, icon, descriptor, and
role_hints fields. Updates all 13 template instantiations with
appropriate values. Adds _TEMPLATE_BY_SLUG lookup dict and
get_templates_for_api() serialiser for the templates endpoint.
2026-04-14 10:36:58 -07:00
65ef65bb4c feat: add Pydantic schemas for Build Your Own tab endpoints 2026-04-14 09:45:05 -07:00
86dd9adbcb refactor: use sqlite3.IntegrityError directly for slug collision guard 2026-04-13 11:25:10 -07:00
69e1b70072 fix: community endpoint quality issues — input validation, slot key guard, slug collision, ValueError handling 2026-04-13 11:23:45 -07:00
9ae886aabf fix: community endpoint spec gaps — ld+json content negotiation + premium post tier filter 2026-04-13 11:20:28 -07:00
9c64de2acf feat(community): community API endpoints — browse, publish, fork, delete, RSS, AP
Adds GET /community/posts, GET /community/posts/{slug}, GET /community/feed.rss,
GET /community/local-feed, POST /community/posts, DELETE /community/posts/{slug},
POST /community/posts/{slug}/fork, and POST /community/posts/{slug}/fork-adapt (501 stub).
Wires init_community_store into main.py lifespan. 7 new tests; 115 total passing.
2026-04-13 11:14:18 -07:00
81107ed238 feat(community): KiwiCommunityStore + pseudonym helpers in per-user store 2026-04-13 10:54:13 -07:00
b1ed369ea6 feat(community): mDNS advertisement via zeroconf — defaults OFF, opt-in per a11y audit 2026-04-13 09:59:50 -07:00
f12699349b feat(community): RSS 2.0 feed generator + ActivityPub JSON-LD scaffold 2026-04-13 09:44:51 -07:00
74c7272a50 feat(community): element snapshot — SFAH scores, allergen detection, dietary tags 2026-04-13 09:19:57 -07:00
1a9a8579a2 feat(community): add COMMUNITY_DB_URL config + community features to tiers 2026-04-13 09:02:44 -07:00
b97cd59920 feat(community): migration 028 — community_pseudonyms table in per-user kiwi.db 2026-04-13 08:13:39 -07:00
19c0664637 fix(review): address code review findings before merge
- 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)
2026-04-12 14:16:24 -07:00
e52c406d0a docs(bsl): document cf-text/LLMRouter routing chain in llm_timing and llm_planner 2026-04-12 14:07:32 -07:00
4281b0ce19 feat(services/bsl): add llm_router — cf-text via cf-orch on cloud, LLMRouter (ollama/vllm) local fallback
refs kiwi#68
2026-04-12 14:07:13 -07:00
f54127a8cc fix(meal-planner): add GET prep-session endpoint, fix list_plans schema, replace assert with ValueError
- Add GET /{plan_id}/prep-session endpoint so frontend can retrieve existing sessions without creating
- Fix list_plans response_model from list[dict] to list[PlanSummary] with proper _plan_summary() mapping
- Replace assert in store.update_prep_task with ValueError (assert is stripped under python -O)
- Add day_of_week 0-6 validation to upsert_slot endpoint
- Remove MagicMock sqlite artifact files left by pytest (already in .gitignore)
2026-04-12 14:04:53 -07:00
062b5d16a1 feat(services/bsl): add llm_planner — LLM-assisted full-week meal plan generation (Paid/BYOK) 2026-04-12 13:58:04 -07:00
5f094eb37a feat(services/bsl): add llm_timing — estimate cook times via LLM for missing corpus data (Paid/BYOK) 2026-04-12 13:58:03 -07:00
482666907b fix(meal-planner): validate meal_type path param, enforce store whitelist safety, add week_start date validation, make PrepTask frozen
- upsert_slot: raise 422 immediately if meal_type not in VALID_MEAL_TYPES
- update_prep_task: assert whitelist safety contract after dict comprehension
- CreatePlanRequest: week_start typed as date with must_be_monday validator; str() cast at call site
- PrepTask: frozen=True; build_prep_tasks rewired to use (priority, kwargs) tuples so frozen instances are built with correct sequence_order in one pass (no post-construction mutation)
- Move deferred import json to file-level in meal_plans.py
- Fix test dates: "2026-04-14" was a Tuesday; updated request bodies to "2026-04-13" (Monday)
2026-04-12 13:51:50 -07:00
bfc63f1fc9 feat(services): add planner.py orchestration helpers 2026-04-12 13:44:27 -07:00
536eedfd6c feat(routes): register meal-plans router at /api/v1/meal-plans
refs kiwi#68
2026-04-12 13:44:08 -07:00
98087120ac feat(api): add /api/v1/meal-plans/ endpoints — CRUD, shopping list, prep session
refs kiwi#68 kiwi#71
2026-04-12 13:44:01 -07:00
b9dd1427de feat(affiliates): register Kiwi grocery retailer programs at startup
refs kiwi#74
2026-04-12 13:15:28 -07:00
25027762cf feat(services): add prep_scheduler — sequences batch cooking tasks by equipment priority 2026-04-12 13:14:54 -07:00
4459b1ab7e feat(services): add shopping_list service with pantry diff
refs kiwi#68
2026-04-12 13:14:08 -07:00
ffb34c9c62 feat(store): add meal plan, slot, prep session, and prep task CRUD methods 2026-04-12 13:13:18 -07:00
067b0821af feat(schemas): add meal plan Pydantic models 2026-04-12 13:12:41 -07:00
594fd3f3bf feat(tiers): move meal_planning to Free; add meal_plan_config/llm/llm_timing keys
refs kiwi#68
2026-04-12 13:12:11 -07:00
3235fb365f feat(db): add meal_plans, slots, prep_sessions, prep_tasks migrations (022-025) 2026-04-12 13:11:34 -07:00
192ecc7078 fix(browse): use subquery for FTS5 MATCH (alias unsupported in WHERE clause) 2026-04-09 12:53:06 -07:00
0d7223a12b fix(browse): remove source_url reference (column is source; field unused in response) 2026-04-09 12:47:23 -07:00
6da86dd0a7 feat(hard-day): tier-sort results — premade first, simple second
Hard Day Mode now prioritises results by effort tier before match_count:
  Tier 0 (premade): frozen/instant title keywords, or ≤2 ingredients with
    heat/microwave-only steps (frozen dinner, heat-and-eat, microwave meal)
  Tier 1 (super simple): ≤3 ingredients + any easy method (quesadilla,
    cheese toast, scrambled eggs)
  Tier 2 (easy/moderate): everything else that passed the 'involved' filter

Assembly templates default to tier 1 (inherently simple). Normal mode sort
is unchanged — match_count only.
2026-04-08 23:18:29 -07:00
a523cb094e perf(browser): replace LIKE scans with FTS5; cache category counts
- 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
2026-04-08 23:10:48 -07:00
f1cde57fdf chore: bump version to 0.2.0 2026-04-08 22:10:36 -07:00
793df1b5cf feat: saved recipes, recipe browser, and recipe detail panel
- Saved recipes: save/unsave, star rating, notes, tags, collections (migrations 018-020)
- Recipe browser: domain/category browsing with pantry match badges, pagination
- Recipe detail panel: full directions, ingredient checklist, swap candidates, prep notes
- Grocery links: affiliate links for missing ingredients
- Nutrition filters and display chips on recipe cards
- Bookmark toggle persisted to saved_recipes table
- Tier gates on saved recipes (paid) and collections (premium)
- Browser telemetry for domain/category click tracking
- Cloud compose: CLOUD_DATA_ROOT volume mount for per-user SQLite trees
- manage.sh: cf-orch agent sidecar in local stack
- README: updated feature list and stack description
2026-04-08 14:35:02 -07:00
c064933b14 refactor: use shorter circuitforge_core.api import for feedback router 2026-04-05 21:21:50 -07:00
f3bc796f2c feat: migrate feedback endpoint to circuitforge-core router
Replace hand-rolled feedback.py with make_feedback_router() from
circuitforge_core.api.feedback. Update tests to mount the shared
router on a minimal FastAPI app and mock at the core module level.
2026-04-05 17:57:36 -07:00
6a59c8dfd1 fix: row_factory in _household_store; validate household_id from Heimdall; monkeypatch CLOUD_DATA_ROOT in accept test; add KIWI_BASE_URL to compose.cloud.yml 2026-04-04 22:59:06 -07:00
c7861344b7 feat: add MessageResponse schema; wire response_model on leave + remove-member endpoints 2026-04-04 22:47:39 -07:00
7650747651 feat: household API endpoints (create, status, invite, accept, leave, remove-member) 2026-04-04 22:45:12 -07:00
dce8d05a09 refactor: use str | None + Field(default_factory=list) in household schemas 2026-04-04 22:41:53 -07:00