포스트

차돈 제작기 #1 - 정비소 사장님을 위한 프로그램 설계

차돈 제작기 #1 - 정비소 사장님을 위한 프로그램 설계

차돈 제작기 #1 - 정비소 사장님을 위한 프로그램 설계

이번 글부터는 차돈이라는 Windows 프로그램을 만든 과정을 세 편으로 나눠 정리해보려고 한다.

차돈은 한 줄로 말하면 이런 프로그램이다.

1
자동차 정비소의 매출/매입을 관리하는 Windows 프로그램

이름은 “자동을 벌어보자”에서 왔다.

정비일지(RO) 등록, 고객 관리, 매입/부품 재고, 일일마감과 결산, 매출통계 그래프, 계산서/견적서 인쇄, 고객 문자 발송까지 정비소 하루 업무를 한 프로그램 안에서 처리하는 것이 목표였다.

차돈 아이콘

시리즈는 이렇게 나눈다.

1
2
3
#1 설계와 데이터 - 스택 선택, UI 전환, 정비일지 중심 데이터 모델
#2 갈아타기와 운영 - 타 앱 자료 반입, 백업, 모바일 조회, 문자 발송
#3 판매의 조건 - 인증키, 서명 업데이트, 세 차례의 보안 감사

이 시리즈도 구현 결과보다는 어떤 문제를 어떤 순서로 풀었는지를 중심으로 쓴다.


1. 사용자는 개발자가 아니다

차돈의 사용자는 개발자가 아니라 정비소 사장님이다.

그래서 처음부터 조건을 이렇게 잡았다.

1
2
3
설치 과정 없이 exe 하나만 실행하면 된다.
데이터는 PC 안의 SQLite 파일 하나에 다 들어간다.
서버가 죽어도 프로그램은 돌아간다.

이 조건에 맞춘 스택은 이렇다.

요소선택
언어/UIPython + PySide6 (Qt)
데이터SQLite 단일 파일 (%APPDATA%\chadon\chadon.db)
배포PyInstaller --onefile차돈.exe
서버Cloudflare Workers + KV (인증/백업/모바일 조회)
CIGitHub Actions (태그 푸시 → 자동 빌드/배포)

SQLite는 DB 서버 없이 파일 하나로 끝난다. 다만 장부 파일을 exe 옆에 두지 않고 윈도 사용자 프로필(%APPDATA%) 아래에 둔 것은 의도적이다. 공용 PC에서 다른 윈도 계정이 장부 파일을 열어볼 수 없게, 사용자 프로필 ACL의 보호를 받는 위치에 두는 것이다.

서버는 인증·클라우드 백업·모바일 조회에만 쓰고, 서버가 죽어도 정비일지 등록과 마감 같은 본업은 전부 로컬에서 돌아간다.


2. tkinter로 시작해서 PySide6로 갈아탔다

처음 UI는 tkinter로 시작했다. 파이썬 기본 포함이라 의존성이 없고, “창 띄우고 표 그리는” 수준이면 충분하다고 생각했다.

하지만 화면이 늘어나면서 한계가 왔다. 정비일지·고객·매입·부품재고·마법사· 통계·마감·백업·환경설정까지, 표와 팝업이 얽힌 화면이 수십 개가 되자 tkinter의 표 위젯과 스타일링으로는 정비 프로그램다운 화면을 만들기 어려웠다.

그래서 UI 전체를 PySide6(Qt)로 이식했다. 대신 tkinter 화면을 지우지는 않고 폴백으로 남겨뒀다.

1
2
python main.py        # 기본: Qt(PySide6) UI
python main.py --tk   # 구버전 tkinter UI (실기기 확인용 폴백)

데이터 계층(db.py)과 화면을 처음부터 분리해 둔 덕에, UI를 통째로 갈아타면서도 데이터 코드는 거의 손대지 않았다. 이 분리는 결과적으로 프로젝트에서 가장 잘한 결정 중 하나였다.

프로젝트 구조는 이렇다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
main.py               실행 진입점
build.bat             Windows .exe 빌드 스크립트
chadon/
  db.py               SQLite 데이터 계층 (정비/고객/매입/부품/마감/통계)
  models.py           Customer 등 데이터 클래스
  printing.py         HTML 인쇄 문서 생성
  backup.py           로컬+클라우드 백업/복원
  app_import.py       타 앱 CSV/XLSX 자료 반입
  highway_import.py   하이웨이 .db 백업 반입
  excel_export.py     엑셀 내보내기
  sms.py              문자 발송 (알리고 연동)
  license.py          인증키 검증
  update.py           자동 업데이트 (Ed25519 서명 검증)
  ui_qt/              Qt(PySide6) 화면 — 기본 UI
  ui/                 (구) tkinter 화면 — --tk 폴백
server/worker.js      Cloudflare Worker (인증/백업/모바일 서버)

3. 핵심은 정비일지(RO)였다

정비소 프로그램의 중심은 결국 정비일지(RO)다.

정비 내역은 한 줄씩 부품값과 공임을 따로 입력하고, 금액은 부품값 × 수량 + 공임으로 자동 계산된다.

여기서 신경 쓴 규칙 몇 가지.

  • 부품선택으로 고르거나 부품명이 기준정보와 일치하는 항목은 저장 시 재고가 수량만큼 자동 차감된다 (수정/삭제 시 복원)
  • 외상매출 = 정비금액 − 계산금액으로 자동 계산
  • 완결처리하면 계산금액이 정비금액으로 채워지고, 완결취소하면 되돌아간다

정비소 현장에서 나온 요구도 그대로 반영했다. 이름 매칭은 띄어쓰기를 무시한다(‘김포택시’ = ‘김포 택시’). 사장님이 장부에 쓰는 이름은 그날그날 띄어쓰기가 다르기 때문이다. 조회 기간도 달력을 누르게 하지 않고 오늘 · 이번주 · 이번달 · 지난달 · 최근3개월 · 올해 · 전체 버튼 한 줄로 끝냈다.

고객명이나 차량번호 칸을 더블클릭하면 그 고객의 정보와 지난 정비일지 전체, 총 미수금이 한 창에 나온다. 미수금현황은 거래처별(거래처가 없으면 고객별) 미수금 합계를 보여주고, 줄을 더블클릭하면 그 거래처의 외상 건만 걸러 보여준다. 받을 돈이 어디 잠겨 있는지가 정비소에서 제일 급한 질문이라서, 이 화면은 어디서든 두 번의 클릭 안에 나오게 했다.


4. 매입이 곧 재고가 되는 흐름

부품 재고를 따로 등록하게 하면 아무도 안 쓴다. 그래서 재고는 입력이 아니라 부수 효과로 쌓이게 했다.

1
2
3
4
매입일지에 부품 구매를 기록
→ 부품 기준정보 자동 등록 (기존 부품이면 단가·회사 갱신)
→ 재고가 매입 갯수만큼 증가
→ 정비일지에서 그 부품을 쓰면 재고 차감

매입을 수정하거나 삭제하면 재고도 자동으로 복원된다. 부품명 칸은 기존 부품 자동완성을 지원해서, 이름 몇 글자를 치면 등록된 부품이 추천되고 고르면 회사·단가가 채워진다.

부품재고 화면은 재고가 0 이하로 내려간 부품을 주황색으로 표시한다. 장부만 열심히 쓰면 재고 관리가 공짜로 따라오는 구조다.


5. 마감·결산·통계는 전부 파생 데이터다

정비일지와 매입일지 하나만 제대로 쌓이면, 나머지 화면은 전부 그 데이터에서 파생된다. 별도 입력이 없다.

  • 일일마감: 하루 매출·계산금액·매입·외상 요약. [마감하기]를 누르면 전체 기록을 로컬+클라우드에 백업하고 오늘/총 미수금/이번달 결과 팝업이 뜬다.
  • 결산업무: 년/월/일 단위로 총매출·정비매출·입금·매입을 집계하고, 아직 못 받은 돈을 외상(수입), 아직 안 준 돈을 외상(소비)로 나눠 보여준다.
  • 매출통계: 기간별 순이익·총매출·총매입·총외상 막대그래프와 추이 그래프. 요약 카드를 클릭하면 해당 항목의 내역(정비일지/매입 목록)으로 바로 내려간다.

통계 그래프에서 하나 신경 쓴 점은 색약 안전 팔레트다. 빨간색을 쓰지 않았다. “적자니까 빨간색”은 개발자에게만 자연스러운 관습이고, 색 구분이 어려운 사용자에게는 그냥 안 보이는 그래프가 된다.


6. 인쇄는 브라우저에 맡겼다

정비소 프로그램은 인쇄가 많다. 계산서(거래명세서), 견적서, 일일마감표, 결산 보고서, 그리고 법정 서식인 정비 명세서까지.

프린터 드라이버를 직접 다루는 대신, 문서를 HTML로 만들어 기본 브라우저에서 열고 브라우저의 인쇄 기능(Ctrl+P)을 쓰게 했다. 어떤 프린터든 브라우저가 알아서 처리하고, 미리보기도 공짜로 얻는다.

계산서는 인쇄할 때마다 방식을 고른다 — 한번에 정비가격 / 정비 내역별 (부품비·공임비) / 정비 견적서 / 정비 명세서(법정 서식). 각 항목마다 부가세를 역산해 항목별 부가세와 합계를 함께 표기한다. 지난번에 고른 방식이 다음 인쇄의 기본값으로 기억된다.


이번 글 요약

차돈의 첫 단계에서 한 핵심 결정은 다음과 같다.

  • 사용자는 사장님이므로 exe 하나 + SQLite 파일 하나로 끝나는 구조를 지켰다.
  • 장부 파일은 exe 옆이 아니라 %APPDATA%에 둬서 다른 윈도 계정이 못 읽게 했다.
  • UI는 tkinter로 시작했다가 PySide6로 이식했고, 데이터 계층 분리 덕에 갈아타기가 쉬웠다.
  • 정비일지 한 줄에 부품값·공임을 분리 입력하고, 재고 차감과 미수금 계산을 자동화했다.
  • 재고는 별도 입력이 아니라 매입 기록의 부수 효과로 쌓이게 했다.
  • 마감·결산·통계는 전부 정비일지/매입일지에서 파생시켰다.
  • 인쇄는 HTML을 만들어 브라우저에 맡겼다.

다음 글에서는 이미 다른 정비 프로그램을 쓰던 정비소가 차돈으로 갈아탈 수 있게 만든 이야기 — 타 앱 자료 반입, 이중 백업, 모바일 조회, 그리고 문자 발송을 정리한다.

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