이 프로젝트는 인프런의 견고한 결제 시스템 구축 강의를 보며 공부할 겸 만든 결제 시스템 프로젝트입니다.
Kotlin, Spring Boot, Kafka, PostgreSQL을 사용해 결제 생성부터 PSP 승인, 정산, 원장 기록, 복구까지 이어지는 전체 흐름을 헥사고날 아키텍처로 구현했습니다.
| 서비스 | 포트 | 역할 |
|---|---|---|
payment-service |
8081 | 체크아웃, PSP 승인, 아웃박스 릴레이, 복구 처리 |
wallet-service |
8082 | 판매자 지갑 정산과 낙관적 락 기반 동시성 제어 |
ledger-service |
8083 | 복식부기 원장 기록 |
모든 서비스는 헥사고날 아키텍처를 기준으로 구성했습니다.
domain: 프레임워크에 의존하지 않음application: 포트와 도메인에만 의존adapter.in: HTTP, Kafka, 스케줄러 같은 외부 입력 수신adapter.out: DB, Kafka, Toss API 같은 외부 연동 구현bootstrap: Spring 빈 설정과 wiring 담당
클라이언트 → 체크아웃 → Toss 승인 요청 → Outbox 저장 → Kafka 발행
↓
payment.confirmed → wallet-service → wallet.updated ─┐
└→ ledger-service → ledger.updated ──┤
↓
payment-service가 최종 완료 처리
| 항목 | 적용 위치 |
|---|---|
| Transactional Outbox | payment-service: 승인 성공 후 바로 Kafka에 보내지 않고 outbox에 저장한 뒤 relay |
| 멱등 소비 | wallet-service, ledger-service: processed-message 테이블로 중복 메시지 방지 |
| 낙관적 락 | wallet-service, payment-service: @Version과 재시도로 동시성 충돌 완화 |
| Dead Letter Queue | 세 서비스 모두 비재시도 가능 실패를 .dlt 토픽으로 이동 |
| Recovery Scheduler | payment-service: EXECUTING, UNKNOWN 상태를 주기적으로 스캔 |
필수 준비물:
- Java 17
- Docker
인프라 실행:
docker compose -f infra/docker-compose.yml up -d애플리케이션 실행:
docker compose -f infra/docker-compose.yml up --build payment-service wallet-service ledger-service| 항목 | URL |
|---|---|
| PostgreSQL | localhost:5432 |
| Kafka | localhost:9092 |
| Kafka UI | http://localhost:8080 |
| Payment 헬스체크 | http://localhost:8081/actuator/health |
| Wallet 헬스체크 | http://localhost:8082/actuator/health |
| Ledger 헬스체크 | http://localhost:8083/actuator/health |
| 메서드 | 경로 | 설명 |
|---|---|---|
POST |
/api/checkout |
결제 주문 생성 |
GET |
/api/payments/{orderId} |
결제 상태와 주문별 wallet/ledger 진행 상황 조회 |
POST |
/api/payments/recovery/scan |
수동 복구 스캔 실행 |
GET |
/api/payments/recovery/pending |
복구 대상 결제 목록 조회 |
GET |
/payments/success |
결제 성공 리다이렉트 페이지 |
Toss 시크릿 키는 TOSS_SECRET_KEY 환경 변수로 주입합니다.
PSP 호출 타임아웃은 기본적으로 connect 3초, read 10초입니다.
payment:
toss:
connect-timeout: 3s
read-timeout: 10sKafka consumer 재시도 설정은 서비스별로 조정할 수 있습니다.
<service>:
messaging:
retry-attempts: 2
retry-backoff: 1s
retry-max-backoff: 10s
retry-multiplier: 2.0
retry-jitter: 0.2
dead-letter-suffix: .dlt- PSP 정산 파일 기반 reconciliation은 아직 구현하지 않았습니다.
- 운영용 대시보드나 관리자 UI는 최소 수준만 구현되어 있습니다.
- Java 17 환경이 필요합니다.
- Gradle 9에서 Kotlin/Detekt 플러그인 관련 deprecation warning이 일부 남아 있지만 테스트는 통과합니다.