Commit graph

94 commits

Author SHA1 Message Date
67b521559e feat(frontend): add ShoppingListPanel with pantry diff and affiliate links 2026-04-12 13:57:48 -07:00
a7fc441105 feat(frontend): add MealPlanGrid compact-expandable week grid component 2026-04-12 13:57:47 -07:00
543c64ea30 feat(frontend): add mealPlan Pinia store with immutable slot updates 2026-04-12 13:57:40 -07:00
4865498db9 feat(frontend): add mealPlanAPI client with TypeScript types 2026-04-12 13:55:14 -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
0b9e3553a7 fix(frontend): remove unused removeConstraint function (TS6133) 2026-04-09 12:31:18 -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
4bb93b78d1 feat(ux/nd): collapse Find tab into level picker + two filter sections with active indicators 2026-04-08 22:51:43 -07:00
8c1443d156 fix(ux/nd): Browse tab auto-selects top category on mount; add Surprise Me button (closes #41) 2026-04-08 22:30:49 -07:00
001e46ba9a fix(a11y): add aria-describedby and persistent hints for wildcard checkbox and tag inputs (closes #40) 2026-04-08 22:27:28 -07:00
d7c0ae011a chore: bump pyproject.toml version to 0.2.0 2026-04-08 22:16:38 -07:00
f1cde57fdf chore: bump version to 0.2.0 2026-04-08 22:10:36 -07:00
3530071187 Merge pull request 'feat: Phase 2 — saved recipes, browser, accessibility, level UX' (#69) from feature/orch-auto-lifecycle into main 2026-04-08 15:13:45 -07:00
74a7c068bc feat(ux): rename creativity levels with descriptive labels and inline descriptions
- "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
2026-04-08 15:03:51 -07:00
e203ad4bdc fix(a11y): WCAG accessibility improvements across frontend
- Global :focus-visible ring in theme.css — covers all interactive elements
  with keyboard-nav focus ring without affecting mouse/touch users
- Removed pulse-urgent animation (safety policy violation — infinite animation)
- Global prefers-reduced-motion guard suppresses all animations system-wide
- Added .sr-only utility class for screen-reader-only content
- Tab bar (RecipesView): role=tablist/tab/tabpanel + aria-selected + arrow key nav
- Modal focus management: trap focus on open, restore on close, Escape to dismiss
  (SaveRecipeModal, RecipeDetailPanel, SavedRecipesPanel new-collection dialog)
- aria-modal=true on all modal dialogs
- Icon-only buttons now have contextual aria-labels:
  chip-remove: "Remove constraint: vegetarian" / "Remove allergy: peanuts"
  bookmark: "Bookmark: {title}" / "Remove bookmark: {title}"
  dismiss: "Hide recipe: {title}"
  browser save toggle: "Save recipe: {title}" / "Edit saved recipe: {title}"
- InventoryList qty +/- buttons: aria-label="Increase/Decrease quantity"
- Quantity number inputs: aria-label="Quantity"
- Select elements (SavedRecipesPanel): labelled via .sr-only for-id pattern
- Star rating group: role=group + aria-labelledby; each star: aria-pressed
- Ingredient checkboxes: label wraps input + span (label association fix)
- aria-live="polite" announcer for dynamic recipe results count
- Dynamic aria-labels on status messages (role=alert/status + aria-live)
2026-04-08 14:35:18 -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
11a0d1f3a6 feat: handle household invite accept on app load via URL hash 2026-04-04 22:53:55 -07:00
7cce05b95a feat: household management UI in Settings (Premium-gated) 2026-04-04 22:51:03 -07:00
70b1319b60 feat: add householdAPI typed wrappers to api.ts 2026-04-04 22:48:25 -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
2db4de6d8f feat: add household Pydantic schemas 2026-04-04 22:40:30 -07:00
e605954254 chore: bump circuitforge-core dep to >=0.8.0; fix stale resources imports
- pyproject.toml: circuitforge-core>=0.6.0 → >=0.8.0 (orch split)
- vl_model.py: circuitforge_core.resources → circuitforge_orch.client
- llm_recipe.py: circuitforge_core.resources → circuitforge_orch.client
2026-04-04 22:39:04 -07:00
ed6813713e test: use tmp_path for _user_db_path tests; remove duplicate comment
Patch _user_db_path tests to monkeypatch CLOUD_DATA_ROOT onto a
tmp_path so they never touch /devl or any real filesystem path.
Remove duplicate X-Real-IP comment block in cloud_session.get_session.
2026-04-04 22:38:41 -07:00
9985d12156 feat: extend CloudUser with household_id + update session resolution
Add household_id and is_household_owner fields to CloudUser dataclass.
Update _user_db_path to route household members to a shared DB path.
Update _fetch_cloud_tier to return a 3-tuple and cache a dict.
Update get_session to unpack and propagate household fields.
2026-04-04 22:30:07 -07:00
9602f84e62 feat: add household_invites migration (017) 2026-04-04 22:27:56 -07:00
63559dcdaa Merge pull request 'feat: feedback button, cf-core env-var LLM config, mobile polish' (#14) from feature/orch-auto-lifecycle into main 2026-04-03 22:01:47 -07:00
c4d0f86366 chore: suppress initial-commit .env false positives in gitleaksignore 2026-04-03 18:57:50 -07:00
f63defa883 fix: mobile overflow — inv-row-right shrink + filter-chip-row width 2026-04-03 18:55:33 -07:00
6791ea22b2 feat: complete feedback button — status probe, requests dep, tests
- 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
2026-04-03 16:52:40 -07:00
504631763b feat: wire cf-core env-var LLM config + coordinator auth (closes #13)
- .env.example: document ANTHROPIC_API_KEY, OPENAI_API_KEY, OLLAMA_HOST,
  OLLAMA_MODEL, CF_ORCH_URL, CF_LICENSE_KEY with usage comments
- config.py: expose CF_LICENSE_KEY in Settings for startup visibility
- pyproject.toml: pin circuitforge-core >= 0.6.0 (env-var auto-config +
  CFOrchClient bearer auth land in 0.6.0)

Bare-metal self-hosters can now run Kiwi with only OLLAMA_HOST set and
zero yaml config. Paid+ users set CF_ORCH_URL + CF_LICENSE_KEY for
managed cloud GPU inference.
2026-04-03 16:48:01 -07:00
61c16af754 feat: in-app feedback FAB + mobile safe-area-inset fixes
- FeedbackButton.vue — floating action button; fires POST /feedback if
  FORGEJO_API_TOKEN is configured, silently hidden otherwise
- feedback.py endpoint — creates Forgejo issues with beta-feedback +
  needs-triage labels; includes version, OS, device info
- App.vue: wire FeedbackButton; use env(safe-area-inset-bottom) for
  bottom-nav clearance (fixes clipped content on iPhone home-bar)
- style.css: overflow-x: hidden prevents stray elements expanding
  mobile viewport
2026-04-03 16:47:50 -07:00
6ff5a5709e fix: mobile nav FOUC + Pantry scan toggle responsive layout
- 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
2026-04-03 11:10:39 -07:00