尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗매달 조용히 빠져나가는 정기 구독을 찾아 정리하는 웹앱입니다. 통장·카드·간편결제 거래내역과 Gmail·네이버메일 영수증을 함께 보고, 직접 등록하지 않아도 구독 목록과 다음 결제일, 돈이 나간 경로(예: 농협은행 계좌 → 카카오페이 → 멜론)를 보여 줍니다.
화면의 데이터는 모두 가상 데이터입니다.
| 단계 | 내용 | 상태 |
|---|---|---|
| 1 | 탐지 엔진을 가상 데이터로 검증 | 완료 |
| 2 | 웹앱 기본 틀: 내역 올리기, 구독 목록, 수정, 여러 내역 교차검증, 로그인(Supabase) | 완료 (가상 데이터와 실제 내역 2종으로 확인) |
| 3 | 메일(IMAP) 수집을 앱에 연결 | 예정 |
| 4 | 배포와 마무리 | 예정 |
실제 거래내역 파일은 토스뱅크 거래내역과 카카오페이 머니 거래내역(둘 다 비밀번호가 걸린 엑셀)으로 확인했습니다. 다른 은행·카드사 파일은 아직 확인하지 않았습니다.
올린 파일은 브라우저 안에서 읽고 분석합니다. 원본 파일과 엑셀 비밀번호는 어디에도 올리지 않으며, Supabase 모드에서는 정리된 거래 행과 메일 내용이 DB에 저장됩니다.
탐지는 packages/engine에 있고, 브라우저와 Node 양쪽에서 같은 코드가 돕니다.
src/io/)
src/reconcile.ts)
농협은행 계좌 → 카카오페이 → 멜론, 신한카드 → 네이버페이 → 네이버플러스 멤버십.농협은행 계좌 → 카카오페이 머니 → 이모티콘 플러스). 그 통장 내역을 올리지 않았어도 머니 내역에 충전 은행이 적혀 있으면(카카오페이 머니의 '은행' 열) 그 계좌로 봅니다.src/detect/recurring.ts)
(주) 같은 표기 제거, 알려진 서비스는 별칭으로 통일).APPLE.COM/BILL)처럼 한 가맹점에 구독이 여러 개면 금액별로 나누고, 해외 결제는 달러 금액으로 비교합니다.주식회사 카카오 → 카카오구독료_카카오페이)은 앞 묶음이 끝난 바로 다음 차례에 같은 금액으로 이어지고 회사 이름이 같을 때 하나로 잇습니다.src/email/parse.ts)
src/match/cross-verify.ts)
Node.js 22.18 이상이 필요합니다 (엔진의 TypeScript 파일을 빌드 없이 실행합니다).
npm install
npm run dev # http://localhost:3000
첫 화면의 가상 데이터로 체험하기를 누르면 데모 사용자의 통장·카드·카카오페이·네이버페이 내역과 메일이 들어갑니다. "내역 올리기" 화면에서 같은 가상 파일을 내려받아 직접 올려 볼 수도 있습니다.
그 밖의 명령 (저장소 루트에서 실행):
npm test # 엔진·웹 단위 테스트
npm run typecheck
npm run build
npm run generate # 데모 데이터 → packages/engine/data/sample
npm run detect # 명령줄로 탐지 → packages/engine/out/result.md
npm run detect -- data/private # 내 파일로 탐지 (CSV·엑셀과 emails-*.json을 넣은 폴더)
npm run evaluate -- 300 # 가상 사용자로 정확도 평가 → packages/engine/out/evaluation.md
실제 개인 데이터는 data/private/에 두세요. 이 폴더는 git에 올라가지 않습니다. 비밀번호가 걸린 엑셀은 환경 변수 CASHLEAK_PASSWORDS(쉼표로 여러 개)로 비밀번호를 주면 차례로 넣어 봅니다. 명령에 직접 적으면 셸 기록에 남으니 주의하세요.
Supabase 스키마와 행 수준 보안 시험은 PostgreSQL이 필요해서 CI(.github/workflows/ci.yml)에서 돌립니다. 로컬에서는 PGHOST 등 접속 환경 변수를 지정하면 npm test -w @cashleak/web에 함께 포함됩니다.
Vercel에 올려 씁니다. 분석과 엑셀 암호 풀기는 브라우저 안에서 하므로 거래내역 파일과 비밀번호는 서버로 가지 않습니다.
apps/web으로 정합니다. 프레임워크(Next.js)와 설치·빌드 명령은 기본값 그대로 둡니다. 엔진(packages/engine)은 Root Directory 밖에 있지만, 기본으로 켜져 있는 "Include source files outside of the Root Directory" 설정 덕분에 함께 빌드됩니다.NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY를 넣습니다 (설정 방법).그다음부터는 main에 머지할 때마다 다시 배포되고, PR마다 미리보기 주소가 생깁니다.
아이폰에서는 Safari로 배포 주소를 열고 공유 → 홈 화면에 추가를 누릅니다. 홈 화면 앱은 Safari와 저장 공간이 따로라서, 내역은 홈 화면 아이콘으로 연 앱 안에서 올려야 합니다. 배포 주소는 누구나 열 수 있지만, 브라우저 저장 모드에서는 각자 기기에만 저장되므로 다른 사람이 내 내역을 볼 수 없습니다.
apps/web/ Next.js 웹앱 (아이폰 홈 화면에 추가해 쓰는 용도)
app/ 화면: 구독 목록, 구독 상세, 결제 내역, 내역 올리기
lib/files.ts 파일 판별·읽기·중복 제거
lib/view.ts 탐지 결과와 사용자 수정을 합쳐 화면용 데이터로
lib/store/ 저장소: 브라우저(localStorage) / Supabase
packages/engine/ 탐지 엔진 (의존성: 엑셀 압축 풀기 fflate, 암호 풀기 @noble/hashes·@noble/ciphers)
src/reconcile.ts 여러 내역 맞추기, 결제 경로
src/detect/ 반복 결제 탐지
src/email/ 메일 영수증 파서
src/match/ 거래·영수증 교차검증, 신뢰도
src/io/ CSV·엑셀(비밀번호 포함) 읽기, 통장·카드·간편결제 내역 가져오기
sim/ 가상 데이터 생성기와 채점
scripts/ generate / detect / evaluate
data/sample/ 데모 사용자 데이터와 정답(truth.json)
test/fixtures/ 비밀번호 걸린 엑셀 시험 파일(가상 데이터)과 만드는 스크립트
supabase/migrations/ DB 스키마와 행 수준 보안 정책
supabase/tests/ 행 수준 보안 시험
docs/ 평가 결과, 실행 예시, Supabase 설정
데모 사용자(구독 18개, 함정 데이터 포함)는 17개를 찾았습니다. 놓친 티빙은 결제 1건에 영수증이 없어 원리상 찾을 수 없는 경우입니다. 실행 결과 예시는 docs/sample-result.md에 있습니다.
가상 사용자 301명(데모 1명 + 무작위 300명) 평가, 전체 결과는 docs/evaluation.md:
| 지표 | 값 |
|---|---|
| 재현율 (찾을 수 있는 구독 기준) | 100% |
| 재현율 (전체, 흔적이 부족한 구독 포함) | 93.7% |
| 재현율: 간편결제 내역도 올린 경우 (235명) | 94.7% |
| 재현율: 통장·카드만 올린 경우 (66명) | 90.0% |
| 정밀도 (이용 중 + 신뢰도 보통 이상, 앱에서 확정으로 보여 주는 목록) | 100% |
| 정밀도 (해지 추정, 신뢰도 낮음까지 전체) | 97.5% |
| 금액 / 주기 / 상태 정확도 | 100% / 100% / 100% |
| 다음 결제일 (±3일 / 정확히 일치) | 100% / 98.8% |
| 결제 경로 정확도 (구독 1,999개) | 100% |
| 간편결제 ↔ 통장·카드 연결 정밀도 / 재현율 (11,245쌍) | 100% / 100% |
오탐 52건은 모두 신뢰도 "낮음"입니다. 대부분 편의점·서점·택시에서 우연히 한 달 간격으로 비슷한 결제가 반복된 경우이고, 간편결제 내역 없이 통장만 올렸을 때 구독과 구분되지 않는 카카오페이·네이버페이 출금이 11건입니다.