/ Portfolio / S1

Booking / Payment · Consistency

Stripe 선결제부터 Webhook·취소·환불까지 결제 상태 흐름을 구축했습니다.

외부 결제와 DB를 하나의 transaction처럼 포장하지 않고, 예약 실패의 보상 흐름과 환불 완료 시점을 분리해 상태 정합성을 보완했습니다.

Role
Stripe 선결제 구축 주도 · 결제 도메인 기여
Scope
Prepayment · Refund
Stack
FastAPI · PostgreSQL · Stripe
Period
2024.11 — 2025.01
설계 원칙

외부 provider의 접수·완료 상태가 확인되기 전에 로컬 업무 상태를 성공으로 앞서 보내지 않습니다.

Problem & constraints

왜 이 문제를 풀어야 했는가

선결제는 예약 생성 전에 시작되므로 PaymentIntent와 로컬 결제 이력을 아직 없는 예약 객체 없이 연결해야 했습니다.

환불은 provider에서 비동기로 완료됩니다. 요청 시점에 mileage와 ticket을 먼저 바꾸면 provider 실패 때 로컬 상태만 앞서갈 수 있었습니다.

Failure boundary

실패하면 어디에서 멈추고, 어떻게 복구하는가

TriggerRiskBoundary
예약 처리 실패외부 결제만 남음PaymentIntent 상태 확인 후 requires_capture는 cancel, succeeded는 refund
비동기 환불 진행 중ticket 삭제·mileage 복원이 먼저 발생refund request와 completion transition 분리
Webhook 재전달·local commit 실패중복 처리·provider/local 불일치provider 상태와 local payment history를 대조하는 운영 확인 대상으로 분리

Decisions

핵심 기술 판단

Correlation

local transaction ID와 payment type을 Checkout·Webhook metadata에 넣어 외부 event를 로컬 이력과 연결했습니다.

Compensation

manual capture 전후 상태에 따라 cancel/refund를 선택하는 provider-side 보상 경계를 뒀습니다.

Completion State

mileage 복원과 ticket 삭제를 환불 요청이 아니라 완료 transition 뒤로 이동했습니다.

System flow

판단을 실제 시스템으로 옮긴 구조

LOCAL

Payment history

예약 전 local transaction과 payment method 생성

PROVIDER

Checkout · PaymentIntent

metadata로 correlation하고 manual capture 대기

BOOKING

예약 처리

성공 시 capture, 실패 시 상태별 cancel/refund

REFUND

Webhook completion

완료 확인 뒤 payment·mileage·ticket 상태 전이

Evidence

운영에서 확인한 결과

Stripe slice구축 주도

Checkout·manual capture·provider compensation

Payment domain정합성 보완

refund·mileage·ticket transition