- Add emailVerification.sendVerificationEmail config to auth/src/auth.ts
using Resend to send verification emails on sign-up
- Add resend npm package to auth/package.json
- Update auth/.env.example with RESEND_API_KEY and FROM_EMAIL
- Create VerifyEmail.tsx page with token verification flow,
spinner UX, success/Error states, and resend option
- Update Register.tsx to redirect to /verify-email after signup
instead of auto-navigating to dashboard
- Add /verify-email route to App.tsx
- Frontend shows 'check your email' step after registration
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Promotes UAT to main including PR #209 (N+1 UPC query fix with SQL containment).
UAT regression: passed (Deal Dottie)
Security review: passed (Stockboy Steve)
CI required checks: all green
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merges Grype-based container image vulnerability scanning and Docker CVE remediation to production.
- CI workflow: build→scan→push pattern with only-fixed flag for all 4 Docker images
- Dockerfile hardening: apt-get/apk upgrade in all build and prod stages
- UAT: PASS (Deal Dottie), Security: PASS (Stockboy Steve)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Vite 6.4.1 has two high-severity vulnerabilities:
- GHSA-4w7w-66w2-5vf9: Path Traversal in Optimized Deps .map Handling
- GHSA-p9ff-h696-f583: Arbitrary File Read via Vite Dev Server WebSocket
Updated to vite 6.4.2.
Fixes CAR-599.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
CTO review: LGTM. CORS methods restricted to explicit list (no TRACE/CONNECT), headers whitelisted, nginx security headers added (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, CSP). Clean diff, CI green.
- Override brace-expansion to >=1.1.13 to resolve GHSA-f886-m6hf-6m8v
- Override lodash to >=4.17.24 to resolve GHSA-r5fr-rjxr-66jc and GHSA-f23m-r3pf-42rh
- Override minimatch to ^10.2.4 to maintain compatibility with brace-expansion@5.x
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: CartSnitch Engineer Bot <cartnoreply@cartsnitch.com>
The GET /me/email-in-address endpoint was unreachable because the Gateway
HTTPRoute routes all /auth/* traffic to Better-Auth (port 3001), not the
API service. This change:
- Moves the endpoint from the /auth router to a new /api/v1/me/ router
- Adds EmailInAddressResponse schema and get_email_in_address service method
- Updates Settings.tsx to call /api/v1/me/email-in-address
Fixes CAR-445.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix(api): replace UUID type with str for Better-Auth nanoid user IDs
Better-Auth uses nanoid strings for user IDs, not UUIDs. Changed all
user_id parameter/return types in the API layer from UUID to str,
removed the obsolete UUID import where unused, and updated the
_validate_session_token return type accordingly.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* feat(scripts): add dev environment seed script and K8s Job
Co-Authored-By: Paperclip <noreply@paperclip.ing>
---------
Co-authored-by: CartSnitch Engineer Bot <cartnoreply@cartsnitch.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Removes the unused `import React from 'react'` line from Dashboard.tsx
to resolve TS6133 error in lighthouse CI. No other code in the file
references the React namespace.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Removed usePriceHistory calls with hardcoded string product IDs (prod1, prod10)
that caused 422 errors against the UUID-expecting API. The Price Trends section
now shows a placeholder until a proper featured-products endpoint is available.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Change frontend to call /alerts (was /price-alerts) and /products/{id}/prices
(was /products/{id}/price-history) to match the backend router mounts.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
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>