Replaces 3-panel layout with 2-panel (sidebar + full-width grid):
- Remove persistent right panel and toolbar + Gericht hinzufügen button
- grid-cols-7 tiles use DesktopDayTile (CSS 3D card flip)
- RecipePickerDrawer slides in on tile CTA / Gericht tauschen
- Page-owned activeSlotId + drawerOpen/drawerSlotId state
- Single Escape handler: drawer > flip priority
- Extend server load to forward recipe tags from /v1/recipes API
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents a silent 400 from the backend when the user submits a form
where every ingredient row has quantity <= 0 or blank name.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Thumbnailator-based ImageCompressor that resizes uploaded images
to a 400px-wide JPEG preview stored in hero_image_preview. The recipe
list uses the preview instead of the full image URL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Store hero image as base64 data URI in text column (V023 migration)
- Add file upload UI to RecipeForm with FileReader preview
- Remove isChildFriendly from RecipeCreateRequest (no form field)
- Fix 500 on save: effort values now lowercase, serves/cookTimeMin changed
from primitive short to nullable Integer to survive omitted fields
- Fix empty categories panel: removed stale tagType=category filter
- Group category tags by type with German headings in recipe form
- Split SuggestionResponse.SuggestionRecipe (no image) from SlotRecipe
- Seed 11 HelloFresh recipes with ingredients, steps and tags (V101)
- Add frontend e2e scaffold, specs and dev yml
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace SwapSuggestionList with RecipePicker in both mobile and desktop
swap contexts. RecipePicker now accepts excludeRecipeId, replacingRecipe,
and isDisabled props. Mobile swap sheet also triggers suggestion fetch
via activePickerDate so green/yellow/red score badges appear during swap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- +server.ts: pass topN=100 so all recipes are scored in one request
- RecipePicker: Empfohlen keeps top 5 with scoreDelta > 0; builds a
scoreMap from all suggestions; shows green/yellow/red delta badge on
every recipe in Alle Rezepte that has a score entry
- Extracted scoreBadge snippet to avoid duplication between sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
"when backend returns error" → "when data is undefined (error response
without data)" — documents that the guard is data?.suggestions ?? [],
not error field inspection.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes the inline interface from RecipePicker.svelte and replaces
any[] in +page.svelte with Suggestion[] — compile-time safety.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cancels the inflight request when activePickerDate changes or picker
closes, preventing stale responses from overwriting suggestions.
Adds page.test.ts covering fetch trigger, suggestion rendering,
and AbortSignal presence.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Derives activePickerDate from mobile pickerOpen/selectedDay and desktop
recipe-picker panel state, then uses $effect to fetch /planner?planId&date
on demand — wires suggestions and isLoading into both RecipePicker instances.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds excludeRecipeId prop to SwapSuggestionList so the meal being
replaced is not offered as a swap candidate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- hooks.server.ts: replace type-cast with actual mapping so isPlanner works
- planner page: set min-h/min-w 40px on prev/next/heute week buttons
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix 7px → 11px font-size on section headers in RecipePicker
- Extract shared slotActions.ts with UUID validation for planId/slotId/recipeId
- Load full recipe list in planner page load (was placeholder current-week slots)
- Update planner/+page.svelte to pass data.recipes as allRecipes to RecipePicker
- Update planner and recipes page.server.ts to use shared slot action helpers
- Fix planner page.server tests: add recipes mock for parallel GET load
- Update action tests to use valid UUIDs (were 'plan-1'/'r1' style strings)
- Add validation-path tests for blank/invalid input on all slot actions
- Add tests for recipes/+server.ts GET endpoint (DayPicker week navigation)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
C4 sheet content: Empfohlen section with variety delta badges,
Alle Rezepte with client-side search filter. GET /planner endpoint
proxies suggestions to backend for lazy client-side loading.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mobile/desktop responsive shopping list page with:
- Three empty states (no plan, no list, all checked)
- Unchecked/checked item sections with divider
- Add custom item form
- Desktop right panel with recipe references
- Filtered staples info
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Load function fetches shopping list and week plan for the current week.
Form actions: check (toggle item), addItem (custom item), generate
(planner-only shopping list generation).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
effortMap had 'Easy'/'Medium'/'Hard' but the API returns 'easy'/'medium'/'hard',
so filtering by difficulty always returned nothing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change all \$derived(() => {...}) to \$derived.by(() => {...}) — values not functions
- Remove unused formatDayLabel import
- Delegate subScores to computeSubScores(), warnings to computeWarnings()
- Remove () call syntax from all template reactive references
Addresses Kai blockers: anti-pattern derived, dead import.
Addresses QA blocker: logic now exercised by unit tests in variety.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix logic bug `{#if !isPlanner === false}` - view/cook buttons now visible for all roles, swap only for planner
- Convert Tauschen from dead button to link with suggestions href
- Add week.ts unit tests (23 tests covering getWeekStart Sunday edge case, prevWeek/nextWeek, weekDays, isToday, formatWeekRange)
- Fix isToday to use UTC consistently (.toISOString().slice(0,10)) instead of local date
- Add server-side role guard to createPlan action (403 for members)
- Add weekStart format validation in createPlan action
- Add isSelected prop to DayMealCard with green treatment
- Make variety banner sticky on mobile (always visible per spec)
- Add day name abbreviation above date badge in desktop column headers
- Remove placeholder Navigation text from desktop sidebar
- Add aria-label to desktop empty tile buttons
- Add variety score partial failure test, multiple overlaps test, WeekStrip today+selected test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three-breakpoint layout (mobile/tablet/desktop) with VarietyScoreCard,
WeekStrip, DayMealCard components. Server loads week plan and variety
score via API; read-only role behavior derived from benutzer.rolle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add try-catch around JSON.parse with fail(400) for malformed input
- Validate effort against allowed values ['Easy','Medium','Hard']
- Fix NaN risk: Number(serves)||undefined instead of Number(serves)
- Add action tests for create/update: validation, JSON.parse crash, success, API error
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>