배경 및 목표

플랜 다운그레이드 처리를 담당하는 워커서비스가 NestJS로 운영되고 있었습니다. 해당 서비스는 트랜잭션 경계가 없이 쿼리가 순차적으로 실행되어, 중간 실패 시 데이터 불일치가 발생했습니다.

  • Executor들은 트랜잭션 경계 없이 순차 실행 → 3번째에서 실패할 경우 1, 2번은 롤백 불가
  • 처리 실패 시 재처리는 메시지 재발행 → 전체 다운그레이드 로직 재실행
  • 0건의 테스트 및 유지보수 어려움

왜 중요했는가

트랜잭션 경계가 없어 세 번째 스텝에서 실패하면 앞선 두 스텝은 롤백되지 않았습니다. 테스트가 0건이라 손을 대는 것 자체가 위험한 상태였습니다. 실제로 외부 연동 API 호출이 실패했을 때 트랜잭션이 없어 앞선 스텝의 변경이 그대로 남는 불일치가 발생했습니다.

제약

제약선택지에 미친 영향
운영 중인 서비스 전환다운그레이드는 상시 동작해야 하므로 중단 후 교체가 불가능합니다. feature toggle 무중단 전환을 전제로 설계했습니다
테스트 0건인 레거시기존 동작을 검증할 기준이 없어, 포팅 전에 기대 동작을 테스트로 먼저 고정해야 했습니다
Kotlin, Spring 스펙으로 통일팀에서 이미 합의된 방향이라, 어떤 언어로 옮길지는 선택지가 아니었습니다

목표

  • 부분 실패를 허용하고, 트랜잭션이 도메인 단위로 격리된 안정적인 다운그레이드 워커로 전환합니다.
  • Admin API로 실패한 스텝만 재처리 가능하고, 테스트로 보호되는 유지보수 가능한 구조를 확보합니다.

맡은 역할과 판단

구분내용
담당 범위포팅 설계와 구현, AI 협업 파이프라인 구상까지 단독으로 담당했습니다
직접 내린 판단1. 21개 Executor를 상속 기반 11개 Service로 재구성해 실패를 도메인별로 격리
2. 재처리를 전체 재실행이 아닌 실패 step 선택 재시도로 변경
3. feature toggle 무중단 전환
판단하지 않은 것Kotlin, Spring 스펙으로 통일하는 방향은 팀 차원에서 합의된 결정이었습니다
AI 협업파이프라인 스텝을 먼저 정의하고 스텝별 에이전트 역할을 지정해 산출물을 만드는 방식으로 진행했습니다

해결 방법과 해결 후보군

후보군 비교

방식원리한계
기존 구조 유지 + 멱등 재처리순차 실행을 그대로 두고 재처리만 멱등하게 보강재처리가 전체 다운그레이드 로직을 재실행
도메인별 서비스 분리 + 서비스 단위 트랜잭션 (채택)Executor를 도메인 단위 Service로 재분류하고 서비스마다 트랜잭션 경계를 부여, 실패한 스텝(failSteps)만 선택 재처리도메인 재분류, 인터페이스 설계 비용이 들지만, 실패 격리와 선택적 재시도, 테스트 보호를 확보

1. 상속을 이용한 도메인별 서비스 분리 + 실패 격리

각 Executor들을 도메인 단위로 재분류하여 Downgrade 인터페이스를 상속한 서비스 클래스들(트랜잭션 경계)로 분리하였습니다. 서비스 단위로 트랜잭션이 보장되도록 실행하여 하나가 실패해도 나머지는 계속 수행합니다. 전체 원자성을 포기하고 부분 성공을 허용한 선택이며, 실패한 스텝은 Admin API로 재처리해 데이터 불일치를 제거합니다.

  • 새 도메인 추가 혹은 로직 변경 시 변경 범위 제한
  • 실패한 스텝(failSteps)만 재처리하도록 Admin Retry API(DowngradeService 리스트 재활용)

2. AI 협업 개발 파이프라인

이번 신규 서비스 포팅 작업은 클로드를 이용하여 개발 파이프라인을 구상하고, AI와 협업을 하며 실무에 적용해 본 프로젝트입니다.

우선 어떤 파이프라인으로 문제를 해결해나갈지 정의합니다. 각 파이프라인의 스텝이 정하고, 스텝에 맞는 에이전트 역할을 정의하여 결과물을 산출합니다.

PhaseClaude사람
1. 이관 분석21개 Executor SQL/API/데이터 흐름 1:1 매핑, 분석 보고서분석 결과 검증, 비즈니스 맥락 보정
2. 설계21개 Executor →11개 Service 책임 재분류 초안아키텍처 결정, feature toggle 전략 수립
3. 티켓 분할11개 티켓 생성 (AS-IS↔TO-BE 쿼리 테스트 케이스 매핑, Given/When/Then TC)티켓 순서/우선순위 판단
4. TDDRED: TC → Kotest 변환 / GREEN: 구현 생성 / REFACTOR: 하네스 자동 검증AS-IS 동작 일치 여부 검증
5. 배포전환 체크리스트, 롤백 시나리오Flag 전환 시점, 모니터링 지표 판단
  • 이관 분석을 통해 누락될 수 있는 요소들을 놓치지 않고, 100% 커버
  • 작성된 티켓 기반의 TDD 테스트 커버리지(80%+)
  • dag로 티켓 병렬 작업(티켓별 구현)을 구성하고 일정 단축 (주어진 기한 20md → 10md)

결과

지표기존 (Node.js)개선 (Spring)
트랜잭션 관리없음 (fire-and-forget)서비스별 독립 트랜잭션 + 실패 격리
실패 복구전체 재실행실패 step만 선택적 재시도 (Admin API)
SQL Injection52건 (Raw SQL 파라미터 직접 삽입)0건 (QueryDSL 파라미터 바인딩)
테스트 커버리지0%80% 이상 (31개 파일)
서비스 구조21개 Executor (중복 포함)11개 Service (책임 분리, 48% 감소)
기술 스택Node.js (NestJS)Kotlin 단일화
일정-20md → 10md
전환 방식-feature toggle 무중단 전환 (중단 0건)