* ci: add frontend-only CI workflow
* docs: update CLAUDE.md for standalone frontend repo
* fix(register): replace check-your-email success state with inline message (#2)
* fix(register): replace check-your-email success state with inline message
Ports PR #181 intent from cartsnitch/cartsnitch to cartsnitch/app.
Removes registrationComplete, resendLoading, resendMessage state and the
handleResendVerification function. After successful signUp.email, now
sets setError('Account created! Please sign in.') instead of showing
the separate "Check your email" page.
Refs: CAR-822, CAR-818
* fix(e2e): update registration test to match new inline success message
Renames 'can register a new account and see check your email screen' to
'shows success message after registration' and asserts .bg-red-50 contains
'Account created! Please sign in.' instead of checking for a heading.
Updates 'can sign in with credentials' test to first register a fresh account
and assert the success message, then proceed with login.
Refs: CAR-822, PR cartsnitch/cartsnitch#181
---------
Co-authored-by: Chris Farhood <chris@farhood.org>
---------
Co-authored-by: Test User <test@example.com>
Co-authored-by: savannah-savings-cto[bot] <269715008+savannah-savings-cto[bot]@users.noreply.github.com>
Co-authored-by: cartsnitch-engineer[bot] <269717931+cartsnitch-engineer[bot]@users.noreply.github.com>
Co-authored-by: Chris Farhood <chris@farhood.org>
The try-block getSession() pattern is correct for real auth mode.
The mock-auth catch block (VITE_MOCK_AUTH) still needs to set
the Zustand flag so ProtectedRoute respects the authenticated state.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Race condition between signUp/signIn completion and ProtectedRoute's
useSession() call caused redirect loops — Better-Auth's session cookie
is not immediately visible to useSession() after signUp/signIn resolves.
Fix: call authClient.getSession() explicitly after signUp/signIn to
synchronize before navigating to protected routes. Fall back to error
message if session not confirmed.
Also removes dead setAuthenticated() calls that only work in mock mode.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Replace hand-rolled JWT auth with Better-Auth session-based authentication.
- Scaffold auth/ Node.js service with Better-Auth, bcrypt password compat,
Postgres adapter mapped to existing users table
- Add Alembic migration (002) creating sessions, accounts, verifications
tables and migrating password hashes to accounts table
- Update FastAPI auth dependency to validate sessions via shared DB
(supports both cookie and Bearer token)
- Remove registration/login/refresh endpoints from API gateway (now
handled by Better-Auth service)
- Update frontend to use better-auth/react client with httpOnly cookies
(no tokens in localStorage or memory)
- Rewrite auth store, Login, Register, Dashboard, Settings, ProtectedRoute
to use session-based auth
- Update all tests to create sessions directly in DB instead of JWT tokens
Resolves CAR-27
See plan: CAR-26#document-plan
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Must-fix:
- Exclude JWT token from Zustand persist (partialize) to prevent
localStorage XSS exfiltration — token now lives in memory only
- Wire all pages through TanStack Query hooks (usePurchases, useProduct,
useProducts, usePriceHistory, useCoupons, usePriceAlerts) with proper
loading skeletons and error states
- Add mock interceptor in api.ts (VITE_MOCK_API=true) so mock data flows
through the same fetch path — single flag to switch to live API
Should-fix:
- Wire theme toggle to DOM (dark class on <html>)
- Fix AccountLinking form inputs (controlled with value/onChange)
- Remove unused err in catch blocks (Login, Register)
- Bump remaining min-h-10 touch targets to min-h-12 (48px)
Build: 128KB initial JS, Recharts 498KB lazy chunk. 5/5 tests pass.
Co-Authored-By: Paperclip <noreply@paperclip.ing>