프로모코드 및 레퍼럴 정책
1. 목적
프로모션 코드와 래퍼럴(친구 초대) 시스템을 통해 사용자 획득과 구독 전환을 촉진합니다. 파트너 협업, 인플루언서 마케팅, 기존 사용자의 추천을 통한 신규 가입 유도를 위한 정책을 정의합니다.
2. 프로모코드 (PromoCode)
2-1. 기본 구조
| 필드 | 타입 | 설명 |
|---|---|---|
code | CharField(50) | 프로모 코드 (unique) |
type | CharField | 유형: corporate / influencer / referral |
name | CharField(100) | 프로모션 이름 |
description | TextField | 프로모션 설명 |
bonus_weeks | IntegerField | 보너스 주 수 |
banner_text | CharField(200) | 프로모 배너 텍스트 (다국어, TranslatableModel) |
2-2. 프로모 코드 유형
| 유형 | 코드 | 설명 |
|---|---|---|
| 기업 프로모션 | corporate | 협업 기업과의 공동 프로모션 |
| 인플루언서 | influencer | 인플루언서 전용 코드 |
| 래퍼럴 | referral | 친구 초대 코드 |
2-3. 사용 제한
| 필드 | 설명 |
|---|---|
max_uses | 최대 사용 횟수 (null이면 무제한) |
current_uses | 현재 사용 횟수 |
one_time_only | 1회 사용 제한 여부 |
new_users_only | 최초 가입자 전용 여부 (has_subscribed_before = False인 사용자만 사용 가능) |
valid_from | 유효 시작일 |
valid_until | 유효 종료일 (nullable) |
is_active | 활성화 여부 |
2-4. 구독 타입 제한 및 오퍼 매핑
| 필드 | 설명 |
|---|---|
subscription_types | 적용 가능한 구독 타입 JSON (예: ["monthly", "six_months", "annual"]) |
offer_mapping | 플랜별 offer ID 매핑 (예: {"subs-monthly-1": "sns50off"}) |
discount_mapping | 플랜별 할인율(%) 매핑 (예: {"subs-monthly-1": 50}) |
ios_offer_code | iOS App Store offer code (예: SNS50OFF) |
2-5. 유효성 검사
프로모 코드는 다음 조건을 모두 충족해야 사용 가능합니다:
is_active = True- 현재 시각이
valid_from이후 valid_until이 null이거나 현재 시각 이전이 아닌 경우max_uses에 도달하지 않은 경우new_users_only인 경우has_subscribed_before = False인 사용자만 사용 가능- 사용자당 1회만 사용 가능 (PromoCodeUsage unique 제약)
2-6. 프로모코드 API
| Endpoint | Method | 설명 |
|---|---|---|
/api/promocodes/apply/ | POST | 프로모 코드 임시 적용 |
/api/promocodes/applied/ | GET | 현재 적용된 프로모 코드 조회 |
/api/promocodes/applied/clear/ | DELETE | 임시 적용 프로모 코드 해제 |
3. 임시 적용 프로모 코드 (AppliedPromoCode)
3-1. 동작 방식
- 프로모 코드를 먼저 임시 적용한 후, IAP 결제를 진행합니다.
- 사용자당 1개의 임시 적용 프로모 코드만 유지됩니다 (OneToOne).
expires_at시점을 초과하면 자동 만료됩니다.- 래퍼럴 코드(
valid_until=None)는 만료 없이 첫 구독 전까지 무기한 유지됩니다.
3-2. 적용 흐름
- 프로모 코드 적용:
POST /api/promocodes/apply/→ AppliedPromoCode 생성 - IAP 결제: 앱 스토어를 통한 인앱 결제 진행
- 서버 검증:
POST /api/payments/verify/→ 결제 검증 시 적용된 프로모 코드 확인 - 사용 기록: PromoCodeUsage 레코드 생성, 보너스 주수 적용
4. 래퍼럴 코드 (ReferralCode)
4-1. 구조
| 필드 | 설명 |
|---|---|
referrer | 추천인 사용자 (FK) |
promo_code | 연결된 프로모 코드 (OneToOne) |
total_referrals | 총 추천 수 |
successful_referrals | 성공한 추천 수 (구독 완료) |
4-2. 래퍼럴 혜택
- 추천인과 피추천인 모두 1주 구독 추가
- 최초 가입 시에만 래퍼럴 코드 입력 가능
- 1회만 사용 가능
- 다른 프로모 코드와 중복 적용 가능 (
is_referral_stackable) - 추천인 최대 보너스 캡: 52주
4-3. 초대 코드 입력 화면 (InvitationCode)
노출 조건
- 대상: 백엔드 응답의
is_new_user == true인 유저 (첫 가입) - 타이밍: 소셜 로그인 직후, 홈 화면 진입 전
- 플로우:
로그인 → InvitationCode 화면 → 홈(selectMap) - 건너뛰기: 항상 가능 (건너뛰기 버튼 상시 활성화)
코드 자동 채움 우선순위
| 순위 | 소스 | 동작 |
|---|---|---|
| 1 | 딥링크 | 코드 즉시 채움, 토스트 메시지 표시. 클립보드 검증 스킵. |
| 2 | 클립보드 | 백그라운드 서버 검증 → 유효 시 자동 채움 |
| 3 | 없음 | 빈칸, 수동 입력 대기 |
클립보드 자동 감지 UX
- 화면 진입 → 코드 입력란 빈칸 + 확인 버튼 disabled
- 백그라운드에서 클립보드 읽기 → 서버 validate API 호출
- 유효한 코드: 입력란에 자동 채움 + 확인 버튼 enabled
- 유효하지 않은 코드: 빈칸 유지 + 확인 버튼 enabled (수동 입력 대기)
- 건너뛰기 버튼은 검증 중에도 항상 enabled
검증 API
| Endpoint | Method | 설명 |
|---|---|---|
/api/promocodes/validate/ | POST | 프로모/래퍼럴 코드 유효성 검증 (임시 적용 없이 유효 여부만 반환) |
4-4. 래퍼럴 API
| Endpoint | Method | 설명 |
|---|---|---|
/api/promocodes/referral/create/ | POST | 래퍼럴 코드 생성 |
/api/promocodes/referral/my-stats/ | GET | 내 추천 현황 조회 |
/api/promocodes/referral/my-benefits/ | GET | 내 래퍼럴 혜택 조회 |
/api/promocodes/referral/rewards/ | GET | 래퍼럴 리워드 목록 조회 |
5. 래퍼럴 리워드 (ReferralReward)
5-1. 구조
| 필드 | 설명 |
|---|---|
referral_code | 래퍼럴 코드 (FK) |
user | 리워드 대상 사용자 |
reward_type | referrer (추천인) 또는 referee (피추천인) |
bonus_weeks | 추가된 구독 주 수 |
subscription | 연결된 구독 (FK) |
status | pending (대기) / applied (적용) / revoked (회수) |
applied_at | 실제 적용 시점 |
revoked_at | 회수 시점 |
revoke_reason | 회수 사유 |
5-2. 최소 유지 기간
- 래퍼럴 혜택에는 최소 유지 기간 14일이 적용됩니다.
- 피추천인이 14일 이내에 구독을 해지하면:
- 피추천인의 보너스 주수만큼
end_date가 감소됩니다. - 추천인의 리워드도
revoked상태로 변경됩니다. - 래퍼럴 코드의
successful_referrals이 감소됩니다.
- 피추천인의 보너스 주수만큼
5-3. 리워드 회수 처리
applied상태의 리워드: 구독에서bonus_weeks만큼 기간을 감소시킨 후 회수pending상태의 리워드: 상태만revoked로 변경- 이미
revoked인 리워드: 중복 회수 방지 (멱등성)
6. 파트너 프로모션 (PartnerPromotion)
6-1. 구조
| 필드 | 설명 |
|---|---|
code | 숏코드 (unique, 예: SxR3OndzSDJM) |
partner_name | 파트너 이름 |
promo_code | 연결된 프로모 코드 (FK, 선택적) |
landing_page | 파트너 전용 랜딩 페이지 URL |
custom_message | 파트너 전용 메시지 |
custom_image_url | 파트너 로고/이미지 URL |
total_clicks | 총 클릭 수 |
total_conversions | 총 전환 수 |
total_views | 총 조회 수 |
conversion_rate | 전환율 (%) = (conversions / clicks) * 100 |
6-2. Web Redirect
- URL:
/r/<code>/ - 파트너 숏코드를 통해 앱 다운로드 또는 프로모션 랜딩 페이지로 리다이렉트합니다.
7. 초대 링크 및 공유
7-1. 초대 링크 구조
- URL:
/invite/<code>/ - 래퍼럴 코드를 포함한 초대 링크를 통해 앱 딥링크로 연결됩니다.
- 공유 URL:
https://penta.pics/invite/<code>
7-2. 공유 문구
공유 문구에는 추천인 코드 텍스트를 포함하여, 딥링크를 통하지 않더라도 수동 입력이 가능하도록 합니다.
디즈니 그림책 앱 '펜타'에서 1주 무료 구독 받아보세요!
추천인 코드: {CODE}
👇 아래 링크로 가입하면 혜택이 자동 적용돼요
https://penta.pics/invite/{CODE}
- 번역 키 기반으로 구현 (한/영/일 + 추후 언어 확장 가능)
- 기존
promo_free_trial번역 키 업데이트
7-3. 딥링크 패턴
| 패턴 | 예시 | 설명 |
|---|---|---|
| HTTPS 초대 | https://penta.pics/invite/{code} | 웹 리다이렉트 → 앱 딥링크 |
| HTTPS 프로모 | https://penta.pics/promo?code={code} | 프로모코드 딥링크 |
| 커스텀 스킴 | penta://promo?code={code} | 앱 직접 호출 |
| Install Referrer | Play Store referrer 파라미터 | Android QR → 설치 → 열기 플로우 |
7-4. 초대 링크 API
| Endpoint | Method | 설명 |
|---|---|---|
/api/promocodes/invite/<code>/info/ | GET | 초대 링크 정보 조회 |
/invite/<code>/ | GET (Web) | 앱 딥링크 리다이렉트 |
8. 클릭 추적 (PromoCodeClick)
프로모션 링크 클릭을 추적합니다.
| 필드 | 설명 |
|---|---|
ip_address | 클릭 IP 주소 |
user_agent | 브라우저 User-Agent |
referer | 리퍼러 URL |
utm_source | UTM 소스 |
utm_medium | UTM 매체 |
utm_campaign | UTM 캠페인 |
utm_term | UTM 키워드 |
utm_content | UTM 콘텐츠 |
device_type | 기기 유형 (mobile / tablet / desktop) |
os | 운영체제 |
browser | 브라우저 |
converted | 전환 여부 |
converted_at | 전환 시각 |
9. 프로모코드 사용 기록 (PromoCodeUsage)
| 필드 | 설명 |
|---|---|
user | 사용자 |
promo_code | 사용한 프로모 코드 |
subscription | 연결된 구독 |
used_at | 사용 시각 |
ip_address | IP 주소 |
user_agent | User-Agent |
applied_bonus_weeks | 적용된 보너스 주 수 |
- 고유 제약:
user+promo_code조합 (사용자당 동일 코드 1회 사용)
10. 파트너 분석 (Analytics)
- Endpoint:
GET /api/promocodes/analytics/<partner_code>/ - 관리자 전용
- 파트너별 클릭 수, 전환 수, 조회 수, 전환율 등의 분석 데이터를 제공합니다.