| # | 영역 | 필드 | 타입 | 옵션 값 / 제약사항 | 입력 예시 |
| ① 캐시 충전 화면 — /me/wallet |
| 1 | 보유 캐시 | 잔액 | readonly(자동) | wallets.balance_paid_cash + wallets.balance_bonus_cash 의 합 — 각각 CHECK 로 음수 불가. 1캐시=1원 고정(환율 개념 없음). 정정 v2.46 — v2.30 에서 단일 balance_cash 가 유상/무상 2버킷으로 쪼개졌는데 이 표만 옛 컬럼명을 쓰고 있었다(같은 화면 ① 영역은 이미 나뉘어 그려져 있었다) | 3,000 |
| 2 | 충전 금액 | 금액 프리셋 | chip 단일선택 × 6 | 1천/5천/1만/3만/5만/10만 + 직접입력. 최소 충전 1,000원으로 확정(v2.29) — 최저 프리셋을 1,000으로 신설. 프리셋은 편의용 바로가기일 뿐 제약이 아니며, 직접입력으로 임의 금액 지정 가능. 1회 한도는 §13 미결정 | 10,000 |
| 2 | 충전 금액 | 직접 입력 | number | 1,000원 이상 정수 — 그 위로는 1원 단위 자유(1,500 · 12,340 모두 허용). 검증은 “1,000 미만” 하나뿐이며, 미달 시에만 결제 버튼 비활성 + 인라인 안내. 프리셋 선택 시 이 칸에 자동 반영 | 10,000 |
| 3 | 결제 수단 | 수단 선택 | chip 단일선택 | 카드 / 계좌이체 / 간편결제 — payments.method. PG사 선정은 §13 미결정 | "카드" |
| 4 | 결제 요약 | 부가세 · 결제금액 | readonly(자동 계산) | 충전 캐시의 10%를 부가세로 가산해 실결제액 산출 — v2.28 공급가액·부가세를 payments.supply_amount_krw / vat_amount_krw로 분리 저장(합계 = amount_krw) — 기존엔 담을 컬럼이 없어 세금계산서·대사가 불가능했음. 별도 가산 방식 채택 | 10,000 + 1,000 = 11,000원 |
| 4 | 결제 요약 | 결제하기 | button | 클릭 시 PG 결제창 → 승인 성공 시 payments INSERT + wallet_transactions(charge) + 잔액 증가가 한 트랜잭션 | "11,000원 결제하기" |
| 5 | 자동 충전 | 사용 여부 | toggle | auto_billing_settings.is_enabled — 기본 OFF. OFF면 잔액 부족 시 오른쪽 결제 모달이 뜨고, ON이면 모달 없이 즉시 자동 충전 후 후원 | ON |
| 5 | 자동 충전 | 발동 임계값 | number | threshold_balance — 이 잔액 미만이면 자동충전 발동 | 1,000 |
| 5 | 자동 충전 | 충전 방식 / 금액 | radio + number | billing_type shortfall(부족분만) / fixed(정액) + charge_amount | fixed · 10,000 |
| 5 | 자동 충전 | 등록 카드 | readonly + 변경 버튼 | billing_key_enc(PG 빌링키, 암호화). 카드번호 원본은 저장하지 않고 마스킹된 표시용 문자열만 보관 | "신한 ****1234" |
| 미사용 캐시 환불 — 안내 문구 전용(v2.30) |
| 10 | 환불 안내 | 정책 문구 | readonly text | 이 블록에는 입력 필드도 버튼도 없습니다. 대상 범위(유상 충전분만) · 프로모션 캐시 제외 · 보너스 회수 · 수수료 MAX(대상액×10%, 1,000원) · 계좌이체 시 매월 말일 입금 — 이 4가지를 문구로만 고지합니다 | — |
| 10 | 환불 안내 | 고객센터 연락처 | readonly(전화번호·운영시간) | 환불 접수는 고객센터 전화가 유일한 경로입니다. 서비스에는 신청 폼·심사 상태·진행 조회 화면을 두지 않으며, 본인 확인·계좌 수집·지급 처리는 상담 과정과 운영자 도구에서 이뤄집니다(§13 운영자 도구와 동일하게 범위 제외) | "1588-0000 · 평일 10:00–18:00" |
| — | 원장 | 이 서비스가 책임지는 범위 | 시스템 동작 | 신청 기능은 없어도 원장은 이쪽 책임입니다 — ① 환불 대상액을 계산할 수 있게 wallets를 유상/무상으로 분리 보관 ② 회수 대상 보너스를 특정할 수 있게 cash_grants에 지급 출처 기록 ③ 환불 집행 시 wallet_transactions에 refund·clawback으로 반영 | — |
| ② 결제 확인 모달 — 잔액 부족 시에만 노출 |
| 6 | 후원 대상 | 상품 썸네일 · 이름 · 가격 | readonly | gift_items.image_url / name / price_cash — 무엇에 결제하는지 명확히 보여주기 위해 상품 정보를 모달에 반복 노출 | "시그니처명 A · 5,000캐시" |
| 7 | 부족 안내 | 보유 · 부족 금액 | readonly(자동 계산) | 보유 잔액과 부족분을 분리해서 표시 — 사용자가 "얼마가 실제로 빠져나가는지" 오해하지 않게 하는 게 이 블록의 목적 | "보유 3,000 · 부족 2,000" |
| 7 | 결제 요약 | 추가 충전액 | readonly(자동 계산) | billing_type=shortfall이면 부족분만, fixed면 설정된 정액. 부가세 포함해 실결제액 산출 | 2,000 + VAT = 2,200원 |
| 8 | CTA | 결제하고 후원하기 | button | 문구를 "후원하기"가 아니라 "결제하고 후원하기"로 명시 — 결제가 함께 일어난다는 사실을 버튼에서 숨기지 않음. 자동충전 ON이면 이 모달 자체가 생략됨 | "결제하고 후원하기" |
| ⑨ 트랜잭션 처리 — 화면 요소는 아니지만 이 화면의 동작 계약 |
| 9 | 원자성 | 단일 트랜잭션 | 시스템 동작 | 잔액 조회(FOR UPDATE) → PG 승인 → 충전 → 차감 → donations INSERT까지 한 트랜잭션. 어느 단계든 실패 시 전체 롤백되어 결제만 되고 후원이 안 되는 상태가 생기지 않음 | 실패 시 "결제 실패, 후원되지 않았습니다" |
| 9 | 원장 | wallet_transactions 2건 | 시스템 동작 | 즉결이어도 charge(+) / donate(−) 2건을 반드시 남김. 각 건에 balance_after 스냅샷을 기록해 원장만으로 잔액 재구성·검증이 가능해야 함 | +2,000 → 5,000 / −5,000 → 0 |
| 9 | 동시성 | 행 잠금 | 시스템 동작 | SELECT balance FOR UPDATE로 잔액 행을 잠가, 동시에 여러 후원이 들어와도 잔액이 음수로 빠지지 않게 함 | — |