English {#english}
Control Plane: Via Zuplo API Gateway vs Direct Worker — Comparison and Recommendation
Purpose: Compare using the Zuplo API gateway for Control Plane vs calling the Worker directly, summarize pros/cons, and give an operational recommendation. No code proposals.
References: tenant-onboarding-flow.md, step5-confirm-submit-to-provisioning-flow.md, prego-control-plane README, onboarding-pulumi-ansible-stripe-zuplo-queue-logpush-analysis.md.
1. Context: Callers and Endpoints
| Caller | Endpoint examples | Auth / notes |
|---|---|---|
| www (browser) | POST /v1/tenants, GET /v1/jobs/:id, GET /v1/subdomain/check, POST /v1/checkout | Public; CORS needed. No API Key (onboarding). |
| Stripe | POST /webhooks/stripe | Stripe signature verification. Must be public URL. |
| GitHub Actions / Ansible / internal | GET/POST /internal/* | Bearer INTERNAL_API_KEY. Server/workflow only. |
| Cron | (Worker internal schedule) | No external call. |
PREGO_CONTROL_PLANE_URL is the “Control Plane entry point” for www and external callers. If it points to Zuplo, Zuplo receives first and proxies to the Worker; if to the Worker URL, the Worker receives directly. Business logic always lives in prego-control-plane (Worker).
2. Via Zuplo API Gateway
Setup: www / Stripe etc. → Zuplo (routing, policies) → Control Plane Worker.
2.1 Pros
| Item | Detail |
|---|---|
| Rate limiting | Path- and client-level limits in Zuplo. Helps with POST /v1/tenants abuse and DDoS. |
| API Key and policies | Can apply API Key policies to /v1/* when needed (www may not use yet; consistent gateway for future B2B/partner API). |
| Observability | Zuplo dashboard for request volume, errors, latency in one place. |
| Single entry | Tenant API (post-provisioning) and Control Plane under same gateway domain → easier unified CORS, domain, auth. |
| Routing/variants | Route to different backends or A/B/canary via Zuplo policies. |
2.2 Cons
| Item | Detail |
|---|---|
| Latency / hop | Request goes Zuplo → Worker; slight extra delay vs direct. |
| Stripe webhook | Stripe sends signed body to webhook URL. Via Zuplo, body must reach Worker unchanged for signature verification; no re-serialization or modification. Requires configuration and verification. |
| Cost | Zuplo usage-based cost. Small at low traffic; notable at high call volume. |
| Ops | Manage Zuplo config, keys, policies and Worker deployment together. Failures need “Zuplo vs Worker” segment debugging. |
| Internal calls | /internal/* is already protected by Bearer; internal systems can call Worker URL directly and skip Zuplo. “Only public via Zuplo” is consistent but yields two URL kinds (public = Zuplo, internal = Worker). |
3. Direct Worker Call
Setup: www / Stripe etc. → Control Plane Worker directly.
3.1 Pros
| Item | Detail |
|---|---|
| Simplicity | Single entry (Worker URL). Set deployment and env (PREGO_CONTROL_PLANE_URL). |
| Latency | No extra hop; shorter response time. |
| Stripe webhook | Worker receives Stripe events directly. No body mutation issues for signature verification. |
| Cost | No Zuplo cost; only Worker, D1, Queue, etc. |
| Debugging | Only Worker logs and Trace to check on failure. |
3.2 Cons
| Item | Detail |
|---|---|
| Rate limiting | Implement in Worker or rely on Cloudflare WAF/Rate Limiting. Path-level limits are more work in Worker alone. |
| Public endpoint protection | POST /v1/tenants etc. fully public → Worker exposed to scraping/retry storms. Need WAF/bot strategy. |
| Observability | Worker metrics and Logpush work, but “API gateway–level” dashboard is separate or Cloudflare-only. |
| Policy consistency | To apply same gateway policies (keys, quotas) as tenant API later, need more Worker logic or add Zuplo in front later. |
4. Comparison Summary
| Criteria | Via Zuplo | Direct Worker |
|---|---|---|
| Rate limiting / DDoS | Easy with Zuplo policies | Worker/WAF or CF features |
| Stripe webhook | Config and body pass-through care | Simple direct receive |
| Latency | One extra hop possible | Shorter |
| Cost | Zuplo cost added | None |
| Ops / debugging | Two layers (Zuplo + Worker) | Worker only |
| Public/internal unity | Public-only via Zuplo → two URLs | Single URL, simple |
| Observability | Zuplo dashboard | Worker / Logpush etc. |
5. Recommendation
-
Current phase (onboarding and provisioning stability first): Prefer direct Worker as default.
- Reasons: Simpler to implement and operate; Stripe webhook received directly by Worker is easier to verify and debug.
- Protect public endpoints (POST /v1/tenants, GET /v1/jobs, etc.) with Cloudflare WAF and Rate Limiting first; add simple rate limit (e.g. by IP/key) in Worker if needed.
-
When to consider Zuplo:
- When you want tenant API and Control Plane under the same domain and policy,
- When you need path- or key-level rate limits and quotas for POST /v1/tenants etc.,
- When opening B2B/partner API on Control Plane paths and want API Key and usage dashboard unified in Zuplo.
Then put Zuplo in front. You can keep Stripe webhook on a direct Worker URL and route only www/public API through Zuplo (hybrid: public = Zuplo → Worker; webhook/internal = direct Worker).
Summary:
- Recommendation: Run with direct Worker for now, protected by WAF and Worker-level rate limit.
- Option: If policy, observability, and unification needs grow, move only public endpoints to Zuplo and keep Stripe webhook and /internal/* on direct Worker.
한국어 {#korean}
Control Plane: Zuplo API 게이트웨이 경유 vs Worker 직호출 비교 및 추천
목적: Control Plane 관련 기능을 Zuplo API 게이트웨이를 경유해 사용할 때와 Worker를 직접 호출할 때의 장단점을 분석·비교하고, 운영 관점에서 추천안을 정리한다. 코드 제안 없음.
참조: tenant-onboarding-flow.md, step5-confirm-submit-to-provisioning-flow.md, prego-control-plane README, onboarding-pulumi-ansible-stripe-zuplo-queue-logpush-analysis.md.
1. 전제: Control Plane 호출처와 엔드포인트 구분
| 호출처 | 엔드포인트 예 | 인증/특성 |
|---|---|---|
| www(브라우저) | POST /v1/tenants, GET /v1/jobs/:id, GET /v1/subdomain/check, POST /v1/checkout | 공개·CORS 필요. API Key 없음(온보딩 단계). |
| Stripe | POST /webhooks/stripe | Stripe Signature 검증. 공개 URL이어야 함. |
| GitHub Actions / Ansible / 내부 | GET/POST /internal/* | Bearer INTERNAL_API_KEY. 서버·워크플로만 호출. |
| Cron | (Worker 내부 스케줄) | 외부 호출 없음. |
PREGO_CONTROL_PLANE_URL이 가리키는 곳이 곧 “www·외부에서 보는 Control Plane 진입점”이다. Zuplo URL이면 Zuplo가 먼저 받아 Worker로 프록시하고, Worker URL이면 Worker가 직접 받는다. 비즈니스 로직은 항상 prego-control-plane(Worker) 에 있다.
2. Zuplo API 게이트웨이 경유 방식
구성: www / Stripe 등 → Zuplo (라우팅·정책) → Control Plane Worker.
2.1 장점
| 항목 | 내용 |
|---|---|
| Rate limiting | Zuplo에서 경로·클라이언트별 제한 설정 가능. POST /v1/tenants 남용·DDoS 완화에 유리. |
| API Key·정책 | 필요 시 /v1/* 에 API Key 정책 적용 가능(현재 www는 미사용이어도, 추후 B2B·파트너 API 노출 시 일관된 게이트웨이). |
| 관측성 | Zuplo 대시보드에서 요청량·에러·레이턴시를 한곳에서 확인 가능. |
| 일관된 진입점 | 테넌트 API(프로비저닝 완료 후)와 Control Plane을 같은 게이트웨이 도메인 아래 두면, CORS·도메인·인증 정책을 통일하기 쉬움. |
| 변형·라우팅 | 경로별로 다른 백엔드로 스위칭하거나, A/B·카나리 배포를 Zuplo 정책으로 처리 가능. |
2.2 단점
| 항목 | 내용 |
|---|---|
| 레이턴시·홉 | 요청이 Zuplo → Worker 로 한 번 더 거치므로, 직호출 대비 소폭 지연 가능. |
| Stripe Webhook | Stripe는 Webhook URL에 서명 검증을 붙여 보냄. Zuplo 경유 시 Zuplo가 body를 그대로 Worker에 전달해야 하고, Worker에서 서명 검증 시 원본 body가 필요. 프록시 시 body 재직렬화·변형이 없어야 함. 설정·검증 필요. |
| 비용 | Zuplo 사용량 기반 비용 추가. 트래픽이 적으면 미미하나, 호출량이 크면 고려 대상. |
| 운영 포인트 증가 | Zuplo 설정·키·정책과 Worker 배포를 함께 관리해야 함. 장애 시 “Zuplo vs Worker” 구간 분리 디버깅 필요. |
| 내부 호출 | /internal/* 는 Bearer로 이미 보호되므로, 내부 시스템이 Worker URL을 직접 호출하면 Zuplo를 거칠 필요가 없음. “공개 엔드포인트만 Zuplo”로 나누면 일관되지만, URL이 두 종류(공개=Zuplo, 내부=Worker)가 됨. |
3. Worker 직호출 방식
구성: www / Stripe 등 → Control Plane Worker 직접.
3.1 장점
| 항목 | 내용 |
|---|---|
| 단순성 | 진입점이 하나(Worker URL). 배포·환경 변수(PREGO_CONTROL_PLANE_URL)만 맞추면 됨. |
| 레이턴시 | 홉이 없어 직호출이므로 상대적으로 짧은 응답 시간. |
| Stripe Webhook | Worker가 Stripe 이벤트를 직접 수신. 서명 검증 시 body 변형 이슈 없음. |
| 비용 | Zuplo 비용 없음. Worker·D1·Queue 등 기존 Cloudflare 비용만. |
| 디버깅 | 장애 시 Worker 로그·Trace만 보면 됨. |
3.2 단점
| 항목 | 내용 |
|---|---|
| Rate limiting | Worker 단에서 직접 구현하거나, Cloudflare WAF/Rate Limiting 규칙에 의존해야 함. Worker만으로는 경로별 세밀한 제한이 상대적으로 번거로움. |
| 공개 엔드포인트 보호 | POST /v1/tenants 등이 완전 공개이면, 스크래핑·재시도 폭주에 Worker가 직접 노출. WAF·Bot 전략으로 보완 필요. |
| 관측성 | Worker 메트릭·Logpush로 해결 가능하지만, “API 게이트웨이 수준” 대시보드는 별도 구축 또는 Cloudflare 대시보드에 의존. |
| 정책 통일 | 나중에 테넌트 API와 동일한 게이트웨이 정책(키·할당량)을 적용하려면 Worker 쪽 로직 추가 또는 Zuplo를 나중에 앞단에 도입해야 함. |
4. 비교 요약
| 기준 | Zuplo 경유 | Worker 직호출 |
|---|---|---|
| Rate limiting / DDoS 완화 | Zuplo 정책으로 적용 용이 | Worker/WAF 구현 또는 CF 기능에 의존 |
| Stripe Webhook | 설정·body 전달 주의 | 직접 수신으로 단순 |
| 레이턴시 | 1홉 추가 가능 | 짧음 |
| 비용 | Zuplo 비용 추가 | 없음 |
| 운영·디버깅 | Zuplo + Worker 두 레이어 | Worker만 |
| 공개/내부 통일 | 공개만 Zuplo로 두면 URL 이원화 | 단일 URL로 단순 |
| 관측성 | Zuplo 대시보드 활용 | Worker/Logpush 등 |
5. 추천
-
현 단계(온보딩·프로비저닝 안정화 우선): Worker 직호출을 기본으로 두는 것을 추천한다.
- 이유: 구현·운영이 단순하고, Stripe Webhook을 Worker가 직접 받는 구성이 검증·디버깅에 유리하다.
- 공개 엔드포인트(POST /v1/tenants, GET /v1/jobs 등)는 Cloudflare WAF·Rate Limiting 규칙으로 1차 보호하고, 필요 시 Worker 내부에 단순 rate limit(예: IP/키별)을 추가하는 방식으로 충분할 수 있다.
-
Zuplo 경유를 고려할 시점:
- 테넌트 API와 Control Plane을 같은 도메인·같은 정책 아래 두고 싶을 때,
- POST /v1/tenants 등에 경로별·키별 세밀한 rate limit·할당량이 필요해질 때,
- B2B·파트너용 API를 Control Plane 경로에도 열고 API Key·사용량 대시보드를 Zuplo로 통일하고 싶을 때
에 Zuplo를 앞단에 두는 구성을 검토하면 된다. 이때 Stripe Webhook은 Worker 직링크를 유지하고, www·공개 API만 Zuplo로 라우팅하는 하이브리드(공개 = Zuplo → Worker, Webhook/내부 = Worker 직호출)도 가능하다.
정리:
- 추천: 당장은 Worker 직호출로 운영하고, WAF/Worker 수준 rate limit으로 보호.
- 선택: 정책·관측·일원화 요구가 커지면 공개 엔드포인트만 Zuplo 경유로 전환하고, Stripe Webhook·/internal/* 는 계속 Worker 직호출 유지.