어떤 기능인가요?
강제 로그아웃이 서버로 올리지 못한 전송 대기 행을 함께 지웁니다. 오프라인에서 만든 타이머가 사용자가 의도하지 않은 경로로 사라질 수 있습니다.
RoomSessionDataCleaner.clearAll()은 database.clearAllTables()입니다. 대기 행과 동기화 완료 행을 구분하지 않습니다. 호출 경로는 ClearSessionUseCase 하나이고, MainViewModel.transitionToLogin()이 그것을 부릅니다. 그런데 transitionToLogin()의 트리거 여섯 개가 전부 사용자가 의도하지 않은 경로입니다.
MainViewModel 줄 |
트리거 |
| 76 |
진입 플로우 catch-all 예외 |
| 86 |
!state.isAuthorized |
| 90 |
getMemberIdUseCase()가 비어 있음 |
| 103 |
invalid_grant |
| 112 |
NoRefreshToken, ConfigError |
| 127 |
forceLogoutFlow |
오프라인을 오래 쓰면 리프레시 토큰이 만료되기 쉽습니다. 그 사용자가 오프라인에서 만든 타이머는 아직 서버에 없는데, 강제 로그아웃 한 번에 알림 없이 사라집니다. 설계 문서 6) 보관 기간은 "동기화 대기(_PENDING) 행은 오래돼도 정리하지 않습니다. 아직 서버에 반영되지 않은 사용자 데이터입니다"라고 정해 두었습니다. 지금 동작은 그 규칙과 어긋납니다.
정리 경로를 세 갈래로 나눕니다.
| 경로 |
처리 |
근거 |
| 명시적 로그아웃, 탈퇴 |
전부 삭제 |
사용자가 의도한 정리. 설계 규칙 D9 |
| 강제 로그아웃(세션 만료 등) |
대기 행 보존, 동기화 완료 행만 삭제 |
의도하지 않은 이탈. 올리지 못한 데이터를 지킴 |
| 계정 전환 |
전부 삭제 |
다른 계정 데이터가 보이면 안 됨. 위험 요소 1 |
같은 계정으로 다시 로그인하면 대기 행이 남아 있어 전송이 이어집니다. 다른 계정으로 로그인하면 AuthRepositoryImpl.checkIsRegistered()가 회원ID 변경을 감지해 전부 지웁니다. #593에서 넣은 경로를 그대로 씁니다.
이 이슈는 정리 범위 분기까지입니다. 전송 자체는 #588에서 다룹니다.
작업 상세 내용
참고할만한 자료(선택)
오프라인 기능 지원 설계 문서의 설계 규칙 D9(로그아웃·탈퇴 시 전부 지움), 6) 보관 기간(대기 행은 정리하지 않음), 위험 요소 1(계정 전환 시 이전 사용자 데이터 노출)이 기준입니다.
D9는 로그아웃과 탈퇴를 대상으로 적었고, 강제 로그아웃을 그 범위에 넣을지는 문서에 없습니다. 이 이슈에서 "의도한 이탈만 전부 지운다"로 좁힙니다.
#588 TimerSyncWorker 설계가 이 결정에 의존합니다. 대기 행을 남기기로 하면 워커는 재로그인 후 이어서 전송해야 하고, 작업 입력의 memberId와 현재 세션을 비교하는 방어가 그대로 유효합니다.
전송 대기 행이 남은 채 사용자가 다시 로그인하지 않으면 행이 영구히 남습니다. 타이머는 계정당 소수라 용량 문제는 없다고 봅니다.
어떤 기능인가요?
강제 로그아웃이 서버로 올리지 못한 전송 대기 행을 함께 지웁니다. 오프라인에서 만든 타이머가 사용자가 의도하지 않은 경로로 사라질 수 있습니다.
RoomSessionDataCleaner.clearAll()은database.clearAllTables()입니다. 대기 행과 동기화 완료 행을 구분하지 않습니다. 호출 경로는ClearSessionUseCase하나이고,MainViewModel.transitionToLogin()이 그것을 부릅니다. 그런데transitionToLogin()의 트리거 여섯 개가 전부 사용자가 의도하지 않은 경로입니다.MainViewModel줄!state.isAuthorizedgetMemberIdUseCase()가 비어 있음invalid_grantNoRefreshToken,ConfigErrorforceLogoutFlow오프라인을 오래 쓰면 리프레시 토큰이 만료되기 쉽습니다. 그 사용자가 오프라인에서 만든 타이머는 아직 서버에 없는데, 강제 로그아웃 한 번에 알림 없이 사라집니다. 설계 문서 6) 보관 기간은 "동기화 대기(
_PENDING) 행은 오래돼도 정리하지 않습니다. 아직 서버에 반영되지 않은 사용자 데이터입니다"라고 정해 두었습니다. 지금 동작은 그 규칙과 어긋납니다.정리 경로를 세 갈래로 나눕니다.
같은 계정으로 다시 로그인하면 대기 행이 남아 있어 전송이 이어집니다. 다른 계정으로 로그인하면
AuthRepositoryImpl.checkIsRegistered()가 회원ID 변경을 감지해 전부 지웁니다. #593에서 넣은 경로를 그대로 씁니다.이 이슈는 정리 범위 분기까지입니다. 전송 자체는 #588에서 다룹니다.
작업 상세 내용
SessionDataCleaner에 동기화 완료 행만 지우는 연산 추가. 기존clearAll()은 그대로 유지ClearSessionUseCase가 명시적 이탈과 강제 이탈을 구분해 정리 범위를 고름MainViewModel.transitionToLogin()은 강제 이탈로 호출. 대기 행을 남김SettingFragment.performLogout의 로그아웃과 탈퇴는 명시적 이탈로 호출. 전부 지움try/finally유지참고할만한 자료(선택)
오프라인 기능 지원 설계 문서의 설계 규칙 D9(로그아웃·탈퇴 시 전부 지움), 6) 보관 기간(대기 행은 정리하지 않음), 위험 요소 1(계정 전환 시 이전 사용자 데이터 노출)이 기준입니다.
D9는 로그아웃과 탈퇴를 대상으로 적었고, 강제 로그아웃을 그 범위에 넣을지는 문서에 없습니다. 이 이슈에서 "의도한 이탈만 전부 지운다"로 좁힙니다.
#588 TimerSyncWorker 설계가 이 결정에 의존합니다. 대기 행을 남기기로 하면 워커는 재로그인 후 이어서 전송해야 하고, 작업 입력의
memberId와 현재 세션을 비교하는 방어가 그대로 유효합니다.전송 대기 행이 남은 채 사용자가 다시 로그인하지 않으면 행이 영구히 남습니다. 타이머는 계정당 소수라 용량 문제는 없다고 봅니다.