앱이 마지막으로 선택한 계좌 순번을 저장하고 있었다. 계좌가 추가되거나 비활성화된 뒤 다시 로그인하면 저장된 순번이 현재 목록 범위를 벗어나거나 전혀 다른 계좌를 가리켰다. 배열 위치를 계좌의 정체성처럼 사용한 것이 문제였다.
목록은 시간에 따라 바뀌지만 저장된 상태는 과거 목록의 모양을 기억하고 있었다.
순번 대신 안정적인 ID를 저장했다
선택 상태에는 목록 인덱스가 아니라 서버가 제공하는 불변 계좌 ID를 저장했다.
Account SelectSaved(
IReadOnlyList<Account> current,
string savedId)
{
return current.FirstOrDefault(x => x.Id == savedId)
?? current.FirstOrDefault(x => x.IsAvailable);
}
저장 ID가 없으면 제품 규칙에 따른 기본 계좌를 선택하고 새 상태를 저장했다.
이전 형식 데이터를 마이그레이션했다
기존 사용자의 설정에는 인덱스만 있었다. 파일 버전을 확인해 당시 목록 정보를 안전하게 복원할 수 있으면 ID로 바꾸고, 확실하지 않으면 기본 계좌로 이동했다.
version 1: selectedIndex
version 2: selectedAccountId
잘못된 인덱스를 억지로 현재 목록에 적용해 다른 계좌를 선택하는 것보다 선택을 초기화하는 편이 안전했다.
개수 변화 시나리오를 만들었다
계좌 추가, 첫 계좌 비활성화, 목록 순서 변경, 계좌 0개, 권한에 따라 일부만 보이는 경우를 확인했다. 로컬 캐시와 서버 응답의 계좌 수가 다를 때는 서버의 현재 목록을 기준으로 선택 상태를 재검증했다.
동일한 계좌가 중복으로 들어오거나 ID는 같지만 표시 속성이 바뀐 경우도 확인했다. 중복은 ID 기준으로 정리하되 어떤 값을 우선할지는 서버 응답 순서가 아니라 명시적인 갱신 규칙을 따랐다. 선택 복원과 목록 정규화를 한 단계에서 뒤섞지 않았다.
화면에는 로컬 선택이 유효한지 확인되기 전 민감한 계좌 데이터를 먼저 표시하지 않았다.
저장 형식 변경 뒤에는 구버전 파일, 이미 새 형식인 파일, 일부만 기록된 파일을 각각 읽었다. 마이그레이션이 여러 번 실행돼도 같은 결과가 나와야 재실행과 앱 강제 종료에 안전했다.
위치와 정체성은 달랐다
배열 인덱스는 화면을 그리는 순간에는 편리하지만 시간이 지나도 같은 대상을 보장하지 않는다. 저장과 API 경계를 넘는 값에는 안정적인 식별자가 필요했다.
이 문제 뒤 목록의 선택 상태를 저장할 때 순서가 바뀔 가능성을 먼저 본다. 과거 상태는 현재 데이터에 그대로 적용하는 값이 아니라 유효성을 다시 확인해야 하는 힌트였다.