OTP Verify and Passcode Flow — Consolidated Planning
Purpose: Single reference for OTP verify flow, failure causes, CORS/network issues, dashboard UX, and KV check.
Source: Merged from otp-verify-and-passcode-flow-check, otp-verify-failure-and-dashboard-ux, otp-verify-network-error-cors-analysis-and-fix, otp-verify-page-kv-check-and-dashboard-b6, verify-email-rsc-and-cors-local-debug.
1. Expected vs Actual Behavior
| Expected | Actual |
|---|---|
| OTP input matches KV → success, redirect to passcode/set | Often “Invalid or expired code” or “Something went wrong” |
| Dashboard shows success/failure clearly | ”예상 장애” shown even when trigger succeeds |
2. OTP Verify Flow (Checklist)
- Client (verify-email):
POST {NEXT_PUBLIC_API_URL}/auth/otp/verify, body{ email, code },credentials: 'include'. Code: 6 digits only, email: trim, toLowerCase. - Zuplo: Route
/auth/otp/verifyto Auth Worker. - Auth Worker:
AUTH_STORE.get('otp:'+email), compare with code. Match → delete OTP, set cookies, 200{ success, next: 'passcode/set' }. Mismatch → 401. - KV key:
otp:{email}— email must be lowercase exact match.
3. Failure Causes (Investigation)
| Cause | Check |
|---|---|
| CORS | Browser (x.pregoi.com) → Zuplo cross-origin. Zuplo/Auth Worker must return Access-Control-Allow-Origin. CORS failure → Failed to fetch → “Network error” or “Something went wrong”. |
| API URL | NEXT_PUBLIC_API_URL empty or wrong → request to wrong host. |
| Email/code mismatch | Client normalization (trim, toLowerCase) vs Auth Worker; KV key uses lowercase email. |
| OTP expiry | TTL elapsed; AUTH_STORE returns null. |
| Server 401 | ”Invalid or expired code” (not catch). “Something went wrong” → fetch failed (network/CORS) before response. |
4. CORS / Network Error Analysis
- verify-email page (fails): Browser directly calls Zuplo. Cross-origin → CORS applies. If Zuplo does not allow
x.pregoi.com, browser blocks response →Failed to fetch→ “Network error”. - Control Plane debug (succeeds): Control Plane Worker calls Zuplo server-to-server. No CORS.
- Fix: Zuplo CORS policy to allow
https://x.pregoi.com(and other tenant origins) for/auth/otp/verify.
5. Passcode Flow
- Next step after OTP success:
passcode/setpage. User sets 6-digit passcode. - Endpoints:
handlePasscodeSet,handlePasscodeRequestReset,handlePasscodeReset,setAuthCookies.
6. Email Flow Dashboard UX
- Issue: Flow B trigger returns 200 but card shows “예상 장애” — confusing.
- Fix: Distinguish “expected failure points” (reference) from “current status”. Show green/red based on actual trigger result.
- B6 (KV code match): After email delivery, add step to verify code matches KV. Green if match, red if not. Auto-run with other Flow B steps.
References
- otp-and-email-consolidated
- runbook/prego-control-plane-dashboard
- apps/client-web:
auth/verify-email/page.tsx,lib/api-client.ts - apps/auth-worker:
handleOtpVerify,handlePasscodeSet
한국어
OTP 검증 및 Passcode 플로우 — 통합 기획
목적: OTP 검증 플로우·실패 원인·CORS·네트워크 에러·대시보드 UX·KV 코드 일치(B6)를 한 문서에서 참조.
요약
- §1 현상: 올바른 OTP 입력 시에도 “Invalid or expired code” 또는 “Something went wrong” 발생. 대시보드 “예상 장애” 문구 혼동.
- §2 검증 플로우: 클라이언트 POST /auth/otp/verify → Zuplo → Auth Worker AUTH_STORE 비교 → 일치 시 passcode/set 이동.
- §3 실패 원인: CORS(브라우저→Zuplo cross-origin), API URL 오설정, 이메일/코드 불일치, OTP 만료.
- §4 CORS: verify-email 페이지는 브라우저가 Zuplo 직접 호출 → CORS 필요. Zuplo에 tenant origin 허용.
- §5·§6: passcode 설정 플로우, 대시보드 B6(KV 코드 일치) 추가.