거래처 담당자가 고객 목록을 엑셀로 올렸습니다. 화면에는 ‘업로드 성공’이 떴는데, 다음 날 동일 고객이 두 번 보이고 일부 전화번호의 앞자리 0이 사라졌습니다. 이때 문제는 CSV 파서 하나가 아닙니다. 파일의 값을 언제부터 운영 데이터로 믿을 것인가라는 경계가 빠진 것입니다.
가져오기는 파일 처리보다 변경 관리에 가깝다
파일을 받는 순간부터 행 하나가 실제 고객, 주문, 재고를 바꿀 수 있습니다. 그래서 먼저 네 가지를 정해야 합니다. 기존 데이터에 덮어쓸지, 새로운 항목만 추가할지, 일부 오류가 있어도 정상 행은 반영할지, 잘못 반영되면 무엇을 되돌릴지입니다. 이 정책이 없으면 같은 파일을 재업로드할 때 결과가 달라집니다.
예를 들어 고객사별 품목 코드가 유일해야 한다면 고유 키는 ‘고객사 + 품목 코드’일 수 있습니다. 이름만 같은 품목은 다른 것일 수도 있습니다. 데이터베이스의 제약과 사용자 화면의 중복 안내가 같은 기준을 써야 합니다. 사람이 이해하는 중복과 시스템이 판단하는 중복을 따로 두면 이력이 쉽게 꼬입니다.
첫 단계: 업로드는 격리하고 형식을 확인한다
원본 파일은 바로 운영 테이블에 넣지 말고 업로드 작업 ID를 붙여 임시 영역에 둡니다. 파일 크기·확장자·실제 형식·인코딩·열 개수·헤더를 확인합니다. CSV의 쉼표, 따옴표, 줄바꿈은 단순한 문자열 분리로 처리하면 깨질 수 있으므로 표준 파서를 사용합니다. 엑셀의 날짜·전화번호·품목 코드는 화면에 보이는 값과 내부 셀 값이 다를 수 있어, 업무상 문자열이어야 할 열을 명시해야 합니다.
OWASP는 파일 업로드에서 허용 형식 목록, 실제 파일 유형 확인, 크기 제한, 권한 확인, 애플리케이션이 생성한 파일명을 권합니다. 파일명이나 브라우저가 보낸 Content-Type만 믿으면 안 됩니다. OWASP 파일 업로드 가이드를 입력 경계의 출발점으로 삼을 수 있습니다.

두 번째 단계: 오류는 ‘몇 건’보다 ‘어느 행의 무엇’인지
검증은 형식, 참조, 업무 규칙으로 나눠야 이해하기 쉽습니다. 형식 오류는 필수 열 누락이나 잘못된 날짜입니다. 참조 오류는 존재하지 않는 거래처 코드입니다. 업무 규칙 오류는 이미 마감된 주문을 수정하려는 경우입니다. 오류 보고서에는 행 번호, 열 이름, 입력값의 안전한 일부, 실패 이유, 수정 방법을 남깁니다. 민감정보를 오류 로그에 그대로 복제하지는 않습니다.
대량 업로드에서 ‘첫 오류 하나만’ 보여주면 사용자는 파일을 수십 번 다시 올려야 합니다. 가능한 오류를 한 번에 수집하되, 너무 큰 파일에는 처리 상한을 둡니다. 특히 중복은 파일 내부 중복과 기존 데이터 중복을 별도로 보여줘야 합니다. 두 경우의 해결책이 다르기 때문입니다.
세 번째 단계: 미리보기와 확정을 분리한다
미리보기에는 신규·수정·건너뛰기·오류 건수와 대표 사례를 보여줍니다. 확정 버튼을 누르면 서버는 미리보기 때의 파일 해시, 매핑 설정, 대상 데이터 버전을 다시 검사합니다. 검토 중 다른 사용자가 같은 데이터를 바꿨다면 오래된 미리보기를 그대로 확정해서는 안 됩니다.
처리 방식은 규모에 따라 달라집니다. 작은 작업은 한 트랜잭션으로 전부 반영하거나 전부 실패시키는 편이 단순합니다. 큰 작업은 묶음으로 처리하면서 행별 결과를 기록할 수 있지만, 이 경우 ‘부분 성공’을 제품 규칙으로 명시해야 합니다. 어느 방식이든 같은 업로드 작업 ID를 다시 실행했을 때 중복 삽입이 일어나지 않도록 설계합니다.

복구와 감사 기록까지 있어야 완료다
되돌리기는 단순히 ‘방금 입력한 행 삭제’가 아닐 수 있습니다. 기존 값을 수정했다면 이전 값을 보관해야 하고, 그 뒤 다른 사용자가 고친 데이터는 무작정 덮으면 안 됩니다. 그래서 업로드 작업별 변경 내역과 원래 값, 확정자, 확정 시각을 기록합니다. 복구 버튼을 제공하지 못하더라도 운영자가 영향 범위를 식별할 수 있어야 합니다.
마지막으로 업로드된 문자열이 언젠가 CSV로 다시 내보내질 수 있다는 점도 기억해야 합니다. 스프레드시트에서 수식으로 해석될 수 있는 값은 출력 시 별도 방어가 필요합니다. OWASP의 CSV Injection 설명처럼 입력 검증과 안전한 내보내기는 서로 다른 경계입니다.
실제 도입에서는 작은 파일로 규칙부터 합의한다
처음부터 모든 엑셀 양식을 허용하지 않는 편이 좋습니다. 샘플 파일 한 장을 만들고 필수 열, 허용 값, 날짜 표기, 중복 키를 고객과 함께 확인합니다. 특히 ‘빈칸’이 기존 값을 지우라는 뜻인지, 그대로 두라는 뜻인지 합의해야 합니다. 숫자처럼 보이는 전화번호나 우편번호도 산술 값으로 취급하지 않습니다. 이 규칙을 양식에 표시하면 오류를 서버에서 잡기 전에 사용자가 예방할 수 있습니다.
운영 지표는 업로드 성공률만 보지 말고, 자주 실패하는 열과 수정 후 재업로드 횟수를 함께 봅니다. 특정 열에서 오류가 반복되면 검증 메시지가 모호하거나 양식이 현장 데이터와 맞지 않는다는 신호입니다. 파서 성능보다 이런 피드백이 업무 시간을 더 크게 줄일 때가 많습니다.
도입 체크리스트
- 업무 키와 중복 시 정책을 문서화했는가?
- 원본 파일을 격리하고 파일 형식·크기·권한을 검증하는가?
- 오류를 행·열·원인별로 한 번에 확인할 수 있는가?
- 미리보기 후 확정 시 데이터가 바뀌었는지 재검사하는가?
- 재시도, 부분 실패, 변경 이력, 복구 범위가 정의돼 있는가?
좋은 가져오기 기능의 기준은 ‘파일을 읽었다’가 아닙니다. 사용자가 무엇이 바뀔지 알고 확정했으며, 문제가 생겼을 때 어떤 행이 바뀌었는지 설명할 수 있는 상태입니다.
#CSV가져오기 #엑셀업로드 #데이터임포트 #데이터검증 #중복처리 #대량등록 #업로드미리보기 #데이터품질 #업무시스템 #보안설계