Commit Graph

43 Commits

Author SHA1 Message Date
7c07bc443b feat(suggestions): C2 — Meal suggestions (variety-aware) (#40)
feat(suggestions): implement C2 meal suggestion screen (Issue #27)

Co-authored-by: Marcel Raddatz <marcel@raddatz.cloud>
Co-committed-by: Marcel Raddatz <marcel@raddatz.cloud>
2026-04-03 11:18:45 +02:00
5d2bb9e84e fix(planner): address all PR review blockers
- 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>
2026-04-03 11:07:47 +02:00
e3f8d8ad73 feat(planner): implement C1 weekly planner home screen (#26)
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>
2026-04-03 11:01:17 +02:00
6505cb4251 test(recipes): add action tests and harden create/update form actions
- 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>
2026-04-03 10:27:54 +02:00
3d49e6b7bf feat(recipes): add /recipes/[id]/edit route with update action
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 10:20:45 +02:00
4e2b0b5727 feat(recipes): add /recipes/new route with create action
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 10:19:27 +02:00
0256b4360b fix(recipes): address B2 review — tags, sort, edit link, types, a11y, tests
- RecipeHero: render tag pills, min-h-[200px/240px], fix back link styling, remove font-[400]
- IngredientList: sort by sortOrder ascending
- StepList: aria-hidden on step circles
- types.ts: add Tag, Ingredient, Step, RecipeDetail shared types
- +page.svelte: add Edit link → /recipes/[id]/edit (desktop topbar)
- Tests: tag pills, sortOrder sort, edit link, image variant, 403-as-404 documented

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 10:07:19 +02:00
00c48a7c96 feat(recipes): implement B2 recipe detail page with mobile/desktop layout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 10:02:20 +02:00
ce860d68e4 feat(recipes): add recipe detail load function with 404 handling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 10:00:02 +02:00
9bb6293d9f fix(recipes): address review feedback — shared type, design system tokens, test coverage
- Extract RecipeSummary type to $lib/recipes/types.ts (was duplicated in 3 files)
- Fix +page.svelte header link: replace Skeleton UI classes with design system tokens
- Fix h1: use font-[var(--font-display)] and correct size
- Fix FilterChipRow: text-[11px] → text-[13px] + tracking-[0.04em] per design system
- Fix RecipeCard metadata: text-[11px] → text-[12px] for readability
- Remove unused imports (vi, beforeEach, afterEach) from page.test.ts
- Add combined search + effort filter test
- Add reset-to-Alle filter test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:53:32 +02:00
47c748145d feat(recipes): implement recipe library page with search and effort filtering
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:49:39 +02:00
a25286e385 feat(recipes): load recipe list from API in page server
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:45:43 +02:00
2d6ddf0e48 fix(staples): apply design-system styles to nav links and settings heading
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:29:53 +02:00
8daaa0e21d fix(staples): pass ctx from URL through load function; fix script order in page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:27:43 +02:00
45b7e7b003 fix(staples): add role guard — only planer role can toggle staples
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:25:40 +02:00
3581af2bf9 fix(staples): forward backend error status code instead of always 500
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:25:06 +02:00
21b873b85b fix(staples): validate isStaple is boolean before forwarding to backend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:24:35 +02:00
65f18cfb43 test(staples): cover API failure fallback in page load
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:24:07 +02:00
7979076f5e feat(invite): stub household invite page as onboarding Continue target
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:16:46 +02:00
d68a9d9312 refactor(setup): redirect to /household/staples?ctx=onboarding after household creation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:16:33 +02:00
97175e7d9d feat(staples): add staples page with onboarding and settings layouts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:16:08 +02:00
3550d681dc feat(staples): load categories and ingredients, group by category
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:14:25 +02:00
54df70a442 feat(staples): add PATCH proxy server route for ingredient staple toggle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:13:02 +02:00
7c66dcad3a refactor(onboarding): clarify test comment and remove unused response mock
HouseholdSetupForm.test.ts: explain that touched+empty drives the $derived
error, not a submit event on the disabled button.
page.server.test.ts: remove unused response key from mockSuccess() —
household creation doesn't set a session cookie.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:32:44 +02:00
2d1604492d feat(onboarding): add max-length validation for household name (100 chars)
Fails fast before the API call with a clear German error message.
Tests boundary: 100 chars accepted, 101 rejected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:31:13 +02:00
e5614ccf30 refactor(onboarding): remove aria-hidden workaround from progress sidebar
Replace getByText with getByRole(heading) in page test to disambiguate
the duplicate "Haushalt benennen" text between sidebar and form.
Revert defaultIgnore change in test-setup.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:28:46 +02:00
6de7f5a9b5 feat(onboarding): add A2 household setup page with responsive progress sidebar layout
Desktop: 300px ProgressSidebar (step 1 active) + flex form area.
Mobile: "Schritt 1 von 3" eyebrow + HouseholdSetupForm.
Also stubs /household/staples as redirect target for A3.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:20:02 +02:00
e85a7ca313 feat(onboarding): add household setup page server action and load guard
Creates household via POST /v1/households, redirects to /household/staples.
Load guard redirects users who already have a household to /planner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:14:39 +02:00
61249af086 feat(auth): add secure flag to JSESSIONID cookie and test JSESSIONID cookie setting
- Add secure: true to cookies.set() in login and signup actions
- Add tests verifying JSESSIONID is forwarded to browser on successful
  login and signup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:50:34 +02:00
16f0feb8d5 fix(auth): fix mock responses in tests and block open redirect in login
- Add response object to mockSuccess() in login and signup tests so
  response.headers.get() no longer throws
- Validate ?redirect= param: must start with / and not // to prevent
  redirecting users to external domains

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:48:48 +02:00
0aa65214fc fix(auth): resolve broken signup/login flow end-to-end
Three root causes fixed:

1. CSRF blocked all backend POSTs — Spring Security's CSRF filter ran
   before permitAll() authorization, returning 401 for signup and login.
   Disabled CSRF since SvelteKit is the only client (never the browser
   directly) and handles its own CSRF via Origin header checks.

2. Login/signup didn't establish Spring Security authentication — they
   stored email in the HTTP session manually but never set the
   SecurityContext, so Principal in /v1/auth/me was always null and
   hooks.server.ts redirected every authenticated request to /login.
   Fixed with authenticateInSession() helper that sets and persists
   the SecurityContext under SPRING_SECURITY_CONTEXT_KEY. Login also
   now invalidates the old session before creating a new one to prevent
   session fixation.

3. redirect() missing throw in hooks.server.ts, signup action, and
   login action — SvelteKit never saw the redirect, so pages silently
   reloaded with no navigation. Also forward JSESSIONID from backend
   response to browser explicitly, since SvelteKit does not
   auto-forward Set-Cookie for cross-origin server-side fetches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 17:31:29 +02:00
ab3363eeec refactor(auth): use shared BrandPanel on login page
Login page now uses the same BrandPanel component as signup
instead of an inline brand panel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 16:45:22 +02:00
999e54de86 feat(auth): build login page with LoginForm, brand panel, and title
Replaces placeholder with full login page: brand panel left,
LoginForm right, svelte:head title, signup link, no-nav-chrome.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 16:21:31 +02:00
73acc0c638 feat(auth): add login server action with validation and redirect
POSTs to /v1/auth/login, validates email/password server-side,
redirects to ?redirect param or /planner on success.
Returns generic error on bad credentials to prevent enumeration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 16:20:02 +02:00
6d0f00c8fb feat(auth): add use:enhance and server error display to signup form
SignupForm now uses use:enhance for progressive enhancement.
Accepts form prop for server-side error display. Shows general
form errors in a banner and field-specific errors inline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:06:21 +02:00
bd9e1334e0 feat(auth): add server-side validation to signup form action
Validates displayName, email, password server-side before calling
the backend API. Handles null from formData.get() safely.
Returns structured field errors via fail(400, { errors }).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:02:33 +02:00
82840bb420 fix(auth): center signup form on wide desktop screens
Form container now horizontally centered on md+ viewports,
left-aligned on mobile for full-width usage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:01:03 +02:00
845e669cde feat(auth): add page title to signup screen
Sets <title>Konto erstellen — Mealprep</title> via svelte:head
for browser tab and accessibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:00:02 +02:00
bfa8f20fe3 test(auth): add no-nav-chrome regression test for signup page
Verifies signup page renders form and brand panel but no
navigation elements (tabs, sidebar, links to app routes).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:48:23 +02:00
596652d6e4 feat(auth): add signup page with form action
Composes BrandPanel + SignupForm in responsive split layout.
Server action POSTs to /v1/auth/signup and redirects to
/household/setup on success.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:47:36 +02:00
66cf538454 refactor(auth): make (public) layout bare, move brand panel into login page
The signup page needs its own brand panel, so the shared layout
becomes a simple slot. Login page now owns its brand panel markup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:38:30 +02:00
d7f317587e refactor(public): add lang="ts" to public layout for consistency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 13:53:56 +02:00
9626bde694 feat(shell): add route groups, layout server load, redirect, and placeholder pages
- (app) group with AppShell layout, loads user/household from locals
- (public) group with full-viewport split layout, /login placeholder
- Root / redirects to /planner for authenticated users
- Placeholder stubs for planner, recipes, shopping, settings, members

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 13:22:34 +02:00