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.json에 Custom CORS 정책prego-web이 정의되어 있음:- allowedOrigins:
$env(ALLOWED_ORIGINS), allowCredentials:true, allowedMethods:["GET","POST","PATCH","OPTIONS"], allowedHeaders:origin, content-type, authorization, ..., maxAge:600.
- allowedOrigins:
-
auth 라우트 (
/auth/discover,/auth/otp/verify,/auth/passcode/set등)는 POST 및 OPTIONS(CORS preflight) 모두 corsPolicy: “prego-web” 적용. OPTIONS는modules/cors-preflight-handler.ts(204 No Content 반환)로 명시 연산 추가되어 라우트 매칭 후 CORS 헤더가 붙음.
따라서 Zuplo 환경 변수 ALLOWED_ORIGINS 에 https://x.pregoi.com 을 넣고 배포하면 CORS가 동작한다.
2. Zuplo에서 허용하는 방법 (권장)
2.1 Zuplo Portal (UI)에서 설정
- Zuplo Portal 에 로그인 후 해당 프로젝트 선택.
- Environment / Variables (또는 Settings → Variables) 로 이동.
- Production (및 필요 시 Preview 등) 환경에서 변수
ALLOWED_ORIGINS를 찾거나 새로 만든다. - 값에
https://x.pregoi.com을 포함한다.- 이미 다른 origin 이 있으면 쉼표로 구분 (공백 없이 또는 한 칸 띄우기):
예:https://app.example.com, https://x.pregoi.com - Zuplo 문서: 끝에 슬래시 없이 입력 (예:
https://x.pregoi.com✅,https://x.pregoi.com/❌).
- 이미 다른 origin 이 있으면 쉼표로 구분 (공백 없이 또는 한 칸 띄우기):
- 저장 후 배포가 자동이면 그대로 반영되고, 수동 배포면 해당 환경을 다시 배포한다.
이렇게 하면 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.
체크리스트:
-
올바른 Zuplo 프로젝트·환경
prego-main-bb45748.d2.zuplo.dev를 서빙하는 프로젝트/브랜치에서 Variables를 수정했는지 확인. (Preview vs Production 구분.) -
변수 이름 정확히
ALLOWED_ORIGINS
대소문자 일치. 값에https://x.pregoi.com포함, 끝에 슬래시 없음. -
배포 반영
Variables 저장 후 해당 환경을 한 번 더 Deploy. 변수만 바꾸고 배포하지 않으면 반영되지 않을 수 있음. -
브라우저 캐시
preflight는 캐시될 수 있음. 시크릿 창에서 재시도하거나, 개발자 도구 Network에서 “Disable cache” 체크 후 다시 요청. -
실제 preflight 응답 확인
Network 탭에서OPTIONS https://prego-main-xxx.d2.zuplo.dev/auth/otp/verify요청을 선택한 뒤, Response Headers에access-control-allow-origin: https://x.pregoi.com이 있는지 확인. 없으면 위 1–3을 다시 점검. -
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). -
요청이 여전히
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
- Variable name:
- 저장 후 Deployments 탭에서 Create deployment 또는 Retry deployment 로 재빌드(재배포) 실행.
(배포가 GitHub Actions 등 다른 경로로 이루어지면, 해당 워크플로에서 사용하는 환경 변수(GitHub repo Settings → Secrets and variables → Actions, 또는 워크플로 내env)에 동일하게NEXT_PUBLIC_API_URL설정 후 재실행.)
-
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.css404 → 로케일 정적 파일 경로.- React #418 (hydration) → 서버/클라이언트 HTML 불일치.
manifest.jsonSyntax error, Service Worker redirect → PWA 설정.
위 항목들은 OTP verify CORS와 별도로, 클라이언트 앱/배포 설정에서 처리하면 됨.
5. 적용 후 확인
- 브라우저에서 https://x.pregoi.com/default/en/auth/verify-email?email=… 로 이동.
- 이메일로 받은 6자리 코드 입력 후 제출.
- Network 탭에서
POST .../auth/otp/verify요청이 성공(200) 이고, 응답 헤더에Access-Control-Allow-Origin: https://x.pregoi.com이 있는지 확인. - “Network error” 없이 passcode/set 페이지로 이동하는지 확인.
6. 문서 이력
- 최초 작성: 방안 A(CORS) 적용 — prego-zuplo 기존 prego-web 정책·ALLOWED_ORIGINS 설정 방법, Zuplo API(Variables)로 ALLOWED_ORIGINS 설정 가능함 명시.