Commit Graph

115 Commits

Author SHA1 Message Date
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
7b497be1c1 test(staples): add empty categories edge case to StaplesManager
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 09:23:48 +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
d577e0231c feat(staples): add StaplesManager with optimistic toggle and debounced PATCH
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:11:51 +02:00
376dc03646 feat(staples): add CategorySection component with eyebrow heading and chip row
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:07:51 +02:00
7bdc049461 feat(staples): add StapleChip component with aria-pressed toggle and focus ring
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 20:06:32 +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
01a321caa9 test(onboarding): add ProgressSidebar test for currentStep=3 (all prior steps completed)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:31:56 +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
3742364956 fix(onboarding): make HouseholdSetupForm subtitle responsive (12px mobile, 14px desktop)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:30:23 +02:00
36dfea34cc fix(onboarding): make HouseholdSetupForm heading responsive and use font-medium
text-[18px] md:text-[28px] matches auth form pattern.
font-medium (500) replaces font-semibold (600) per design system rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:29:52 +02:00
66525484a6 fix(onboarding): correct Tailwind arbitrary font-family syntax in HouseholdSetupForm
font-['var(--font-display)'] → font-[var(--font-display)] so Fraunces
display font is applied correctly to the h1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:29:21 +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
175bfbe7dd feat(onboarding): add HouseholdSetupForm component with disabled-until-valid continue button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:13:41 +02:00
b9ef06fd73 feat(onboarding): add ProgressSidebar component with 3-step active/completed/future states
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 19:08:38 +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
c27c97ff7d feat(auth): add LoginForm component with validation and password toggle
Email/password fields, client-side validation, password show/hide,
server error display via form prop, signup link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 16:18:49 +02:00
b3607ca47a test(auth): add password length boundary tests (7 fails, 8 passes)
Parameterized test verifying the exact boundary of the 8-character
minimum password requirement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:07:42 +02:00
7de18740f2 test(auth): add multi-error test for empty form submission
Verifies all three validation errors (name, email, password) appear
simultaneously when submitting a completely empty form.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:07:07 +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
afcea6590d feat(auth): add autocomplete attributes to signup form inputs
name, email, new-password for better browser/password-manager support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:58:59 +02:00
75a13d9df1 fix(auth): style login link green/font-medium per spec
Spec shows green text with font-weight 500, no underline by default.
Was dark text with underline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:57:47 +02:00
b71c98662b fix(auth): use --green-dark on submit button for WCAG AA contrast
--green (#3D8C4A) gives 4.16:1 against white — fails AA.
--green-dark (#2E6E39) passes comfortably.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:56:49 +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
d3a8518298 feat(auth): add SignupForm component with validation and password toggle
Form with name/email/password fields, client-side validation,
inline error messages, and password show/hide toggle.
Uses native form action for progressive enhancement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:45:54 +02:00
e8fe69a543 feat(auth): add BrandPanel component for signup screen
Renders brand identity with logo, app name, tagline, and feature icons
on green-dark background. Responsive: banner on mobile, 440px column
on desktop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:41:10 +02:00
56fc7e6052 feat(auth): add /signup to public routes
Allow unauthenticated access to the signup page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:39:17 +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
682580e11d feat(nav): add hover state on inactive tablet and desktop nav items
Applies hover:bg-[var(--color-subtle)] to inactive nav links for
visual feedback on pointer devices.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 14:04:50 +02:00
5c066d33ef feat(nav): add emoji icons to all nav components
Renders emoji icons in MobileTabBar (stacked above label),
TabletNavBar (inline), and DesktopSidebar (16px, 20px column).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 14:03:53 +02:00
4bd020fa16 test(nav): add parameterized active-state tests for all routes
Proves active state logic generalizes beyond /planner by testing
all 4 mobile nav routes with writable page store.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 14:01:26 +02:00
bd8e901685 fix(nav): use segment-boundary route matching to prevent false positives
Extracts isActiveRoute() into shared nav module. Matches exact path
or path + '/' prefix, preventing /settings from matching /settings-advanced.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 14:00:18 +02:00
aeaca76534 fix(auth): handle users without household — fallback to 'Kein Haushalt'
Removes non-null assertions on householdId/householdName. Users who
haven't joined a household get a fallback name in the sidebar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 13:58:37 +02:00
32550377aa fix(auth): read JSESSIONID cookie to match Spring Security default
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 13:57:34 +02:00
92c7d8f92e feat(auth): preserve redirect URL when redirecting to /login
Appends ?redirect= with the original pathname so the login page
can redirect back after successful authentication.

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