# Issue #277/#302 트러블슈팅 기록: 로그인 후 공백 화면 + 새로고침 시 signin 회귀 ## 기준 시점 - 2026-02-23 KST - 재현 환경: `https://sss.hmac.kr` (WASM 배포) ## 증상 - 로그인 직후 URL은 `/{locale}` 또는 `/{locale}/dashboard`로 보이지만 화면이 렌더링되지 않음 - 이후 새로고침하면 `/{locale}/signin`으로 되돌아감 - 콘솔/백엔드 수집 로그: - `Null check operator used on a null value` - `wasm-function[765]` 포함 스택 반복 ## 스택 매핑 결과 (source-map + no-strip-wasm) - 매핑 커맨드: - `python3 scripts/map_wasm_stack.py --wasm userfront/build/web/main.dart.wasm --sourcemap userfront/build/web/main.dart.wasm.map --frame ...` - 핵심 프레임: - `wasm-function[765]` -> `_TypeError._throwNullCheckErrorWithCurrentStack` - 상위 프레임 -> Flutter `NavigatorState.didUpdateWidget/_updatePages` 경로 - 결론: - 단일 위젯 null 접근보다, 라우트 갱신 타이밍/중복 네비게이션 경쟁에서 `Navigator` 내부에서 터지는 양상 ## 지금까지 시행착오와 실패 내역 1. `LocaleGate`, `LanguageSelector`의 `EasyLocalization.of(context)` null 방어만 적용 - 결과: 동일 예외 재발 - 이유: 루트 원인은 로케일 위젯 단일 null 접근이 아니라 네비게이션 경쟁 구간 2. `/ko` 루트에서 signin 강제 리다이렉트만 강화 - 결과: 최초 진입은 일부 개선됐지만 로그인 직후/새로고침 회귀 지속 - 이유: 로그인 성공 경로가 루트(`/{locale}`)와 엮이면서 라우트 재평가가 중첩 3. 로그인 화면에서 `AuthNotifier.notify()` + `context.go(...)` 동시 수행 - 결과: 간헐적 경쟁 상태 유발 가능성 확인 - 조치: 로컬 네비게이션 1회 가드 도입(`_goLocalizedHomeOnce`) 4. cookie 세션 승격이 토큰 저장 이후 덮어쓰는 경합 - 결과: 일부 흐름에서 저장 상태 불안정 가능성 - 조치: `cookie_session_policy` 추가, 토큰 존재 시 불필요한 cookie 승격 차단 5. `/:locale` 엔트리가 redirect 없이 매칭되는 구조 - 결과: `/ko` 직접 진입 시 페이지 스택 재계산 과정에서 `NavigatorState.didUpdateWidget/_updatePages` 경로 null check 재발 - 이유: `/ko`는 실질 화면이 아닌 분기 지점인데, 명시적 redirect 경로가 없으면 라우트 갱신 타이밍 경쟁에 취약 - 조치: `/:locale`를 redirect 전용 엔트리로 확정(비로그인 `/{locale}/signin`, 로그인 `/{locale}/dashboard`) ## 최종 반영 방향 (이번 패치) 1. 로그인 성공 기본 경로를 명시적으로 `/{locale}/dashboard`로 고정 - `buildLocalizedHomePath()` 반환값을 `/{locale}/dashboard`로 변경 - `/:locale` 엔트리는 `/:locale/dashboard`로 redirect 전용 처리 2. 라우터/화면 역할 분리 - 보호 경로 검사는 router redirect에서 수행 - 대시보드는 필요 시 cookie 세션 복구를 1회 시도 후 signin 이동 3. 중복 네비게이션 억제 - 로그인 성공 시 내부 이동은 1회만 수행 ## 검증 - 추가 테스트: - `userfront/test/login_navigation_race_test.dart` - `userfront/test/cookie_session_policy_test.dart` - `userfront/test/router_redirect_widget_test.dart` (`/{locale}` 직접 진입 시 signin/dashboard 분기 검증) - 갱신 테스트: - `userfront/test/locale_utils_test.dart` (home path `/{locale}/dashboard` 기준) - 실행: - `flutter test` - `flutter test --platform chrome test/router_redirect_widget_test.dart test/login_navigation_race_test.dart test/cookie_session_policy_test.dart` ## 남은 리스크 - 실제 브라우저 저장소 정책(localStorage 차단/쿠키 정책)에 따라 세션 판정이 달라질 수 있음 - 운영 검증 시 네트워크/스토리지 상태를 함께 수집해야 원인 분리 가능 ## 운영 확인 체크리스트 1. 비로그인으로 `/{locale}` 접속 시 즉시 `/{locale}/signin` 이동 2. 로그인 성공 시 `/{locale}/dashboard` 진입 3. `/{locale}/dashboard`에서 새로고침 후 세션 유지 (동일 브라우저) 4. 실패 시 `RECOVERY_NAV_NULL_CHECK`와 wasm frame 동시 수집