OTP and Email — Consolidated Planning
Purpose: Single reference for OTP flow, template ownership, formatting, Zuplo callers, email delivery, Resend migration, and templates.
Source: Merged from otp-email-flow, otp-email-newline-*, otp-email-readability, otp-email-zuplo-api, otp-input-ui, email-delivery-flow-verification-dashboard, email-resend-migration, email-templates-unified-design, feature-email-templates-frappe.
1. OTP Flow and Template Ownership
sequenceDiagram
participant C as client-web
participant Z as Zuplo Gateway
participant A as Auth Worker
participant Q as Queue
participant M as Mail sender
participant R as Resend
C->>Z: POST /auth/otp/request {email}
Z->>A: forward
A->>A: USER_MAP check, OTP gen, AUTH_STORE.put
A->>Z: POST /email {to, subject, content}
Z->>Q: push message
Z-->>C: 200 {success}
Q->>M: consume
M->>R: send
Note over C,R: Verify: C->>Z->>A: POST /auth/otp/verify {email,code}; A checks AUTH_STORE
1.1 User Registration (Pre-requisite)
- Admin registers users in Frappe → sync to USER_MAP KV (
user:map:{email}). - OTP is sent only to users present in USER_MAP.
1.2 OTP Request → Email
| Step | Actor | Action |
|---|---|---|
| 1 | Client | POST /auth/otp/request (email, lang) → Zuplo Gateway |
| 2 | Auth Worker | USER_MAP check, OTP generate, AUTH_STORE.put, template load, Zuplo POST /email |
| 3 | Zuplo /email | Queue or Resend direct |
| 4 | Mail sender | Queue consumer → Resend API |
Template stored in: apps/auth-worker/src/email-otp-template.ts. Frappe does not own OTP body.
1.3 OTP Verify
- Client
POST /auth/otp/verify(email, code) → Auth Worker compares with AUTH_STORE, deletes on match, sets cookies, returnsnext: 'passcode/set'.
2. Zuplo Email API Callers
| Caller | Trigger | Template source |
|---|---|---|
| Auth Worker | POST /auth/otp/request, /auth/passcode/request-reset | email-otp-template.ts, getOtpEmailBodyHtml |
| Frappe | frappe.sendmail → patch → send_via_zuplo | Caller-provided content |
Shared: POST /email (Zuplo), body { to, subject, content, tenant_id? }.
Env: ZUPLO_EMAIL_API_URL, ZUPLO_EMAIL_API_KEY (Auth); mail_sender_api_url, mail_sender_api_key (Frappe).
3. Readability and Formatting
- Issue: OTP email sentences run together; line breaks not applied.
- Rule: Separate blocks with
\n\n(BR), structure: greeting → blank → OTP request text → blank → usage → blank → OTP code (ref) → blank → sign-off. - Fix: Ensure
OTP_BODYinemail-otp-template.tsuses BR/BR2; HTML generation converts\n→<br>. Avoid excess newlines; cap per block.
4. Resend Migration
- Current: pregoi-mail-sender uses Cloudflare send_email (destination address restriction).
- Target: Resend API (
POST https://api.resend.com/emails).RESEND_API_KEYas Worker Secret. - Unchanged: Zuplo → Queue → pregoi-mail-sender flow; only the final send step changes to Resend.
5. Email Delivery Flows
| Flow | Trigger | Path |
|---|---|---|
| A (Frappe) | Frappe send_via_zuplo | Frappe → POST /email (Zuplo) → Queue/Resend |
| B (OTP/Passcode) | Auth API | Client → POST /auth/otp/request → Auth Worker → POST /email → Queue/Resend |
Dashboard: GET /internal/email-flow-dashboard, POST /internal/email-flow/trigger-flow-a, POST /internal/email-flow/trigger-flow-b (Bearer INTERNAL_API_KEY).
6. Email Templates — Unified Design
- OTP: Auth Worker code (
email-otp-template.ts). - Frappe transactional: Frappe Email Template doctype or code-based content.
- Design: Consistent layout, minimal decoration, clear OTP block.
7. OTP Input UI
- Requirements: Error on fail → clear 6 digits, focus first box; paste support (6 digits); visible digits (6 boxes) instead of masked dots.
- Location:
apps/client-webverify-email page,otp-digit-boxes.tsx,code-entry-form.tsx.
References
한국어
OTP 및 이메일 — 통합 기획
목적: OTP 플로우·템플릿 소유·가독성·Zuplo 호출·이메일 전달·Resend 마이그레이션·템플릿 통합·OTP 입력 UI를 한 문서에서 참조.
요약
- §1 OTP 플로우: USER_MAP 선등록 → 클라이언트 OTP 요청 → Auth Worker(USER_MAP·AUTH_STORE)·Zuplo POST /email → Queue → Resend. 검증: POST /auth/otp/verify.
- §2 Zuplo 호출 경로: Auth Worker(OTP·패스코드), Frappe(sendmail 패치). 공통 POST /email.
- §3 가독성:
\n\n(BR)로 문단 구분, greeting → OTP 코드 블록 → sign-off 구조. - §4 Resend: Cloudflare send_email → Resend API 전환. RESEND_API_KEY Worker Secret.
- §5 이메일 플로우 A/B: Frappe 직접 vs Auth API 경유. 대시보드 /internal/email-flow-dashboard.
- §6·§7: 템플릿 통합, OTP 입력 UI(6칸 숫자·붙여넣기·에러 시 초기화).