카드 알림을 노션 가계부로 자동 기록하기 (1) — 왜 만들었고 어떻게 굴러가나

폰에 오는 카드·은행·페이 알림을 그대로 읽어 노션 가계부에 자동 기록하는 개인 프로젝트. 1편은 동기와 전체 구조, 그리고 유실 방지 설계.

📌 card2notion 시리즈 (1/3) — 폰 알림 → 노션 가계부 자동 기록. 이 편은 왜 만들었나 · 전체 구조 · 유실 방지 설계.

가계부를 손으로 쓰는 게 싫었다

돈을 쓸 때마다 폰에는 이미 알림이 온다. 카드 승인, 계좌 입출금, 카카오페이 정산… 근데 그걸 다시 손으로 가계부에 옮겨 적는 게 너무 귀찮았다. 며칠 밀리면 영수증 뒤지다가 포기.

그래서 만들었다. 폰 알림을 그대로 읽어 노션 가계부에 자동으로 한 줄씩 쌓는 시스템. 이름은 card2notion.

image.png

🔒 코드는 개인 저장소라 비공개다. 이 시리즈엔 핵심 조각만 발췌해 붙인다.


뱅크샐러드 놔두고 왜 직접 만들었나

사실 가계부 앱은 좋은 게 많다. 뱅크샐러드처럼 계좌·카드를 다 연결하면 알아서 긁어모아 분류까지 해주는 것도 있다. 나도 그거 쓰려고 깔았다.

근데 계좌 연동하고, 인증하고, 권한 이것저것 주다가… 귀찮아서 중간에 접었다. 결국 제대로 안 썼다.

웃긴 건, 직접 만드니까 오히려 안 접었다는 거다. 남이 만든 앱은 며칠 쓰다 안 보게 되는데, 내가 만든 건 자꾸 열어본다. 분류가 틀리면 고치고 싶고, 요약이 안 예쁘면 손보고 싶다. 애착이 생기니까 계속 쓴다.

가계부는 기능이 아무리 좋아도 계속 쓰게 되느냐가 전부다. 나한텐 “내가 만든 것”이 그 답이었다. 완벽하진 않아도 내 손에 맞으니까.

🛠️ 완성도보다 애착이 이긴다. 남의 완벽한 앱보다, 내가 만든 부족한 쪽을 결국 더 자주 열어보게 된다.


목표

  • 카드/은행/페이 알림이 오면 → 노션 가계부 DB에 자동 기록
  • 수입 / 지출 / 이체 / 정산 / 부채상환을 알아서 분류
  • 월별 요약(순저축, 저축률, 카테고리별 지출)을 노션에서 바로 보기
  • 서버 비용 0원. 집에 굴러다니는 PC로 자가호스팅.

준비물: 남는 PC, 안드로이드 스마트폰

  • 아이폰은 애플 보안 특성 상 폰알림 파싱이 안된다ㅠㅠ

전체 구조

갤럭시 폰 알림
   │  (Tasker가 알림 텍스트 캡처)

Tasker → HTTP POST (알림 원문 + 앱 패키지명)

FastAPI 웹훅 (집 PC · Docker · HTTPS)
   │  1. 노이즈/광고 필터
   │  2. 파싱 (금액·가맹점·유형)
   │  3. 자동 분류 (카테고리·성격)

Notion 가계부 DB (한 줄 추가)
   +
Notion Budget 페이지 (월간 요약 자동 갱신)

폰에서 Tasker가 알림을 잡아 우리 집 서버로 쏘고, 서버가 파싱·분류해서 노션에 적는다.


핵심 구현 1 — 파싱 전에 거른다

알림이라고 다 거래가 아니다. 광고도 오고 “이자 낼 날이에요” 같은 안내도 온다. 그래서 파싱 전에 단계별로 거른다. 제일 골치 아팠던 건 안내성 알림이었다. 안내 문구가 들어 있어도 “승인”·“완료”가 같이 있으면 실거래라 통과시켜야 한다.

REMINDER_MARKERS = ("예정", "안내", "납입일", "부족", "채워", "갚아야", "갚는 날")
COMPLETION_MARKERS = ("승인", "완료", "되었어요", "받았어요", "보냈어요")

# 안내 문구가 있어도 '승인/완료'가 같이 있으면 실거래 → 통과
if any(m in text for m in REMINDER_MARKERS) and not any(c in text for c in COMPLETION_MARKERS):
    return {"status": "skipped", "reason": "reminder/notice"}

핵심 구현 2 — 유실은 절대 안 된다

돈 기록이라 한 건이라도 놓치면 안 된다. 그래서 노션 API가 실패해도 잃지 않게, 실패분은 큐에 쌓고 폰엔 “접수됨”으로 답한다. 그래야 폰이 재전송을 안 하고, 서버가 나중에 조용히 재시도한다.

try:
    notion_client.add_transaction(item)
except Exception:
    _queue_pending(item)          # 실패분을 재시도 큐에 적재
    _journal(item, "queued")
    return {"status": "queued"}   # 폰엔 '접수됨'으로 응답

여기에 3중 안전장치를 더 뒀다.

  • journal — 받은 알림은 skip 사유까지 전부 기록. “이건 왜 안 들어왔지?“를 원문으로 추적.
  • pending 큐 — 노션 실패분을 몇 분마다 재시도.
  • 멱등 기록(seen) — 14일 윈도우. 같은 알림이 두 번 와도 중복 기록 안 함.

💡 돈 기록은 유실이 곧 신뢰 문제다. “실패하면 큐에 쌓고 폰엔 접수됨으로 답한다”가 이 프로젝트에서 제일 중요한 한 줄이었다. 이 journal이 나중에 파서 버그를 잡을 때도 그대로 생명줄이 됐다.


왜 이렇게 만들었나

왜 Tasker. 안드로이드는 알림 접근 권한만 주면 모든 앱의 알림 텍스트를 읽을 수 있다. 카드사 앱을 크롤링할 필요 없이, 이미 오는 알림을 재활용.

왜 자가호스팅. 개인 금융 데이터를 남의 클라우드에 안 올리고 싶었다. 집 PC + Docker면 충분. 컨테이너를 restart: unless-stopped로 띄워두면 컴퓨터를 껐다 켜도 도커만 올라오면 그대로 동작.

왜 노션. 이미 쓰고 있었고, DB·페이지·코드블록만으로 가계부 + 대시보드를 다 만들 수 있다. 앱을 따로 만들 이유가 없었다.


다음 편

구조 자체는 이렇게 단순한데, 진짜 지옥은 알림 텍스트 파싱이었다. 카드사마다, 은행마다, 페이마다 형식이 다 다르고, 같은 은행도 입금과 출금 문구가 다르다.

➡️ 2편 — 알림 텍스트 파싱의 지옥에서 계속.

댓글

익명 댓글입니다. 닉네임과 내용이 저장되며, 서로 존중하는 표현을 부탁드려요. 부적절하거나 광고성 댓글은 예고 없이 삭제될 수 있습니다.