포스트

차돈 제작기 #2 - 갈아타기, 이중 백업, 그리고 문자 발송

차돈 제작기 #2 - 갈아타기, 이중 백업, 그리고 문자 발송

차돈 제작기 #2 - 갈아타기, 이중 백업, 그리고 문자 발송

이전 글에서는 차돈의 스택 선택과 정비일지 중심 데이터 모델을 정리했다.

이번 글은 그 다음 단계다. 기능이 다 돌아가도 정비소는 넘어오지 않는다. 이유는 하나다.

1
몇 년치 장부가 이미 다른 프로그램 안에 있다.

그래서 이번 글의 주제는 기능이 아니라 데이터의 이동이다. 남의 프로그램에서 가져오고, 잃어버리지 않게 지키고, 밖에서도 볼 수 있게 하는 일.


1. 타 앱 자료 가져오기: 통로는 CSV였다

기존 사용자들은 Highway5/BizHigh5 같은 다른 정비 프로그램을 쓰고 있었다.

그런데 이런 프로그램의 내부 DB는 대부분 비공개(독점) 형식이라 직접 열 수 없다. 대신 어느 프로그램이든 있는 엑셀(CSV) 내보내기 기능을 통로로 삼았다.

1
2
3
4
5
타 앱에서 CSV/XLSX 내보내기
→ 차돈 마법사에서 파일 선택
→ 열 이름(차량번호, 고객명, 정비금액, RoNo...) 자동 인식
→ 매핑을 직접 수정하고 미리보기 확인
→ 반입

여기서 실제로 발목을 잡은 것은 형식이 아니라 인코딩이었다. 한글 CSV는 프로그램마다 cp949, euc-kr, utf-8이 제각각이라 자동 인식하게 했다.

열 자동 인식도 절대 100%를 믿지 않았다. 자동 매핑은 초안일 뿐이고, 반입 전에 사람이 매핑을 고치고 미리보기로 확인하는 단계를 반드시 거친다. 남의 몇 년치 장부를 한 번에 들이붓는 작업에서 “아마 맞겠지”는 없다.

반입 규칙도 정비일지 데이터 모델과 맞물리게 했다.

  • 반입된 정비일지의 입금액은 계산금액으로 기록되어 결산·매출통계에 그대로 반영된다
  • 매입일지를 반입하면 부품 기준정보가 자동 등록되고 재고가 늘어난다
  • 같은 이름의 부품(띄어쓰기 무시)은 중복 등록하지 않고 기준정보만 갱신한다

CSV보다 한 단계 더 나간 것이 하이웨이 .db 백업 파일 직접 반입이다. 이 경우에도 매입 전표가 부품 재고로 쌓이고, 정비 세부내역 중 부품명이 기준정보와 일치하는 항목은 재고에서 차감된다. 반입이 끝난 순간부터 재고 화면이 실제 재고에 가깝게 맞춰져 있도록.

갈아타는 비용을 줄이는 것이 신규 사용자 확보의 절반이었다.


2. 백업은 로컬 + 클라우드 이중으로

정비소 데이터는 곧 돈이다. PC가 고장 나면 몇 년치 장부가 날아간다.

그래서 백업을 두 겹으로 만들었다.

방식
로컬data/backups/에 저장, 최근 30개 보관
클라우드DB를 gzip 압축해 Cloudflare KV에 업로드, 인증키당 최대 10개

클라우드 쪽은 10개가 넘으면 가장 오래된 백업부터 서버에서 자동 삭제된다.

그리고 백업을 사용자의 기억력에 맡기지 않았다.

  • 일일마감 [마감하기]를 누르면 전체 기록이 로컬+클라우드에 항상 백업된다
  • 결산 인쇄 시에도 자동 백업이 돈다 (기본 켬)
  • 수동으로는 [백업] 메뉴에서 지금 백업, 클라우드만 백업, 선택 복원/삭제가 된다

복원 쪽에도 안전장치를 넣었다. 복원 직전에 현재 자료를 로컬 백업으로 먼저 보존하고, 내려받은 파일은 gzip을 푼 뒤 SQLite format 3 매직 바이트를 확인해서 진짜 DB 파일일 때만 교체한다. 복원하다가 장부를 날리는 최악의 시나리오를 막기 위해서다.

PC를 교체하면 새 PC에서 인증키를 다시 등록하고 [클라우드에서 복원] 한 번이면 끝난다. 다만 클라우드 자료는 등록된 PC에서만 열린다 — 인증키가 남에게 새 나가도 자료는 열리지 않는다. 이 기기 바인딩이 왜 필요했고 처음 설계가 어떻게 뚫렸는지는 다음 글(보안 감사)에서 자세히 쓴다.


3. 모바일 조회: 서버는 데이터를 해석하지 않는다

백업이 클라우드에 올라가 있으니, 덤으로 모바일 조회를 붙일 수 있었다.

PC 차돈의 환경설정에서 아이디와 비밀번호를 설정하면, 휴대폰 브라우저에서 https://chadon.mokky.store/review에 로그인해 정비일지·부품재고·매출확인을 읽기 전용으로 볼 수 있다. 퇴근한 사장님이 침대에서 오늘 매출을 확인하는 용도다.

재미있는 부분은 구조다.

1
2
서버는 백업 파일(gzip SQLite)을 해석하지 않는다.
휴대폰 브라우저가 파일을 받아 sql.js로 직접 연다.

서버는 암호화된 통로일 뿐이고, 데이터 해석은 사용자 기기에서만 일어난다. 서버에 조회용 API를 만들지 않으니 서버가 뚫려도 “장부를 조회하는 기능” 자체가 없고, 조회 화면의 검색·집계는 전부 브라우저 안에서 돈다.

세부 규칙 몇 가지.

  • 조회 내용은 마지막 클라우드 백업 기준이다. 매일 [마감하기]를 하면 최신이 된다
  • 매출확인은 금일/이번주/이번달/올해/전체 기간별로 총매출·순이익·미수금·미정산금을 보여준다
  • 아이디/비밀번호를 새로 설정하면 기존 아이디 기록은 서버에서 즉시 삭제된다
  • [조회 해제] 버튼을 누르면 모바일 로그인이 즉시 차단된다

4. 문자 발송: 내 서버가 아니라 사장님 계정으로

정비소는 문자를 많이 보낸다. 정비 완료 안내, 입고 접수, 미수금 안내, 검사 시기 안내까지.

차돈은 문자 발송을 내장하되, 발송 주체를 내 서버로 만들지 않았다. 각 정비소가 자기 알리고(smartsms.aligo.in) 계정으로 보내고, 문자 요금은 정비소가 알리고에 충전한 금액에서 차감된다. 내가 문자 요금을 정산하는 중간 사업자가 되는 순간 프로그램이 아니라 통신 서비스가 되기 때문이다.

발송 흐름은 정비일지와 붙어 있다.

1
2
3
4
정비일지에서 건 선택 → [문자]
→ 고객 전화번호·이름 자동 입력
→ 서식의 치환변수({고객명} {차량번호} {정비금액} {미수금}...)가 그 건의 값으로 치환
→ 90바이트 이하는 SMS, 넘으면 LMS로 자동 전환

입력 중에 바이트 수가 표시되고, 발송 결과는 성공/실패와 내용이 sms_log에 남는다. 알리고 테스트 모드(과금 없음)로 연동 확인도 할 수 있게 했다.

처음 설정이 제일 어려운 부분이라 — 발신번호 사전등록제(법정 의무), API 키 발급, 발송용 IP 등록 — 문자발송 탭을 처음 열면 절차를 설명하는 안내 창이 한 번 뜨게 했다. “문자가 갑자기 안 나가요”의 답은 대부분 IP 변경·발신번호 미등록·잔액 부족이라서, 그 내용도 안내에 박아뒀다.


5. 자동 알림: 규칙 = 조건 + 문구

문자에서 한 발 더 나간 것이 자동 알림 규칙이다.

정비소의 단골 관리는 사실 주기 관리다. 엔진오일은 6개월, 자동차 검사는 2년마다 돌아온다. 이걸 사장님 머리에 맡기지 않고 규칙으로 만들었다.

1
규칙 = 기준(정비일지 검색어 or 고객 검사일) + 주기(개월) + 보낼 문구

기본 규칙은 두 개다 — 엔진오일(정비일지의 ‘엔진오일’ 최근 시행일 기준 6개월), 자동차 검사(고객 검사일 기준 23개월 — 주기보다 짧게 잡아 미리 알림). ‘미션오일 24개월’, ‘타이어 36개월’ 같은 규칙을 얼마든지 추가할 수 있다.

프로그램 시작 몇 초 뒤 대상 고객을 찾아서, 기본은 목록을 보여주고 확인 후 발송, 원하면 완전 자동 발송(09~20시에만)도 된다. 자동 발송에서 제일 무서운 것은 중복 발송이라 규칙을 엄격하게 잡았다.

  • 같은 고객에게 같은 기준일로는 1번만 나간다
  • 다시 정비하면 기준일이 바뀌어 다음 주기에 또 나간다
  • 실패한 건은 다음 실행 때 재시도한다
  • 확인 창에 그 고객에게 마지막으로 보낸 같은 알림과 직전 문자를 함께 보여준다

내장 서식은 전부 정보성 안내로만 만들었다. 광고성 문자는 (광고) 표기, 080 수신거부, 야간 발송 금지, 사전 수신동의 같은 별도 법정 의무가 붙기 때문에, 그 경계를 프로그램이 흐리지 않게 했다.


6. 엑셀 내보내기: 나가는 문도 열어뒀다

타 앱에서 차돈으로 들어오는 문을 만들었으니, 나가는 문도 만들었다.

  • 화면별 [엑셀저장]: 지금 조회된(찾기/거르기 적용된) 내용을 그대로 저장
  • 결산 [엑셀저장]: 결산업무 탭의 집계표
  • 전체 내보내기: 정비일지/세부내역/고객/매입/부품/일일마감을 시트별로 나눈 한 파일

전체 내보내기는 사실상 세무사 전달용이다. 정비소 장부는 결국 세무 신고로 이어지는데, “차돈에서 뽑아서 세무사한테 보내면 끝”이 되어야 프로그램이 장부로 신뢰받는다.

openpyxl이 없는 환경에서는 엑셀에서 바로 열리는 CSV로 자동 대체 저장된다. 내보내기 기능이 환경 때문에 조용히 죽는 일은 없게 했다.


이번 글 요약

이번 단계에서 한 핵심 결정은 다음과 같다.

  • 타 앱 반입은 독점 DB 해석 대신 CSV/XLSX 통로로 풀고, 인코딩 자동 인식과 수동 매핑 확인을 넣었다.
  • 반입된 자료가 재고·결산·통계에 바로 맞물리게 했다.
  • 백업은 로컬 30개 + 클라우드 10개 이중으로 하고, 마감하기에 백업을 묶어 사용자의 기억력에 의존하지 않게 했다.
  • 복원은 현재 자료 보존 + SQLite 매직 검증을 거쳐야만 교체한다.
  • 모바일 조회는 서버가 데이터를 해석하지 않는 구조(sql.js)로 만들었다.
  • 문자는 정비소 자신의 알리고 계정으로 보내고, 자동 알림은 중복 발송 방지 규칙을 엄격하게 잡았다.
  • 엑셀 내보내기로 나가는 문(세무사 전달)도 열어뒀다.

다음 글은 마지막 편이다. 판매를 전제로 한 프로그램에 필요했던 것들 — 인증키와 기기 바인딩, Ed25519 서명 자동 업데이트, 그리고 Critical 취약점을 찾아낸 세 차례의 보안 감사를 정리한다.

이 글은 모든 권리 보유 입니다. 출처를 밝힌 게시글 링크 공유만 가능하며, 전문 복제·전재는 허용되지 않습니다.