feat: 개인정보 수집·이용 동의 프로세스 추가

- QR 라벨에 개인정보 동의 안내 문구 추가 (18pt 작은 글씨)
- 웹앱에 핀테크 스타일 개인정보 동의 체크박스 추가
- 백엔드 API에서 개인정보 동의 검증 추가
- 개인정보보호법 준수 강화

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
시골약사 2026-01-23 18:51:20 +09:00
parent d2ad64ebd8
commit 1717f4c6c2
3 changed files with 97 additions and 1 deletions

View File

@ -276,6 +276,7 @@ def api_claim():
nonce = data.get('nonce')
phone = data.get('phone', '').strip()
name = data.get('name', '').strip()
privacy_consent = data.get('privacy_consent', False)
# 입력 검증
if not phone or not name:
@ -284,6 +285,13 @@ def api_claim():
'message': '전화번호와 이름을 모두 입력해주세요.'
}), 400
# 개인정보 동의 검증
if not privacy_consent:
return jsonify({
'success': False,
'message': '개인정보 수집·이용에 동의해주세요.'
}), 400
# 전화번호 형식 정리 (하이픈 제거)
phone = phone.replace('-', '').replace(' ', '')

View File

@ -166,6 +166,72 @@
font-weight: 400;
}
.privacy-consent {
margin: 24px 0 8px 0;
}
.checkbox-container {
display: flex;
align-items: center;
cursor: pointer;
user-select: none;
padding: 4px 0;
}
.checkbox-container input[type="checkbox"] {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.checkmark {
position: relative;
height: 24px;
width: 24px;
background-color: #f8f9fa;
border: 2px solid #e9ecef;
border-radius: 6px;
transition: all 0.2s ease;
flex-shrink: 0;
}
.checkbox-container:hover .checkmark {
border-color: #6366f1;
background-color: #ffffff;
}
.checkbox-container input:checked ~ .checkmark {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
border-color: #6366f1;
}
.checkmark::after {
content: "";
position: absolute;
display: none;
left: 7px;
top: 3px;
width: 6px;
height: 11px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
.checkbox-container input:checked ~ .checkmark::after {
display: block;
}
.consent-text {
margin-left: 12px;
color: #495057;
font-size: 14px;
font-weight: 500;
letter-spacing: -0.2px;
}
.btn-submit {
width: 100%;
padding: 18px;
@ -382,6 +448,14 @@
</div>
</div>
<div class="privacy-consent">
<label class="checkbox-container">
<input type="checkbox" id="privacyConsent" required>
<span class="checkmark"></span>
<span class="consent-text">개인정보 수집·이용 동의</span>
</label>
</div>
<button type="submit" class="btn-submit" id="btnSubmit">
포인트 적립하기
</button>
@ -442,12 +516,18 @@
const phone = document.getElementById('phone').value.trim();
const name = document.getElementById('name').value.trim();
const privacyConsent = document.getElementById('privacyConsent').checked;
if (!phone || !name) {
showAlert('전화번호와 이름을 모두 입력해주세요.');
return;
}
if (!privacyConsent) {
showAlert('개인정보 수집·이용에 동의해주세요.');
return;
}
btnSubmit.disabled = true;
btnSubmit.textContent = '처리 중...';
alertMsg.style.display = 'none';
@ -462,7 +542,8 @@
transaction_id: tokenInfo.transaction_id,
nonce: tokenInfo.nonce,
phone: phone,
name: name
name: name,
privacy_consent: true
})
});

View File

@ -92,6 +92,7 @@ def create_qr_receipt_label(qr_url, transaction_id, total_amount, claimable_poin
font_amount = ImageFont.truetype(font_path, 40) # 금액 (크게)
font_points = ImageFont.truetype(font_path, 36) # 포인트 (강조)
font_small = ImageFont.truetype(font_path, 28) # 안내 문구
font_tiny = ImageFont.truetype(font_path, 18) # 개인정보 동의 (작게)
else:
raise IOError("폰트 없음")
except (IOError, OSError):
@ -101,6 +102,7 @@ def create_qr_receipt_label(qr_url, transaction_id, total_amount, claimable_poin
font_amount = ImageFont.load_default()
font_points = ImageFont.load_default()
font_small = ImageFont.load_default()
font_tiny = ImageFont.load_default()
# 3. QR 코드 생성 (우측 상단) - 크기 및 해상도 개선
qr = qrcode.QRCode(
@ -162,6 +164,11 @@ def create_qr_receipt_label(qr_url, transaction_id, total_amount, claimable_poin
# 안내 문구
guide_text = "QR 촬영하고 포인트 받으세요!"
draw.text((x_margin, y), guide_text, font=font_small, fill=0)
y += 35
# 개인정보 동의 안내 (작은 글씨)
privacy_text = "(QR 스캔 시 개인정보 수집·이용에 동의한 것으로 간주됩니다)"
draw.text((x_margin, y), privacy_text, font=font_tiny, fill=0)
# 5. 테두리 (가위선 스타일)
for i in range(2):