Repository navigation
fix(core): 로그아웃 응답을 기다리는 동안 설정 화면을 떠나면 로컬 세션 정리가 취소된다 #2243
Description
작업 유형
bug — 버그·오동작
주 담당 모듈
core — 코어
개요
설정에서 로그아웃을 확인한 뒤 서버 응답을 기다리는 동안 뒤로가기로 설정 화면을 떠나면 로그아웃이 끝나지 않은 채 사라집니다. 서버는 로그아웃을 처리해 refresh 토큰을 지웠고 푸시 대상(DELETE users/push-tokens)도 해제됐는데, 앱에는 토큰과 로그인 상태가 그대로 남습니다. 다음 재기동에서 앱은 홈으로 들어가고 해제했던 푸시 대상을 다시 등록합니다. 액세스 토큰 수명(서버 설정 JWT_ACCESS_EXPIRATION, 배포 예시 설정 기준 1시간)이 다할 때 재발급이 400/1107 로 거절되어 그제서야 강제 로그아웃됩니다. 선제 재발급 deadline 이 살아 있는 프로세스라면 만료 60초 전 선제 재발급에서 같은 거절을 받습니다.
기준과 원인
2026-10-03 확인 기준은 develop 756e456f1f4d280a630fcbe119bb1645e683f97e입니다.
SettingViewModel.logout79~85행은viewModelScope.launch안에서authRepository.logout()을 기다립니다. 설정 홈의SettingViewModel은 설정 홈 entry 범위입니다. 설정 로컬 스택이 홈 하나뿐일 때 시스템 뒤로가기는 루트 NavHost 로 흘러Route.Settinghost 가 루트 백스택에서 빠지고, 그 ViewModelStore 와 함께 이 ViewModel 이 정리되어 코루틴이 취소됩니다. 설정 안에서 더 깊이 들어가는 이동은 ViewModel 을 살려 두므로 취소는 host 이탈에서만 납니다.AuthRepositoryImpl.logout132~147행은runCatchingCancellable로 감싸CancellationException을 그대로 던집니다. HTTP 대기 중 취소되면 뒤의localStoreRegistry.clearScope(StoreScope.SESSION)과expiryTracker.clear()가 실행되지 않습니다. KDoc 의 "SESSION 스코프 로컬 저장소와 선제 reissue deadline 은 서버 호출 결과와 무관하게 항상 정리한다" 는 계약이 호출자 취소에는 지켜지지 않습니다.- 서버(Afternote-BE origin/main
6adc0c4AuthService.logout)는 요청을 받은 이상 refresh 를 삭제합니다. 클라이언트의 취소는 서버에 전달되지 않습니다.
재현 순서
Android API 36 에뮬레이터에 756e456 빌드(서버 주소 상수와 cleartext 허용만 로컬 모의 서버용으로 바꿈)를 설치하고, 모의 서버가 POST auth/logout 처리를 해제 신호까지 보류하도록 했습니다. 실측에서는 도착 6초 뒤에 해제했습니다.
- A 세션으로 홈 진입 → 설정 → 로그아웃 → 예. DELETE users/push-tokens 200, POST auth/logout 도착.
- 응답을 기다리는 동안 뒤로가기 → 홈. 홈 재조회가 A 토큰으로 200.
- 서버가 로그아웃을 처리(refresh 삭제, 200 응답).
- 앱 상태를 읽습니다.
기대 결과는 로그아웃 확인 뒤에는 어디로 이동하든 로컬 세션이 정리되고 온보딩으로 가는 것입니다. 실제 결과는 홈 유지, DataStore 의 access·refresh·session_id 전부 그대로, 콜드 스타트도 홈, 기동 시 PUT users/push-tokens 로 푸시 대상 재등록입니다. 서버 쪽은 refresh 가 삭제된 상태입니다.
모의 서버 로그(발췌):
08:39:50.414 DELETE /users/push-tokens A-access-1 -> 200 (로그아웃 '예')
08:39:52.500 GET /users/me A-access-1 -> 200 (뒤로가기 → 홈 재조회)
08:39:56.483 POST /auth/logout A-access-1 -> 200 (6064ms 보류 후 처리, refresh 삭제)
08:40:05.987 GET /app/version A-access-1 -> 200 (콜드 스타트: 홈)
08:40:06.489 PUT /users/push-tokens A-access-1 -> 200 (푸시 대상 재등록)
완료 조건
- 로그아웃 확인 뒤 호출한 화면·ViewModel 이 사라져도 로컬 세션 정리와 로그인 상태 전환이 끝납니다.
- 로그아웃 HTTP 가 취소되거나 실패해도 로컬 정리는 실행됩니다(기존 best-effort 계약 유지).
- 호출자가 취소되는 중의 로그아웃을 회귀 테스트로 검증합니다.
참고
- fix(core): 로그아웃 뒤 늦은 재발급 성공이 이전 세션을 복원한다 #2237, fix(core): 이전 세션의 재발급 거절이 새 로그인 세션을 삭제한다 #2238 의 Android 재현 중 발견했습니다. 증거는 로컬 감사 폴더
.personal-harness/audits/2026-10-03-bug-audit/android-session-repro/의 logs/scenario3-run-stdout.txt(실행 stdout 전문)·logs/scenario3-requests.jsonl·harness/scenario3.sh·shots/s3-*.png 입니다. - fix(core): AuthRepository.logout() 토큰 정리 누락 + Result 이중 wrap #163 은
logout()의 토큰 정리 누락, 로그아웃 시 로컬 저장소 3개가 지워지지 않음 — DataStore 수명(scope) 계약 도입 #912 는 SESSION 스코프 일괄 정리를 다뤘고 호출자 취소는 다루지 않았습니다. - 설정 MVI 전환(fix: 설정 조회 오류·재시도와 저장 실패 안내 연결 (#708) #2231)과 무관하게 core 의 logout 계약 결함입니다. 화면 쪽 배선 변경은 완료 조건에 넣지 않습니다.
Activity
github-actions commentedon Oct 2, 2026
bug 이슈는 사이드바 Fields > Priority 로 심각도를 지정해야 합니다. 판정 기준:
값이 비어 있어도 이슈를 닫지는 않습니다. 이 안내는 이슈당 한 번만 답니다.