기술

데이터 동기화에서 삭제를 반영하니 대조불가 5건이 0건이 됐습니다

2026.10.159분 읽기

프랜차이즈 ERP 는 외부 회계 SaaS 의 원장을 수집해 자체 표에 쌓아 두고, 그 표로 가맹점 채권 현황과 로열티 미납을 봅니다. 어느 날 한 가맹점의 한 달 로열티가 채권 현황 화면에서 '대조불가'로 떴습니다. 금액이 안 맞는 것도 아니고 아예 없는 것도 아니라, 댈 수가 없다는 상태였습니다.

처음 확인한 규모는 전표 네 건이었습니다. 화면에 대조불가로 뜬 행은 운영 전체로 다섯이었는데, 그 차이를 그때는 보지 않았습니다. 그래서 자료 하나가 꼬인 문제로 읽었습니다. 그것이 첫 번째 오판이었습니다.


수집기는 넣고 고치기만 했습니다

원인은 외부 회계 SaaS 에서 지운 전표가 우리 원장 표에 그대로 남아 있는 것이었습니다. 수집기에는 새로 생긴 전표를 넣는 길과 바뀐 전표를 고치는 길이 있었고, 삭제를 반영할 길은 아예 없었습니다. 넣기와 고치기는 응답에 값이 들어오니 자연히 코드가 생기는데, 삭제는 응답에 안 오는 것이라 코드에 자리가 안 생깁니다.

실제 규모는 네 건이 아니었습니다. 한 달치 로열티 일괄 발행분 전량이었습니다. 상대 쪽 담당자가 그 발행분을 두 차례에 걸쳐 지우고 새 번호로 다시 넣는 중이었고, 그 사이 우리 표에는 지운 것과 다시 넣은 것이 겹쳐 쌓였습니다. 발행 대상은 수백 곳 규모였고 상대 쪽 입력은 아직 진행 중일 수 있는 상태였습니다.

규모가 바뀌면 처방도 바뀝니다. 네 건이었다면 손으로 지우고 끝났을 일입니다. 한 달치 일괄 발행분이고 상대가 아직 작업 중이라면, 수집기가 삭제를 스스로 알아내는 길을 만들어야 합니다.

외부 시스템 수집기에 넣기와 고치기만 있고 삭제 반영 경로가 비어 있어 지워진 전표가 우리 표에 남는 구조


상대가 알려주는 삭제 이력은 절반만 쓸 수 있었습니다

먼저 상대 시스템이 알려주는 값으로 판정할 수 있는지 봤습니다. 삭제 전표를 복구해 주는 화면의 응답에 수정 시각과 수정자 칸이 있었습니다. 이것이 있으면 언제 누가 지웠는지까지 남으니 가장 깔끔한 방법입니다.

그런데 다른 메뉴에서 전송된 전표는 그 칸에 기록이 남지 않았습니다. 문제가 된 로열티 전표가 바로 그 종류였습니다. 가장 필요한 자리에서만 못 쓰는 수단이라 버렸습니다. 대신 거래처 원장 화면을 직접 열어 그 전표가 없는 것을 눈으로 확인했습니다.

남은 방법은 응답 대조입니다. 연도별로 원장을 다시 받아, 우리 표에 있는데 응답에 없는 전표를 지워진 것으로 보는 방식입니다. 모든 종류의 전표에 통합니다. 대신 위험이 한 방향으로 큽니다.

판정 방법

쓸 수 있는 범위

위험

상대의 수정 시각·수정자

일부 전표만 — 다른 메뉴 전송분은 기록이 없음

낮음. 다만 가장 필요한 전표에 기록이 없었음

응답에 없으면 지워진 것

모든 전표

응답이 덜 와도, 조회 조건이 어긋나도 멀쩡한 전표를 지워진 것으로 표시함

상대가 덜 준 것과 상대가 지운 것은 우리 눈에 똑같이 보입니다. 상대 시스템이 왜 덜 줬는지는 우리가 알 수 없습니다. 그래서 응답 대조로 가면서, 그것만으로는 쓰지 않는다는 조건을 같이 걸었습니다.

수집한 값이 조용히 빠지는 자리는 삭제만이 아닙니다. 상태 필터가 모르는 값 하나를 만나 반년치 자료가 조용히 빠져 있던 기록이 있습니다.

상대의 수정 이력으로 판정하는 방법과 응답에 없으면 지워진 것으로 보는 방법의 좌우 비교


합이 맞을 때만 지웁니다

응답 대조에 독립된 검증 수단을 붙였습니다. 같은 로그인으로 받을 수 있는 잔액입니다. 계정과 연도의 조합마다 사라진 전표를 뺀 거래처별 차변·대변 합을 구하고, 그것이 받아온 잔액과 전부 맞을 때만 '지워짐'으로 표시합니다. 응답이 덜 왔다면 합이 안 맞으니 그 자리에서 걸립니다.

애매할 때 멈추는 쪽으로 기본값을 뒀습니다.

합이 하나라도 안 맞으면 아무것도 지우지 않고 알람을 올립니다 — 검증하지 못한 삭제 후보가 있다는 알람입니다

잔액을 받을 수 없는 연도는 한 번에 지울 수 있는 건수에 상한을 둡니다(10건 또는 전체의 5% 중 큰 쪽)

응답이 목록 모양이 아니면 그대로 예외로 떨어뜨립니다 — 빈 응답을 전부 지워졌다고 읽는 것이 가장 큰 사고입니다

다시 들어온 전표는 되살립니다 — 상대 쪽이 지우고 다시 넣는 중이라 이 되살림이 실제로 쓰였습니다

우리 표에는 살아 있는지를 표시하는 칸을 하나 더했습니다. 기본값은 살아 있음이고, 운영 DDL 은 승인을 받고 실행했습니다. 수집기는 작년과 올해를 연도별로 매번 다시 수집하도록 바꿨습니다.

응답 대조로 찾은 삭제 후보를 잔액 합과 교차 검증해 통과할 때만 지우고 안 맞으면 알람을 올리는 판정 흐름


칸을 더하는 일은 읽는 쪽을 전부 세는 일입니다

상태 칸을 더하고 읽는 쿼리를 하나라도 빠뜨리면, 틀린 숫자가 조용히 화면으로 나갑니다. 그 표를 읽는 쿼리 여섯 곳(채권 현황 4곳, 로열티 미납 2곳)에 살아 있는 것만 보는 조건을 넣었습니다. 그리고 그 표를 읽는 쿼리 수와 살아 있는 것만 보는 조건이 걸린 쿼리 수를 맞춰 보는 테스트를 붙였습니다.

테스트를 옛 코드에 대고 돌려 실패하는 것을 먼저 확인했습니다. 이 순서를 밟지 않으면 그 테스트가 무엇을 막는지 알 수 없습니다. 조건을 빼먹은 쿼리가 나중에 하나 생기면 이 테스트가 잡습니다.

지운 것의 파급이 엉뚱한 화면에서 드러나기도 합니다. 항목 하나를 지웠더니 지난달 손익이 같이 사라졌던 기록이 있습니다.

수집 한 번으로 그 발행분 전량이 지워짐으로 반영됐습니다. 교차 검증은 대조한 거래처 전부에서 통과했고, 네 해 치 데이터의 모든 계정에서 거래처 불일치와 우리 표에만 있는 거래처가 각각 0이었습니다. 알람은 올라오지 않았습니다.

운영 채권 현황

전

후

일치

대부분

전량

불일치

236

0

대조불가

5

0

남긴 흔적은 셋입니다. 표의 새 칸, 알람 하나, 그리고 쿼리를 빠뜨리면 실패하는 테스트입니다.


남은 한계

이 처방이 모든 연도에 걸려 있는 것은 아닙니다. 몇 해 이전 자료는 상대 쪽이 전표 조회에 0건을 돌려줍니다. 회계 기수 문제로 추정하지만 확인하지 않았습니다. 그래서 그 연도는 다시 수집하지 못하고 잔액 스냅샷도 없습니다. 옛 연도에는 이 처방이 안 걸려 있는 상태입니다.

잔액이라는 독립된 검증 수단이 있어야 성립하는 방식이기도 합니다. 합을 맞춰 볼 값이 없는 도메인에서는 응답에 없으면 지워진 것이라는 판정을 그대로 쓸 수 없습니다. 그때는 건수 상한 같은 약한 가드만 남는데, 그것은 사고를 늦출 뿐 막지는 못합니다.

상대 쪽이 작업 중이면 우리 표는 계속 흔들립니다. 이번에도 입력이 진행 중이어서, 지금 맞다는 결과가 다음 수집에서 또 바뀔 수 있는 상태였습니다. 한 시점의 일치를 완료로 읽으면 안 됩니다. 수집 비용도 늘었습니다. 삭제를 알려면 전체를 다시 받아야 해서 연도별 전량 재수집으로 바꿨고, 데이터가 더 커지면 이 방식 자체가 먼저 한계에 닿습니다.


외부 데이터를 수집해 쓰는 팀이 점검할 것

수집기에 삭제를 반영하는 길이 있습니까. 없으면 지금 우리 표에는 상대가 지운 데이터가 남아 있습니다

지워진 것을 무엇으로 판정합니까. 상대가 삭제 이력을 주는지, 모든 종류의 데이터에 다 주는지를 따로 확인합니다

응답에 없으면 지워진 것으로 볼 때, 합을 맞춰 볼 독립된 값을 같이 받습니까

검증에 실패하면 멈추고 알리는 쪽이 기본값입니까. 빈 응답과 모양이 다른 응답을 각각 어떻게 처리하는지 적어 둡니다

상태 칸을 더했다면 그 표를 읽는 쿼리를 전부 셌습니까. 빠뜨리면 실패하는 테스트를 붙이고 옛 코드에 대고 돌려 봅니다

대조가 안 맞을 때는 금액 계산을 먼저 의심하기 쉽습니다. 이번 건은 계산이 아니라 우리 표에 남아 있던 데이터가 원인이었고, 그 틀어짐이 대조불가라는 애매한 모양으로 나타나 원인을 가렸습니다. 외부 데이터를 수집해 쌓는 표를 만들 때, 지워진 것은 어떻게 아는가를 한 줄 적어 두면 이 사고를 한 번에 막을 수 있습니다.

#데이터동기화#삭제반영#소프트삭제#정합성#교차검증