# 스쿨뮤직 VVIP 멤버십 - 파일 설명 및 적용방법

> **작성일**: 2026.05.28
> **이 문서를 가장 먼저 읽으세요.**
> **모든 파일은 폴더에 보이는 번호 순서대로 읽으면 됩니다.**
> **각 Step 제목은 "개발자 관점 (고객 관점)" 형식입니다.**

---

## 0. 폴더 구조 (한눈에)

```
스쿨뮤직-VVIP-멤버십-최종/

├── 00-파일설명 및 적용방법.md                   → 지금 보고 있는 파일 (먼저 읽기)
│
│   [Step 1. 멤버십 가입 초대 팝업 (고객 발견)]
├── 01-sm-vvip-invite-popup-v2.css            → 초대 팝업 스타일
├── 01-sm-vvip-invite-popup-v2.js             → 초대 팝업 로직 (사이트 푸터 삽입, 자동 노출)
│
│   [Step 2. 멤버십 가입 페이지 (고객 검토/결정)]
├── 02-membership-v2.html                     → 가입 랜딩 (플랜 선택 + 약관 + FAQ)
│
│   [Step 3. 결제 화면 (고객 결제 진행)]
├── 03-sm-payment-popup.html                  → 결제 수단 선택 모달 (카드/계좌 7종)
├── 04-sm-payment-fail-popup.html             → 결제 실패 안내 (재시도 유도)
├── 05-membership-welcome-popup.html          → 결제 성공 후 환영 팝업
│
│   [Step 4. 멤버십 현황·상품가 적용 (고객 가입 후 일상)]
├── 06-membership-status.html                 → 현황 페이지 (회원정보 프레임에 embed)
├── 07-schoolmusic-product-style.js           → 상품 상세에 VVIP 가격 카드·CSS 자동 주입
│
│   [Step 5. 해지·환불 화면 (고객 이탈 검토)]
├── 08-membership-cancel-popup.html           → 자동연장 해지 신청 (iframe 모달)
├── 09-membership-cancel-done-popup.html      → 해지 완료 (iframe 모달 이어서)
├── 10-membership-refund-confirm-popup.html   → 환불 확인 + 혜택 안내 (iframe 모달, 1단)
├── 10-membership-refund-form.html            → 환불 신청 폼 (iframe 모달, 2단, 결제수단별 분기)
│
│   [Step 6. 갱신·재가입 안내 (고객 만료/재방문)]
├── 11-membership-renewal-notice-popup.html   → 만료 7일 전 안내 (향후 SMS로 대체 예정)
├── 12-membership-rejoin-popup.html           → 만료/해지 후 재가입 유도
│
│   [기타]
├── 99-vvip-popup-preview-v2.html             → 초대 팝업 로컬 테스트용 (배포 X)
├── assets/                                   → 배경·아이콘·결제수단 로고 이미지 폴더
└── 07-CSS 적용 이미지.png                        → 상품 상세 적용 결과 미리보기 (참고용)
```

---

## 1. 동작 방식 (어떤 페이지에서 무엇이 동작하는지)

각 인터랙션을 구체적으로 풀어쓴 가이드. 어디서 무엇이 트리거되고 어떤 파일이 호출되는지 확인용.

---

### 1-1. VVIP 초대 팝업 (메인 페이지 진입 시)

- **트리거**: 사이트 어느 페이지든 진입 시
- **동작**:
  1. 공통 푸터의 `01-sm-vvip-invite-popup-v2.js` 자동 로드
  2. 백엔드가 회원 등급 확인 후 `window.SM_IS_VVIP = true` 주입
  3. JS가 페이지 로드 시 자동으로 팝업 DOM 생성 -> 화면 노출
  4. 일반 회원에게는 `SM_IS_VVIP = false` -> 팝업 노출 안 함
- **사용자 액션**:
  - "이벤트 페이지 이동" 클릭 -> `02-membership-v2.html` 로 이동
  - "오늘 하루 보지 않기" 클릭 -> `localStorage` 에 다음 날짜 저장 -> 다음 날 재진입까지 미노출
  - 닫기(X) 또는 ESC -> 모달만 닫힘, 다음 세션 재진입 시 다시 노출

---

### 1-2. 가입 페이지 -> 결제 흐름

- **`02-membership-v2.html` 진입**: VVIP 등급만 백엔드에서 통과시킴
- **동작**:
  1. 플랜 선택 라디오 (자동연장 29,000원 / 1년 단일 35,000원) 클릭 -> 결제 요약 가격·버튼 텍스트가 실시간으로 바뀜
  2. 약관 동의 체크박스 클릭 -> "VVIP 멤버십 시작하기" 버튼 활성화
  3. 버튼 클릭 -> `03-sm-payment-popup.html?plan=annual-renew&amount=29000` 호출
- **결제 팝업에서**:
  - 결제수단 7종 표시 (신용카드 / 토스페이 / 페이나우 / 페이코 / 무통장입금 / 가상계좌 / 토스 퀵계좌이체)
  - 무통장입금 선택 -> 은행 드롭다운 + 입금자명 입력란 노출
  - 결제 게이트웨이 호출
  - **성공** -> `05-membership-welcome-popup.html?name=...&plan=...` 호출
  - **실패** -> `04-sm-payment-fail-popup.html` 호출 -> "다시 시도하기" 클릭 시 결제 팝업으로 복귀

---

### 1-3. 가입 후 일상 - 상품 상세 페이지에서 VVIP 가격 노출

- **트리거**: 상품 상세 페이지 진입 (`/Shop/index.php3?Good_no=*` 또는 `/mobile/product_view.php?Good_no=*`)
- **동작**:
  1. 푸터에 삽입한 `07-schoolmusic-product-style.js` 자동 로드
  2. CSS 인라인 삽입
  3. **VVIP 가격 카드**를 기존 가격표 아래에 자동 주입
  4. 페이지의 `<img src="...npay_icon3.png">` 옆 텍스트를 추출 -> 상단 강조 박스 자동 생성
  5. **스쿨뮤직 혜택 박스** ("일반카드결제시 12개월 무이자 가능") 주입
  6. 가격 텍스트에 SUIT Variable 폰트 + weight 920 적용


**자동 주입되는 CSS·요소 항목 (요약)**:

| 범주 | 적용 대상 | 주입 내용 |
|---|---|---|
| **외부 폰트** | 전체 페이지 | Pretendard Variable / Noto Sans KR / SUIT Variable (CDN 로드) |
| **검색창** | `#keyword` 인풋 | 빨간 테두리(3px), 둥근 모서리, 높이 46px |
| **썸네일** | `#thumbnail_large_area`, `#dis_pic img` | 둥근 모서리(14px), 그림자, 호버 시 살짝 떠오름 |
| **VVIP 가격 카드 (PC)** | `.sm-mem-*` 클래스 (8종) | 회비·누적 절약·일반가 대비 할인 표시 행 |
| **VVIP 가격 카드 (모바일)** | `.sm-mobile-mem-*` 클래스 (10종) | 모바일 전용 세로 카드 + 엠블럼 + 가격 행 |
| **카드 이벤트 박스** | `.sm-benefit-host`, `.sm-mobile-card-*` | Npay 이벤트 텍스트 추출 → 상단 강조 박스 + 스쿨뮤직 혜택 박스 |
| **가격 텍스트** | `#reset_formated_price_area` | SUIT Variable 폰트 + weight 920 (굵게) |
| **수량 input** | `#quantitys`, `#quantitys2` | 둥근 모서리, 깔끔한 스타일 |
| **NaverPay 버튼** | `#btnNaverRequest` | 모서리 정리 (기존 동작·onclick은 절대 건드리지 않음) |
| **CSS 변수** | `:root` | 색상 토큰 18종 정의 (`--c-ink`, `--c-red`, `--c-npay` 등) |
| **공통 텍스트** | `body, table, tr, td, span, div, a, p, b, ...` | Pretendard 폰트로 통일 (`!important`) |

> 총 약 73개 CSS 셀렉터 + sm-* 클래스 20종 주입. 기존 PHP 마크업은 그대로 두고 빈 `<tr><td colspan="2">` 영역에만 새 요소 추가.

---

### 1-4. 현황 페이지 - 회원정보 프레임에서 동작

- **트리거**: 회원이 회원정보 메뉴 -> VVIP 멤버십 메뉴 진입
- **셋업**: 부모 사이트가 `<iframe src="06-membership-status.html">` 로 embed
- **백엔드 주입 필수**:
  - `<body data-payment-method="bank">` <- 회원 결제수단 채워주기
  - `data-field` 표 (planName, paidAmount, totalSaved 등 7종) 채워주기
- **사용자 액션**:
  - **"자동연장 해지" 클릭** -> `smOpenModal()` 호출 -> `08-cancel-popup` 을 iframe 모달로 띄움 (현황 위에 오버레이)
  - **"환불 신청" 클릭** -> `data-payment-method` 값을 읽어 `10-membership-refund-form.html?paid={method}` 로 페이지 이동
  - **"멤버십 이용약관" 클릭** -> `02-membership-v2.html#terms` 로 이동

---

### 1-5. 자동연장 해지 흐름 (iframe 모달)

- **트리거**: 현황 페이지 "자동연장 해지" 버튼
- **동작**:
  1. 현황 페이지가 오버레이를 띄우고 iframe 안에 `08-cancel-popup.html` 로드
  2. 해지 사유 chip 선택 + "해지 신청" 클릭 -> iframe 내부에서 `09-cancel-done-popup.html` 로 이동 (모달은 그대로)
  3. 완료 팝업의 "현황으로 돌아가기" 클릭 -> `postMessage('sm-close-modal')` 부모에게 전달
  4. 현황 페이지가 메시지 받아 모달 오버레이 닫음 -> 현황 페이지로 복귀

---

### 1-6. 환불 신청 흐름 (iframe 모달, 2단)

- **트리거**: 현황 페이지 "환불 신청" 버튼 (`data-payment-method` 자동 전달)
- **`10-membership-refund-form.html` 진입 시**:
  1. URL `?paid=` 파라미터 읽음
  2. 카드 계열 (`card`, `toss-pay`, `paynow`, `payco`) -> "원 결제수단으로 자동 환불" 안내만 노출
  3. 계좌 계열 (`bank`, `vbank`, `toss-quick`) -> 환불 받을 계좌 입력란 노출 (은행/계좌번호/예금주)
- **환불 계산 (백엔드가 data-field 로 채움)**:
  - `결제 금액 - 누적 받은 할인 = 환불 가능 금액`
  - 환불 가능 금액 > 0 -> `.eligibility.ok` 배너 노출 (차액 환불 안내)
  - 환불 가능 금액 <= 0 -> `.eligibility.no` 배너 노출 (환불 불가, 만료까지 멤버십 유지)
- **사용자 액션**:
  - 환불 사유 chip 선택 (선택사항)
  - 계좌 정보 입력 (계좌 계열만)
  - 동의 체크박스 -> "환불 신청하기" 버튼 활성화
  - 신청 클릭 -> 백엔드 접수 -> 현황 페이지로 복귀

---

### 1-7. 만료 임박·재방문 알림

- **만료 7일 전 사이트 진입 시**: `11-membership-renewal-notice-popup.html` 자동 노출 (향후 SMS 발송으로 대체 예정)
  - "확인" -> 닫기 / "자동연장 해지" -> 해지 팝업 이동
- **만료/해지 후 재방문 시**: `12-membership-rejoin-popup.html` 자동 노출
  - "VVIP 멤버십 다시 시작" -> `02-membership-v2.html` 이동
  - "30일 동안 보지 않기" -> localStorage 기록

---

## 2. 30초 요약

- 폴더: `/school/` 에 모든 파일 업로드 (번호 prefix는 그대로 유지)
- 구성: 메인 페이지 3 + 모달 팝업 7 + 스크립트 2 + CSS 1 + 자산 11
- 인코딩: **전부 EUC-KR**
- 가격: 자동연장 **29,000원** / 1년 단일 **35,000원**
- 가입 자격: VVIP로 마킹된 회원만 (수동 운영)

---

## 3. 파일별 역할

### Step 1. 멤버십 가입 초대 팝업 (고객 발견)

> **개발자**: VVIP 등급 회원에게 사이트 진입 시 자동 노출되는 팝업 (`SM_IS_VVIP` 플래그 기반)
> **고객**: 멤버십 존재를 처음 인지하는 순간

| 파일 | 역할 |
|---|---|
| `01-sm-vvip-invite-popup-v2.js` | VVIP 등급에게 자동 노출되는 초대 팝업 로직 |
| `01-sm-vvip-invite-popup-v2.css` | 초대 팝업 스타일 |

> 적용: 사이트 공통 푸터. `SM_IS_VVIP` 변수로 노출 분기. (8-2 코드 참고)

### Step 2. 멤버십 가입 페이지 (고객 검토/결정)

> **개발자**: 가입 랜딩 페이지 본체 (플랜 선택 + 약관 + FAQ)
> **고객**: 혜택 확인 후 가입 여부를 결정하는 단계

| 파일 | 역할 |
|---|---|
| `02-membership-v2.html` | 가입 페이지 (랜딩). 플랜 선택 + 약관 + FAQ |

### Step 3. 결제 화면 (고객 결제 진행)

> **개발자**: 결제 팝업 3종 (선택 / 실패 / 완료)
> **고객**: 결제 진행과 결과 확인

| 파일 | 노출 시점 |
|---|---|
| `03-sm-payment-popup.html` | 가입 페이지 "VVIP 멤버십 시작하기" 클릭 시 |
| `04-sm-payment-fail-popup.html` | 결제 게이트웨이 실패 응답 |
| `05-membership-welcome-popup.html` | 결제 성공 후 첫 진입 (환영 안내) |

### Step 4. 멤버십 현황·상품가 적용 (고객 가입 후 일상)

> **개발자**: 현황 페이지 + 상품 상세에 VVIP 가격 카드 자동 주입
> **고객**: 평소 사이트 이용하면서 혜택 확인 및 사용

| 파일 | 역할 |
|---|---|
| `06-membership-status.html` | 멤버십 현황 페이지 (회원정보 프레임에 embed) |
| `07-schoolmusic-product-style.js` | 상품 상세 페이지에 VVIP 가격 카드 자동 주입 |

### Step 5. 해지·환불 화면 (고객 이탈 검토)

> **개발자**: 현황 페이지 액션 버튼에서 분기되는 모달/페이지
> **고객**: 멤버십을 그만두거나 환불을 고민하는 단계

| 파일 | 진입 경로 |
|---|---|
| `08-membership-cancel-popup.html` | 현황 "자동결제 해지" -> iframe 모달로 노출 (1단) |
| `09-membership-cancel-done-popup.html` | 자동결제 해지 신청 접수 후 (iframe 안에서 이어서, 2단) |
| `10-membership-refund-confirm-popup.html` | 현황 "환불 신청" -> iframe 모달 (1단, 환불 확인 + 혜택 안내) |
| `10-membership-refund-form.html` | 환불 신청 계속 -> iframe 안에서 이동 (2단, 결제수단별 분기) |

### Step 6. 갱신·재가입 안내 (고객 만료/재방문)

> **개발자**: 만료 임박 알림 + 만료 후 재방문 시 재가입 유도 팝업
> **고객**: 갱신 시점에 인지하거나, 이탈 후 다시 돌아왔을 때

| 파일 | 노출 시점 |
|---|---|
| `11-membership-renewal-notice-popup.html` | 만료 7일 전 (향후 SMS로 대체) |
| `12-membership-rejoin-popup.html` | 만료/해지 후 다시 방문한 회원 |

### 자산 (assets/)

- `corona-membership-hero.png`, `membership-status-hero.png` - 배경 이미지
- `sm-card.png`, `toss_logo2.png`, `paynow.png`, `PAYCO_Sticker_Logo.png` 외 - 결제수단 아이콘
- `escrow_banner.gif` - 에스크로 배너
- `07-CSS 적용 이미지.png` - 상품 상세 적용 예시 (참고용)

### 기타

- `99-vvip-popup-preview-v2.html` - VVIP 초대 팝업 로컬 미리보기용 (배포 X)

---

## 4. 백엔드 작업 체크리스트

### [필수] 회원 테이블 컬럼 추가

| 컬럼 | 타입 | 설명 |
|---|---|---|
| `is_vvip` | bool | VVIP 등급 (운영자 수동 마킹) |
| `membership_status` | enum | active / expired / cancelled |
| `membership_plan` | enum | annual-renew / annual-once |
| `membership_paid_amount` | int | 29000 / 35000 |
| `membership_started_at` | date | 가입일 |
| `membership_expires_at` | date | 만료일 (가입일 + 365) |
| `membership_payment_method` | string | 결제수단 코드 (아래 6-2 참고) |
| `membership_auto_renew` | bool | 자동연장 여부 |
| `payment_failed` | bool | 자동연장 결제 실패 여부 (재시도 7일간 true) |
| `agreed_marketing_at` | datetime | 마케팅 수신 동의 시각 (선택) |

### [필수] 카테고리 테이블

| 컬럼 | 타입 | 설명 |
|---|---|---|
| `vvip_discount_rate` | float | 카테고리별 5~15% (상품별 X) |

### [필수] 환불 폼 결제수단 분기

현황 페이지의 "환불 신청" 버튼이 결제수단을 환불 폼에 전달해서 계좌 입력란 노출 여부를 자동 분기합니다.

- 현황 페이지 `<body>` 태그에 `data-payment-method` 속성을 채워주세요:

```html
<body data-payment-method="bank">  <!-- 백엔드가 회원의 결제수단으로 채움 -->
```

- 가능한 값: `card`, `toss-pay`, `paynow`, `payco`, `bank`, `vbank`, `toss-quick`
- "환불 신청" 클릭 시 JS가 자동으로 `?paid={method}` 로 환불 폼에 전달
- 환불 폼이 카드 계열이면 안내만, 계좌 계열이면 환불 계좌 입력란 노출

---

### [필수] 접근 제어

- `/school/02-membership-v2.html` 진입 시 VVIP가 아닌 회원 차단/리다이렉트
- VVIP 여부는 `window.SM_IS_VVIP` 자바스크립트 변수로도 노출 필요 (아래 9-2 참고)

### [필수] 환불 정책 구현

- **환불 가능 금액 = 결제 금액 - 누적 받은 할인 금액**
- 환불 가능 금액 > 0 -> 차액 환불 (예: 29,000원 결제, 12,000원 할인 받았으면 17,000원 환불)
- 환불 가능 금액 <= 0 -> 환불 없음 (받으신 할인이 결제 금액 이상)
- 환불 폼 표시 분기:
  - 환불 가능 금액 > 0 -> `<div class="eligibility ok">` 노출
  - 환불 가능 금액 <= 0 -> `<div class="eligibility no">` 노출
- 환불 신청 접수 후 영업일 3~7일 내 처리

---

### [필수] 멤버십 상태 분기 (현황 페이지)

`06-membership-status.html`의 `<body>` 태그에 회원의 현재 상태를 채워 주세요:

```html
<body data-membership-status="active"      <!-- active / expired / cancelled -->
      data-payment-failed="false"            <!-- true 면 결제 실패 배너 노출 -->
      data-payment-method="bank">
```

- `active`: 현재 그대로 (모든 액션 노출)
- `expired`: "다시 시작" 안내만 노출, 해지/환불 버튼 숨김
- `cancelled`: "해지된 상태" 안내, 환불 버튼은 노출
- `data-payment-failed="true"`: 자동연장 결제 실패 알림 배너 자동 노출

---

### [선택, 향후 작업] SMS 발송

- 자동연장 7일 전 사전 안내 (전자상거래법 권고)
- 자동연장 결제 성공/실패 알림
- 알리고, NHN Toast SMS 등 별도 솔루션 연동

---

## 5. 전체 사용자 흐름

```
[메인 페이지] 02-membership-v2.html
      |
      | "VVIP 멤버십 시작하기" 클릭
      v
[결제 팝업] 03-sm-payment-popup.html
      |
      +-- 실패 --> 04-sm-payment-fail-popup.html --> 재시도
      |
      +-- 성공 --> 05-membership-welcome-popup.html
                          |
                          | "VVIP 특별가 보러 가기"
                          v
                  [상품 상세 페이지 - VVIP 가격 자동 적용]

──────────────────────────────────────────────────

[현황 페이지] 06-membership-status.html
      |
      +-- "자동연장 해지" --> [iframe 모달] 08-cancel-popup --> 09-cancel-done-popup
      |                       (아래 7번 참고)
      +-- "환불 신청" --> [iframe 모달] 10-refund-confirm-popup --> 10-refund-form

──────────────────────────────────────────────────

[만료 7일 전 진입] 11-renewal-notice-popup (향후 SMS 대체)
[만료/해지 후 재방문] 12-rejoin-popup
```

---

## 6. 페이지별 URL 파라미터 (백엔드 -> 프론트)

### 5-1. 결제 팝업 `03-sm-payment-popup.html`

```
?plan=annual-renew&amount=29000
?plan=annual-once&amount=35000
```

### 5-2. 환불 폼 `10-membership-refund-form.html`

```
?paid=card           // 신용카드
?paid=toss-pay       // 토스페이
?paid=paynow         // 페이나우
?paid=payco          // 페이코
?paid=bank           // 무통장입금
?paid=vbank          // 가상계좌
?paid=toss-quick     // 토스 퀵계좌이체
```

- `card / toss-pay / paynow / payco` -> "원 결제수단으로 자동 환불" 안내만 노출
- `bank / vbank / toss-quick` -> 환불 받을 계좌 입력 필수 노출

### 5-3. 웰컴 팝업 `05-membership-welcome-popup.html`

```
?name=홍길동&plan=annual-renew&amount=29000&from=2026.05.21&to=2027.05.20
```

### 5-4. 갱신 안내 팝업 `11-membership-renewal-notice-popup.html`

```
?date=2027.05.20&amount=29000&method=신한카드%20*1234
```

### 5-5. 재가입 팝업 `12-membership-rejoin-popup.html`

```
?name=홍길동&saved=82400&from=2026.05.21&to=2027.05.20
```

---

## 7. 주요 페이지 `data-field` 채워야 할 값

### 7-1. 현황 페이지 (06-membership-status.html)

| `data-field` 속성 | 채울 값 예시 |
|---|---|
| `planName` | "스쿨뮤직 VVIP 멤버십" |
| `planType` | "자동연장 결제" 또는 "1년 단일 결제" |
| `price` | "29,000원" 또는 "35,000원" |
| `startedAt` | 가입일 (YYYY.MM.DD) |
| `expiresAt` | 만료일 (YYYY.MM.DD) |
| `totalSaved` | 누적 절약 금액 (SUM) |
| `purchaseCount` | 혜택 사용 횟수 (COUNT) |

### 7-2. 환불 신청 폼 (10-membership-refund-form.html)

| `data-field` 속성 | 채울 값 예시 |
|---|---|
| `planName` | "스쿨뮤직 VVIP 멤버십" |
| `planType` | "자동연장 결제" 또는 "1년 단일 결제" |
| `paidAmount` | "29,000원" |
| `startedAt` | 가입일 (YYYY.MM.DD) |
| `usageCount` | 혜택 사용 횟수 (예: "3회") |
| `calcPaid` | 환불 계산 - 결제 금액 (예: "+ 29,000원") |
| `calcSaved` | 환불 계산 - 누적 받은 할인 (예: "- 12,000원") |
| `refundAmount` | 환불 가능 금액 (예: "17,000원") |
| `refundAmountInline` | 위와 동일 값 (배너 안의 b 태그) |

---

## 8. 현황 페이지의 팝업 호출 (iframe 모달 패턴)

`06-membership-status.html` 이 회원정보 프레임 안에 embed 되는 상황을 고려해, "자동연장 해지" 플로우는 **iframe 모달**로 동작합니다.

### 동작 흐름

```
06-status.html (회원정보 프레임 안)
      |
      | "자동연장 해지" 클릭
      v
오버레이 + iframe(08-cancel-popup.html)  <- status 위에 모달처럼 표시
      |
      | "해지 신청" 클릭
      v
iframe 내부에서 09-cancel-done-popup.html 로 이동
      |
      | "현황으로 돌아가기" 클릭
      v
postMessage('sm-close-modal') -> status 가 오버레이 닫음
      |
      v
06-status.html (원래 화면 복귀)
```

### 핵심 함수

| 위치 | 함수 | 역할 |
|---|---|---|
| `06-status.html` | `smOpenModal(url)` | 오버레이 표시 + iframe `src` 설정 |
| `06-status.html` | `smCloseModal()` | 오버레이 숨김 + iframe 비우기 |
| `06-status.html` | `message` 리스너 | `'sm-close-modal'` 수신 시 `smCloseModal()` 호출 |
| `08-cancel-popup.html` `09-cancel-done-popup.html` | `smCloseFn()` | 부모 감지 후 postMessage 또는 fallback 페이지 이동 |

### 단독 페이지로도 동작

`08-cancel-popup.html`, `09-cancel-done-popup.html`을 브라우저에서 직접 열면 `smCloseFn()`의 fallback이 `location.href='06-membership-status.html'` 실행 -> 기존 단독 페이지 동작 그대로 유지. 로컬 테스트·디버깅에 유리.

### 다른 팝업도 같은 패턴으로 띄우려면

1. `06-status.html` 액션 버튼에서 `smOpenModal('파일명.html')` 호출
2. 해당 팝업 파일에 `smCloseFn()` 헬퍼 함수 추가 + 닫기/완료 버튼에서 호출

---

## 9. `<script>` 삽입 예시 코드 (실제 통합)

### 9-1. 상품 상세 페이지 (PC + 모바일)

상품 상세 PHP 템플릿의 `</body>` 직전 또는 공통 푸터에:

```html
<script src="/school/07-schoolmusic-product-style.js?v=20260528" charset="UTF-8" defer></script>
```

**자동 동작:**
- CSS 인라인 삽입
- VVIP 멤버십 안내 카드를 가격표 아래에 삽입
- 페이지의 `<img src="...npay_icon3.png">` 옆 텍스트를 자동 추출해 상단 강조 박스 생성
- 스쿨뮤직 혜택 박스 ("일반카드결제시 12개월 무이자 가능") 추가
- 가격에 SUIT Variable 폰트 + weight 920 적용

> 기존 스크롤·NaverPay 버튼·onclick 핸들러는 절대 건드리지 않음

> **인코딩 주의:** 이 JS 파일은 **UTF-8 + BOM** 입니다.
> 파일 맨 앞 BOM(`EF BB BF`)이 EUC-KR 호스트 페이지에서도 한글이 안 깨지게 강제합니다 (브라우저 인코딩 판별 최우선).
> 편집기로 다시 저장 시 반드시 **BOM 유지** ("UTF-8 with BOM"). BOM이 사라지면 한글이 깨집니다.
> 자세한 내용은 `07-CSS주입-디자인명세.md` 9번 참고.



### 9-2. 메인 페이지 헤더 또는 공통 푸터 (VVIP 초대 팝업)

```html
<link rel="stylesheet" href="/school/01-sm-vvip-invite-popup-v2.css?v=20260528">

<script>
  // VVIP 여부 - 세션/회원등급 가져와서 주입
  window.SM_IS_VVIP = <?= $isVvip ? 'true' : 'false' ?>;

  // 고객 이름과 이벤트 URL
  window.SM_VVIP_INVITE_V2 = {
    customerName: "<?= addslashes($userName) ?>",
    eventUrl: "/school/02-membership-v2.html"
  };
</script>
<script src="/school/01-sm-vvip-invite-popup-v2.js?v=20260528" defer></script>
```

**동작 규칙:**
- `SM_IS_VVIP === true` 일 때만 팝업 노출
- 이미 가입한 회원에게는 `SM_IS_VVIP = false` 처리 (백엔드 분기 필요)
- "오늘 하루 보지 않기" 클릭 시 localStorage(`sm_vvip_invite_v2_hide_until`)에 다음 날짜 저장
- ESC 또는 배경 클릭 시에는 영구 차단되지 않고 같은 세션 재진입 시 다시 노출

> 캐시 무효화: 파일 수정 시 `?v=` 뒤 날짜를 새로 갱신

---


### 9-3. 적용 제외 상품 안내 (선택)

상품 상세 페이지 중 VVIP 특별가 적용 제외 상품(브랜드 NPP/MAP 정책, 위탁/중고/전시품 등)에는 `<body>` 태그에 다음 속성 추가:

```html
<body data-vvip-excluded="true">
```

이렇게 하면 `07-schoolmusic-product-style.js` 가 VVIP 가격 카드 대신 "이 상품은 VVIP 특별가 적용 대상에서 제외됩니다" 안내를 자동 표시합니다.

---

## 10. 최근 변경 사항 (2026.05.28 기준)

| 변경 내용 | 영향 파일 |
|---|---|
| **파일명 번호 prefix 부여** (고객 여정 순서) | 전 파일 |
| **02 결제 버튼 핸들러 완성**: alert만 띄우던 미완성 코드 -> 03 결제 팝업으로 이동 | `02-membership-v2.html` |
| **03/04 결제 팝업 취소 동작 수정**: `window.close()` -> `location.href='02-membership-v2.html'` | `03-sm-payment-popup.html`, `04-sm-payment-fail-popup.html` |
| **환불 흐름 2단 + iframe 모달화**: 10-refund-confirm-popup 신규 + 모달 통일 | `06-membership-status.html`, `10-membership-refund-confirm-popup.html`, `10-membership-refund-form.html` |
| **자동결제 해지 vs 환불 용어 분리·명확화** (FAQ + 약관 + 현황 패널) | `02-membership-v2.html`, `06-membership-status.html`, `08-membership-cancel-popup.html` |
| **수동 처리 / 접수 톤 통일**: 모든 신청 "접수 -> 영업시간 내 순차 처리" | `05-welcome`, `08-cancel`, `09-cancel-done`, `10-refund-*` |
| **고객센터 시간 통일**: 평일 10:00~18:00, 점심시간 13:00~14:00 제외 | `02-membership-v2.html`, `04-sm-payment-fail-popup.html`, `08-membership-cancel-popup.html` |
| **환불 정책 복원**: 결제 금액 - 누적 받은 할인 = 환불 가능 금액 (계산 박스 + 3-state 분기) | `10-membership-refund-form.html` |
| **고객 관점 보완 11종** (상태별 UI, 결제 실패 배너, 개인정보 동의, 결제 이탈 경고, 적용 제외 라벨 등) | 여러 파일 |
| **관리자 페이지 섹션 삭제** (개발자 측 후속 작업 예정) | `00-파일설명 및 적용방법.md` |
| iframe 모달 패턴 도입 (현황 → 해지 → 완료) | `06-status`, `08-cancel-popup`, `09-cancel-done-popup` |
| 환불 폼: 결제수단별 분기 (`?paid=` 파라미터) | `10-membership-refund-form.html` |
| VVIP 초대 팝업: 라이트 에디토리얼 디자인 리뉴얼 | `01-sm-vvip-invite-popup-v2.{js,css}` |
| 신규 4종 팝업 추가 (결제 실패/환불 폼/갱신 안내/재가입) | 각 신규 파일 |
| 가입 완료 환영 팝업 신규 추가 | `05-membership-welcome-popup.html` |
| placeholder "홍길동" -> "OOO" 일괄 치환 | 전 파일 |
| 전 파일 EUC-KR 인코딩 통일 | 전 파일 |

---

## 11. 의도적으로 안 만든 것

- 결제수단 변경 UI (필요 시 별도 요청)
- 잔여 기간 환불 (한국 마켓 관행상 제외)
- 상품별 VVIP 가격 (카테고리 단위 할인율로 단순화)
- VVIP 자동 등급 판별 (운영자 수동 마킹)

---


## 12. 모바일 QA 체크리스트

배포 전 실제 모바일에서 다음 항목 확인:

| 항목 | 확인 내용 |
|---|---|
| 가입 페이지 | 플랜 선택 라디오 터치 동작, 약관 동의 체크박스 터치 영역 |
| 결제 팝업 | 결제수단 7종 모두 터치로 선택 가능, 무통장입금 폼 가독성 |
| 현황 페이지 | iframe 모달이 작은 화면에서 잘 보이는지 (스크롤·닫기 가능) |
| 환불 폼 | 은행 드롭다운 22개 + 직접 입력 토글 정상 동작 |
| 초대 팝업 | 라이트 테마 텍스트 가독성, 닫기 버튼 터치 영역 충분 |
| 상품 상세 | VVIP 가격 카드 모바일 세로 레이아웃, 폰트 크기 |
| 자동연장 알림 | "오늘 보지 않기" localStorage 동작 (Safari 사파리 사파리는 ITP 정책 주의) |

**브라우저 추천**: Chrome (Android), Safari (iOS), 삼성 인터넷 (Android)

---

## 13. 주의사항

### 인코딩

- 모든 파일 **EUC-KR**
- 새 파일 추가 시 EUC-KR 저장 필수
- EUC-KR에 없는 문자 사용 금지: em dash, 체크표시 등
- 필요 시 SVG로 대체

### 캐시 무효화

- 외부 스크립트/CSS 참조 시 `?v=20260528` 쿼리 적용
- 파일 수정 시 날짜 값 갱신

### 적용 제외 상품 (VVIP 할인)

- 브랜드 NPP/MAP 정책 상품
- 단순 배송비
- 위탁/중고/전시품

### 외부 CDN

- `07-schoolmusic-product-style.js` 가 Pretendard / Noto Sans KR / SUIT Variable 폰트를 jsdelivr / Google Fonts 에서 로드
- 회사 정책상 외부 CDN 차단이 필요하면 폰트를 자체 호스팅 후 `@font-face` 경로 교체

---

**문의**: 배포 후 디자인/문구 수정은 "3. 파일별 역할" 표에서 해당 파일을 찾아 진행. 데이터 필드 추가는 "4. 백엔드 작업 체크리스트" 우선 활용. 새로운 모달 팝업 추가는 "7. iframe 모달 패턴" 참고.
