로그아웃하고 다른 계정으로 들어갔는데 이전 계정에서 만든 알림이 다시 나타났다. 서버가 잘못 보낸 줄 알았지만 새 계정의 알림 API 응답에는 해당 항목이 없었다. 앱 안에 남아 있던 예약 작업과 로컬 캐시가 로그인 이후 다시 화면을 만들고 있었다.
로그아웃은 인증 정보만 지우는 작업이 아니었다. 사용자 세션 동안 시작한 일의 생명주기를 끝내야 했다.
알림이 만들어지는 경로를 전부 찾았다
알림은 서버 푸시, 주기 조회, 로컬 예약, 화면 복원 네 경로에서 생길 수 있었다. 어느 경로가 마지막으로 항목을 넣는지 출처를 표시해 확인했다.
public record AlarmItem(
string LocalId,
AlarmSource Source,
string OwnerSession,
DateTimeOffset TriggerAt);
실제 로그에는 내용 전문이나 사용자 식별값 대신 세션별 임시 ID와 출처만 남겼다.
구독 해제만으로는 부족했다
로그아웃 때 이벤트 구독을 끊어도 이미 예약된 코루틴과 비동기 작업이 나중에 완료될 수 있었다. 세션 취소 토큰을 전달하고 결과 적용 전에 현재 세션과 같은지 확인했다.
sessionCancellation.Cancel();
alarmPoller.Stop();
localScheduler.ClearForSession(sessionKey);
alarmStore.RemoveUserScopedItems();
다음 로그인에서는 새 토큰과 새 저장소 범위로 시작했다.
유지할 알림과 지울 알림을 나눴다
앱 업데이트처럼 계정과 무관한 시스템 알림은 로그아웃 뒤에도 유지할 수 있었다. 계좌 상태나 거래 관련 알림은 사용자 범위라 반드시 정리해야 했다. 전부 지우거나 전부 남기지 않고 소유 범위를 데이터에 포함했다.
로그아웃, 세션 만료, 다른 계정 로그인, 앱 강제 종료 후 재실행을 각각 확인했다. 종료 경로가 달라도 사용자별 항목이 넘어가지 않아야 했다.
시작한 작업에는 끝내는 규칙이 필요했다
알림 기능을 만들 때 어떻게 받는지에 집중했지 언제 중단되는지는 뒤늦게 봤다. 오래 실행되는 작업은 화면이 닫히는 것, 로그아웃하는 것, 앱이 종료되는 것을 구분해야 했다.
이 문제 이후 백그라운드 작업과 캐시를 추가할 때 소유 세션과 정리 시점을 함께 정한다. 이전 사용자 흔적이 남지 않는 것은 기능 정확성과 개인정보 보호 모두에 필요한 조건이었다.