[개발] 구글 시트 대신 MySQL! n8n으로 구축한 가계부 자동화 시스템 구축기 (feat. 시놀로지 & 삽질 기록)
1. 시작하며: 왜 자동화인가?
매일 쏟아지는 카드 결제 문자와 이메일들. 이걸 일일이 가계부 앱에 입력하는 건 사실상 불가능에 가깝다.
"개발자라면 반복 작업은 자동화해야지"라는 생각으로 n8n을 이용해 카드 사용 내역을 자동으로 수집하는 시스템을 구축하기 시작했다.
2. 구글 스프레드시트(Google Sheets)에서 MySQL로 넘어간 이유
처음에는 가장 접근하기 쉬운 구글 스프레드시트를 저장소로 사용했다. 눈으로 보기도 편하고 관리가 쉬웠기 때문이다. 하지만 시스템을 고도화하려다 보니 몇 가지 치명적인 단점이 보였다.
- 데이터가 쌓일수록 느려짐: 몇 달 치 데이터만 쌓여도 로딩과 검색이 눈에 띄게 느려진다.
- 복잡한 쿼리의 한계: "지난달 식비만 합산", "특정 카드사의 1년 치 통계" 같은 집계 데이터를 뽑아내려면 수식이 굉장히 복잡해진다.
- 데이터 무결성 문제: 실수로 셀을 건드리면 데이터가 꼬일 위험이 크다.
결국 제대로 된 DB를 쓰자는 결론을 내렸고, 운영 중인 시놀로지 NAS(Docker)에 올려둔 MySQL로 마이그레이션을 결정했다.
3. 구축 과정과 시행착오 (Trial & Error)
MySQL 연동은 생각보다 신경 쓸 부분이 많았다. 내가 겪었던 대표적인 삽질 포인트들을 공유한다.
① DB 설계: "중복"을 어떻게 막을 것인가?
가장 큰 고민은 "똑같은 결제 내역이 중복으로 저장되면 어떡하지?" 였다. 워크플로우를 테스트하다 보면 같은 메일을 여러 번 파싱 하게 되는데, 그때마다 데이터가 계속 쌓이면 가계부로서의 가치가 없어진다.
- 해결책: 이메일마다 고유하게 존재하는
Message-ID를 활용했다. - DB 테이블을 만들 때
message_id컬럼에UNIQUE제약 조건을 걸었다. - 이렇게 하면 DB 레벨에서 원천적으로 중복 저장을 막아준다.
CREATE TABLE transactions (
...
message_id VARCHAR(255) NOT NULL UNIQUE, -- 이게 핵심!
...
) ...;
② n8n 설정: Insert인가 Upsert인가?
구글 시트 노드에는 Upsert (없으면 추가, 있으면 수정) 메뉴가 대놓고 있어서 편했는데, MySQL 노드에는 Insert, Update만 있어서 당황했다.
- 해결책:
Insert오퍼레이션을 선택하되, 옵션에서Skip on Conflict를 켜주면 된다. - "일단 넣어봐(Insert). 근데 중복 키 에러가 나면? 그럼 건너뛰어"라는 방식이다. 이 옵션 하나로 중복 걱정이 사라졌다.
③ 보안과 접속 권한 (Host IP vs Docker Network)
보안을 위해 root 계정을 쓰지 않고, 가계부 전용 유저를 따로 만들기로 했다. 그런데 접속 권한을 줄 때 IP 설정에서 애를 먹었다.
-
시도 1: 시놀로지 NAS의 IP (
192.168.x.x)로 권한을 줌 → 실패 -
이유: n8n도 Docker 컨테이너고, MySQL도 Docker 컨테이너다. 둘 사이의 통신은 외부 공유기 IP가 아닌 Docker 내부 네트워크 IP를 타고 들어온다.
-
시도 2: 모든 IP 허용 (
%) → 성공은 했으나 찜찜함 -
보안상 좋지 않다.
-
최종 해결: Docker 내부 대역(
172.%) 만 허용 -
Docker 컨테이너들이 사용하는
172.x.x.x대역만 열어주니 보안도 챙기고 연결도 안정적으로 되었다.
④ 날짜 계산의 늪 (리포트 자동화)
"매월 1일에 지난달 리포트를 메일로 받자"는 목표를 세웠는데, 단순히 쿼리만 날리면 2월 1일에 받은 메일 제목이 "2월 가계부"가 되어버린다. (실제 내용은 1월 것인데!)
- 해결책: Javascript Code 노드를 이용해 "현재 날짜 - 1달" 을 계산해서 제목을 동적으로 생성하도록 로직을 짰다.
- SQL 쿼리에서도
DATE_FORMAT(NOW() - INTERVAL 1 MONTH ...)를 활용해 정확히 "지난달 1일 ~ 말일" 데이터만 긁어오도록 처리했다.
4. 결과물: 자동화된 삶
이제 나는 카드를 긁기만 하면 된다. 나머지는 시스템이 알아서 한다.
- 실시간 수집: 카드 결제 메일이 오면 n8n이 파싱 해서 MySQL에 꽂아 넣는다.
- 월간 리포트: 매월 1일 아침 9시, 지난달 총지출액과 카드사별(Olive/SMBC) 사용 금액이 정리된 예쁜 HTML 메일이 도착한다.
- 연간 리포트: 매년 1월 1일, 1년 치 통계가 날아온다.
구글 시트의 버벅거림에서 벗어나 MySQL의 쾌적함과 n8n의 강력한 자동화를 맛보니 다시는 수동 입력으로 돌아갈 수 없을 것 같다. 혹시 홈서버나 NAS를 돌리고 있다면, 이 조합을 강력하게 추천한다.

