Initial commit: OpenClaw 워크스페이스 버전관리 시작
설정·스크립트·스킬·문서·큐레이션 메모리 추적. 시크릿(credentials/identity)·런타임 상태(state/logs/sessions/sqlite)· 백업(clobbered/bak)·dream 캐시는 .gitignore로 제외. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
# 골디 📒 — 업무 브리핑
|
||||
|
||||
> 관리자님께 드리는 골디 운영 현황 보고서입니다. **골디는 이 문서를 읽지 않습니다** — 관리자님이 그동안 골디에게 시켜둔 업무·규칙을 본인이 한눈에 확인·점검하기 위한 문서입니다. 새 지시·기존 지시 변경이 있을 때만 갱신합니다.
|
||||
> 마지막 갱신: 2026-05-26
|
||||
|
||||
---
|
||||
|
||||
## 한눈에 보기
|
||||
|
||||
골디는 가계부 자동 입력·정리를 책임지는 에이전트입니다. 지금 운영 중인 일을 큰 갈래로 보면 네 종류입니다.
|
||||
|
||||
1. **자동으로 도는 업무 세 가지** — 결제문자 후잉 동기화(매시 4번), 가희 잔액 리마인더(매월 25일), 월간 결산(매월 1일)
|
||||
2. **수동으로 부를 수 있는 명령 여덟 가지** — 수동 분개·잔액 조회·rule 편집 등
|
||||
3. **텔레그램 자연어 대화** — 골디 봇에게 "잔액 알려줘" "○○ 등록해줘" 식으로 말 걸면 알아서 처리
|
||||
4. **자동 알림 다섯 종** — 후잉이 분개를 거절했거나, 자동 분개 보정이 발동했거나, 가희님 답신이 왔을 때 골디가 먼저 텔레그램으로 말 걸어옴
|
||||
|
||||
이 중 가장 큰 자동 업무인 결제문자 동기화 안에는 다섯 개의 우선 룰(정기결제 분개)과 네 개의 자동 보정 로직(잔액 차이로 누락분 분개)이 묻혀 돌고 있습니다. 아래에 차례로 풀어 설명드리겠습니다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 자동으로 도는 업무
|
||||
|
||||
### 1-1. 결제문자를 후잉으로 자동 옮기는 일
|
||||
|
||||
#### 언제 어떻게 도는가
|
||||
|
||||
매시 **0분·15분·30분·45분**에 macOS launchd가 `whooing_sync.py`를 실행합니다. 즉 한 시간에 네 번, 하루 96번 돕니다. LLM 세션을 부팅하지 않고 파이썬 스크립트만 실행하는 가벼운 방식입니다 — 과거에는 OpenClaw cron(LLM 경유)으로 돌렸지만 매 실행마다 세션을 띄워 토큰 비용이 월 7천만 토큰까지 올라간 적이 있어서, 2026년 4월 24일에 launchd 단독 운영으로 바꿨습니다. 그 OpenClaw cron 잡은 `enabled:false`로 박제해뒀고 다시 활성화하지 않습니다.
|
||||
|
||||
#### 무엇을 하는가
|
||||
|
||||
스크립트가 하는 일은 다섯 단계로 정리할 수 있습니다.
|
||||
|
||||
**(1) iMessage DB에서 결제 SMS 수집.** `imsg` CLI를 통해 `~/Library/Messages/chat.db`를 읽어 카드사·은행 발신번호에서 온 메시지를 가져옵니다. 어떤 발신번호를 신뢰할지는 `state/whooing_account_map.json`에 매핑돼 있고, 이 중 `confirmed:true`인 번호만 자동 처리됩니다. 확인 안 된 번호(예: 새로 등록된 카드사)는 한 번 들어왔을 때 unmapped 로그만 남기고 자동 전송은 하지 않습니다.
|
||||
|
||||
**(2) 같은 금액 입↔출 SMS를 5분 안에 짝지어 이체로 합성 (페어 매칭).** 본인 계좌 사이에서 돈을 옮기면 카드사·은행이 양쪽에서 각각 SMS를 보내는데, 그걸 그대로 두 건으로 처리하면 가계부에 같은 돈이 두 번 잡힙니다. 그래서 5분 윈도우 안에 같은 금액의 입금·출금 SMS가 짝지어지면 1건의 자산↔자산 이체로 합성해서 보냅니다. 짝을 못 짠 입출금이 5분 이내면 hold 상태로 두고 다음 사이클에 다시 짝짓기를 시도합니다.
|
||||
|
||||
**(3) 우선 룰 적용.** `state/whooing_overrides.json`에 등록된 정기결제·시간대 룰을 위에서 아래로 평가합니다. 첫 매칭 룰의 분개 형식으로 후잉에 보냅니다. 현재 다섯 개가 등록돼 있는데, 다음 절(1-2)에서 풀어 설명드립니다.
|
||||
|
||||
**(4) 가맹점 매핑.** 우선 룰에 잡히지 않으면 `state/whooing_merchant_map.json`의 exact·contains 룰을 평가합니다. 예: "스타벅스" → 식비.
|
||||
|
||||
**(5) 모르면 "기타비용"으로 분개 (default fallback).** 우선 룰도 가맹점 매핑도 매칭이 없으면 `기타비용 ← {결제수단}`으로 자동 분개합니다. 이건 2026-04-24에 관리자님이 결정하신 정책입니다. 모르는 인명 송금이 들어왔다고 해서 `박영춘 → 식비` 같은 exact 룰을 늘리지 말고, 일단 기타비용으로 떨어뜨린 다음 후잉 UI에서 사후 카테고리 이동하라는 원칙입니다. 단 입금(`deposit`) 종류는 이 fallback 없이 raw 폴백으로 갑니다 — 수익·이체·환급을 구분하기 어렵기 때문입니다.
|
||||
|
||||
그 외에 SMS 잔액과 후잉 잔액 차이로 자동 보정하는 로직 네 가지가 매 사이클 함께 돕니다. 이건 1-3절에서 따로 풀어 설명드립니다.
|
||||
|
||||
#### 관리자님이 시킨 핵심 규칙
|
||||
|
||||
- **OpenClaw cron으로 되돌리지 말 것.** 매 실행 LLM 토큰 비용이 너무 큼.
|
||||
- **텔레그램 알림에 SMS 원문을 박지 말 것.** 2026-05-10에 한 번 골디 봇이 동결됐는데, 알림 본문에 결제 SMS 원문이 들어가서 텔레그램 smishing 필터에 오탐된 게 원인이었습니다. 그 이후로 알림에는 라벨·시각·금액 같은 메타데이터만 넣습니다.
|
||||
- **인증번호·간편인증서·계좌개설 안내 문자는 후잉에 보내지 않음.** `SKIP_PATTERNS`에 등록돼 있어서, 결제·이체와 무관한 문자는 raw 폴백조차 가지 않습니다.
|
||||
- **미확인 발신번호는 자동 등록 X.** 새 발신번호의 첫 메시지가 들어오면 unmapped 기록만 남기고, 관리자님이 실제 내용을 확인한 뒤 `confirmed:true`로 승격해야 자동 처리됩니다. 잘못된 자동 등록을 막기 위함입니다.
|
||||
- **결제문자와 분류를 같이 보내도 자동 등록하지 않음.** "스타벅스 5800원 식비로" 같이 메시지를 보내도, "등록해줘"라는 명시적 요청이 없으면 골디는 자동동기화·분류 힌트로만 기록하고 후잉에 보내지 않습니다.
|
||||
- **FDA 누락 시 조용히 무동작.** launchd는 Full Disk Access 권한을 상속받지 못합니다. macOS 시스템 설정 → 개인정보 보호 및 보안 → 전체 디스크 접근 권한에 `/opt/homebrew/bin/imsg`가 등록돼 있어야 Messages DB를 읽을 수 있습니다. 누락되면 stderr에 에러는 찍히지만 stdout은 "새 결제 메시지 없음"으로 끝나기 때문에 오류처럼 보이지 않습니다. 맥을 옮기거나 imsg를 재설치하면 재등록이 필요합니다.
|
||||
|
||||
---
|
||||
|
||||
### 1-2. 지금 등록된 우선 룰 다섯 개
|
||||
|
||||
`state/whooing_overrides.json`에 정기결제·시간대 조건 분개 룰이 다섯 개 박혀 있습니다. JSON 파일을 직접 편집하면 `whooing_sync.py`가 매 사이클 다시 읽어서 적용하므로, 코드 수정이나 launchd 재기동 없이 즉시 반영됩니다.
|
||||
|
||||
**1번 — 쿠팡 정기결제.** 카드승인이고 가맹점에 "쿠팡"이 들어가고 금액이 정확히 **7,890원**이고 매월 **29일**(주말이면 다음 평일까지 허용)이면 `지식,문화 ← {결제수단}` 분개로 보냅니다. 항목명은 `계정결제_쿠팡`.
|
||||
|
||||
**2번 — 평일 점심 인명송금.** 출금이고 결제수단이 하나·신한·카뱅 중 하나이고 가맹점이 한글 2~4자 인명이고 가맹점 매핑에 등록 안 돼있고 **평일 13:00~14:30 KST**에 발생한 거래면 `식비 ← {결제수단}` 분개로 보냅니다. 항목명은 `점심식사`, 메모는 `{인명}에게 송금 | {원문}`. 동료들과 점심 더치페이 송금을 자동으로 식비로 잡기 위한 룰입니다.
|
||||
|
||||
**3번 — 퇴직연금 자동이체.** 출금이고 하나은행이고 메모에 "44891006239452"가 포함되고 금액이 **100,000원**이고 매월 **25일**(주말이면 다음 평일)이면 `하나IRP(효원) ← 하나은행(효원)` 분개. 항목명은 `퇴직연금`.
|
||||
|
||||
**4번 — 프리드라이프 정기납부.** 출금이고 하나은행이고 메모에 "프리드"가 들어가고 금액이 **33,000원**이고 매월 **25일**(주말이면 다음 평일)이면 `의료,건강,보험 ← 하나은행(효원)` 분개. 항목명은 `프리드라이프`.
|
||||
|
||||
**5번 — 우체국보험 정기납부.** 출금이고 하나은행이고 메모에 "우체"가 들어가고 금액이 **251,790원**이고 매월 **25일**(주말이면 다음 평일)이면 `의료,건강,보험 ← 하나은행(효원)` 분개. 항목명은 `보험료`.
|
||||
|
||||
**이 룰들은 동시에 이상거래 감지에도 쓰입니다.** 특히 3·4·5번은 금액까지 정확히 일치해야 매칭됩니다. 만약 금액이나 결제일이 한 푼이라도 어긋나면 룰에 안 잡혀서 default fallback("기타비용")으로 빠지고, 이때 raw 폴백 알림이 자동으로 텔레그램으로 옵니다. 즉 "보험료가 갑자기 인상됐다" 또는 "정기결제가 이상한 날 빠졌다" 같은 변화를 즉시 감지할 수 있습니다. 보험료가 정상적으로 인상됐다면 룰의 `amount_eq` 값만 새 금액으로 갱신하면 됩니다.
|
||||
|
||||
---
|
||||
|
||||
### 1-3. 잔액 차이로 자동 보정하는 분개 네 종
|
||||
|
||||
후잉이 알아서 분개하지 못하는 케이스(SMS가 오지 않거나, 결제는 됐는데 누락된 케이스 등)를 매 사이클 잔액 비교로 자동 보정합니다. 같은 보정이 중복으로 일어나지 않도록 `state/whooing_balance_alerts.json`에 carrier별 상태를 박아 관리합니다.
|
||||
|
||||
#### ① 카뱅 은행이자 자동 분개
|
||||
|
||||
카카오뱅크는 이자나 캐시백을 줄 때 별도 SMS를 보내지 않을 때가 있습니다. 그러면 후잉에 등록된 카뱅 잔액이 SMS 기반으로 추적되는 잔액보다 살짝 작아지는 현상이 생깁니다. 그래서 매 사이클 비교해서 후잉 잔액이 SMS 잔액보다 **5,000원 이내로 적으면** 그 차액만큼 `이자 / 기타수익` (left=카카오뱅크, right=기타수익)으로 자동 분개합니다.
|
||||
|
||||
이건 횟수·날짜 제한 없이 매번 실행됩니다. 정상 SMS deposit이 나중에라도 들어오면 차이가 0이 돼서 자동 미발화됩니다. 분개 결과는 "💰 카뱅 은행이자 자동 분개 +N원" 알림으로 텔레그램에 옵니다.
|
||||
|
||||
#### ② 현대카드 문자메시지 이용료 300원 자동 분개
|
||||
|
||||
현대카드는 매월 문자메시지 이용료 300원을 부과하는데, 별도 승인 알림 SMS 없이 누적 사용액에만 슬쩍 붙습니다. 그래서 후잉 카드 부채가 SMS 누적액보다 **정확히 300원** 적은 케이스가 매월 한 번 발생합니다.
|
||||
|
||||
이 패턴이 감지되면 `문자메시지 이용료 / 주거,통신 ← 현대카드` 분개로 자동 처리합니다. 월 1회만 실행되도록 `last_sms_fee_month` 상태로 중복 방지. "📨 현대카드 문자메시지 이용료 자동 분개 300원" 알림이 옵니다.
|
||||
|
||||
#### ③ 현대카드 라이나생명 보험료 31,100원 자동 분개
|
||||
|
||||
라이나생명 보험료(31,100원)는 현대카드에 결제되는데, 결제 SMS가 익일 지연 도착하는 패턴입니다. 그런데 카드 누적 사용액에는 당일 반영되기 때문에 후잉 부채와 SMS 누적액 사이에 **정확히 31,100원** 차이가 생깁니다.
|
||||
|
||||
이 패턴이 감지되면 `보험료 / 의료,건강,보험 ← 현대카드`로 자동 분개합니다. 월 1회만 실행, `last_hyundai_insurance_month` 상태로 중복 방지. "🛡️ 현대카드 보험료 자동 분개 31,100원" 알림.
|
||||
|
||||
그리고 다음날 라이나생명 31,100원 SMS가 늦게 도착하면 그건 raw 전송하지 않고 스킵합니다 (이미 자동 보정으로 분개됐기 때문). `_should_skip_hyundai_insurance_duplicate` 함수가 같은 달 안에서는 같은 보험료 SMS를 두 번 분개하지 않도록 막습니다.
|
||||
|
||||
#### ④ 연료 가수금 150,000원 스킵
|
||||
|
||||
주유소에서 카드를 꽂으면 결제 전에 우선 150,000원 한도로 가수금을 잡아둡니다 (FUEL_PREAUTH_AMOUNT). 실제 주유 금액으로 정정될 때 새 SMS가 오는데, 가수금 150,000원을 그대로 분개하면 이중계상이 됩니다. 그래서 주유소 가맹점 + 금액 150,000원 패턴은 후잉에 보내지 않고 스킵합니다.
|
||||
|
||||
---
|
||||
|
||||
### 1-4. 가희님 잔액 리마인더와 자동분개
|
||||
|
||||
가희님 주머니(현금성 자산 합계)는 SMS로 추적할 수 없어서 가희님께 잔액을 직접 받아 반영하는 채널이 따로 있습니다. 이건 별도 cron이 아니라 **결제문자 동기화 사이클이 끝날 때마다 함께 호출**됩니다 (`gahee_reminder.run()`). 즉 매 15분 사이클에 piggyback. 실제로 가희님께 메시지가 가는 건 매월 25일 10시 이후 첫 사이클에 한 번뿐입니다.
|
||||
|
||||
#### 발신 게이트
|
||||
|
||||
KST 기준으로 오늘이 25일 이상이고 현재 시간이 10시 이상이고 이번 달에 아직 발신한 적 없으면(`last_sent_month`로 추적), 가희님(`+821055595428`)께 `state/gahee_reminder.json`의 `message_template`을 iMessage로 한 번 보냅니다. 25일에 Mac이 꺼져 있었으면 26일이든 28일이든 켜졌을 때 보냅니다. 다음 달로 넘어가면 이번 달은 포기.
|
||||
|
||||
#### 답신 처리
|
||||
|
||||
발신 후에는 가희님 답신을 매 사이클 폴링합니다. 처리는 단계적으로 합니다.
|
||||
|
||||
먼저 답신이 **이미지 첨부**면 자동분개를 하지 않고 골디 텔레그램으로 "이미지 답신 — 직접 처리 부탁" 알림만 보냅니다. 관리자님이 직접 보고 처리하거나 가희님께 텍스트로 다시 요청해야 합니다.
|
||||
|
||||
답신이 **텍스트 여러 통**이면 마지막만 분개합니다. 가희님이 잔액을 수정해서 다시 보내는 경우, 첫 메시지로 잘못 분개되는 사고를 막기 위해서입니다. 이전 N-1통은 워터마크만 갱신하고 별도 알림으로 스킵 사실을 보고합니다.
|
||||
|
||||
마지막 텍스트는 정규식으로 `라벨 : 금액` 페어를 추출합니다. 예: "국민 : 42,995 신한 : 4,161,585". 페어가 한 개도 안 나오면 포맷 오류로 보고 자동분개를 중단하고 텔레그램으로 알립니다. 페어가 하나 이상이면 모든 페어의 합계를 계산해 후잉의 `가희주머니` 현재 잔고와 비교합니다.
|
||||
|
||||
차이가 양수면 `가희주머니 ← 가희비밀주머니_수익`(수익), 음수면 `기타비용 ← 가희주머니`(비용), 0이면 분개 생략하고 알림만 보냅니다. 메모란에는 라벨별 잔액 원본을 그대로 박습니다 — 예: `[자동] 가희 잔액 갱신 | 국민:42,995 신한:4,161,585 ... | 합계 X (이전 Y)` (200자 truncate).
|
||||
|
||||
#### 관리자님이 시킨 핵심 규칙
|
||||
|
||||
**안전장치 박지 말 것.** 2026-05-21에 관리자님이 명시적으로 결정하신 사항입니다. 차액 임계치(예: 100만원 이상이면 거부), 금액 상한, diff threshold 같은 가드를 추가하지 말고 무조건 분개하라는 원칙입니다. 잘못 분개되면 후잉 UI에서 사후 정정하면 됩니다.
|
||||
|
||||
**현금성 계좌만 반영.** 가희님 키움 예수금이나 미수금처럼 주식 정보는 합계에서 빼고 메모에도 안 적습니다.
|
||||
|
||||
**비교 기준은 매번 후잉에서 새로 조회.** 이전 잔고 값을 메모리에 캐싱하지 않습니다 — 그 사이에 분개가 누적되면 즉시 stale 상태가 되기 때문입니다.
|
||||
|
||||
**발신 문구 변경은 state JSON 직접 편집.** `state/gahee_reminder.json`의 `message_template`을 바꾸면 다음 발신부터 새 문구가 나갑니다. 코드 재배포 불필요.
|
||||
|
||||
만약 분개가 후잉 API 일시 장애로 실패하면 워터마크를 갱신하지 않아 다음 사이클(15분 후)에 같은 메시지로 재시도합니다.
|
||||
|
||||
---
|
||||
|
||||
### 1-5. 월간 결산
|
||||
|
||||
매월 **1일 05:00 KST**에 OpenClaw cron(jobs.json의 `08e9a978`, agent=budget)이 발화합니다. 이 작업은 본문에 자연어 요약이 필요해서 launchd가 아닌 LLM cron으로 돌아갑니다. cron payload에 적힌 step을 골디 세션이 차례로 실행합니다.
|
||||
|
||||
#### 1단계 — inbox 처리
|
||||
|
||||
매월 1일 04:30(결산 30분 전)에 stock 에이전트가 본인 증권 계좌 잔액을 `securities_balance` envelope으로 골디 inbox(`agents/budget/inbox/incoming/`)에 떨어뜨립니다. 결산 시작 시점에 골디가 이 envelope을 읽어, payload의 `totals.total`과 후잉 `증권(효원)` 자산의 차액을 계산해 자동 분개합니다.
|
||||
|
||||
차액이 양수면 `증권(효원) / 주식평가수익`, 음수면 `주식평가손실 / 증권(효원)`. 안전 가드로 `|차액|<1만원`이면 노이즈로 보고 skip하고, `|차액|>1억원`이면 분개를 거부하고 텔레그램 alert를 보내고 envelope을 `failed/`로 옮깁니다. 처리 끝난 envelope은 `processed/`로 이동.
|
||||
|
||||
이전엔 1·10·20일 세 번 운영이었으나 10일·20일은 결산 메일이 발송 안 돼서 envelope만 inbox에 쌓이는 dead-end였습니다. 2026-05-11에 매월 1일 한 번으로 단일화했습니다.
|
||||
|
||||
#### 2단계 — 결산 실행
|
||||
|
||||
`monthly_settlement.py`가 `whooing_balance.py --json`을 호출해 현재 후잉 잔액 스냅샷을 만들고, `state/monthly_snapshots.json`에 저장된 전월 스냅샷과 비교해 계정별 증감을 계산합니다.
|
||||
|
||||
#### 3단계 — 보고
|
||||
|
||||
Gmail로 관리자님께 본문 메일을 보냅니다 (`gog gmail send --to mini.snowoyh@gmail.com`, 제목 `[월간결산] YYYY년 M월 자산 변동`). 본문엔 모든 계정 증감이 절대값 내림차순으로 정렬돼 있습니다. 동시에 골디 텔레그램으로는 순자산 변동 한 줄 + ±100만원 이상 변동 top 5만 짧게 요약해서 보냅니다.
|
||||
|
||||
#### 추가 플래그
|
||||
|
||||
- `--dry-run` — 메일·텔레그램 전송 안 하고 본문만 stdout
|
||||
- `--no-send` — 전송 생략, 스냅샷 저장과 stdout만 (복구·재실행용)
|
||||
- `--as-of YYYY-MM-DD` — 기준일 강제 지정
|
||||
|
||||
#### inbox 관리 정책
|
||||
|
||||
- `processed/`의 envelope은 mtime 30일 초과하면 자동 삭제 (월간결산 cron 진입부에서 매월 GC)
|
||||
- `failed/`는 5건 이상 적체되면 결산 메일·텔레그램에 ⚠️ 한 줄 추가 — **자동 삭제는 안 함**. 관리자님이 검토 후 수동 삭제
|
||||
- 같은 envelope이 두 번 처리되지 않도록 `state/inbox_state.json`의 `processed[]`에 최근 1000개 message_id 누적
|
||||
|
||||
---
|
||||
|
||||
## 2. 수동으로 부를 수 있는 명령
|
||||
|
||||
자동 업무 외에 관리자님이 직접 부를 수 있는 명령이 여덟 가지 있습니다.
|
||||
|
||||
### 2-1. 수동 분개 1건 — `whooing_manual.py`
|
||||
|
||||
iMessage 결제문자를 거치지 않고 한 건을 직접 후잉에 분개합니다. 두 가지 모드가 있습니다.
|
||||
|
||||
**Structured 모드** — 항목·금액·차변·대변을 직접 지정합니다.
|
||||
```bash
|
||||
python3 ~/.openclaw/agents/budget/workspace/skills/whooing-sync/scripts/whooing_manual.py \
|
||||
--item "스타벅스" --money 5800 --left "식비" --right "신한신용(효원)" \
|
||||
[--date YYYYMMDD --memo "오전 커피"]
|
||||
```
|
||||
`whooing_accounts.json` 차트에 등록된 계정명만 허용됩니다. 차트에 없는 이름은 후잉이 거부.
|
||||
|
||||
**Raw 모드** — 원문 메시지를 그대로 보내 후잉 자체 파서에 맡깁니다.
|
||||
```bash
|
||||
python3 .../whooing_manual.py --message "스타벅스 5800원 신한신용"
|
||||
```
|
||||
|
||||
**사전 확인** — `--dry-run`을 붙이면 실제 POST 없이 어디로 갈지만 보여줍니다.
|
||||
|
||||
용도는 잘못 분개된 건 역분개, 차트 외 입력 점검, 카드 외 수동 입력(현금 거래 등).
|
||||
|
||||
### 2-2. 카드 취소·환불 처리
|
||||
|
||||
카드 결제 후 환불·취소가 일어나면 structured 분개로 처리하지 말고 **raw 모드**(`--message`)로 원문을 그대로 보내야 합니다. 그러면 후잉이 -금액으로 자동 상쇄합니다. structured로 환불을 분개하려고 하면 이중계상 위험이 있습니다.
|
||||
|
||||
### 2-3. 후잉 잔액 조회 — `whooing_balance.py`
|
||||
|
||||
```bash
|
||||
python3 .../whooing_balance.py [--section-id <ID>] [--as-of YYYY-MM-DD] [--json]
|
||||
```
|
||||
|
||||
후잉 OpenAPI(`bs.json`/`accounts.json`/`sections.json`)로 자산·부채·자본 잔액을 조회합니다. 기본 출력은 마크다운으로 카테고리별 합계와 계정별 금액(0원 계정은 생략, 금액 내림차순)을 보여줍니다. 읽기 전용이므로 dry-run 개념이 없고 바로 실행해도 안전합니다.
|
||||
|
||||
가희주머니 차액 계산, 월간 결산 검증, 임의 시점 스냅샷 등에 쓰입니다. 외부(메일·텔레그램 외)로 잔액 데이터를 내보내려면 관리자님 허락이 먼저입니다.
|
||||
|
||||
### 2-4. inbox `securities_balance` 단독 처리 — `inbox_handler.py`
|
||||
|
||||
```bash
|
||||
python3 ~/.openclaw/agents/budget/workspace/skills/monthly-settlement/scripts/inbox_handler.py [--dry-run]
|
||||
```
|
||||
|
||||
월간결산 cron이 자동으로 이걸 호출하지만, 점검이나 재처리가 필요할 때 단독으로 부를 수 있습니다. `--dry-run`은 분개 POST 없이 검증만 합니다.
|
||||
|
||||
### 2-5. 우선 룰 추가·수정·삭제 — `state/whooing_overrides.json` 직접 편집
|
||||
|
||||
JSON 파일을 텍스트 에디터로 열어서 룰 객체를 추가하거나 수정하거나 삭제하면 됩니다. 일시 비활성화는 `enabled:false`, 우선순위 변경은 배열 순서로 합니다 (위에 있는 룰이 먼저 매칭됨). `whooing_sync.py`가 매 사이클 재로딩하므로 코드 수정도 launchd 재기동도 필요 없습니다.
|
||||
|
||||
룰 매처 키는 `kind`(card_approval/withdrawal 등), `merchant_contains`, `merchant_regex`, `merchant_unmapped`, `amount_eq`, `carrier_in`, `weekday_in`, `scheduled_day_of_month` + `weekend_policy`, `time_kst_between` 등입니다. 분개 결과(`post`)에는 `{merchant}`, `{raw}`, `{amount}`, `{carrier_account}` 변수가 치환됩니다.
|
||||
|
||||
**정기결제·자동이체·시간대 조건 분개는 전부 여기.** 일반 가맹점 분류(스타벅스→식비 등)는 `whooing_merchant_map.json`에 둡니다.
|
||||
|
||||
### 2-6. 가맹점 매핑 추가 — `state/whooing_merchant_map.json` 직접 편집
|
||||
|
||||
exact / contains 룰로 가맹점명을 후잉 계정에 매핑합니다. 자주 가는 카페·교통·통신 같이 고정된 가맹점이 후보입니다.
|
||||
|
||||
**인명 송금은 추가하지 않습니다.** 2026-04-24에 관리자님이 결정하신 정책입니다. 새 이름 송금이 들어와도 손대지 말고 기타비용 fallback에 맡긴 다음 후잉 UI에서 사후 카테고리 이동.
|
||||
|
||||
### 2-7. 발신번호 confirm 승격 — `state/whooing_account_map.json` 직접 편집
|
||||
|
||||
새 카드사·은행 발신번호가 들어왔을 때 메시지 내용을 확인하고 매핑이 정확하다고 판단되면 해당 엔트리의 `confirmed: false`를 `true`로 바꿉니다. 그러면 다음 사이클부터 자동 처리에 포함됩니다.
|
||||
|
||||
확인된 번호: 하나 계좌이체 `+8215991111`, 신한은행 `+8215778000`, 신한카드 `+8215447000`. (과거에 신한카드를 `+8215447200`으로 잘못 등록한 시기가 있었는데 실사용 번호가 아니라서 confirmed=false 상태로 대기 중입니다.)
|
||||
|
||||
### 2-8. 동기화 dry-run 점검 — `whooing_sync.py --dry-run`
|
||||
|
||||
후잉에 실제 POST하지 않고 어떤 SMS가 어떤 발신번호에서 잡혀서 어디로 갈지 stdout에 표시만 합니다. 알림도 발송 안 함. 디버깅·점검용입니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 텔레그램 봇으로 자연어 대화
|
||||
|
||||
골디는 자기 텔레그램 봇을 가지고 있습니다 (`botToken: 8775...`, dmPolicy: allowlist `8443122995`). 관리자님이 자연어로 말 걸면 위 명령들을 알아서 호출합니다.
|
||||
|
||||
### 3-1. 잔액·자산 질문
|
||||
|
||||
"잔액 확인", "후잉 잔액", "자산 얼마야", "순자산 얼마야", "○○카드 얼마 썼어", "○○계좌 잔고" 같은 표현이 들어오면 `whooing_balance.py`를 호출해서 결과를 그대로 또는 질문 맥락에 맞게 한 줄로 요약해서 답합니다. 예: "순자산 350,797,204원 · 자산 3.52억 · 부채 1,339,391원". 의심스러우면 `--as-of`로 다른 날짜 찍어 비교.
|
||||
|
||||
### 3-2. 수동 등록 7단계 프로토콜
|
||||
|
||||
"한 건 등록해줘", "가계부에 넣어줘" 류 요청에는 **한 번에 하나씩** 묻는 일곱 단계로 진행합니다. 사용자가 이미 정보를 제시한 단계는 건너뜁니다.
|
||||
|
||||
먼저 **항목**을 묻습니다 — "어떤 항목이에요? (예: 스타벅스)". 그 다음 **금액** — "얼마인가요? (원)". 세 번째로 **결제수단(right)**을 묻는데, 이때 `whooing_accounts.json`의 부채(카드)·자산(통장) 목록을 번호 매긴 후보로 제시합니다. 네 번째로 **카테고리(left)**를 묻습니다 — 결제면 비용 카테고리, 입금이면 수익 카테고리, 이체면 자산·부채 카테고리를 번호로 제시. 다섯 번째로 **날짜**(기본 오늘 KST), 여섯 번째로 **메모**(없으면 스킵). 마지막으로 확인 후 실제 POST하고 결과 한 줄 보고.
|
||||
|
||||
원칙은 세 가지입니다. **차트에 없는 계정명으로 절대 추측 POST 금지** — 모르면 반드시 재질문. **사용자가 이미 한 문장에 "스타벅스 5800원 신한카드로" 다 말했다면** 카테고리만 확인하고 바로 실행. **카드 취소·환불이면 structured가 아니라 raw 모드**(`--message`)로 보내 후잉이 상쇄하게 함.
|
||||
|
||||
### 3-3. 동기화·결산 호출
|
||||
|
||||
"가계부 동기화", "후잉 동기화", "결제내역 정리" 같은 표현 → `whooing_sync.py` 직접 실행
|
||||
"이번달 결산", "월간 결산", "자산 변동 요약" 같은 표현 → `monthly_settlement.py` 직접 실행
|
||||
|
||||
---
|
||||
|
||||
## 4. 골디가 먼저 텔레그램으로 말 걸어오는 알림
|
||||
|
||||
`notify.py`가 골디 텔레그램 채널로 발송하는 자동 알림들입니다. `--dry-run` 호출 시에는 모든 알림 발송 안 함.
|
||||
|
||||
**(1) 후잉 거절 실패 알림.** webhook이 4xx/5xx 또는 본문에 `fail`이나 `Error :`를 반환한 분개를 알립니다. 실패 1건당 1메시지 보내되, 한 사이클에 4건 이상 실패하면 앞 3건만 상세 표시하고 나머지는 카운트로 요약합니다.
|
||||
|
||||
**(2) raw 폴백 알림.** 후잉이 200 받았지만 structured 매칭에 실패해 raw 모드로 넘어간 건입니다. 사이클당 1메시지로 모아서 보내며, 최대 3건만 나열하고 초과분은 카운트. 이건 단순 알림이 아니라 두 가지 의미가 있습니다 — 첫째, parser·carrier_to_account·merchant_map을 보완할 신호. 둘째, 정기결제 우선 룰(1-2의 3·4·5번)에 매칭되지 않은 케이스 = **이상거래·금액 변동 즉시 감지**.
|
||||
|
||||
**(3) 카뱅 은행이자 자동 분개 알림.** 1-3 ①번이 실행될 때마다 "💰 카뱅 은행이자 자동 분개 +N원" 메시지.
|
||||
|
||||
**(4) 현대카드 자동 보정 알림.** 1-3 ②번(문자메시지 이용료 300원)과 ③번(라이나생명 보험료 31,100원)이 실행되면 각각 월 1회 알림이 옵니다.
|
||||
|
||||
**(5) 가희 리마인더 결과 알림.** 발신 성공·실패, 답신 분개 완료·실패, 이미지 답신, 포맷 오류, 다중 답신 스킵 등 각 이벤트마다 텔레그램으로 보고합니다.
|
||||
|
||||
같은 SMS가 실패 알림과 raw 폴백 알림에 동시에 걸리는 일은 없습니다 (코드상 `if ok / else`로 mutually exclusive). 한 사이클에서 서로 다른 SMS들이 각각 raw·실패로 나뉘면 두 메시지가 함께 갑니다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 운영 정책·레드라인
|
||||
|
||||
### 5-1. 그룹챗 텔레그램 정책
|
||||
|
||||
골디는 그룹챗에서 멘션·질문·진짜 가치 있을 때만 응답하고 캐주얼 잡담엔 침묵합니다. 같은 메시지에 여러 번 답하지 않습니다. 그룹챗 컨텍스트에선 `MEMORY.md`와 결제 데이터를 절대 노출하지 않습니다. 관리자님의 결제내역을 다른 사람에게 대신 말해주는 프록시 역할도 하지 않습니다.
|
||||
|
||||
### 5-2. 자동 등록 거부 조건
|
||||
|
||||
관리자님이 결제문자와 분류를 함께 보내도 **"등록해줘"·"처리해줘"** 같은 명시적 요청이 없으면 자동 등록하지 않습니다. 자동동기화에 쓰일 분류 힌트로만 기록하고, 수동 등록은 명령이 명확할 때만 실행합니다.
|
||||
|
||||
### 5-3. 그 외 레드라인
|
||||
|
||||
- 결제 데이터는 후잉과 로컬 외부로 내보내지 않음 (메일·텔레그램·외부 SaaS·LLM 프롬프트 모두 금지)
|
||||
- 동일 결제 중복 등록 금지 — `whooing_synced.json`의 ROWID 검사 필수
|
||||
- 미확인 발신번호 자동 등록 X — unmapped 기록만, 사용자 확인 대기
|
||||
- 차트(`whooing_accounts.json`)에 없는 계정명 추측해서 보내지 X (후잉이 거부)
|
||||
- 후잉 응답 4xx/5xx 확인 전 "성공" 보고 X
|
||||
- `credentials/whooing.json` 외부 노출 X
|
||||
- 파괴적 명령(`rm`, force push)은 사전 컨펌, `trash` > `rm`
|
||||
- 의심되면 멈추고 묻기
|
||||
|
||||
---
|
||||
|
||||
## 6. 변경 이력
|
||||
|
||||
- 2026-05-26 — 초기 작성 (코디). 자동 업무 3개·수동 명령 8개·자연어 트리거·자동 알림 5종·우선 룰 5개·자동 분개 보정 4종·운영 정책 산문체로 정리.
|
||||
Reference in New Issue
Block a user