관리 화면이나 다른 기기에서 세션 상태가 바뀌면 현재 앱은 그 사실을 늦게 알 수 있었다. 실시간 연결이 살아 있으면 이벤트를 받았지만 연결이 잠깐 끊겼다면 다음 API 요청에서 인증 오류가 날 때까지 화면은 로그인 상태처럼 보였다. 두 경로의 사용자 안내도 달랐다.
세션 변경을 특정 팝업 이벤트가 아니라 앱 전체 인증 상태의 전이로 다뤄야 했다.
여러 신호를 하나의 전이로 모았다
실시간 세션 종료 이벤트, API의 인증 실패, 주기 세션 확인 결과가 같은 상태 변경 함수를 호출했다.
void InvalidateSession(SessionEndReason reason)
{
if (session.State == SessionState.Invalid) return;
session.MarkInvalid(reason);
requests.CancelAll();
navigator.ShowSessionEnded(reason);
}
중복 신호가 와도 요청 취소와 화면 이동은 한 번만 실행됐다.
세션 종료 처리를 특정 화면 객체에 두지 않고 앱 수명의 서비스에 두었다. 로그인 화면 위에 있거나 앱이 백그라운드인 경우에도 상태는 먼저 바뀌고, 화면이 활성화되면 안전한 안내를 한 번 표시했다. 이벤트 수신 시점과 UI 표시 시점을 분리했다.
이유와 공개 가능한 안내를 분리했다
내부적으로는 권한 변경, 다른 로그인, 관리자 종료, 만료를 구분했다. 사용자에게 그대로 노출하면 불필요한 정보가 될 수 있어 제품 정책에 맞는 안내 문구로 변환했다.
로그에도 세션 종료 분류와 요청 ID만 남기고 토큰이나 계정 값은 기록하지 않았다.
중요한 작업의 결과를 확인했다
세션이 바뀌는 순간 전송 중이던 요청은 서버에서 처리됐지만 응답을 못 받았을 수 있었다. 특히 중복 실행 영향이 있는 작업은 새로 로그인한 뒤 무작정 재시도하지 않고 조회 API나 작업 ID로 결과를 확인했다.
단순 조회는 새 세션에서 다시 불러오고, 입력 중이던 값은 민감도와 화면 정책에 따라 복원하거나 폐기했다.
테스트에서는 실시간 연결이 정상인 경우, 연결이 끊긴 사이 변경된 경우, API 요청 도중 변경된 경우를 나눴다. 같은 최종 상태에 도달하되 중복 팝업이나 자동 재연결이 없어야 했다.
인증 변경은 전역 이벤트였다
팝업 하나를 띄우는 것으로 끝내면 백그라운드 요청과 실시간 구독이 계속 움직일 수 있었다. 세션 상태를 먼저 바꾸고 모든 데이터 경로가 이를 따르게 해야 했다.
이 작업을 통해 보안 이벤트와 사용자 경험이 따로 있지 않다는 걸 배웠다. 권한을 즉시 막으면서도 사용자가 왜 다시 로그인해야 하고 진행 중 작업은 어떻게 됐는지 이해할 수 있어야 했다.