TL;DR
- 기존 가격을 새 상품의 정확한 미러 가격으로 대응시키고 고객 결제 조건을 바꾸지 않은 채 실시간 구독을 이전하는 Stripe 카탈로그 마이그레이션임.
- 이전 대상 구독은 금액, 통화, 결제 주기, 수량, 갱신일, 결제 수단과 할인 조건을 유지하며, 접근 권한 판정 기준은 상품명에서 가격 메타데이터로 이동함.
- 배치 작업은 라이브 API를 기준으로 이전 계획을 만들고 구독을 이전 가능 여부별로 분류하며, 예시에서는 124건 중 117건 이전·7건 제외임.
- 저장소는 가격 확인·메타데이터 설정·구독 항목 교체·권한 부여 SQL을 제공하지만, 새 상품과 미러 가격은 생성하지 않음.
--apply와 확인 입력을 요구하고, 변경 전후 검증·멱등성 키·별도 롤백 키를 사용하며 민감한 내보내기 파일의 제한된 보관을 요구함.
Stripe 카탈로그 마이그레이션
- 고객이 지불하는 금액을 바꾸지 않고 실시간 구독을 새 Stripe 상품 카탈로그로 옮기는 저장소임.
- 기존의 모든 가격에 새 상품 아래 정확히 일치하는 미러 가격을 두는 마이그레이션을 위한 Python 스크립트와 SQL을 포함함.
- 구독의 금액, 통화, 결제 주기, 수량, 갱신일, 결제 수단과 할인 조건을 유지하고, 권한 부여 기준을 상품명에서 가격 메타데이터로 옮기는 방식임.
- 구독, 평생 라이선스, 업데이트 기간이 있는 영구 라이선스, 임대 후 소유(rent-to-own) 요금제가 포함된 완료된 마이그레이션에서 추출한 프로젝트임. 계정 ID와 고객 데이터는 설정값과 자리표시자로 대체됨.
쓰기 전에 마이그레이션 확인
- 배치 작업은 드라이런(dry run)으로 시작함. 라이브 API에서 출발지와 목적지의 대응표를 다시 만들고
out/plan.csv를 기록하며, 이전할 구독과 제외 사유별 구독을 모두 나열함. - 예시 수치는 총 124건이며, 117건 이전 대상과 7건 제외 대상으로 구성됨.
- 제외 사유는
no_mirror[studio/web/std]3건,renews_imminently2건,has_schedule1건,multi_item[2]1건임. - 위 수치는 예시이므로
--apply를 추가하기 전에 자체 계정의 계획을 검토해야 함.
마이그레이션 모델
- Stripe 가격은 상품 연결 관계를 유지하므로 카탈로그 재구성은 다음 네 단계로 진행함.
- 새 상품 생성.
- 실시간 구독자가 있는 각 기존 가격에 대해 금액, 통화, 결제 주기, 결제 주기 횟수와
tax_behavior가 일치하는 미러 가격 생성. - 새 가격에 구조화된 메타데이터를 추가한 뒤 각 구독 항목을 정확한 미러 가격으로 교체하고
proration_behavior: none설정 적용. - 상품명이 아니라 가격 메타데이터를 기준으로 접근 권한 판정.
- 저장소는 가격에 태그를 지정하고 검증하며, 구독 교체 계획을 세우고 적용하는 기능과 권한 부여 SQL을 제공함. 상품이나 미러 가격은 생성하지 않음.
시작하기
- Python 3.9 이상,
stripe-python10 이상이 필요하며 SQL은 Supabase를 대상으로 함. - 가상 환경을 만들고 활성화한 뒤 의존성을 설치하고,
config.example.py를config.py로 복사하는 순서로 준비함. config.py에 상품 ID, 티어 규칙과 고유한 멱등성 접두사를 입력해야 함.STRIPE_API_KEY는 로컬 비밀 저장소에서 불러와야 하며, 라이브 키를 스크립트에 붙여 넣거나 커밋하거나 보고서에 포함해서는 안 됨.- 먼저 읽기 전용 검사와 드라이런을 실행함:
scripts디렉터리에서audit_tax_behavior.py,write_price_metadata.py,migrate_one.py,migrate_all.py를 차례로 실행함. - 배치 작업 전에
sql/entitlements.sql을 배포해야 함. 기존 가격과 새 가격이 올바르게 권한으로 해석되는지 확인한 뒤, 리허설·첫 배치·전체 실행·검증 순서로 마이그레이션 당일 실행 지침을 따라야 함.
안전 모델
- 먼저 드라이런을 실행함. Stripe를 변경하는 스크립트에는
--apply가 필요하며, 실시간 구독 변경에는yes입력도 필요함. - 정확히 일치하는 미러 가격만 사용함. 라우팅은 티어, 채널, 임대 후 소유 여부, 통화, 결제 주기, 결제 주기 횟수와 금액을 기준으로 하며, 일치 항목이 없거나 여러 개면 건너뜀.
- 계약 조건의 무단 변경을 방지함. 배치 작업은 세금 설정 불일치, 여러 항목이 있는 구독, 스케줄이 있는 구독, 연결된 애플리케이션과 설정된 안전 기간 안에 갱신되는 구독을 거부함.
- 모든 쓰기 작업을 검증함. 각 구독을 변경 전후에 읽고, 달라질 수 있는 값은
price_id와 상품뿐임. 예상하지 않은 변경이 처음 발견되면 배치 작업을 중단함. - 안전한 재시도와 롤백을 지원함. 모든 쓰기에 멱등성 키를 사용하며, Stripe는 키를 재사용하면 저장된 응답을 반환하므로 롤백에는 별도의 키 네임스페이스를 사용함.
- 생성된 계획, 결과와 내보내기 파일에는 구독 ID, 고객 ID와 가격 ID가 포함됨.
out/,*.csv와config.py는 버전 관리에서 제외되지만 제한된 접근이 가능한 곳에 보관해야 함.export_migration_origins.py는--no-email을 전달하지 않으면 고객 이메일을 포함함.
포함 항목
- 설정:
config.example.py— 계정별 ID, 라우팅 규칙과 메타데이터 규칙. - 마이그레이션:
scripts/— 감사, 메타데이터 계획, 리허설, 배치, 검증과 롤백. - 권한 부여:
sql/— 참조 스키마, 판정기, 프로젝션과 커뮤니케이션 쿼리. - 운영:
docs/RUNBOOK.md— 마이그레이션 당일의 순서별 점검 목록. - 규칙:
docs/CONVENTIONS.md— 가격 별칭 문법과 메타데이터 키. - 교훈:
docs/LESSONS.md— 원래 마이그레이션에서 발견한 실패와 예외 사례.
한계
- 즉시 적용 가능한 마이그레이션이 아니라 참고 구현임. 대상 카탈로그 생성, Stripe 데이터베이스 동기화, 임대 후 소유 요금제 완료 처리는 제공하지 않음.
- Supabase 역할과 사용자 조회를 조정하지 않은 일반 PostgreSQL 지원도 제공하지 않음.
- 라이브 키를 사용하기 전에 자체 스키마와 API 버전에서 라우팅 및 SQL을 테스트해야 함.
라이선스
- MIT 라이선스, © 2026 Loris Comba.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요