[바이브코딩 도전기] Claude Code + VS Code로 가계부 기능을 하나씩 붙여나간 과정

1편에서 NAS에 PHP 환경을 올리고, 2편에서 기본 틀을 잡은 뒤, 이번엔 본격적으로 기능을 붙이기 시작했다. 도구는 VS Code와 Claude Code. 터미널에서 Claude Code를 실행하면 현재 프로젝트 파일을 읽고, 내가 원하는 걸 말하면 코드를 직접 수정해준다. 처음엔 반신반의했는데, 쓰다 보니 꽤 실용적인 루틴이 생겼다.

전체 흐름은 단순하다. VS Code에서 파일 열기 → Claude Code에 요청 → 수정된 파일 확인 → NAS에 업로드 → 브라우저에서 확인 → 문제 있으면 다시 Claude Code에 질문. 이걸 기능 하나마다 반복한다. 생각보다 오류가 많이 나오고, 생각보다 금방 해결되기도 한다.


튜토리얼 툴팁이 다른 요소 뒤로 숨어버리는 문제

처음 만든 기능 중 하나가 화면 첫 진입 시 보여주는 튜토리얼 툴팁이었다. 그런데 실제로 켜보니 툴팁이 하이라이트 처리된 요소 뒤로 숨어버렸다. 분명히 z-index를 높게 줬는데도 안 됐다.

Claude Code에 상황을 설명하고 물어봤더니, 문제가 z-index 숫자 자체가 아니라 stacking context에 있다고 짚어줬다. 부모 요소에 transform이나 opacity가 걸려 있으면 자식의 z-index가 아무리 높아도 그 부모 범위 안에서만 쌓인다는 거다. 해결책은 툴팁 DOM을 <body> 바로 아래로 옮기는 것이었다.

style.css에서 툴팁 관련 z-indexvisibility를 조정하고, 툴팁 엘리먼트를 JS로 document.body.appendChild해서 붙이는 방식으로 바꿨다. 브라우저에서 확인하니 이번엔 제대로 위에 떴다. 이런 CSS 레이어링 문제는 직접 겪어봐야 감이 오는 부분인데, Claude Code가 원인을 꽤 정확하게 짚어줘서 시간을 많이 아꼈다.


iOS 홈 화면에 추가했더니 아이콘이 없었다

PWA처럼 홈 화면에 추가해서 쓰고 싶었다. 아이폰에서 Safari로 접속해 홈 화면에 추가했는데, 아이콘 자리에 그냥 빈 화면 캡처가 들어갔다.

원인은 단순했다. apple-touch-icon은 SVG를 인식하지 못한다. PNG 파일이 필요하다. 그래서 macOS의 qlmanagesips 명령어로 SVG를 PNG로 변환했다. 만든 크기는 180×180, 192×192, 512×512, 그리고 파비콘용 32×32.

# SVG를 PNG로 렌더링 (예시)
qlmanage -t -s 512 -o . icon.svg
sips -z 180 180 icon.png --out apple-touch-icon.png

이후 manifest.webmanifest 파일을 새로 만들어서 아이콘 경로와 크기를 등록했고, HTML <head><link rel="apple-touch-icon">도 추가했다. 다시 홈 화면에 추가하니 아이콘이 정상적으로 나왔다. 사소한 것 같아도 매일 쓸 앱이니까 이런 디테일이 은근히 중요하다.


월급명세서에 수시급여 이름을 직접 입력하게 만들기

월급 화면을 만들 때, 정기급여 항목은 고정이지만 수시급여는 달마다 이름이 다를 수 있다. 예를 들어 어떤 달엔 “특별 상여”, 어떤 달엔 “프로젝트 인센티브” 같은 식으로. 처음엔 그냥 드롭다운으로 고정값만 고르게 했는데, 쓰다 보니 불편했다.

수정 범위가 DB, API, 화면 세 군데였다. DB의 salary_records 테이블에 label 컬럼을 추가하고, payroll.php API에서 해당 컬럼을 읽고 쓰도록 수정하고, payroll.js에서 입력 필드를 텍스트 입력으로 바꿨다.

Claude Code에 “수시급여 이름을 자유 입력으로 바꾸고 싶다, DB 컬럼도 추가해야 한다”고 설명했더니 세 파일을 한 번에 수정해줬다. 물론 DB 마이그레이션은 직접 실행해야 했다. 기존 데이터가 있어서 ALTER TABLE로 컬럼을 추가하고 기본값을 설정하는 작업을 따로 했다.


연도·월 이동 버튼이 가끔 안 눌리는 문제

대시보드, 월급, 카드 화면 모두 상단에 연도·월을 앞뒤로 넘기는 버튼과 “오늘” 버튼이 있다. 그런데 화면이 처음 로드될 때 버튼이 가끔 반응을 안 했다.

원인은 모듈 초기화 타이밍이었다. JS 모듈이 완전히 준비되기 전에 버튼에 이벤트를 붙이려다 실패하는 경우가 생겼던 거다. 해결 방법으로 이벤트 위임 방식을 썼다. 버튼 각각에 직접 리스너를 붙이는 대신, 상위 컨테이너에 리스너를 하나 달고 클릭된 요소가 어떤 버튼인지 판단해서 처리하는 방식이다.

이렇게 하면 DOM이 완전히 준비되지 않은 시점에도 이벤트를 놓치지 않는다. 수정 후엔 새로고침 직후에도 버튼이 안정적으로 동작했다.


카드 내역 필터와 일괄 수정 기능

카드 내역이 쌓이기 시작하면서 필터가 필요해졌다. 기간 조건을 추가했는데, 여기서 한 가지 더 신경 쓴 게 있다. 필터를 걸고 나서 “선택 삭제”를 누를 때, 필터 조건이 삭제 API에도 같이 전달돼야 한다는 점이었다. 안 그러면 화면에 보이는 것과 실제 삭제되는 것이 달라질 수 있다.

일괄 수정 기능도 붙였다. 여러 행을 체크박스로 선택한 뒤 태그, 메모, 국내외 여부를 한 번에 바꾸는 update_bulk API를 만들고, 화면에는 선택 시 하단에 일괄 수정 패널이 뜨는 방식으로 구현했다.

체크박스 드래그 선택도 넣었는데, 여기서 작은 버그가 있었다. 드래그를 시작한 첫 번째 행이 선택됐다가 바로 토글돼서 해제되는 문제였다. 드래그 시작 시점에 이미 클릭 이벤트가 한 번 발생하기 때문이었다. 드래그 시작 행은 직접 토글하는 방식으로 따로 처리해서 해결했다.


카드 청구월 재분류 — 카드사마다 다른 결제일 처리

카드사마다 결제일과 사용 기간 오프셋이 다르다. 예를 들어 A카드는 매월 15일 결제에 전월 사용분이고, B카드는 25일 결제에 당월 사용분인 식이다. 처음엔 이걸 무시하고 거래일 기준으로만 월을 분류했는데, 실제 가계부를 쓰다 보니 청구월 기준으로 봐야 의미가 있다는 걸 느꼈다.

카드사별로 결제일과 오프셋을 설정하고, 거래일을 기준으로 어느 청구월에 해당하는지 다시 계산하는 로직을 추가했다. 이 작업을 적용하고 나면 기존에 입력된 거래 데이터의 청구월이 바뀔 수 있다. Claude Code도 이 점을 명확하게 안내해줬다. 예를 들어 특정 카드의 6월 거래가 실제론 5월 사용분으로 재분류될 수 있다는 식으로. 데이터를 건드리는 변경이라 적용 전에 DB 백업을 먼저 했다.


개발하면서 느낀 것들

Claude Code를 쓰는 방식이 점점 자리를 잡아가고 있다. 처음엔 “이거 만들어줘”처럼 뭉뚱그려 요청했는데, 이제는 “현재 이런 구조인데, 이 부분에서 이런 문제가 생긴다, 어떻게 수정하면 좋겠냐”처럼 맥락을 같이 넘기는 게 훨씬 결과가 좋다는 걸 알았다.

수정된 파일을 그냥 올리지 않고, VS Code에서 diff를 한 번 훑어보는 습관도 생겼다. AI가 내가 요청하지 않은 부분을 같이 바꾸는 경우가 가끔 있어서, 의도치 않은 변경이 섞이지 않았는지 확인하는 게 중요하다.

NAS에 올리고 나서 실제로 써보는 시간도 개발만큼 중요하다. 만들 때는 몰랐던 불편함이 며칠 쓰다 보면 눈에 보인다. 이번 편에서 정리한 기능들도 대부분 그렇게 발견해서 고친 것들이다.

다음엔 지출 분석 차트와 예산 대비 현황 화면을 붙이는 과정을 정리해볼 생각이다.


시리즈 글 모아보기

댓글 남기기