Joyuno's Dev Blog

2026-04-24 (금) 개발일지

dev-blog

오늘의 TIL: 다섯 개 프로젝트를 오가는 풀스택 전쟁

오늘은 정말 여러 프로젝트를 왔다갔다 한 하루였다. 아침에는 블로그 자동화 스크립트가 망가진 걸 수정하고, 오후에는 소명시스템 UI 개선, 저녁에는 트레이딩 봇 전략까지… 머리가 몇 개인지 모르겠다.

AI 블로그 자동화 스크립트의 한국어 번역 실패

아침에 joyuno.github.io 프로젝트의 AI 논문 요약 자동화 스크립트를 확인했다. 이전에는 arxiv, huggingface, git trend를 가져와서 한국어로 요약 및 번역해주던 스크립트가 갑자기 번역을 안 하고 있었다. “왜 그런지 이유좀 찾아와”라는 메모만 덩그러니.

우선 sources.yaml과 GitHub Actions의 daily-digest 워크플로 로그를 까봤다. 그러자 명백한 단서가 나왔다.

⚠️ Gemini 요약 실패: 429 You exceeded your current quota
* Quota exceeded for metric: ...generate_content_free_tier_input_token_count, limit: 0, model: gemini-3.1-pro

알고 보니 간단했다. 한동안 gemini-3-pro-preview (내부적으론 gemini-3.1-pro)를 무료 티어로 쓰고 있었는데, Google이 이 모델의 무료 티어 한도를 0으로 잘라버린 것이었다. 4/22 포스트부터 갑자기 영어 abstract만 그대로 나오던 것도 이때부터. 코드는 멀쩡했고 단지 외부 API 정책이 바뀌었을 뿐.

해결은 두 줄로 끝났다:

  1. config/sources.yaml의 모델을 gemini-3-pro-preview → gemini-2.5-pro (아직 free tier 살아있음)
  2. GitHub Secret GEMINI_API_KEY 갱신 후 워크플로 수동 트리거

수동 트리거 결과 1분 1초만에 한국어 요약이 다시 정상 출력됐다.

배운 점: 외부 API에 의존하는 자동화는 “내 코드가 안 망가져도 어느 날 갑자기 망가진다”. 워크플로 실패 시 GitHub Issue를 자동으로 생성하도록 알림 체계를 강화해야겠다는 생각이 들었다.

소명시스템의 예외 정책 UI 개선

소명처리시스템에서 pulse5 실행 전에 예외 대상자 등록 방식을 개선하는 작업이 있었다. 기존의 수동 입력 방식에서, 카드 드래그 형식으로 직관적으로 등록할 수 있게 바꾸는 작업.

051_employee_exceptions.py와 052_employee_exception_delegation.py를 수정하면서 가장 큰 문제는 중복 카드 버그였다. 같은 사람이 두 번씩 나오는 현상이 발생했는데, 디버깅해보니 임직원 정보(인사DB)와 tr-box 계정정보가 각각 조회되어 합쳐지면서 생긴 문제였다.

여기서 고민이 생겼다: “프로젝트 취지상 tr-box 사용자계정은 필요없다고 생각해?” 실제로 소명 처리 시스템이라면 임직원 정보만 있어도 충분한데, 두 데이터소스를 모두 유지해야 할까?

결국 중복 제거 로직을 추가하면서도, 두 데이터소스를 모두 유지하기로 했다. 왜냐하면 tr-box 계정정보에는 최근 로그인 기록 같은 운영 데이터가 있어서 추후 확장성을 고려해야 했기 때문.

ExceptionPolicyForm.tsx와 TargetExceptionForm.tsx를 수정하면서 예외 정책 생성 시 자동 위임자 선정 기능도 추가했다. 이 부분은 생각보다 간단했는데, 이미 있는 위임 로직을 재활용하면 됐다.

배운 점: UI 개선할 때 데이터 모델까지 함께 고려해야 한다. 단순히 보기 좋게만 만들면 뒤에서 데이터 중복 같은 문제가 발생할 수 있다.

Flutter 앱의 iOS 시뮬레이터 캡처 전략

사주 프로젝트에서는 아이폰 시뮬레이터 캡처 관련 작업을 했다. 앱 출시용 스크린샷을 더 자연스럽고 이쁘게 만들기 위해서인데, 여기서 재미난 발견을 했다.

compatibility_screen.dart와 fortune_screen.dart의 UI를 보면서, 시뮬레이터 캡처 시 실제 기기와의 차이를 최소화하는 방법을 고민했다. 특히 Info.plist의 설정들이 시뮬레이터와 실제 기기에서 다르게 동작할 수 있다는 점을 확인했다.

가장 유용했던 건 ilgan_compat.py에서 발견한 천간지지(干支) 호환성 계산 로직을 Flutter 쪽에서도 동일하게 구현해야 한다는 점이었다. 백엔드와 프론트엔드의 계산 결과가 일치하지 않으면 사용자 경험이 깨질 테니 말이다.

배운 점: 앱 스크린샷용으로 시뮬레이터를 사용할 때는 실제 기기와의 차이를 인지하고, 가능한 실제 기기에서도 테스트해야 한다.

C++ 터미널 앱의 인증 우회 모드

ficeptterminal 프로젝트에서는 인증 우회 관련 문서 작업을 했다. 01-noauth-mode.md부터 04-verify.md까지의 가이드를 업데이트하면서, AuthManager.cpp의 실제 구현을 확인했다.

여기서 흥미로웠던 점은 HttpClient.cpp에서 FINCEPT_DEV_MODE 환경 변수를 체크하는 로직이었다. 개발 모드에서는 가격 검증을 우회할 수 있도록 한 부분인데, 이걸 문서화하면서 보안과 편의성의 균형점을 다시 생각하게 됐다.

cmake --build로 릴리즈 빌드를 테스트해보니, 인증 우회 모드가 실제로 잘 동작하는지 확인할 수 있었다.

배운 점: 개발용 우회 기능을 만들 때는 반드시 문서화하고, 프로덕션에서는 자동으로 비활성화되는 안전장치가 필요하다.

트레이딩 봇의 전략 개선 인사이트

마지막으로 bit-scalp 프로젝트에서 트레이딩 전략을 분석했다. “현재까지의 수익 손실과 매매타이밍을 봤을때 개선점”을 찾아보라는 요청이었다.

risk_manager.py와 settings.py를 분석하면서 몇 가지 인사이트를 발견했다:

  1. TP(테이크 프로핏) 트레일링은 다시 빼는 게 좋을 것 같다. 백테스트 결과 오히려 수익을 줄이고 있었다.
  2. SL(스탑로스)은 2.5%로 더 엄격하게 낮춰도 될 것 같다. 현재 3%에서는 너무 늦게 커트되는 경우가 많았다.
  3. 가장 중요한 건 매크로 점수에 따른 차별화된 전략이 부족하다는 점. rsi_trend.py에서 RSI 지표만 보고 있을 뿐, 실제로 매크로 점수에 따라 TP/SL이나 코인 선정이 변하지 않고 있었다.

python -m src.main으로 봇을 실행해보니, 로그에서 명확하게 볼 수 있었다: “매크로 점수에 따라 변하지않으면 의미가 없지않아?”라는 지적이 정확히 맞았다.

배운 점: 알고리즘 트레이딩에서 가장 중요한 건 일관된 전략보다 상황에 맞게 변하는 적응형 전략이다. 단순한 규칙보다 컨텍스트 인식이 훨씬 중요하다.

오늘의 한줄

다섯 개의 다른 컨텍스트를 오가며 작업하니 머릿속 컨텍스트 스위칭 비용이 엄청났지만, 각 프로젝트의 인사이트가 서로 시너지를 내는 경험도 있었다.