client-side router.push races with Set-Cookie processing. redirect() in the
server action sends cookie + redirect in one response — browser applies the
new JWT before navigating, so middleware sees mustChangePassword=false.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After changePassword the API issues a new JWT with mustChangePassword=false.
The server action now reads Set-Cookie from the API response and sets it
in the browser so the middleware sees the updated flag and allows /dashboard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Client-side fetch to NEXT_PUBLIC_API_URL was unreachable in production.
Replace with a server action that uses API_INTERNAL_URL (http://api:3001)
server-to-server — no browser connectivity required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use window.location.href for full page reload after login (ensures auth state)
- Add API_INTERNAL_URL for server-side requests within Docker network
- Remove unnecessary credentials:'include' from SSR fetch calls
- Update planning state for Phase 03 progress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create (auth) route group with standalone layout (no sidebar/header, D-04)
- Create (portal) route group wrapping children with AppShell
- Move dashboard page into (portal) route group
- Add Next.js middleware for JWT-based route protection using jose
- Create session.ts with verifySession/getSessionFromCookies helpers
- Create auth-actions.ts server actions: login, logout, fetchCurrentUser
- Create Zustand auth-store for client-side user state
- Install jose and zod dependencies
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>