1. 목적
- 현재
/trial에 구현된 비즈니스 이메일 검증·수동 승인 플로우를 문서로 고정한다. - 향후 client-web·admin-web·www 등 모든 공개 호출자가 동일한 패턴으로 Zuplo API를 경유하고, Cloudflare(Pages·Workers·Zone) 쪽 기능을 일관되게 적용할 수 있도록 변경 방향을 정의한다.
- 본 문서는 기획·계약 순서만 다룬다. 구현은 How to add an API 및 prego-zuplo runbook을 따른다.
구현 업데이트 (www /trial): 브라우저는 NEXT_PUBLIC_ZUPLO_API_URL 로 Zuplo에 직접 POST /api/trial/* 합니다. 예전 Pages Functions → Zuplo 프록시 경로는 제거되었습니다. 거버넌스: API gateway & BFF governance.
2. 현재 구현 플로우 (요약)
2.1 사용자 여정
- 사용자가 www
GET /trial접속 (마케팅 헤더/푸터, 다크 모드 등 기존 셸). - 회사 이메일 입력 후 Continue → 클라이언트가 trial 이메일 분류 API 호출.
- 응답에 따라:
- 자동 트라이얼 허용 →
admin-websignup으로 이동 (plan=free,region=sg,from_trial=1, 선택적trace_*/ 온보딩 상관 ID). - 수동 승인 필요 → 전면 모달 안내; Start Manual Onboarding →
POST /api/trial/manual-approval/request후/trial/manual-approval/verify에서 업무 이메일 OTP(필요 시) 및 단계별 폼 → 회사 정보 제출 (submit-details). 이메일 딥링크/trial/manual-approval/complete?token=는 동일 verify 플로우로 리다이렉트.
- 자동 트라이얼 허용 →
2.2 시퀀스 (현재 프로덕션 기준)
sequenceDiagram
participant U as Browser (www)
participant Z as Zuplo
participant CP as Control Plane Worker
U->>Z: POST /api/trial/email/check
Z->>CP: POST /v1/trial/email/check
CP-->>Z: JSON
Z-->>U: JSON
U->>U: 허용 시 location → admin-web /signup?...
opt manual approval (request, draft, email OTP, submit-details)
U->>Z: POST /api/trial/manual-approval/request | GET/PATCH draft | email/send-otp | email/verify-otp | submit-details
Z->>CP: /v1/trial/manual-approval/...
end
2.3 저장소·계약 매핑
| 구간 | 역할 | 저장소 / 산출물 |
|---|---|---|
| UI | 폼, 에러 매핑, x-trace-id 전달 | Prego apps/www — TrialPageClient, TrialEmailGate, TrialBlockedModal, app/trial/manual-approval/verify, lib/trial-gateway.ts |
| 브라우저 → Zuplo | NEXT_PUBLIC_ZUPLO_API_URL (trial CORS는 게이트웨이 trial-access 조각 15-trial-access-* …) | apps/www/lib/trial-gateway.ts |
| 공개 API 정의·라우트 | 경로·CORS·핸들러 | prego-zuplo trial-access 조각 (15-trial-access-* … 19-trial-access-*, oas-manifest.json), modules/trial-access-handlers.ts |
| 도메인 로직 | 이메일 분류·수동 승인·업무 이메일 OTP·드래프트 | prego-control-plane v1/trial/*, D1 0027·0028, Resend / OTP_PEPPER (SMS OTP 제거됨 — remove-phone plan) |
| 온보딩 이동 | admin-web 가입 URL | apps/www ADMIN_BASE_URL, onboarding-trace |
Zuplo 핸들러는 Control Plane URL(CONTROL_PLANE_URL)로 프록시만 수행한다. ERP 규칙은 Frappe(prego_saas)가 아니라 CP 쪽 계약을 따른다.
3. “이질적”인 지점 (통합 기획의 출발점)
| 항목 | 현재 | 리스크 |
|---|---|---|
| 브라우저 → API | 프로덕션은 www 동일 출처 → Functions → Zuplo. 로컬은 Zuplo 직접 | CORS·환경 변수 이중 관리, 문서화 부족 시 운영 혼선 |
| Zuplo vs Worker | Trial은 Zuplo → CP가 이미 표준 | 다른 흐름은 CP 직접 URL을 쓰는 경우가 있으면 Zuplo vs 직접 Worker와 불일치 |
| Cloudflare “기능” | Pages(정적·Functions)·Zone(WAF·Rocket Loader)·Workers(CP)가 각각 분산 | Rate limit, 로그, 추적 ID를 한 패턴으로 묶기 어려움 |
통합 목표는 “브라우저가 보는 공개 HTTP 엔드포인트의 첫 홉은 항상 Zuplo(또는 의도적으로 동일한 게이트)” 이고, Cloudflare는 그 앞·옆에서 정책을 적용하는 형태로 정리하는 것이다.
4. 목표 아키텍처 (Zuplo API + Cloudflare)
4.1 원칙
- 공개 브라우저 API는 Zuplo에 노출된 경로(
config/*.oas.json→ sync-oas → verify)만 사용한다. 도메인 규칙은 Zuplo에 넣지 않고 CP/Frappe에 둔다 (tenant trust). - www는 가능한 한 동일 출처(
/api/...)로 호출해 CORS를 원천 차단하고, 그 백엔드는 Zuplo로만 붙인다 (현재 Pages Functions 프록시와 동일한 방향). - Cloudflare 기능은 아래처럼 역할을 분리해 기술한다.
| Cloudflare 계층 | Trial 플로우에 쓸 수 있는 기능 (예시) |
|---|---|
| Pages | 정적 자산, functions/ 프록시, 빌드 시 NEXT_PUBLIC_* |
| Zone (www) | WAF, Bot, Rocket Loader 끔, 캐시 규칙 |
| Workers (CP 등) | D1, 내부 시크릿, 비즈니스 API 구현체 |
| Zuplo | 라우팅, CORS, rate limit, API 키, 관측, Stripe 등 다른 업스트림과 동일한 게이트 |
4.2 통합 후 “한 장” 흐름 (목표)
flowchart LR
subgraph clients [Clients]
WWW[www 브라우저]
CW[client-web]
AW[admin-web]
end
subgraph edge [Edge]
P[Pages Functions 선택]
Z[Zuplo API]
end
subgraph cf [Cloudflare Workers]
CP[Control Plane]
AI[prego_ai 등]
end
WWW -->|권장: same-origin /api| P
P --> Z
WWW -.->|개발만 직접| Z
CW --> Z
AW --> Z
Z --> CP
Z -.->|다른 라우트| AI
- 목표: client-web·admin-web에서도 가능하면 Zuplo 베이스 URL 한 종류로 호출하고, www만 동일 출처 프록시 예외를 유지하거나, 장기적으로 Workers 라우트 하나로 통일하는 방안을 검토한다.
5. 구현 단계 (권장 순서)
계약 우선 순서는 플랫폼 허브의 How to add an API를 따른다.
| 단계 | 작업 | 산출물 |
|---|---|---|
| A | Trial 관련 경로를 OpenAPI·Zuplo에 단일 진실원으로 유지 | prego-zuplo OAS, pnpm run sync-oas / verify |
| B | ALLOWED_ORIGINS, x-trace-id — www·Pages preview·client-web 출처가 누락되지 않게 runbook 점검 | prego-zuplo runbook |
| C | Pages Functions ZUPLO_API_URL·프로덕션 빌드 NEXT_PUBLIC_* — 배포 체크리스트에 고정 | apps/www/README, Cloudflare 대시보드 |
| D | (선택) client-web·admin-web의 CP/Zuplo 직접 호출을 감사하고, Zuplo 경로로 수렴 | 각 앱 ADR 또는 작은 설계 문서 |
| E | 관측: Zuplo 대시보드 + CP Logpush에서 같은 trace로 상관 | x-trace-id / trace_* |
6. 비기능·운영
- 보안: 브라우저에 내부 Worker URL을 노출하지 않는다. Zuplo 또는 동일 출처 프록시만.
- CORS: Zuplo 측
prego-webCORS와 trialallow-all정책의 차이를 운영 문서에 명시; 장기적으로 혼선이 없게 정책 이름·출처 목록 정리. - Rocket Loader: www에서 클라이언트 스크립트가 깨지지 않도록 www README 배포 절차 유지.
7. 참고 문서
- Control Plane: Zuplo vs 직접 Worker
- Tenant & trust boundaries
- Dependency inspection for AI
- Monorepo
apps/www/README.md— Pages root,functions/, 환경 변수 - 외부: prego-zuplo
docs/runbook/README.md
8. English summary {#english-summary}
Purpose: Document the current www /trial flow (email check → optional manual approval → redirect to admin-web signup with trace), and define a target where all public callers converge on the Zuplo API, with Cloudflare (Pages Functions for same-origin proxy, Zone policies, Workers behind Zuplo) applied consistently. Implementation follows OpenAPI-first in prego-zuplo and platform contract order; no code in this doc.
9. 구현 상태 (Prego 모노레포) {#implementation-status}
| 단계 | 상태 | 비고 |
|---|---|---|
| A — Trial 경로 OpenAPI·Zuplo | 기존 유지 | prego-zuplo config/15-trial-access-* … 19-trial-access-*, trial-access-handlers.ts |
B — CORS·x-trace-id | 운영 설정 | Zuplo ALLOWED_ORIGINS, runbook |
C — Zuplo 직접 (NEXT_PUBLIC_ZUPLO_API_URL) | 브라우저 → Zuplo | apps/www/lib/trial-gateway.ts; 검증은 verify-www-pages-functions.mjs (/api/country 등만) + verify:trial-functions 별칭 |
| D — client-web·admin-web Zuplo 수렴 | 부분 적용 | client-web api-client는 이미 게이트웨이 베이스 사용. admin-web 레거시 PREGO_CONTROL_PLANE_URL은 온보딩 /v1/* 전용; trial과 무관. 전면 Zuplo화는 별도 마이그레이션. |
| E — 관측·trace | 기존 | x-trace-id / trace_*, trial-gateway에서 전달 |
CI: .github/workflows/deploy-pages.yml — verify:pages-functions 실행 (verify:trial-functions는 동일 스크립트 별칭).