Skip to content

www 패키지 페이지·Google 로그인·이메일 인증·언어 선택 개선 기획

목적: (1) 패키지 선택 페이지에서 IP 기반 국가 기본값, (2) Google sign-in 미설정 에러 원인·개선, (3) 이메일 인증코드 미수신 원인·해결, (4) 이메일 인증코드 인라인 입력(페이지 이동 없음), (5) 언어 선택 확장 및 브라우저 감지 기본값.
범위: 기획·요구사항·원인 분석·개선안만 정의. 코드 생성은 별도 단계.


1. 패키지 선택 페이지 — IP 기반 국가 기본값

1.1 요구사항

  • 패키지 선택(Step 1) 페이지 진입 시 사용자 IP를 바탕으로 접속 국가를 인식하여, Country 선택기의 기본값으로 설정한다.

1.2 현행

  • locale.js fetchGeoCountry(): Cloudflare Pages functions/api/country.jsGET /api/countryCF-IPCountry 헤더 기반 국가 코드 반환.
  • getEffectiveCountry(): stored > geoCountry > null.
  • init(): renderLocaleSelector()!getStoredCountry() 이면 fetchGeoCountry() 호출.
  • 이슈: fetchGeoCountry()가 비동기이므로, 초기 렌더 시 Country 드롭다운이 “Select country”로 표시되었다가 나중에 geo 값으로 갱신됨. 패키지 페이지에 진입할 때 아직 geo가 로드되지 않았을 수 있음.

1.3 개선안

항목내용
로드 시점index.html 로드 시(또는 DOMContentLoaded) fetchGeoCountry()먼저 호출하고, 응답 수신 후 renderLocaleSelector() 실행. 또는 renderLocaleSelector() 내부에서 geo가 없으면 로딩 표시 후 fetch 완료 시 재렌더.
패키지 페이지 특화Step 1이 보일 때 Country 선택기에 geo 기반 기본값이 반영되어 있도록, fetchGeoCountry() 완료 후 setCountry(geoCountry)로 저장(사용자가 아직 선택하지 않은 경우).
배포 환경/api/country는 Cloudflare Pages Functions에서만 동작. 로컬 개발 시 CF-IPCountry 없으면 빈 응답. 로컬용 fallback(예: 외부 IP→국가 API 또는 기본값 null)은 선택.

1.4 구현 포인트

  • locale.js init(): fetchGeoCountry()를 await/순차화하여, geo 수신 후 renderLocaleSelector() 호출.
  • 또는 fetchGeoCountry() 완료 시 geoCountrysetCountry(geoCountry)로 저장(저장값이 없는 경우만).
  • Country→Region 매핑(예: KR→sg, US→us)은 기존 region 선택 로직과 연동 시 검토.

2. Google sign-in “Google sign-in is not configured” — 원인 및 개선

2.1 에러 발생 위치

  • signup.html (line 131–136): Google 버튼 클릭 시 api.getGoogleAuthUrl(returnUrl) 반환값이 없거나 '#' 이면 showError('Google sign-in is not configured.') 호출.

2.2 원인

원인설명
PREGO_AUTH_URL 미설정api.js getGoogleAuthUrl() (line 246–249): PREGO_AUTH_URL이 비어 있으면 '#' 반환.
환경 변수 주입 누락www는 정적 HTML. PREGO_AUTH_URL은 배포 시 <script>window.PREGO_AUTH_URL='...';</script> 형태로 주입해야 함. Cloudflare Pages 등에서는 빌드 시점 또는 Workers/Pages 환경변수를 HTML에 주입하는 설정 필요.
Auth 서비스 미배포PREGO_AUTH_URL이 가리키는 Auth Worker/Gateway가 Google OAuth를 지원하지 않거나, /auth/google 경로가 없음.

2.3 확인 절차

  1. 브라우저 콘솔에서 window.PREGO_AUTH_URL 확인 — 비어 있으면 환경 주입 문제.
  2. Auth URL이 설정되어 있으면 GET {PREGO_AUTH_URL}/auth/google?return_url=... 호출 가능 여부 확인.
  3. Auth 서비스(Zuplo/Worker)에 Google Client ID, Client Secret, redirect_uri 설정 여부 확인.

2.4 개선안

항목내용
즉시배포 환경에서 PREGO_AUTH_URL을 Auth Gateway URL(예: Zuplo /auth/google 노출 URL)로 설정. 빌드/배포 스크립트 또는 Pages 환경변수 → HTML injection.
UIPREGO_AUTH_URL이 없을 때 Google 버튼을 비활성화 또는 숨김하고, “Google sign-in is not available” 툴팁/문구 표시. (에러 클릭 후 표시보다 예방적.)
대체 진입PREGO_CONTROL_PLANE_URL 등 다른 URL에 /auth/google이 있다면, Auth 전용 URL을 별도로 두거나 프록시 경로를 PREGO_AUTH_URL로 통일.
문서화apps/www/README.md, docs/runbook/tenant-onboarding-flow.mdPREGO_AUTH_URL 설정 절차 및 Google OAuth 연동 요건 명시.

3. 이메일 인증코드 미수신 — 원인 분석 및 해결안

3.0 증상

  • 이메일 인증 버튼(“Send verification code”) 클릭 시 UI에서는 성공으로 보이나, 실제 이메일이 수신함에 도착하지 않음.

3.0.1 플로우 요약

  • wwwapi.sendEmailOtp(email)PREGO_AUTH_URL/auth/email/send-otp (실제 호출) 또는 mock 모드 (PREGO_AUTH_URL 미설정 시)
  • Zuplo auth-handler (authEmailSendOtpHandler): Control Plane D1에 OTP 저장 → Resend API로 이메일 발송

3.0.2 원인 분석

#원인환경설명
1PREGO_AUTH_URL 미설정로컬api.js 254–278행: base가 비어 있으면 실제 fetch 없이 resolve({ success: true, message: 'OTP sent (mock)' }) 반환. 이메일 발송 요청이 절대 나가지 않음. 로컬에서 index.html/signup.html을 그대로 열고 PREGO_AUTH_URL을 주입하지 않으면 이 상황에 해당.
2RESEND_API_KEY 미설정배포Zuplo auth-handler.ts 324–353행: RESEND_API_KEY가 없으면 Resend API를 호출하지 않고 context.log.warn("RESEND_API_KEY not configured...")200 + “OTP sent” 반환. OTP는 D1에 저장되지만 이메일은 발송되지 않음.
3CONTROL_PLANE_URL / INTERNAL_API_KEY 미설정배포auth-handler가 D1 저장 전에 500 "Control Plane not configured" 반환. 이 경우 사용자에게 에러가 표시되므로, 이메일 미수신만 보인다면 1·2번 가능성이 큼.
4Resend API 실패배포emailResponse.ok가 false여도 auth-handler는 200을 유지. Resend API 에러(할당량 초과, 도메인 미인증 등) 시 이메일 미발송. Zuplo 로그 확인 필요.
5CORS / 네트워크로컬→배포www를 localhost에서 실행하고 PREGO_AUTH_URL이 배포 URL이면, CORS가 localhost를 허용해야 함. 미허용 시 브라우저에서 fetch 실패 → 사용자에게 에러 표시됨.

3.0.3 로컬 환경인 경우

  • 로컬에서 www만 실행하고 PREGO_AUTH_URL을 설정하지 않으면 → 원인 1에 해당.
  • 로컬에서 이메일까지 수신하려면:
    1. 배포된 Zuplo Gateway URL을 PREGO_AUTH_URL로 설정 (예: index.html 또는 빌드 시 <script>window.PREGO_AUTH_URL='https://xxx.zuplo.app';</script>)
    2. Zuplo에 RESEND_API_KEY, CONTROL_PLANE_URL, INTERNAL_API_KEY 설정
    3. CORS에서 http://localhost:* 허용

3.0.4 해결안

대상조치
로컬 개발(1) 로컬용 PREGO_AUTH_URL을 배포된 Auth Gateway로 설정하거나, (2) mock 모드일 때 “OTP sent (mock)” 대신 “로컬 개발 모드: 실제 이메일은 발송되지 않습니다. 테스트 코드 123456 사용” 등 명시적 안내 표시.
배포Zuplo 환경변수에 RESEND_API_KEY 설정. Resend 대시보드에서 도메인 인증(noreply@pregoi.com 등) 확인.
디버깅브라우저 Network 탭에서 POST .../auth/email/send-otp 호출 여부 확인. 호출이 없으면 PREGO_AUTH_URL 미설정. 200인데 메일이 없으면 Zuplo/Resend 설정 확인.
문서화apps/www/README.md, docs/runbook/에 PREGO_AUTH_URL 및 Zuplo 환경변수(RESEND_API_KEY 등) 설정 절차 명시.

4. 이메일 인증코드 — 인라인 입력(페이지 이동 없음)

4.1 요구사항

  • 이메일 인증코드를 다른 페이지로 이동하지 않고, 이메일 주소 입력 필드 바로 아래에 일반 input으로 숫자를 받음.
  • Verify 버튼 클릭 시 해당 페이지에서 인증 처리.

4.2 현행

  • index.html Step 2: 이미 인라인 패턴 있음 — 이메일 폼 + #otp-section(hidden) + #otp-code input + #btn-verify-otp. OTP 발송 후 섹션 표시, Verify 클릭 시 api.verifyEmailOtp() 호출.
  • signup.html: OTP 발송 후 signup-verify.html리다이렉트. signup-verify.html에서 6칸 OTP 박스로 입력.

4.3 개선안

페이지변경
signup.htmlOTP 발송 후 리다이렉트하지 않고, 이메일 입력 필드 아래에 (1) 인증코드 input 필드(6자리 숫자), (2) Verify 버튼을 추가. Verify 성공 시 index.html?signin=success 등으로 이동.
signup-verify.html유지 — 직접 URL 접근(예: 북마크, 이메일 링크) 시 fallback. 또는 signup.html로 통합 후 삭제 가능(선택).
input 형태단일 <input type="text" inputmode="numeric" maxlength="6" pattern="[0-9]*"> 또는 기존 6칸 박스. 요구사항 “일반 input field”에 따라 단일 input 권장.

4.4 구현 포인트

  • signup.html: #otp-section 블록 추가(초기 hidden). Send verification code 성공 시 (1) otp-section 표시, (2) 리다이렉트 제거.
  • Verify 버튼: api.verifyEmailOtp(email, code) 호출. 성공 시 세션 저장 후 index.html 이동.
  • Resend 버튼: 기존과 동일.

5. 언어 선택 — 확장 및 브라우저 감지 기본값

5.1 요구사항

  • 기본 언어: English.
  • 옵션 추가: Korean, Japanese, Chinese, Vietnamese, Arabic.
  • 기본값 결정: 브라우저의 기본 사용 언어(navigator.language)를 감지하여, 지원 언어에 포함되면 해당 언어를 기본값으로 설정.
  • 번역: 현재 번역본 없음. 모든 언어 선택 시 일단 영어 콘텐츠만 표시.

5.2 현행

  • locale.js SUPPORTED_LANGS: [{ code: 'en', label: 'English' }] 만 존재.
  • getEffectiveLocale(): stored > browser > ‘en’.
  • getBrowserLang(): navigator.language 또는 navigator.userLanguage 의 첫 부분(예: ‘ko-KR’ → ‘ko’).

5.3 개선안

항목내용
SUPPORTED_LANGSen, ko, ja, zh, vi, ar 추가. label: English, 한국어, 日本語, 中文, Tiếng Việt, العربية.
기본값getEffectiveLocale(): 1) localStorage 저장값 2) navigator.language/navigator.languages[0] 에서 지원 코드 매칭 3) ‘en’.
매핑zh-CN, zh-TWzh. ar-SA, ar-EG 등 → ar.
콘텐츠언어 코드별 번역 없음. 모든 lang 값에 대해 동일한 영어 텍스트 사용. getEffectiveLocale() 반환값만 저장하고, UI 문자열은 영어 고정.
선택기상단 header의 Language 드롭다운에 6개 옵션 노출.

5.4 구현 포인트

  • SUPPORTED_LANGS 배열 확장.
  • getBrowserLang(): navigator.languages 순회하며 지원 코드와 첫 번째 매칭 반환.
  • 번역: Phase 1에서는 적용하지 않음. 향후 i18n 파일 또는 스크립트 도입 시 확장.

6. 요약 및 적용 순서

#항목변경 대상우선순위
1IP 기반 국가 기본값locale.js (fetchGeoCountry 순서, setCountry 적용)P1
2Google sign-in 원인·개선PREGO_AUTH_URL 설정, signup.html 버튼 비활성화 조건P1
3이메일 인증코드 미수신PREGO_AUTH_URL 로컬 설정, Zuplo RESEND_API_KEY, mock 모드 안내P1
4이메일 인증 인라인signup.html (otp-section, Verify 버튼, 리다이렉트 제거)P1
5언어 옵션·브라우저 감지locale.js (SUPPORTED_LANGS, getBrowserLang)P2

7. 참조

Help