
연휴를 맞아 정말 오랜만에 글을 쓴다!
올해 4월부터 6월까지 진행한 정산 개편 프로젝트를 전사 직원들 앞에서 발표할 기회가 있었다. 전사 발표라는 특성상 기술적인 내용은 최소화하고, 재무팀과의 협업 경험에 집중했다. 개발자와 비개발자 간 소통이 왜 어렵고, 어떻게 극복할 수 있는지를 공유하는 것이 더 의미 있다고 생각했기 때문이다.
이 글은 그때 다루지 못했던 기술적 고민들을 정리한 회고다. 2개월간 혼자서 진행한 연 500억 원 규모의 정산 시스템 이관 프로젝트에서 무엇을 고민했고, 어떻게 해결했으며, 무엇을 배웠는지 공유하고자 한다.
높은 수준의 내용은 아닐 수 있지만, 비슷한 상황에 있는 누군가에게 도움이 되길 바란다 :)
레거시 정산 배치는 데이터팀이 작성한 N개의 복잡한 쿼리를 MyBatis Mapper를 통해 그대로 실행하는 구조였다. 이 "한방 쿼리" 방식은 수동 매출 상품 같은 엣지케이스나 복잡한 결제/환불 시나리오를 제대로 처리하지 못했고, 비즈니스 로직이 쿼리에 전부 녹아져있어 원인파악과 버그 수정이 쉽지 않았다. 결과적으로 매월 3~5일간 재무팀과 개발팀이 수작업으로 데이터를 보정해야 했다.
2025년 초 상품권 결제수단이 정산 로직 검증 없이 추가되면서 문제가 본격화되었다. 3월부터 데이터 정합성이 심각하게 틀어졌고, 3~4월에는 매 월초 2주간 BE 팀의 절반 이상과 재무팀 전원이 데이터 보정에 투입되는 상황이 반복되었다. 이 재무적 리스크를 근본적으로 해결하기 위해 재무팀 담당자 2분과 협업하여 정산 시스템 전면 개편을 단독으로 진행하게 되었다.
아래는 정상적인 매출 마감 (정산 인식) 플로우의 매우 간략화된 도식도이다.

월부의 정산은 크게 2가지로 나누어져있다.
결제 인식
외부 결제/환불이 발생할 때 이를 정상적으로 인식하여 사내 DB에 저장한다. 이 때 특정 상품에 대한 결제/환불 시점, 상태, 금액 등이 일치해야 한다.
정산
결제/환불 데이터를 통해 각 결제 건들에 대한 월정산을 통해 매출 인식한다. 월부의 경우 강의가 주력 상품이기 때문에, 발생주의에 근거하여 실제 서비스를 제공한 비중에 따라서 매출을 분할하여 인식해야 한다.
여기서 발생주의란, 요약하면 결제가 일어난 시점이 아닌, 실제 고객이 기대한 서비스를 제공한 시점에 제공받은 서비스의 비율을 기준으로 매출을 인식해야한다는 것이다. 이를 간단한 예시를 통해 자세히 알아보자.
Q) 9월 10일부터 10월 10일까지 총 30일 수강할 수 있는 9만원짜리 강의를 8월 28일에 구매했다면, 월정산일 때 어떻게 매출/선수금을 인식해야 할까?
이를 표로 정리해보면 아래와 같다.
| 월 | 매출 | 선수금 |
|---|---|---|
| 8월 | 0₩ | 90,000₩ |
| 9월 | 60,000₩ | 30,000₩ |
| 10월 | 30,000₩ | 0₩ |
정산 개편에서 해결해야 할 핵심 문제는 두 가지였다.
1. 결제 데이터 정합성 문제
2. 정산 로직의 유지보수 불가능한 구조

문제의 본질은 명확했다.
📌 첫째, 결제 데이터 자체를 제대로 수집하지 못했다.
📌 둘째, 수집된 데이터를 바탕으로 정산을 계산할 때 오류가 발생했다.
정산 계산 오류가 특히 심각했던 이유는, 상품과 결제수단에 따라 매출/선수금 인식 기준이 모두 달랐기 때문이다. 부분 환불, 특수 매출 인식 기준을 가진 상품 등 다양한 케이스에 대한 처리 로직이 수백 줄의 SQL 쿼리 안에 숨어있어, 어디서 무엇이 잘못되었는지 파악하기조차 어려웠다.
📌 완전한 결제 데이터 정합성 확보 필요
기존 결제 도메인은 주문 상태(결제 대기, 결제 완료, 환불 대기, 환불 완료 등)를 업데이트하는 구조였다. 이는 두 가지 문제를 야기했다.
이를 해결하기 위해 Append-Only한 원장 테이블을 도입했다. 모든 결제/환불 이력을 수정 없이 누적하여, 특정 시점으로의 복구와 감사(audit)를 가능하게 했다.
📌 확장 가능한 정산 로직 설계 필요
회사 성장과 함께 다양한 상품과 결제수단(구글 인앱, 베네피아 포인트, 애플 제3자 결제, 유튜브 쇼핑 등)이 추가되었다. 기존 SQL 기반 구조는 이를 감당할 수 없었고, 새로운 케이스마다 수동 정산이 필요했다. 특히 상품권 같은 신규 상품은 기존 강의와 다른 선수금/매출 인식 기준을 가졌기에, 지속적으로 확장 가능한 구조가 필수였다.
이를 도메인 모델과 전략 패턴 도입으로 해결했다. 상품 유형과 결제수단별로 독립적인 정산 전략을 정의하여, 새로운 케이스 추가 시 기존 코드 수정 없이 확장할 수 있도록 설계했다.
1. 확장 가능한 정산 로직 구조: Kotlin + JPA + 전략 패턴
기존 MyBatis SQL에 묶여있던 도메인 로직을 애플리케이션으로 이관하고, Kotlin과 JPA를 도입했다. 핵심은 전략 패턴 적용이었다. 상품 유형(강의, 상품권, 구독 등)과 결제수단(PG, 구글 인앱, 베네피아 등)별로 정산 전략 인터페이스를 정의하고, 각 케이스에 맞는 구현체를 분리했다.
이를 통해 얻은 이점은 아래와 같다.
추가적으로 비즈니스 로직을 코드로 이관한 후 다양한 정산 케이스에 대한 단위 테스트와 통합 테스트를 작성할 수 있었고, 이를 통해 품질을 보장할 수 있었다.
2. 데이터 이력 추적: Append-Only 원장 테이블
기존에는 주문 테이블의 필드를 직접 업데이트하여 변경 이력을 관리할 수 없었다. 특정 시점의 정산 데이터를 재생성할 수 없었고, PG사와 데이터 불일치 발생 시 원인 추적이 불가능했다.
이를 해결하기 위해 모든 결제/환불 이벤트를 시간순으로 쌓는 불변 원장 테이블을 신설했다. 각 이벤트는 절대 수정되지 않고, 새로운 상태 변경은 새 레코드로 추가되도록 재설계했다.
3. 실시간 정합성 모니터링: 대사 배치
데이터 정합성 문제를 사후에 발견하는 것이 아니라, 주기적으로 검증하는 대사 배치를 구현했다. 이를 통해 데이터 유실을 조기에 발견하고 대응할 수 있게 되었다.
4. 성능 및 안정성 개선: Spring Batch 전환
기존 Spring Scheduler 기반 배치는 단일 트랜잭션으로 모든 데이터를 처리했다. 이는 두 가지 문제를 야기했다:
Spring Batch의 Reader/Processor/Writer 구조를 적용하고, 청크(chunk) 단위로 트랜잭션을 분리했고, 이를 통해 문제를 해결할 수 있었다.
2개월간의 프로젝트 기간 동안 PM 없이 재무팀과 직접 소통하는 과정은 양측 모두에게 쉽지 않은 도전이었다.
📌 문제 1: 요구사항 문서화 부재
재무팀은 비개발 직군으로서 구체적인 요구사항을 문서로 정리하는 것에 익숙하지 않았다. 구두 소통 중심으로 요구사항을 전달하다 보니:
📌 문제 2: 도메인 언어의 차이
재무 용어와 개발 용어 간의 간극이 컸다. 같은 개념을 서로 다른 단어로 표현하거나 , 같은 단어를 다르게 이해하는 경우가 빈번했다. 이로 인해 요구사항을 정확히 이해했다고 생각했지만, 막상 구현된 결과물이 재무팀의 기대와 다른 경우가 많았다.
서로 최선을 다했지만, 이러한 소통 방식의 차이는 프로젝트 진행에 큰 장애물이었다.
빠른 실행을 중시하는 스타트업에서 '문서화'는 종종 비효율의 상징처럼 여겨진다. 하지만 정산 개편 프로젝트를 진행하며 우리는 정반대의 결론에 도달했다.복잡한 비즈니스 로직과 끊임없이 변하는 요구사항 속에서, 명확한 용어 정의와 구조화된 요구사항 문서는 필수였다.
구두 소통이나 메신저 기록만으로는 컨텍스트가 빠르게 소실되었고, 담당자가 바뀔 때마다 같은 질문이 반복되었다. 문서 기반 소통으로 전환한 후, 이러한 비효율이 크게 개선되었다.
예상치 못한 수확도 있었다. PM 없이 재무팀과 개발팀이 직접 협업하면서, 서로의 도메인 언어를 이해하게 된 것이다. 재무팀은 개발 용어에, 개발팀은 재무 로직에 익숙해졌고, 이는 이후 소통의 질을 크게 향상시켰다.
문서 초안을 재무파트에서 작성해주셨고, 프로젝트 기간 동안은 해당 문서를 기준으로 소통하고 구두 소통한 내용은 슬랙에 옮기고, 그 날에 문서에 최신화하기로 협의했다.
이외 소통에 필요한 다양한 내용을 정의, 정리했는데, 몇 가지 예시로는 다음과 같다.
정산 프로젝트를 진행하며 가장 크게 느낀 점은 도메인 복잡도를 보다 쉽게 이해하는 과정이 필요하다는 것이었다다.
월부에는 별도의 정산팀이 존재하지 않았고, 개발자들이 다른 프로젝트들과 달리 비즈니스 규칙에 대한 깊은 이해 없이는 코드만으로 문제를 파악하기 어려웠다. 이를 고려해 프로젝트가 마무리된 직후, 개발하며 정리했던 도메인 지식과 기술 문서를 체계화하여 향후 담당자가 빠르게 컨텍스트를 이해할 수 있도록 정리해두었다.

어떻게 개선되었을까?! 다시 문제 상황으로 돌아가보자

우선 대사배치를 통해 외부 결제와 내부 DB의 데이터 정합성을 확보할 수 있었다.

그리고 정산 로직을 최신화하고 수정하여 선수금 / 매출액을 정확하게 계산해낼 수 있었다.

임팩트로는 크게 2가지로 나눌 수 있을 것 같다.
첫째는 프로젝트의 핵심 KR이었던 데이터 정합성 확보이다.
가장 문제였던 상품권 정산 로직 안정화 및 데이터 정합성을 확보하였으며,
25년 9월 현재 기준으로 결제 정합성은 100%, 상품권 매출 인식 정확도는 99%까지 확보할 수 있었다.
둘째는 구성원들의 리소스 절약이다.
매 월초마다 진행되던 재무팀 & 개발자의 결산 마감 직전 수정 건수는 95% 이상 감소하였다. 매월 최소 3일, 최대 2주를 정산 데이터 수정에만 썼던 과거에 비해, 현재는 이슈가 0~1건 이내로 줄어드는 놀라운 효과를 직접 체감할 수 있었다..!
파트별로 자세한 수치는 담당자 인터뷰를 통해 계산해보았다.
| 구분 | 리소스 감소율 |
|---|---|
| 개발 | 95%↓ |
| 재무 | 59%↓ |
| CX | 80%↓ |



사실 나도 비개발자 출신인 만큼 개발자가 필요한 만큼의 요구사항을 알아서 가져오기를 기대하는 것은 합리적이지 못하다는 것을 잘 안다. 그리고 개발에 필요한 구체적인 요구사항을 전달하는 것이 어려운 일이라는 것도 공감한다.
그러나 문제를 제대로 해결하기 위해서 개발자와 소통하는 과정에서 어떠한 것이 필요한지 이해하는 것은 모두를 위해 필요하다고 생각한다. (PM/PO 분들 정말 리스펙합니다..) 이를 설명하기 위해 유튜브 전과자의 영상을 캡쳐하여 발표를 진행했는데, 이 부분에서 개발, 비개발 파트 모두 공감을 많이 느끼셨던 것 같다 ㅎㅎ
🙋♂️: "왜 4월부터 정산 TF가 생기면서 재무적인 이슈가 발생하게 되었는지 쉽게 이해할 수 있었다"
💁♀️ "왜 개발자분들이 여러 질문을 하고, 리스크 관점에서 생각하게 되었는지 이해할 수 있었고, 그런 과정에서 많은 고민을 하셨다는 것을 느꼈다"
🙆♂️: "큰 프로젝트에 대해서는 문서 기반으로 소통하는 공식을 우리 파트에도 적용해보면 좋겠다"
발표가 끝나고 임직원분들이 직접 말씀으로, DM으로 소중한 피드백을 주셔서 매우 감사했다. 슬랙에서 응원도 많이 해주셔서 더욱..! 감사했다.

이번 프로젝트를 통해서 기술적인 고민, 커뮤니케이션, 일정 관리, Spec 산정, 품질 관리 등 정말 다양한 분야에서 많이 성장함을 느낄 수 있었다.
아직 개선해야 할 것들은 늘 그렇듯 많다!
현재는 월부의 결제 모듈을 Java 에서 Kotlin으로 이관하고 여러 결제 수단을 추상화하는 프로젝트를 진행하고 있으며, 보다 안정적이고 유연한 결제 경험을 제공하기 위해 노력하고 있다.
긴 글 읽어주신 분들께 감사를 표하며 글을 마친다!! 연휴야 가지마!!

Nice post — really thoughtful and practical. Documentation as the single source of truth is underrated, and your examples (integrity criteria, real-case verification, and developer-side notes) show exactly how it reduces rework and improves cross-team understanding.
A few quick takeaways I liked:
Defining financial terms up front so developers can write meaningful QA tests.
Using real-life examples to validate rules (great for edge cases).
Keeping a living doc that’s updated the same day avoids context loss.
I wrote a short piece on applying the same doc-first approach to app/platform projects (how to document integrations, test cases, and release notes) — it may be useful as a companion reference: https://magistvv-apkk.com
Thanks for sharing this — concrete wins (95% dev time reduction!) make the case for documentation impossible to ignore.
정산 자동화 개편이 단순히 수기 업무를 소프트웨어로 옮기는게 아니라, 구두로 전해오던 규칙과 수기로 행하던 업무들을 체계적으로 정리하고 자동화할 수 있도록 프로세스를 정립하는 일 자체가 정말 핵심인 것 같더라구요.
그 과정에서 우리 회사가 어떻게 얼마나 돈을 버는지 자연스레 보게되어 신기하고 재밌기도한 것 같습니다.
어려운 과정이 많았을 것 같은데, 글은 재미있게 써주셔서 몰입해서 읽었네요 ㅎㅎ
인상깊은 글 잘 읽었습니다 :)