2026-04-22 (수) 개발일지
오늘의 TIL: 드롭쉬핑 가격 버그, 사주 인증 플로우, 그리고 PDF 차트의 함정
오늘은 정말 다양한 프로젝트를 오가면서 각각의 구덩이에 빠져들었다가 기어나오는 하루였습니다. 드롭쉬핑 자동화에서는 생각치 못한 가격 버그를 발견했고, 사주 앱에서는 인증 플로우의 치명적인 구멍을 메웠으며, 소명 처리 시스템에서는 PDF 차트 렌더링의 함정에 빠졌다가 해결했습니다.
드롭쉬핑: 1380배 차이의 가격 버그
문제: 사용자가 “상품 가격이 너무 비싸다”고 보고했습니다. 확인해보니 $14,183,781 같은 말도 안 되는 가격이 표시되고 있었죠. 이게 대체 무슨 일이지?
시도: 처음에는 API 환율 계산 로직을 의심했습니다. CJ API에서 원화(KRW) 가격을 받아서 달러로 변환하는 로직을 다시 확인했는데, 이미 checkout.service.ts와 description.service.ts에는 적절한 환율 계산이 구현되어 있었습니다.
해결: 알고 보니 문제는 데이터베이스에 남아있는 과거 데이터였습니다. 이전에 KRW 환율(1380배)로 계산된 가격이 그대로 DB에 저장되어 있었고, 새로 추가된 상품들만 올바른 달러 가격을 가지고 있었습니다. classification.service.ts의 배치 처리 로직을 수정하여 기존 상품들의 가격을 일괄 재계산했습니다.
배운 점: 데이터 마이그레이션을 할 때는 항상 기존 데이터의 정합성을 확인해야 합니다. 새로운 로직이 추가되어도 오래된 데이터는 그대로 남아 있을 수 있으니까요. 이 버그로 112개 상품을 일일이 확인하는 삽질을 1시간 넘게 했네요.
사주 앱: IndexedStack의 함정과 인증 플로우
문제: 앱을 실행하면 자꾸 “서버 연결 안 됨” 에러가 나면서 로그인 페이지 대신 메인 페이지가 나타났습니다. 더 웃긴 건 IndexedStack 위젯에서 런타임 에러가 발생한다는 것이었죠.
시도: 처음에는 단순히 네트워크 연결 문제인 줄 알았습니다. api_service.dart의 베이스 URL을 확인하고, 서버 상태를 점검했지만 별 문제가 없었습니다. IndexedStack 에러는 탭 개수가 변경된 후 핫 리로드에서 발생하는 일반적인 문제라고 생각해서 무시했죠.
해결: 진짜 문제는 Splash 화면의 인증 로직에 있었습니다. 기존 코드는 토큰만 확인하고 프로필 완성 여부는 체크하지 않았어요. 그래서 이전에 로그인했던 사용자의 토큰이 남아있으면, 프로필 설정도 안 된 채로 바로 홈 화면으로 넘어가버렸습니다. splash_screen.dart와 auth_service.dart를 수정하여 checkLoginStatus() 메서드가 프로필 완성 상태까지 확인하도록 변경했습니다.
배운 점: 인증 플로우는 단순히 토큰 유효성 검사만으로 끝나면 안 됩니다. 사용자의 실제 서비스 이용 가능 상태(프로필 완성, 약관 동의 등)까지 체크하는 완전한 플로우를 설계해야 합니다. 이 간단한 사실을 놓쳐서 30분을 날렸네요.
소명 처리 시스템: PDF 차트는 왜 안 보일까?
문제: 소명 처리 보고서 PDF에 시각화 자료들이 전혀 나타나지 않았습니다. 데이터는 분명히 있었는데(4월 19일~22일, 3건 요청), 차트는 빈 공간으로 남아있었죠.
시도: 처음에는 CSS 스타일이나 PDF 패딩 설정 문제인 줄 알았습니다. pdf_generator.py의 레이아웃 로직을 확인하고, 차트 요소의 위치와 크기를 조정해봤지만 소용이 없었습니다.
해결: 문제는 reportlab의 Drawing 객체와 Image 객체의 혼동에 있었습니다. 기존 코드는 renderPDF.draw(d, buf)로 PDF drawing bytes를 생성한 후, 이걸 Image()로 읽으려고 했습니다. 하지만 Image()는 PNG/JPEG 같은 실제 이미지 파일을 기대하는데, PDF drawing bytes는 이미지가 아니었죠. 해결책은 간단했습니다: Drawing 객체를 직접 story에 추가하는 것이었습니다.
배운 점: 라이브러리의 추상화 레벨을 정확히 이해해야 합니다. “이미지처럼 생겼으니까 Image 클래스로 넣으면 되겠지”라는 추측이 오류를 야기했어요. _draw_bar_chart, _draw_line_chart, _draw_donut_chart 세 함수 모두 Drawing 반환 방식으로 수정하니 바로 해결됐습니다.
부수적 발견들
오늘은 몇 가지 재미있는 부수적 발견도 있었습니다:
-
Claude MCP 연결 문제:
claude-context서버가 Cursor IDE와의 연결이 끊겨서 실패 상태였습니다. 알고 보니 Cursor가 제공하는 내장 MCP 서버였는데, IDE를 재시작하니 해결됐네요. 가끔은 가장 간단한 해결책(재시작) 이 정답일 때가 있습니다. -
자동매매 봇의 트레일링 버그:
settings.py의 하드코딩된 트레일링 값(0.5%)이 전략 설정(1.5%)을 덮어씌우고 있었습니다. BCHUSDT가 0.8% 상승만 해도 트레일링이 활성화되어 조기 청산되는 참사가 발생했죠. 설정 파일의 우선순위를 항상 의식해야 합니다.
오늘의 한줄
데이터는 항상 거짓말을 할 준비가 되어 있고, 라이브러리는 당신이 생각하는 대로 동작하지 않으며, 가장 간단한 해결책은 종종 가장 눈에 띄지 않는다.