핵심 요약
- 구독은 네 계층이에요. 구독 템플릿 → 구독 정책 → 구독 상품 → 구독 계약 순으로 흘러요.
- 가격이 두 군데 나오는 건 버그가 아니라 규칙과 결과를 나눠 저장하기 때문이에요. 규칙은 템플릿, 결과는 상품이에요.
- "구독 플랜"이라는 단어는 네 계층 중 어느 것을 가리키는지 모호해서 문서에서 쓰지 않아요.
- 이 문서는 "단어 뜻"을 정리해요. "승인/거절/재활성화" 같은 액션 용어는 구독 용어 사전을 봐요.
이런 상황이라면
관리자 화면에서 구독 템플릿을 만들고 월 9,900원을 입력했어요. 그리고 상품을 등록할 때 같은 가격을 또 입력하라고 해요. 어느 쪽이 최종 가격인지, 템플릿을 수정하면 상품 가격도 같이 바뀌는지 헷갈려요.
이 글은 구독에서 다루는 각 엔티티가 무엇이고 가격·정책이 어떤 경로로 상품과 계약에 도달하는지 정리해요.
1네 계층
| 계층 | 권장 용어 | 내부 모델 | 역할 |
|---|---|---|---|
| 1 | 구독 템플릿 | SubscriptionSetting (상품과 연결되지 않은 것) |
여러 상품에 재사용할 정책·계산 규칙 팩 |
| 2 | 구독 정책 | SubscriptionSetting (상품에 귀속된 것), SubscriptionSettingSnapshot |
특정 상품에 고정된 정책 |
| 3 | 구독 상품 | Product + embedded SubscriptionPeriod |
고객에게 노출되는 회차별 가격표를 가진 상품 |
| 4 | 구독 계약 | OrderSubscription + embedded SubscriptionSettingSnapshotEmbed |
주문 시점에 정책을 박아 살아 있는 계약 |
SubscriptionSetting이 "템플릿"이기도 하고 "정책"이기도 한 이유는 한 모델이 상품 귀속 여부에 따라 두 역할을 겸하기 때문이에요. 코드 주석에도 그대로 적혀 있어요. "subscription_setting 은 템플릿에서도 사용되므로 pd_id 에 속하지 않을 수 있음."
흐름은 단방향이에요.
- 관리자가 템플릿을 등록해요.
- 상품을 만들 때 템플릿을 참조해 상품 귀속 정책과 회차 가격표를 생성해요.
- 고객이 구독을 신청하면 상품의 정책이 계약 쪽에 스냅샷으로 박혀요.
- 계약 스냅샷은 불변이에요. 이후 템플릿·상품을 수정해도 이미 체결된 계약의 정책은 바뀌지 않아요.
2왜 가격이 두 군데 나오나
가격은 같은 숫자가 두 번 저장된 게 아니라 다른 것 두 개예요.
템플릿 가격 = 계산 규칙
모델: SubscriptionSettingPrice + SubscriptionSettingPriceOption.
apply_target: 상품원가에 적용할지, 회차비용에 적용할지 지정해요.price_type: 정률(1) / 정액(2).use_prepaid,use_deposit: 선급금·보증금 여부.- 옵션의
price가 음수면 할인이에요.
즉 "이 템플릿을 바인딩하면 원가에 10%를 더하고, 1회차에 보증금 50,000원을 얹어요" 같은 함수를 저장해요.
상품 회차 가격 = 결과 가격표
모델: SubscriptionPeriod (Product·ProductOption에 embed).
cost_price: 원가.display_price: 판매가.tax_free_price: 비과세가.discount_price,discount_price_type: 할인가·할인 유형.expected_residual_value: 예상 잔존가치(렌탈·리스).use_times_benefit: 회차별 혜택 사용 여부.
즉 "1회차 9,900원, 2회차 9,900원, …, 12회차 8,000원" 같은 계산된 결과 표가 들어가요.
관계
규칙(템플릿) → 자동계산 → 결과표(상품) 한 방향이에요. 상품에 박힌 회차 가격이 고객에게 보이고 결제의 기준이 돼요. 템플릿의 규칙은 한 번 계산되고 나면 상품에 복제돼요. 템플릿을 수정해도 기존 상품·계약 가격이 자동으로 갱신되지 않는다는 뜻이에요.
관리자 UX에서 두 번 입력하는 것처럼 보이는 이유는, 템플릿의 계산 규칙이 모든 상품의 가격을 자동으로 덮지 못하기 때문에 상품 쪽에도 결과 숫자가 남기 때문이에요. 이 구조의 설계 의도는 "상품이 팔린 뒤 가격이 멋대로 바뀌지 않게 고정"하는 데 있어요.
3관리자 UI 라벨 vs 제안 용어
현재 관리자에서 실제로 쓰이는 한글 라벨과 이 문서에서 제안하는 용어를 대조해요. "기존 그대로 유지"인 행과 "정리 제안"인 행을 한 표에 담았어요.
엔티티 명칭
| 대상 | 관리자 UI 현재 라벨 | 제안 용어 | 이유 |
|---|---|---|---|
SubscriptionSetting (상품 미연결) |
구독 템플릿 | 구독 템플릿 (유지) | 이미 UI 주류 표현이고 "재사용 가능한 정책 팩"이라는 의미가 잘 살아 있어요. |
SubscriptionSetting (상품에 연결됨) |
구독 템플릿명 / 구독 정책 / 구독 설정 (혼용) | 구독 정책 (통일) | 같은 화면 안에 세 단어가 섞여요(section.vue:114, 142-143). 상품에 묶인 상태와 템플릿 자체를 한 단어가 덮어버려서 "상품의 템플릿"이라는 기형적 표현이 생겨요. 상품에 박히면 "정책"으로 불러요. |
| "기본 템플릿" (시스템 기본값, 삭제 불가) | 기본 템플릿 | 기본 구독 템플릿 | "기본 설정" 탭과 한 화면에서 보이면 무엇이 기본인지 흐려져요(select.vue:46). "구독"을 붙여 정체성을 명시해요. |
SubscriptionSettingPrice (+Option) |
(독립 라벨 없음, 탭 내부) | 회차 자동계산 규칙 | "가격"이라는 단어를 쓰면 상품 쪽 회차 가격표와 구분되지 않아요. "규칙"이라는 말로 결과 숫자가 아니라 함수임을 드러내요. |
SubscriptionPeriod (Product embed) |
회차 / 회차 설정 / 구독기간(회차) | 회차 가격표 | 현재 UI는 "회차"에 기간·가격·할인을 모두 태워서 불러요. "가격표"를 붙이면 상품 쪽 결과 숫자라는 점이 분명해져요(템플릿 쪽 규칙과 구분). |
SubscriptionTimesBenefit |
회차별 혜택 | 회차 혜택 (유지) | 이미 명확해요. |
SubscriptionSettingSnapshot |
(내부 필드, UI 미노출) | 정책 스냅샷 (상품) | 상품 버전에 고정된 불변 사본임을 이름에 박아요. |
SubscriptionSettingSnapshotEmbed |
(내부 필드, UI 미노출) | 정책 스냅샷 (계약) | 위와 동일 취지. 상품/계약 중 어느 시점에 고정됐는지 라벨로 드러내요. |
Product (구독 연결 상태) |
구독 상품 | 구독 상품 (유지) | 그대로 둬요. |
OrderSubscription |
구독 / 주문 구독 (혼용) | 구독 계약 | "구독"만 쓰면 템플릿·상품·살아 있는 계약 셋이 섞여요. 문서·API·관리자 상세 화면에서는 "계약", 좌측 메뉴 짧은 라벨은 "구독"을 허용. |
OrderSubscriptionBill |
회차 / 구독 결제 | 회차 청구 | "구독 결제"는 최초 결제·재결제·수동 결제가 다 뭉쳐져요. "청구"가 회차 단위 개념을 선명하게 표현해요. |
상품 편집 폼 안의 구독 섹션
| 현재 라벨 | 제안 | 이유 |
|---|---|---|
"구독" (토글 제목) |
구독 판매 사용 | use_subscription을 켠다는 뜻이 드러나게. |
"구독 템플릿명" (필드 라벨) |
적용된 구독 템플릿 | 현재 라벨은 "이름만 입력하는 필드"처럼 보여요. 실제로는 모달로 템플릿을 선택하는 참조 필드예요. |
"미리 정의한 구독 설정을 상품에 적용할 수 있어요." |
미리 정의한 구독 템플릿을 상품에 적용할 수 있어요. | "구독 설정"이라는 일반 명사 대신 엔티티명으로. |
"불러오기를 클릭하여 구독 정책을 적용해주세요." |
불러오기를 클릭하여 구독 템플릿을 적용해주세요. | 같은 화면에서 "템플릿/정책"이 번갈아 등장하는 혼용의 근원이에요. 선택 단계는 "템플릿 적용", 적용 결과가 "이 상품의 구독 정책"이 돼요. |
"구독 설정값 초기화" / "구독 설정값이 초기화돼요." |
구독 정책과 회차 가격 초기화 | 무엇이 날아가는지 대상이 구체적이게. |
구독 템플릿 편집 UI (탭 구조)
| 현재 탭 라벨 | 제안 | 이유 |
|---|---|---|
기본 설정 |
기본 정보 | "기본"이 "기본 템플릿"과 혼동될 수 있어요. |
반복 요금(회차 설정) |
회차 자동계산 규칙 | 이 탭이 실제로 편집하는 건 SubscriptionSettingPrice 계산 규칙이에요. 상품 쪽 "회차 가격표"와 분리돼요. |
구독 중 옵션 |
운영 중 정책 | 무엇의 옵션인지 드러내요. 해지·일시정지·연체 규칙을 다뤄요. |
(만기 관련) / Expiration |
만기 처리 정책 | — |
(미결제/연체) / NonPayment |
미납 처리 정책 | — |
(부가 설정) / Additional |
부가 정책 | — |
회차 가격표 UI (상품 편집)
| 현재 라벨 | 제안 | 이유 |
|---|---|---|
구독기간 |
구독 기간 (띄어쓰기) | 사소한 정규화. |
회차 설정 |
회차 가격 설정 | 이 UI에서 입력하는 건 기간이 아니라 회차별 금액이에요. |
회차 추가하기 |
회차 가격 추가 | 액션이 "가격 입력"임을 드러내요. |
구독 기간(회차)에 따른 구독료(회차별 판매가)를 설정할 수 있어요. |
구독 기간별 회차 가격을 설정할 수 있어요. | "구독료/판매가" 이중 표현을 하나로. |
무제한 회차 설정 |
무제한 구독 (회차 미지정) | 무엇이 무제한인지 명확히. |
구독 타입 프리셋
| 현재 라벨 | 제안 | 이유 |
|---|---|---|
정기구독 |
정기구독 (유지) | — |
정기배송 |
정기배송 (유지) | — |
렌탈/리스 |
렌탈·리스 | 슬래시 대신 중점으로 통일(본 용어집 전체 규칙). |
종량제 |
사용량 기반 구독 | 사내 모델명 usage_based_subscription·에러 메시지 "사용량 기반 구독 상품"(ko.yml:2022)과 일치시켜요. 고객에게는 "종량제"도 통하니 두 라벨을 병기해도 돼요. |
계약·청구
| 개념 | 관리자 UI 현재 | 제안 | 이유 |
|---|---|---|---|
| 구독 계약 목록 | 주문 구독 / 구독 관리 |
구독 계약 | API 엔드포인트도 order_subscriptions. "주문 구독"은 동사·명사 경계가 애매해요. |
| 구독 계약 상세 | (탭별 혼용) | 구독 계약 상세 | — |
| 회차 청구 목록 | (혼용) | 회차 청구 | — |
| 회차 금액 조정 | 금액 조정 | 회차 금액 조정 (유지 기조) | 현재 라벨 OK. |
| 구독 취소/중도 해지 | 해지 | 해지 (유지) | 액션 용어는 구독 용어 사전 규칙을 따라요. |
쓰지 말 것
"구독 플랜"은 현재 관리자 UI에는 없지만 사내 대화에서 과거 용어로 남아 있어요. 문서와 UI 전반에서 쓰지 않아요. 플랜이라는 단어가 튀어나오면 맥락을 보고 구독 템플릿 / 구독 정책 / 구독 상품 / 회차 가격표 중 하나로 바꿔 적어요. URL 상의 /subscription/plan/*은 "계약을 설계하는 단계"를 뜻하는 단계명으로만 남기며, 본문에서는 엔티티를 위 용어로 불러요.
4모델-API-한글 용어 매핑
관리자 API와 공개 API에서 다루는 리소스를 용어에 맞춰 정리해요.
| 모델 | API 리소스 | 권장 용어 |
|---|---|---|
SubscriptionSetting |
subscription_settings |
구독 템플릿 / 구독 정책 (pd_id 유무로 구분) |
SubscriptionSettingPrice |
템플릿 하위 구조 | 템플릿 가격 규칙 |
SubscriptionSettingPriceOption |
템플릿 하위 구조 | 템플릿 가격 옵션 |
SubscriptionPeriod |
상품 하위 구조 | 회차 가격표 |
SubscriptionTimesBenefit |
회차 가격표 하위 구조 | 회차 혜택 |
SubscriptionSettingSnapshot |
상품 하위 구조 | 정책 스냅샷 (상품 단위) |
SubscriptionSettingSnapshotEmbed |
구독 계약 하위 구조 | 정책 스냅샷 (계약 단위) |
Product |
products |
상품 (구독이 붙으면 구독 상품) |
OrderSubscription |
order_subscriptions |
구독 계약 |
OrderSubscriptionBill |
order_subscription_bills |
회차 청구 |
관리자 화면에서 보이는 "템플릿 목록"은 SubscriptionSetting 중 pd_id가 없는 레코드를, "이 상품의 구독 설정"은 pd_id가 있는 레코드를 각각 필터링해 보여주는 것이에요. 같은 테이블을 두 가지 이름으로 부르는 이유예요.
5자주 혼동되는 것
템플릿 vs 정책
둘 다 SubscriptionSetting이지만 상품에 묶였는지 여부가 달라요. 묶이지 않은 것이 템플릿, 묶인 것이 정책이에요. 문서에서 "이 상품의 템플릿"이라고 쓰면 혼동을 일으키니 "이 상품의 구독 정책"으로 써요.
정책 vs 정책 스냅샷
정책은 현재 시점의 값이고, 스냅샷은 과거 어느 시점에 박힌 불변 사본이에요. 상품 단위 스냅샷(SubscriptionSettingSnapshot)은 상품 버전이 바뀔 때 쓰이고, 계약 단위 스냅샷(SubscriptionSettingSnapshotEmbed)은 주문이 생성된 시점의 정책을 고정해요. 계약이 체결된 뒤 정책을 수정해도 해당 계약은 스냅샷을 따라요.
상품 vs 구독 상품
상품은 엔티티, 구독 상품은 "구독 정책이 붙은 상품"이라는 상태를 가리키는 말이에요. 별도 테이블이 있지는 않아요. 문서에서 "구독 상품을 만들어요"는 "상품에 구독 정책을 바인딩해요"와 같아요.
구독 vs 구독 계약
"구독"이라는 단어만 쓰면 템플릿·상품·계약 중 어느 것인지 흐릿해요. 살아 있는 고객의 구독 건을 가리킬 때는 구독 계약(OrderSubscription)이라고 쓰고, 약어가 필요하면 "계약"이라고 써요.
플랜
앞서 적었듯 엔티티 용어에서 "플랜"은 쓰지 않아요. 사내·외부 문서에서 "플랜"이라는 단어를 만나면 문맥을 보고 템플릿·정책·상품·회차 가격표 중 어느 것인지 옮겨 적어요.
