fix(03): login redirect + API internal URL for Docker networking

- 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>
This commit is contained in:
2026-06-20 09:28:05 +02:00
parent f5a775c0df
commit 46a6e277b8
5 changed files with 11 additions and 12 deletions
+5 -5
View File
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
milestone: v1.0 milestone: v1.0
milestone_name: milestone milestone_name: milestone
status: executing status: executing
stopped_at: Completed 02-02-PLAN.md stopped_at: context exhaustion at 75% (2026-06-19)
last_updated: "2026-06-19T10:27:41.286Z" last_updated: "2026-06-19T12:37:50.398Z"
last_activity: 2026-06-19 -- Phase 03 execution started last_activity: 2026-06-19 -- Phase 03 execution started
progress: progress:
total_phases: 6 total_phases: 6
completed_phases: 1 completed_phases: 1
total_plans: 12 total_plans: 12
completed_plans: 7 completed_plans: 10
percent: 17 percent: 17
--- ---
@@ -93,6 +93,6 @@ Items acknowledged and carried forward from previous milestone close:
## Session Continuity ## Session Continuity
Last session: 2026-06-18T11:41:48.372Z Last session: 2026-06-19T12:37:50.391Z
Stopped at: Completed 02-02-PLAN.md Stopped at: context exhaustion at 75% (2026-06-19)
Resume file: None Resume file: None
+2 -1
View File
@@ -45,7 +45,8 @@
"post_planning_gaps": true, "post_planning_gaps": true,
"security_enforcement": true, "security_enforcement": true,
"security_asvs_level": 1, "security_asvs_level": 1,
"security_block_on": "high" "security_block_on": "high",
"_auto_chain_active": false
}, },
"ship": { "ship": {
"pr_body_sections": [ "pr_body_sections": [
+1 -2
View File
@@ -27,8 +27,7 @@ export default function LoginPage() {
startTransition(async () => { startTransition(async () => {
const result = await login(formData); const result = await login(formData);
if (result.success) { if (result.success) {
router.push('/'); window.location.href = '/';
router.refresh();
} else { } else {
setError(result.error ?? 'invalidCredentials'); setError(result.error ?? 'invalidCredentials');
} }
+1 -4
View File
@@ -3,7 +3,7 @@
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'; const API_URL = process.env.API_INTERNAL_URL || process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
export interface AuthUser { export interface AuthUser {
id: string; id: string;
@@ -39,7 +39,6 @@ export async function login(formData: FormData): Promise<LoginResult> {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }), body: JSON.stringify({ username, password }),
credentials: 'include',
}); });
if (!response.ok) { if (!response.ok) {
@@ -51,7 +50,6 @@ export async function login(formData: FormData): Promise<LoginResult> {
// Forward the session cookie from the API response to the browser // Forward the session cookie from the API response to the browser
const setCookieHeader = response.headers.get('set-cookie'); const setCookieHeader = response.headers.get('set-cookie');
if (setCookieHeader) { if (setCookieHeader) {
// Parse the session cookie value from the API response
const sessionMatch = setCookieHeader.match(/session=([^;]+)/); const sessionMatch = setCookieHeader.match(/session=([^;]+)/);
if (sessionMatch) { if (sessionMatch) {
const cookieStore = await cookies(); const cookieStore = await cookies();
@@ -59,7 +57,6 @@ export async function login(formData: FormData): Promise<LoginResult> {
httpOnly: true, httpOnly: true,
secure: process.env.NODE_ENV === 'production', secure: process.env.NODE_ENV === 'production',
sameSite: 'lax', sameSite: 'lax',
// D-02: 30 days if rememberMe, otherwise session cookie (browser close)
...(rememberMe ...(rememberMe
? { maxAge: 30 * 24 * 60 * 60 } ? { maxAge: 30 * 24 * 60 * 60 }
: {}), : {}),
+2
View File
@@ -8,6 +8,8 @@ services:
environment: environment:
HOSTNAME: "0.0.0.0" HOSTNAME: "0.0.0.0"
NEXT_PUBLIC_API_URL: "http://localhost:3001" NEXT_PUBLIC_API_URL: "http://localhost:3001"
API_INTERNAL_URL: "http://api:3001"
JWT_SECRET: ${JWT_SECRET:-tessera-dev-jwt-secret-change-in-production}
networks: networks:
- frontend-net - frontend-net
- backend-net - backend-net