2026-08-30 (일) 개발일지
오늘의 트러블슈팅 — OTLP 누수, 지원서 본문 경합, 앱 아이콘 전면 교체
오늘은 세 가지 전혀 다른 성격의 이슈를 처리했다. 하나는 방치된 백엔드 mock이 OTLP 트래픽을 계속 흘리고 있던 문제, 둘째는 SK Careers 지원서에 자소서 본문을 밀어넣다가 세션 만료와 글자수 제한에 동시에 걸린 경우, 마지막은 Flutter 앱의 아이콘 교체가 반쪽만 적용됐던 사례다. 셋 다 원인을 잘못 짚으면 시간을 크게 날릴 수 있는 유형이었다.
demo_apps — 백엔드 mock 하나가 주말 내내 OTLP를 흘리고 있었다
금요일 10시부터 돌고 있는 전송원이 있다는 걸 확인한 시점에서 시작했다. 애초에 시뮬레이터와 동백 앱은 이미 꺼져 있는 상태였고, 남은 건 백엔드 mock(PID 18095) 하나였다. 이 프로세스가 <INTERNAL_IP>:14318로 OTLP 연결을 2개 유지하며 주말 내내 데이터를 보내고 있었다.
처음 가설은 시뮬레이터나 앱 중 하나가 아직 살아 있을 거라는 생각이었다. 하지만 ps aux로 프로세스 목록을 훑었더니 시뮬레이터는 PID 자체가 없었고, 동백 앱도 마찬가지였다. 그제서야 백엔드 mock을 의심하게 됐다. netstat으로 확인하니 8080 포트만 열려 있었고, 해당 프로세스가 정확히 OTLP 엔드포인트로 연결을 유지 중이었다.
해법은 단순했다 — graceful 종료. kill -SIGTERM 18095로 보내고 2초 뒤 kill -SIGKILL로 확실히 정리했다. 종료 후 75초 간격으로 두 번 조회해서 확인했지만, 더 중요한 건 왜 이 mock이 주말 내내 돌고 있었는가였다. 개발 환경 정리 스크립트가 금요일 오후에 백엔드 mock을 빼먹은 게 원인이었다. 스크립트에 docker-compose down만 있고, 로컬에서 실행 중인 단독 프로세스는 포함되지 않은 케이스였다.
검증: ps aux | grep otel로 더 이상 프로세스가 없음을 확인. 스크립트에 pkill -f otel-collector 같은 fallback을 추가하는 걸 남은 과제로 남겼다.
자동이력서지원 — 세션 만료와 글자수 제한, 두 번의 낙차
SK Careers 지원서에 활동내역을 기입하는 과정에서 세 가지 이슈가 동시에 터졌다. 먼저 세션이 만료돼 로그인 페이지로 튕겼다. 카카오 로그인은 브라우저에서 직접 사람이 해야 하는 항목이라, 그동안 로컬에 남아 있는 본문 사본을 찾아봤다.
로컬에 있던 3건(테라시스 경력/CodeFill 팀 프로젝트/개인 프로젝트)은 원본이라 믿고 검토부터 시작했다. 그런데 글자수가 실제보다 낮게 적혀 있었다. 테라시스 경력 본문은 496자로 상한 500자에 가까웠지만, 개인 프로젝트 행의 “7개 소스”는 실제로는 수집기 10종(arxiv·huggingface·github_trending 등 10개)을 커버하고 있었다. 숫자가 안 맞았다.
원인은 서버에 저장된 본문과 로컬 사본의 버전 차이였다. 내가 마지막으로 저장한 건 7개였지만, 중간에 수집기 목록을 10종으로 늘리고 저장한 기록이 서버에만 남아 있었다. 세션 만료 때문에 로컬이 갱신되지 않은 시점의 스냅샷을 보고 있었던 것.
해법: 로그인을 마친 뒤 서버의 실제 본문을 불러와 대조했다. ApplicationSave API가 200을 반환하는 걸 확인하고, 고등학교 행은 아예 빼기로 했다. 입력 방식이 한국과 달라서 맞추기 어렵다는 판단이었다. 최종적으로 학력은 푸단대학교 1건만 남기고, 테라시스 경력 497자, 개인 프로젝트 499자, CodeFill 499자로 각각 본문을 정리했다.
검증: 새로고침 후 highSchoolRows: 0을 확인. 서버에 반영된 상태에서 실측했다. 남은 과제는 세션 타임아웃을 감지하는 로직을 추가하는 것. 만료된 세션에서 로컬 캐시를 신뢰하지 말아야 한다는 걸 이번에 뼈저리게 배웠다.
사주 앱 아이콘 — 스플래시·로그인·회원가입에 인앱 로고가 안 바뀌었다
지난번 작업에서 홈스크린 앱 아이콘(iOS AppIcon.appiconset 15종, Android mipmap 5종)만 교체하고, 인앱 로고(BrandMark 위젯) 를 그대로 뒀다. 그래서 스플래시 화면, 로그인, 회원가입, 헤더 아바타에는 여전히 예전 매화 아이콘이 떠 있었다. 사용자 입장에서는 “뭘 바꿨다는 거냐”는 피드백이 나올 만했다.
처음엔 BrandMark 위젯만 새 이미지로 교체하면 끝날 줄 알았다. 그런데 헤더 아바타는 Material 위젯으로 감싸져 있어서 CircleAvatar의 backgroundImage가 따로 처리되고 있었다. 그리고 점수 다이얼 화면(compatibility_gauge.dart)에서 57.9점이 회색으로 표시되는 문제도 같이 발견됐다 — 점수가 60점 미만이면 textLight 색상으로 빠지고, 배경 그라데이션이 color + cinnabar로 섞여 탁해지는 구조였다.
진짜 원인은 match_detail_screen.dart에서 점수 매핑 로직이 프리미엄 화면과 불일치했던 점이다. 프리미엄에서는 금색 단일 그라데이션인데, 기본 화면에서는 점수대별로 색을 다르게 매핑하다 보니 57.9점 < 60이면 회색에 가까운 textLight로 빠져서 마치 에러처럼 보였다.
해법 — 세 가지를 동시에 처리했다.
brand_mark.dart에 새 이미지(오 원상 + 연 + 매화)를 박고,splash_screen.dart와matching_screen.dart에서 위젯을 다시 참조compatibility_gauge.dart에서 점수 < 60일 때도 프리미엄과 동일한 금색 그라데이션을 따르도록 수정match_detail_screen.dart에서 57.9점 소수점 한 자리 표시로 정리
검증: Android/iOS 각각 빌드 후 스플래시 진입 → 로그인 → 회원가입 → 헤더 아바타 순으로 새 아이콘이 뜨는 걸 확인. 점수 다이얼도 57.9점이 회색이 아닌 금색 계열로 정상 표시됐다. PDF 문서 첫 페이지 대표화면도 새 캡처로 교체했다.
남은 과제: 아바타에 사진이 안 나오는 케이스는 사용자가 사진을 등록하지 않은 경우라 예외 처리로 커버할 수 있지만, 기본 이니셜 표시의 폰트 크기와 정렬이 미묘하게 안 맞는 쪽이 더 신경 쓰였다.
오늘의 한줄
방치된 프로세스 하나가 주말 내내 트래픽을 흘릴 수 있고, 로컬 캐시는 세션 만료 후 믿을 수 없으며, 앱 아이콘 교체는 홈스크린과 인앱을 반드시 나눠서 검증해야 한다.