Skip to content

English {#english}

Fix “Network error” on x.pregoi.com OTP page by allowing Origin https://x.pregoi.com in Zuplo. Add it to env var ALLOWED_ORIGINS and redeploy; auth routes use corsPolicy: "prego-web". Ref: otp-verify-network-error-cors-analysis-and-fix. Full details: see Korean section below.


한국어 {#korean}

Runbook: Zuplo CORS — x.pregoi.com 허용 (OTP 인증 페이지 Network error 해결)

목적: x.pregoi.com OTP 인증 페이지에서 코드 입력 시 “Network error. Check your connection and try again.” 이 나오는 원인(CORS)을 해결하기 위해, Zuplo에서 Origin https://x.pregoi.com 을 허용하도록 설정한다.
참조: otp-verify-network-error-cors-analysis-and-fix


1. 현재 구조

  • prego-zuplo 저장소의 config/policies.jsonCustom CORS 정책 prego-web 이 정의되어 있음:

    • allowedOrigins: $env(ALLOWED_ORIGINS), allowCredentials: true, allowedMethods: ["GET","POST","PATCH","OPTIONS"], allowedHeaders: origin, content-type, authorization, ..., maxAge: 600.
  • auth 라우트 (/auth/discover, /auth/otp/verify, /auth/passcode/set 등)는 POSTOPTIONS(CORS preflight) 모두 corsPolicy: “prego-web” 적용. OPTIONS는 modules/cors-preflight-handler.ts(204 No Content 반환)로 명시 연산 추가되어 라우트 매칭 후 CORS 헤더가 붙음.

따라서 Zuplo 환경 변수 ALLOWED_ORIGINShttps://x.pregoi.com 을 넣고 배포하면 CORS가 동작한다.


2. Zuplo에서 허용하는 방법 (권장)

2.1 Zuplo Portal (UI)에서 설정

  1. Zuplo Portal 에 로그인 후 해당 프로젝트 선택.
  2. Environment / Variables (또는 Settings → Variables) 로 이동.
  3. Production (및 필요 시 Preview 등) 환경에서 변수 ALLOWED_ORIGINS 를 찾거나 새로 만든다.
  4. 값에 https://x.pregoi.com 을 포함한다.
    • 이미 다른 origin 이 있으면 쉼표로 구분 (공백 없이 또는 한 칸 띄우기):
      예: https://app.example.com, https://x.pregoi.com
    • Zuplo 문서: 끝에 슬래시 없이 입력 (예: https://x.pregoi.com ✅, https://x.pregoi.com/ ❌).
  5. 저장 후 배포가 자동이면 그대로 반영되고, 수동 배포면 해당 환경을 다시 배포한다.

이렇게 하면 Access-Control-Allow-Origin, Access-Control-Allow-Credentials, OPTIONS preflight 처리 모두 prego-web 정책에 의해 동작한다.

2.2 환경별로 다른 값이 필요한 경우

  • Production: ALLOWED_ORIGINS = https://x.pregoi.com (필요 시 다른 상용 도메인 추가)
  • Preview/Staging: 동일하게 넣거나, 테스트용 도메인만 넣어도 됨.

3. Zuplo API를 통한 설정 가능 여부

  • CORS 정책 내용 자체 (allowedOrigins, allowCredentials, allowedMethods 등)
    policies.json 에 정의되어 있으며, Zuplo REST API로 이 JSON을 수정하는 API는 제공되지 않는다.
    설정 변경은 Portal UI 또는 Git 연동 저장소의 config 수정 후 배포로만 가능하다.

  • 환경 변수 ALLOWED_ORIGINS
    → Zuplo Developer API (Variables API)설정·변경 가능하다.

    • 문서: Variables - The Zuplo Developer API
    • 예: PATCH /v1/accounts/{accountName}/projects/{projectName}/branches/{branchName}/variables/ALLOWED_ORIGINS
    • 계정/프로젝트/브랜치 이름과 API 인증이 필요하다.

정리:

  • Access-Control-Allow-Origin, Allow-Credentials, OPTIONS preflight 동작 자체는 이미 prego-web 정책으로 구현되어 있음.
  • 어떤 Origin을 허용할지환경 변수 ALLOWED_ORIGINS 로 제어되며,
    • Portal UI에서 수동 설정 가능
    • Zuplo Developer API (Variables API)ALLOWED_ORIGINS 값 설정/수정 가능
  • CORS 정책 정의(policies.json)는 API로 변경할 수 없고, Git/Portal에서만 수정 가능.

4. 트러블슈팅 (여전히 CORS 오류가 날 때)

에러 메시지 예:
Access to fetch at 'https://prego-main-xxx.d2.zuplo.dev/auth/otp/verify' from origin 'https://x.pregoi.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

체크리스트:

  1. 올바른 Zuplo 프로젝트·환경
    prego-main-bb45748.d2.zuplo.dev 를 서빙하는 프로젝트/브랜치에서 Variables를 수정했는지 확인. (Preview vs Production 구분.)

  2. 변수 이름 정확히 ALLOWED_ORIGINS
    대소문자 일치. 값에 https://x.pregoi.com 포함, 끝에 슬래시 없음.

  3. 배포 반영
    Variables 저장 후 해당 환경을 한 번 더 Deploy. 변수만 바꾸고 배포하지 않으면 반영되지 않을 수 있음.

  4. 브라우저 캐시
    preflight는 캐시될 수 있음. 시크릿 창에서 재시도하거나, 개발자 도구 Network에서 “Disable cache” 체크 후 다시 요청.

  5. 실제 preflight 응답 확인
    Network 탭에서 OPTIONS https://prego-main-xxx.d2.zuplo.dev/auth/otp/verify 요청을 선택한 뒤, Response Headersaccess-control-allow-origin: https://x.pregoi.com 이 있는지 확인. 없으면 위 1–3을 다시 점검.

  6. OPTIONS가 404를 반환하는 경우
    Zuplo는 내부적으로 CORS preflight(OPTIONS)를 처리하지만, 경로가 라우트에 매칭되어야 해당 라우트의 corsPolicy가 적용될 수 있음. 404가 나오면: (a) 해당 환경에 최신 config가 배포되었는지 확인, (b) ALLOWED_ORIGINS가 비어 있지 않은지 확인. 배포 후 Prego client-web에서 NEXT_PUBLIC_API_URL=<Gateway URL> npm run test:headers 로 CORS 검사 재실행 가능 (기획: verify-email-rsc-and-cors-local-debug-plan.md).

  7. 요청이 여전히 prego-main-bb45748.d2.zuplo.dev 로 가는 경우
    그 URL은 CORS/OPTIONS가 적용된 배포가 아님. 클라이언트가 사용하는 API URL은 빌드 시점NEXT_PUBLIC_API_URL에 박히므로, x.pregoi.com 을 서빙하는 배포에서 해당 변수를 설정한 뒤 재빌드·재배포 해야 함.
    설정 위치 (client-web = Cloudflare Pages 기준):

    • Cloudflare Dashboard → Workers & Pages → 해당 Pages 프로젝트(prego-client-web 등) → Settings → Variables and Secrets
    • Production (및 필요 시 Preview)에서 변수 추가/편집:
      • Variable name: NEXT_PUBLIC_API_URL
      • Value: https://prego-main-a8d4dfe.zuplo.app
    • 저장 후 Deployments 탭에서 Create deployment 또는 Retry deployment 로 재빌드(재배포) 실행.
      (배포가 GitHub Actions 등 다른 경로로 이루어지면, 해당 워크플로에서 사용하는 환경 변수(GitHub repo Settings → Secrets and variables → Actions, 또는 워크플로 내 env)에 동일하게 NEXT_PUBLIC_API_URL 설정 후 재실행.)
  8. ALLOWED_ORIGINS는 이미 설정했는데 계속 CORS 오류가 나는 경우
    변수만으로는 부족할 수 있음. 실제 배포된 Gateway에 라우트별 CORS 정책 할당·OPTIONS 연산이 반영되어 있어야 함.
    원인 추적: prego-zuplo 레포 docs/runbook/cors-error-cause-finding.md 참고.
    실제 Preflight 응답 확인: prego-zuplo에서 ./scripts/check-cors-response.sh https://prego-main-bb45748.d2.zuplo.dev 실행 후 상태 코드(204 vs 404)와 access-control-allow-origin 헤더 유무 확인.

동시에 보일 수 있는 다른 오류 (CORS와 무관)

  • GET .../default/en?_rsc=... 404 → Next.js 라우팅/세그먼트 이슈.
  • GET .../locales/en/en.css 404 → 로케일 정적 파일 경로.
  • React #418 (hydration) → 서버/클라이언트 HTML 불일치.
  • manifest.json Syntax error, Service Worker redirect → PWA 설정.
    위 항목들은 OTP verify CORS와 별도로, 클라이언트 앱/배포 설정에서 처리하면 됨.

5. 적용 후 확인

  1. 브라우저에서 https://x.pregoi.com/default/en/auth/verify-email?email=… 로 이동.
  2. 이메일로 받은 6자리 코드 입력 후 제출.
  3. Network 탭에서 POST .../auth/otp/verify 요청이 성공(200) 이고, 응답 헤더에 Access-Control-Allow-Origin: https://x.pregoi.com 이 있는지 확인.
  4. “Network error” 없이 passcode/set 페이지로 이동하는지 확인.

6. 문서 이력

  • 최초 작성: 방안 A(CORS) 적용 — prego-zuplo 기존 prego-web 정책·ALLOWED_ORIGINS 설정 방법, Zuplo API(Variables)로 ALLOWED_ORIGINS 설정 가능함 명시.
Help