일기 slecs

946원 차이를 끝까지 파고 앱들은 제출 행렬

목차

오전 시작을 정산 화면 앞에서 했다. 어제 드릴다운 초안을 올려두고 잔 거라, 오늘 아침 가장 먼저 할 일은 "수수료가 왜 이렇게 나오는지 파트너가 직접 확인할 수 있게 만들기"였다. 기능이 없는 게 아니라 있는데 설명이 부족한 경우가 제일 애매하다. 파트너 입장에서는 숫자가 떨어져 나와 있고, 그 숫자가 어디서 왔는지 못 따라가면 불신이 쌓인다. 그걸 해소하는 게 오늘의 주 목표였다.

수수료가 한 줄 숫자로 끝나면 안 된다는 판단

파트너 정산 간단히보기 화면에는 이미 수수료 합계가 찍혀 있었다. 문제는 그게 정률인지, 건당인지, 올림이 붙은 건지 전혀 구분이 없었다는 것. 정률 수수료는 충전금액에 비율 곱하는 단순 계산이라 파트너가 직접 검산할 수 있다. 그런데 건당 수수료는 다르다. 충전 한 건당 고정 금액을 떼는데, 여기서 이월 유입분이 섞이면 직접 세어봐도 숫자가 안 맞는다.

오늘 오전 내내 거기에 박혀 있었다.

파트너 정산 간단히보기 수수료 정률/입금건당 분리 표시 (DB 무변경) 이 커밋이 제일 오래 걸렸다. DB를 건드리지 않으면서 기존 데이터로 정률분과 건당분을 각각 뽑아내야 했다. 쿼리 매퍼를 열어서 기존 ledger 구조를 다시 읽었다. 입금 건수 기준으로 건당 부과액을 끊어내려면 충전 이벤트마다 어떤 수수료 규칙이 적용됐는지를 역추적해야 하는데, 과거 데이터엔 그 컨텍스트가 명시적으로 없었다.

그래서 과거 수수료 건 ledger 재연 분해 — ALTER 없이 전 기간 정률/건당/올림 표시 커밋이 뒤따라 나왔다. 테이블 구조를 바꾸지 않고, 쿼리 레벨에서 시점별 수수료 규칙을 조건 분기로 재연하는 방식. 지저분하지만 마이그레이션 없이 전 기간 데이터를 그대로 쓸 수 있다는 장점이 분명했다. 운영 중인 시스템에서 ALTER는 항상 부담이니까.

분리는 됐는데, 이번엔 올림 표기가 문제였다.

약 +0원이 화면에 찍히는 걸 보고

건당 수수료를 분할 부과할 때 소수점 올림이 발생한다. 한 달에 여러 번 충전하면 회차마다 올림이 붙고, 그게 누적되면 최종 합계와 단순 계산 결과가 조금 달라진다. 이걸 표시하려고 약 +N원 형식을 썼는데, 어떤 케이스에서는 올림이 1원 미만이라 약 +0원이 찍혔다. 의미도 없고 오히려 헷갈린다.

fix: 드릴다운 문구·폭 다듬기 — '약 +0원' 제거(1원 미만 표기) 커밋. 1원 미만이면 그냥 표시 자체를 안 한다. 그리고 정확값은 툴팁으로 숨겨뒀다. 화면에는 원 단위 반올림한 값만, 정말 정확하게 보고 싶은 사람은 툴팁 열어보게. 올림 표시 원 단위 반올림 (약 +N원) — 소수점 노출 제거, 정확값은 툴팁 커밋이 그 작업이다.

그런데 여기서 다시 막혔다. 정확값을 나중에도 재현할 수 있으려면 올림분을 어딘가 저장해야 한다는 생각이 들었다. 지금은 쿼리로 그때그때 계산하는데, 계산 로직이 바뀌면 과거 수치가 달라질 수 있다. 그래서 수수료 올림분 정확값 memo 기록 — 건당 분할 올림까지 검산 커버 커밋에서 유틸 클래스에 memo 기록 방식을 추가했다. 나중에 감사 요청 들어왔을 때 숫자가 흔들리면 안 된다.

946원이라는 숫자

이월 유입분 분리 커밋 메시지에 "946원류 차이 완전 자가검산"이라고 썼다. 실제로 테스트 데이터에서 파트너 한 곳의 건당 수수료 합계가 직접 계산한 것보다 946원 차이가 났었다. 처음엔 버그인 줄 알고 쿼리를 세 번 다시 읽었다. 알고 보니 이월 유입분이 당월 건수에 포함되어 계산되는 구조 때문이었다.

이월 유입분이란, 전월에 충전했지만 당월에 정산이 이뤄진 건을 말한다. 이게 당월 건수에 합산되면 건당 수수료가 실제 충전 건수보다 더 많이 부과된 것처럼 보인다. 건당 수수료 이월 유입분 분리 표시 커밋에서 이걸 별도 행으로 뺐다. 파트너가 보기에 "이건 지난달 충전분에 대한 수수료입니다"라는 맥락이 있어야 946원이 이상한 숫자가 아니라 납득 가능한 숫자가 된다.

그 다음 검산 3단계 — 충전건별 건당 수수료 표를 추가했다. 충전 이벤트별로 회원, 충전액, 장수, 건당 부과, 기준 대비 초과를 줄줄이 펼쳐서 보여주는 테이블. 파트너가 직접 한 행씩 대조할 수 있게. 이 정도 되면 "우리 시스템이 수수료를 임의로 뗀다"는 오해는 생길 수가 없다.

드릴다운 분해 표현도 손봤다. 원래는 한 줄에 쭉 나열되는 식이었는데, 항목별로 줄바꿈하고 일상어로 바꿨다. "정률 N원 + 건당 M원 + 올림 K원 = 합계"라는 구조를 누가 읽어도 따라갈 수 있게.

드릴다운 폭이 420px로 고정돼 있었던 것도 고쳤다. 모바일에서는 괜찮은데 데스크탑에서는 좁아 보였다. 720px로 늘리면서 분해 줄이 더 자연스럽게 배치됐다.

건수 라벨 문제도 있었다. 드릴다운에 "건수"라고만 써두니 입금 건수인지 부과 건수인지 헷갈린다는 피드백이 있었다. 드릴다운 건수 라벨 '부과 건수'로 명확화 — 입금 건수 오독 방지 커밋. 충전 수수료는 충전(입금) 건수, 결제 수수료는 결제 건수가 기준인데 이게 같은 "건수"로 보이면 안 된다. 툴팁으로 각각 설명도 붙였다.

당겨서 새로고침이 결제를 날릴 뻔했다

정산 작업하는 사이에 다른 이슈가 하나 올라왔다. 앱 웹뷰에서 결제 화면을 당겨 새로고침하면 결제 페이지가 초기화된다는 것. 사용자가 결제 직전에 실수로 당겼다가 처음부터 다시 하게 되는 상황. 불편함을 넘어서 결제 이중 시도 가능성도 있다.

no-pull-refresh.js를 공통화한 커밋이 여기서 나왔다. 처음에는 결제·인증 화면 각각에 인라인으로 막아뒀는데, 이번에 6개 페이지에 일괄 적용하면서 공통 스크립트로 뺐다. ai-chat, cancelRequest, checkout, contact, kyc, payAccount - 전부 당겨 새로고침이 위험한 화면들이다.

그런데 PTR(Pull to Refresh) 비활성 자체가 생각보다 까다로웠다. 앱 PTR 비활성 재전송 강화 — onPageFinished 재활성 타이밍 레이스 봉합 커밋 메시지에서 보이듯이, onPageFinished 타이밍에 재활성화가 먼저 일어나는 레이스 컨디션이 있었다. 웹뷰가 페이지 로딩을 완료했다고 알린 직후, PTR 비활성 신호가 아직 도달하기 전에 사용자가 당기면 뚫렸다. load, pageshow 이벤트에 각각 걸고, 추가로 지연 3회를 줘서 타이밍 창을 최대한 닫았다.

휴대폰 인증 조각(_phone-auth.jsp)에도 내장했다. 인증 쓰는 화면이 어디 붙느냐에 따라 자동으로 PTR 차단이 되게. 조각 단위로 관리하면 나중에 인증 화면 추가될 때 매번 따로 안 넣어도 된다는 장점이 있다.

반응형 20페이지를 한 번에

파트너포탈 반응형 이슈가 누적돼 있었다. 295px, 390px 뷰포트에서 가로넘침이 발생하는 페이지들. 295/390px 20페이지 가로넘침 0 커밋. commission, dashboard, settlement JSP 세 파일과 common.css, 사이트별 CSS 두 개를 함께 수정했다.

가로넘침은 대부분 고정 폭 요소가 원인이다. 표가 min-width로 고정돼 있거나, 카드 안에 있는 텍스트가 줄바꿈이 안 되거나. 간단히보기 모바일 뷰포트 — 표 가로스크롤 격리 + 설명줄 줄바꿈 강제 커밋이 그 중 하나. 표는 스크롤 컨테이너 안에 격리해서 표만 옆으로 스크롤되게, 설명줄은 강제로 줄바꿈 되게.

290px짜리 폴더블 기기에서 이 화면을 쓰는 파트너가 얼마나 있을지 모르겠지만, 튀어나오는 걸 그냥 두는 건 습관상 싫다.

예치금 관리 요약 카드 쉬운 설명줄 추가도 같은 맥락이다. 숫자만 있고 그게 뭔지 설명이 없으면 파트너 입장에서는 물어봐야 한다. 물어보기 전에 화면에서 읽을 수 있게. 작은 커밋이지만 CS 인입 줄이는 종류의 작업들이다.

영수증 번호 검색은 리뷰 피드백을 반영했다. 엑셀 다운로드 경로 동기화가 안 돼 있었고, 파라미터 위조 방어가 미흡했다. 영수증 승인번호(TN-일련번호) 포맷과 발급번호 모두 검색에 매칭되게 쿼리 매퍼도 수정했다. 파트너가 영수증 번호로 직접 찾아볼 수 있으니 CS 대응도 편해진다.

앱들 제출 행렬

오후 들어서는 모바일 앱 쪽 작업이 겹쳤다. Play 콘솔에서 8/6에 신청한 배치 16개 앱의 프로덕션 승인이 오늘(8/8) 처리됐다. play_prod_apply.json에 오버레이 반영했다. AgoLog도 별도로 승인.

여러 앱에 걸쳐 비슷한 패턴의 커밋이 반복됐다. ITMS-90683, ITMS-90068 두 코드가 오늘 자주 등장했는데:

  • ITMS-90683: 위치 권한 purpose string 없는 앱. 광고 SDK가 위치 API를 참조하면 App Store Connect에서 거절한다. NSLocationAlwaysAndWhenInUse, NSLocationWhenInUse 두 가지 모두 넣어야 한다. 이걸 여러 앱 Info.plist에 "선반영"으로 넣어두는 커밋들이 오늘 여러 개 나왔다.
  • ITMS-90068: iOS deployment target 문제. 15.0 미만 앱이 섞여 있었다. project.pbxproj에서 IPHONEOS_DEPLOYMENT_TARGET을 15.0으로 맞췄다.

SPM 자동 마이그레이션 비활성도 건드렸다. reddose에서 같은 사고가 있었다는 메시지가 커밋에 있어서, Package.resolved를 복원하고 자동 마이그레이션을 비활성화했다. SPM이 알아서 업그레이드를 시도하다가 호환성이 깨지는 경우가 있었던 것 같다.

안드로이드 빌드번호는 앱마다 다르게 올라갔다. Play 프로덕션 첫 출시인 앱들이 여럿인데, 빌드번호 범프와 함께 서명 설정도 같이 잡았다. android/app/build.gradle.kts에 release signing config 추가, iOS는 ExportOptions.plist에서 수동 서명으로.

NSCameraUsageDescription도 Info.plist에 추가했다. 광고 SDK가 카메라 API를 참조하면 App Store가 걸어내는 또 다른 게이트. 실제로 앱이 카메라를 쓰지 않아도 SDK 레벨에서 참조가 있으면 심사 통과가 안 된다.

Pro 게이트들

여러 앱에서 비슷한 작업이 있었다. 무료 플랜 사용자에게는 일부 기능만 열어주고, 핵심 기능은 Pro 전용으로 가리는 게이트를 강화하는 작업. 세션 히스토리 3건 제한, 전체 통계 Pro 전용, 실수 체크 3회 제한, 연속 로깅 10분 캡, 기간 PDF 리포트 Pro 전용, 히스토리/통계/사진 비교 Pro 전용.

앱마다 각자의 l10n arb 파일에 다국어 문자열을 추가했다. 영어를 기준으로 독일어, 스페인어, 프랑스어, 이탈리아어, 일본어, 아랍어, 힌디어 등이 따라붙는다.

AgoLog는 오늘 v1 초기 구현 커밋이 들어갔다. 원탭 기록 추적기, 8로케일, 로컬 전용, 평생 Pro IAP 구조. 앱 아이콘까지 들어갔고, RTL 스와이프 정렬, 삭제 undo, 알림 토글 힌트 같은 리뷰 피드백도 반영됐다. 9개 시나리오 e2e 통합 테스트도 있다. 8/8 Play 프로덕션 승인이 같이 떴다.

eBay 0건 mock 시세 제거 커밋도 있었다. 실 키로 전환한 다음에 결과가 0건일 때 가짜 mock 데이터를 폴백으로 보여주던 게 남아 있었던 것. 이걸 제거하고 빈 상태 UI + 크레딧 환불로 대체했다. 있지도 않은 시세를 보여주는 건 서비스 신뢰도 문제다.

포즈 가이드 팩은 오늘 빌드번호 범프와 함께 출시됐다. 152개 포즈, 무료 2개 Pro 150개 구조, 실루엣 코드렌더, 2인 골격, 8개국어. 1.9(16) 범프. store/listing.md에 1.9 리스팅 포즈 가이드 반영 기록.

자동화된 것들

psy 쪽 일 자동 생성 커밋이 오늘 자동으로 들어왔다. friend-boardgame-type, ktx-travel-type, night-market-spirit 세 개. 커버 이미지와 JSON이 같이. 이쪽은 건드릴 게 없다.

1.0.5 자동 제출 스크립트(gs_autosubmit_105.py)도 오늘 커밋됐다. 1.0.4 심사 종료를 감지하면 1.0.5를 자동 제출하는 구조, mac cron 30분 주기. 스토어 제출 타이밍을 직접 지켜보지 않아도 되게.


총괄하고 나면 이런 날은 작업 전환 비용이 제일 크다. 정산 드릴다운에 집중하다가 no-pull-refresh 버그로 컨텍스트 스위치, 다시 앱 빌드 범프로 이동, 중간에 ITMS 코드 대응, 다시 정산으로 돌아와 946원 추적. 각각을 끝낼 때는 나름 깔끔한데, 오가는 사이에 뭔가 빠뜨린 게 없나 하는 찝찝함이 남는다.

정산 드릴다운은 오늘로 어느 정도 형태가 잡혔다. 검산 3단계까지 넣었으니 파트너가 자기 수수료를 직접 검증할 수 있는 구조는 됐다. 남은 건 실제 파트너 반응.

댓글 0

첫 댓글 달아줘.