풀스택
"텅~ 장" 개발일지
개인 웹 가계부 서비스 "텅~ 장"을 하루 동안 13개 세션(113차~125차)에
걸쳐 작업한 내용 정리. 블로그 글 작성용 초안 자료.
오늘 한 일 한눈에 보기
- 카드 관리에 "체크카드(즉시결제)" 토글 추가
- 메모 첨부 이미지 클라이언트 압축(용량 92.7% 감소)
- 1인 사업자용 "세금 계산기" 기능 전체 구축 (스키마 → API → UI → Push 알림 → 배포)
- 구글 검색 노출을 위한 SEO 기본 요소 추가
- 개인정보처리방침/이용약관 페이지 + 실제 회원 탈퇴 기능
- 비로그인 사용자용 랜딩 페이지(기능 소개 + 실제 스크린샷)
- README 최신화
1. 체크카드(즉시결제) 토글 (113차)
계기: "카드 탭에 체크카드 토글을 하나 만들어서 혜택은 적용되고 결제는
바로 적용되도록 하는건 어때, 요새 지역 화폐 카드가 많이 있잖아" 라는
요청에서 출발.
- 이 앱의 "카드"는 원래 신용카드(청구일/마감일이 있고 나중에 청구되는
구조)를 전제로 설계돼 있어서, 결제 즉시 통장에서 빠지는 체크카드(지역화폐
카드 등)와는 근본적으로 안 맞는 구조였음
- 카드마다
is_debit 플래그를 추가해서, 켜면 청구기간 계산을 아예
건너뛰고 거래일 그대로 그 달에 즉시 반영되도록 처리
- 혜택(할인/적립) 매칭은 원래도
card_id 등록 여부만으로 판단하고
있었기 때문에 별도 수정 없이 체크카드에서도 그대로 동작 — 요청하신
"혜택은 적용되고" 조건은 이미 만족하고 있었음
- 월간 리포트·엑셀 카드별 정산 시트도 체크카드는 청구기간 없이 즉시
반영하도록 함께 수정
2. 메모 첨부 이미지 압축 (114차)
계기: "메모에 이미 첨부하잖아, 이거 용량 줄이는 방법이 뭘까?"
- 메모 첨부 이미지가 지금까지 압축 없이 원본 그대로 R2에 저장되고
있었던 걸 확인
- 업로드 전 프론트엔드 단계에서
<canvas>로 긴 변 1600px 이하로
리사이즈 후 WebP로 재인코딩하는 방식 도입(compressImageForUpload)
- GIF는 애니메이션이 깨지지 않도록 압축 대상에서 제외, 압축 실패/
미지원 환경에서는 원본 그대로 업로드하는 폴백 처리
- 실측 결과: 4800.9KB JPEG 원본 → 349.4KB WebP로 92.7% 감소
3. 세금 계산기 (1인 사업자용) — 오늘의 메인 작업 (115~120차)
가장 많은 세션을 투입한 기능. 스키마 설계부터 실제 원격 배포까지 하루
안에 끝냄.
(1) 기반 스키마 + 설정 UI (115차)
user_tax_settings(과세유형: 일반과세/간이과세/프리랜서 3.3%, 업종별
부가율 등), tax_brackets_config(연도별 종합소득세 세율·누진공제표) 테이블 신설
- 지출 분류마다 "세무 경비 인정 여부", 거래마다 "거래처 접대 여부",
카드마다 "사업용 카드 여부"를 각각 설정할 수 있게 함
- 원칙: 간이과세자 부가율이나 세율 정보는 절대 임의로 채우지 않고,
값이 없으면 "모르면 홈택스에서 확인 후 입력"으로 안내(추정치 남발 방지)
(2) 추정 계산 API (116차)
GET /api/tax/estimate?month=YYYY-MM — 그 달 확정 매출(예정/비정산
제외) 기준으로 부가세·종합소득세를 추정
- 종합소득세는 연초~해당월 누적 순수익을 연환산해서 세율 구간을 조회한
뒤 다시 경과월수로 일할 계산
- 과세유형별로 계산식이 다 다름(일반과세: 매출세액-매입세액 / 간이과세:
공급대가×업종 부가율×10% / 프리랜서 3.3%: 부가세 해당 없음)
- 수기 계산과 대조 검증까지 완료(예: 확정매출 100만원 기준 부가세
95,000원, 종소세 54,120원 등 정확히 일치 확인)
(3) 화면 (117차)
- 수입/지출 계산기 옆에 "세금 계산기" 탭 추가
- "이 계산은 수입/지출 계산기와 기준이 다릅니다(세무 경비 기준)" 안내를
항상 먼저 보여주고, 신고를 대체하지 않는 참고용 추정치라는 걸 숫자
옆 배지 + 하단 면책 박스로 계속 강조
(4) 세금 마감 리포트 Push 알림 (118~120차)
- 카드 청구 마감 알림(
workers/card-settlement-notifier)과 같은 구조로,
매월 말일 자정(한국시간)에 그 달 세금 추정 결과를 요약해 Push로 발송하는
별도 Cloudflare Workers Cron(workers/monthly-tax-reporter) 신규 구축
- Cloudflare Cron이 "매월 말일"을 직접 표현할 수 없어서, 매일 자정에
실행하며 "오늘이 1일인지"를 체크하는 방식으로 우회
- 로컬 검증 후 원격 D1 마이그레이션 적용 + 메인 앱 배포까지 완료
(다만 Worker의 VAPID 비밀키 재등록은 사용자 확인 필요로 일단 보류)
4. 구글 검색 노출용 SEO 기본 요소 (121~122차)
- 구글 서치 콘솔 소유권 확인용 메타 태그 등록
<title>을 "텅~ 장 → 텅~ 장 — 나만의 가계부 서비스"로 키워드 노출,
description/og:* 태그, canonical 링크 추가
robots.txt, sitemap.xml 신규 작성
- 목적: 서치 콘솔 등록의 실제 목표가 "구글 검색 노출로 신규 가입자
유입"이라는 걸 먼저 확인하고, 그 목적에 필요한 최소 요소만 구성
5. 개인정보처리방침/이용약관 + 회원 탈퇴 (123차)
- 법적 문서 작업을 진행하다가 애초에 회원 탈퇴 기능 자체가 없었다는 걸
발견 → 함께 구현하기로 확정
- 탈퇴 시: 비밀번호 재확인 → 메모 첨부 이미지(R2) 개별 삭제 → 사용자
데이터를 참조하는 전체 테이블(카드/거래/예산/메모/템플릿/구독/설정 등
20여 개) 배치 삭제 → 세션 쿠키 삭제까지 실제로 동작하도록 구현
(D1은 FK cascade가 없어서 전부 명시적으로 나열해서 지움)
- 회원가입 시 이용약관 동의 체크박스를 필수로 추가(동의 전 제출 버튼 비활성화)
/privacy, /terms는 로그인 여부와 무관하게 접근 가능한 정적 페이지로 구현
- 검증: 실제로 카드/거래/예산/세금설정/메모(+R2 이미지)를 채운
계정으로 탈퇴시켜서 20여 개 테이블이 전부 0건이 되는지, R2 이미지가
실제로 삭제되는지, 탈퇴 후 같은 세션 쿠키로 API 호출 시 401이 뜨는지까지
직접 확인
6. 비로그인 랜딩 페이지 (124차)
- 기존 로그인/가입 폼은 그대로 두고, 그 위에 헤드라인 + 핵심 기능 요약
- 실제 화면 스크린샷 섹션을 추가하는 방식으로 결정(검증된 기존 폼
로직은 건드리지 않음)
- 데모 계정에 실제 수입/지출/카드/혜택/예산/세금설정 데이터를 채운 뒤
모바일 뷰포트로 홈/카드/세금계산기 화면을 실제로 캡처해서 사용
(목업 이미지 아님)
- 캡처 과정에서 헤드리스 환경에 한글 폰트가 없어서 글자가 네모(□)로
깨지는 걸 발견 → 한글 폰트 설치 후 재캡처해서 해결
- "무료로 시작하기" 버튼 클릭 시 로그인/가입 폼으로 스크롤 이동
7. README 최신화 (125차, 오늘 마지막 작업)
- 위 6개 작업(세금 계산기, 랜딩 페이지, 법적 문서/회원탈퇴, SEO) 전부가
README에 반영이 안 되어 있었던 걸 정리
- 기능 목록, 프로젝트 구조 트리, DB 스키마 설명을 실제 코드 상태와 다시
맞춤
오늘 하루 숫자로 보면
- 작업 세션 13개 (113차 ~ 125차)
- 신규 테이블 2개(
user_tax_settings, tax_brackets_config), 신규
마이그레이션 2개(029, 030)
- 신규 Cloudflare Workers Cron 1개(
monthly-tax-reporter)
- 메모 이미지 용량 92.7% 절감
- 회원 탈퇴 시 정리되는 테이블 20여 개