Skip to content

English {#english}

Tenant Onboarding Flow (www → Provisioning Complete)

End-to-end reference from demo web (www) to Control Plane, workflow, Ansible, and Zuplo. Env (summary): NEXT_PUBLIC_PREGO_ADMIN_BASE_URL (www), NEXT_PUBLIC_PREGO_CONTROL_PLANE_URL, NEXT_PUBLIC_PREGO_AUTH_URL, billing proxy, plus admin-web Google OAuth + PREGO_ZUPLO_INTERNAL_API_KEY for Zuplo session completion. 6 steps: 1 Package → 2 Login → 3 Payment → 4 Tenant info → 5 Confirm → 6 Provisioning.

Ref: tenant-onboarding-demo-www-plan, provision-tenant-pipeline. Post-submit resource allocation (7 steps, case handling, R1–R8, Phase, Runbook): tenant-onboard-resource-allocation-flow-plan §1, §6–§8.


1. Demo web environment variables

SiteVariableDescription
wwwNEXT_PUBLIC_PREGO_ADMIN_BASE_URLRedirect after package selection. Default https://m.pregoi.com in app code.
admin-webNEXT_PUBLIC_PREGO_CONTROL_PLANE_URLZuplo (public gateway) base. Tenant APIs and trial handoff (/internal/* on this host) use this URL.
admin-webNEXT_PUBLIC_PREGO_AUTH_URLZuplo Auth base (email OTP, Singpass, POST /auth/google/complete-session).
admin-webGOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETServer-only. App-owned Google OAuth; register redirect https://<admin>/api/auth/google/callback. On Workers, optional Actions Variable ADMIN_GOOGLE_CLIENT_ID sets plain GOOGLE_CLIENT_ID at deploy (deploy-admin-web-worker.yml); otherwise dashboard / wrangler.
admin-webPREGO_ZUPLO_INTERNAL_API_KEYSame as Zuplo INTERNAL_API_KEY (server-only).
admin-webPREGO_CONTROL_PLANE_INTERNAL_API_KEYSame as Control Plane INTERNAL_API_KEY (Worker Secret). Required for www /trial → admin /signup server handoff (POST /api/trial/onboarding-handoff-verify). See Trial email (www) and admin handoff.
admin-webPREGO_JWT_COOKIE_DOMAINOptional (e.g. .pregoi.com) when session cookie must be sent to the AUTH_URL origin. Optional Actions Variable ADMIN_PREGO_JWT_COOKIE_DOMAIN at Worker deploy (deploy-admin-web-worker.yml).
admin-webNEXT_PUBLIC_PREGO_BILLING_PROXY_URLBilling proxy URL. billing page GET with ?tenant_id=xxx, display JSON.
admin-webNEXT_PUBLIC_PREGO_WWW_BASE_URLStep 2 “Previous”, nav “Choose package”. Default https://www.pregoi.com in app code.

www does package selection; admin-web does onboarding wizard (Steps 2–6) and tenant admin (dashboard, billing). Legacy static HTML may inject window.PREGO_* at deploy; Next.js apps use NEXT_PUBLIC_* at build time.

1.1 Cloudflare Pages build (www / admin-web)

Both apps depend on workspace packages (@platform/shell, @platform/theme-context). In Cloudflare Pages, use the monorepo root as the project root (not apps/www or apps/admin-web alone).

Pages projectBuild commandBuild output / deploy
prego-wwwpnpm install --frozen-lockfile && pnpm --filter prego-www run buildStatic: apps/www/out (output: 'export').
admin-web (Worker)pnpm install --frozen-lockfile && pnpm --filter prego-admin-web run cf:buildNot static out/. Workers: .open-next/; R2 prego-admin-opennext-cache (Pulumi pulumi up or wrangler r2 bucket create). Deploy: cf:deploy, cf:deploy:with-vars (env → Worker --var), or GitHub Deploy admin-web (ESLint, then cf:deploy:with-vars). Or Node / Vercel / Docker. See apps/admin-web/README.md.

GitHub Actions: .github/workflows/deploy-pages.yml (Build Pages Apps) runs pnpm run lint:www-admin, then pnpm --filter prego-www run build, pnpm --filter prego-admin-web run cf:build, and pnpm run build:storybook — verification only; it does not upload to Cloudflare.

Local dev from repo root: pnpm install, then pnpm --filter prego-www run dev (port 3001) or pnpm --filter prego-admin-web run dev (port 3002). Match CI before pushing: pnpm run lint:www-admin. See apps/www/README.md, apps/admin-web/README.md, www & admin-web deployment, Build Pages Apps, and optional Deploy admin-web (Cloudflare Worker).


2. Control Plane integration summary

UseMethod/PathNotes
Free tenant createPOST /v1/tenantstier, region, subdomain_slug, subdomain_name, company_name (max 60), abbr (2–5), admin_email, admin_name, admin_phone (opt), additional_users. 202 + job_id.
Paid CheckoutPOST /v1/checkoutplan_tier, region, subdomain_slug, subdomain_name, company_name, abbr, success_url, cancel_url. STRIPE_SECRET_KEY, STRIPE_PRICE_ID.
Job statusGET /v1/jobs/:idorigin_url, optional origin_url_with_trace (prego_trace when trace_id set). Clients may send x-trace-id for Zuplo or gateway log correlation.
Provision jobs (operator JSON)GET /internal/provision-jobsBearer INTERNAL_API_KEY; list items include the same origin_url / origin_url_with_trace fields as job status.
Subdomain checkGET /v1/subdomain/check?slug=, optional subdomain_name, use_same_as_slug.
Tenant billing (internal)GET /internal/billing?tenant_id=Bearer INTERNAL_API_KEY. company_name, abbr, admin_email, admin_name, admin_phone, additional_users, stripe_*.
Admin testGET /internal/billing-testHTML shell; load table with Bearer (browser uses cp_internal_key). JSON: GET /internal/billing-test-data (Bearer).

Migrations: 0008_tenant_subdomain_billing.sql, 0009_additional_users.sql, 0010_abbr.sql, 0012_admin_phone.sql, 0013_workflow_dispatch_log.sql.
Flow: www package → admin-web Steps 2–6 (login → payment → tenant info → confirm → provisioning). Plan: www-admin-web-folder-restructure-plan, tenant-onboarding-demo-www-plan §16.

Option B (Queue): Stripe webhook → Control Plane sends to prego-provision-queue → same Worker’s Queue consumer uses D1 workflow_dispatch_log for idempotency then calls workflow_dispatch. Needs wrangler [[queues.producers]] / [[queues.consumers]], PROVISION_QUEUE binding, wrangler queues create prego-provision-queue. Consumer uses GITHUB_TOKEN, GITHUB_WORKFLOW_DISPATCH_URL.

2.1 Stripe test mode

For local/staging Step 3: Control Plane STRIPE_SECRET_KEY (sk_test_…), STRIPE_PRICE_ID (test price); Stripe Dashboard Test mode, test Products/Prices; admin-web NEXT_PUBLIC_PREGO_CONTROL_PLANE_URL; test card 4242 4242 4242 4242. Flow: Step 2 → Step 3 → Pay → Stripe Checkout → test card → success_url → Step 4.


3. Workflow input (workflow_dispatch)

Control Plane: on Stripe Webhook, Option B sends to Queue; consumer calls workflow_dispatch idempotently via workflow_dispatch_log. (Option A: Webhook calls workflow_dispatch directly.) Inputs: job_id, tenant_id, region, target_server_id, create_new_server; subdomain_slug, canonical_hostname (for DNS and callback); callback origin_url = https://{subdomain_slug}.pregoi.com → tenant_runtime.origin_url.


4. Troubleshooting order

  1. “Available” not shown in admin-web → Control Plane GET /v1/subdomain/check, admin-web PREGO_CONTROL_PLANE_URL.
  2. No provisioning after paid payment → Stripe Webhook received?, D1 provider_events, provision_jobs, tenants_master, GITHUB_WORKFLOW_DISPATCH_URL, GITHUB_TOKEN.
  3. No link after provisioning complete → Callback sends origin_url?, GET /v1/jobs/:id origin_url / origin_url_with_trace; trace_id vs x-trace-id for log correlation.
  4. Billing page empty → PREGO_BILLING_PROXY_URL, proxy calls GET /internal/billing (Bearer), tenant_id (localStorage or URL).
  5. additional_usersprovision-tenant-pipeline §3.5. GET /internal/billing?tenant_id= then pass to Ansible.
  6. Provisioning failure → Control Plane GET /internal/onboarding-dashboard, enter job_id or tenant_id, check step status. prego-control-plane-dashboard.
  7. Resource allocation, plan limits, saturationprego-control-plane-dashboard#배포 후 검증 R1–R8. Pre-deploy checklist: tenant-onboard-resource-allocation-flow-plan §10.
  8. Browser blocks cross-origin API (CORS / preflight) → Configure prego-zuplo Portal ALLOWED_ORIGINS and route CORS allowedHeaders (include x-trace-id when clients send it). Not the Prego monorepo docs/runbook/ tree — README (index) · folder · Tenant & trust boundaries.

5. Admin page URLs (Control Plane Worker)

UsePathNotes
Internal consoleGET /internal/consoleHTML. Hub: snapshot, recent jobs (quick-open links), tenants directory, trace. Bearer in page; empty field falls back to sessionStorage cp_internal_key.
Dashboard (metrics)GET /internal/dashboardHTML. Bearer for metrics; cp_internal_key / legacy prego_dashboard_apikey prefill.
Metrics APIGET /internal/metrics/summaryBearer. JSON.
Tenant·billing listGET /internal/billing-test (HTML) / GET /internal/billing-test-data (JSON)Bearer for data. Browser: Load on billing-test uses sessionStorage cp_internal_key.
Single tenant billingGET /internal/billing?tenant_id=Bearer. JSON.
Onboarding step statusGET /internal/onboarding-status?job_id= or ?tenant_id=Bearer. JSON. Step progress/errors; origin_url / origin_url_with_trace, trace_id when resolvable (same as job status). Dashboard HTML links tenant when URLs exist.
Onboarding dashboardGET /internal/onboarding-dashboardHTML. job_id/tenant_id steps; tenant open link when status JSON has origin_url / origin_url_with_trace.
TraceGET /internal/trace/:trace_idBearer.
Email flowGET /internal/email-flow-dashboardHTML.

한국어 {#korean}

테넌트 온보딩 플로우 (www → 프로비저닝 완료)

데모 웹(www)부터 Control Plane·워크플로·Ansible·Zuplo까지 전 구간 연동 시 참고용 요약.

flowchart LR
  subgraph www["www (apps/www)"]
    W1[1 패키지 선택]
  end
  subgraph admin["admin-web (apps/admin-web)"]
    W2[2 로그인] --> W3[3 결제]
    W3 --> W4[4 테넌트 정보]
    W4 --> W5[5 확인]
    W5 --> W6[6 프로비저닝 대기]
  end
  W1 -->|?plan=&region=| admin
  W5 -->|POST /v1/tenants| CP[Control Plane]
  CP -->|202 + job_id| W6
  CP --> WF[workflow_dispatch]
  WF --> P[Pulumi]
  P --> AN[Ansible]
  AN --> ZU[Zuplo Sync]
  ZU --> CB[provision-complete]
  CB --> CP

Ref: tenant-onboarding-demo-www-plan, provision-tenant-pipeline. 제출 후 리소스 할당 단계별 상세(7단계)·케이스별 관리·R1~R8 상세 요건·구현 Phase·Runbook 운영 절차: tenant-onboard-resource-allocation-flow-plan §1·§6·§7·§8.


1. 데모 웹 환경 변수

사이트변수설명
wwwNEXT_PUBLIC_PREGO_ADMIN_BASE_URL패키지 선택 후 리다이렉트 대상. 앱 코드 기본값 https://m.pregoi.com.
admin-webNEXT_PUBLIC_PREGO_CONTROL_PLANE_URLControl Plane Worker URL. 설정 시 createTenantFree, getJobStatus, checkSubdomainAvailable, createCheckoutSession이 실제 API 호출.
admin-webNEXT_PUBLIC_PREGO_AUTH_URLZuplo Auth 베이스(이메일 OTP, Singpass, POST /auth/google/complete-session).
admin-webGOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET서버 전용. 자사 Google OAuth; 리디렉션 URI https://<admin>/api/auth/google/callback 등록. Workers: 선택 Actions 변수 ADMIN_GOOGLE_CLIENT_ID 로 배포 시 일반 변수 반영(deploy-admin-web-worker.yml); 없으면 대시보드·wrangler.
admin-webPREGO_ZUPLO_INTERNAL_API_KEYZuplo INTERNAL_API_KEY와 동일(서버 전용).
admin-webPREGO_JWT_COOKIE_DOMAIN(선택) 세션 쿠키를 AUTH_URL 출처에 보낼 때 예: .pregoi.com. Workers 배포 시 선택 변수 ADMIN_PREGO_JWT_COOKIE_DOMAIN (deploy-admin-web-worker.yml).
admin-webNEXT_PUBLIC_PREGO_BILLING_PROXY_URL결제 정보 조회 프록시 URL. billing에서 ?tenant_id=xxx로 GET 후 JSON 표시.
admin-webNEXT_PUBLIC_PREGO_WWW_BASE_URLStep 2 “Previous”, nav “Choose package” 링크. 앱 코드 기본값 https://www.pregoi.com.

www는 패키지 선택만 담당하고, admin-web이 온보딩 위저드(Step 2~6) 및 tenant admin(dashboard, billing 등)을 담당. 레거시 정적 HTML은 배포 시 window.PREGO_* 주입 가능; Next.js는 빌드 시 NEXT_PUBLIC_* 사용.

1.1 Cloudflare Pages 빌드 (www / admin-web)

두 앱 모두 워크스페이스 패키지(@platform/shell, @platform/theme-context)에 의존한다. Cloudflare Pages에서는 apps/www만 루트로 두고 npm 빌드하면 실패할 수 있으므로, 모노레포 루트(.) 를 프로젝트 루트로 쓴다.

Pages 프로젝트빌드 커맨드출력 / 배포
prego-wwwpnpm install --frozen-lockfile && pnpm --filter prego-www run build정적 apps/www/out (output: 'export').
admin-web (Worker)pnpm install --frozen-lockfile && pnpm --filter prego-admin-web run cf:build정적 out/ 아님. Workers: .open-next/, R2 prego-admin-opennext-cache (Pulumi pulumi up 또는 wrangler r2 bucket create). 배포: cf:deploy, cf:deploy:with-vars, Actions Deploy admin-web(ESLint 후 cf:deploy:with-vars). apps/admin-web/README.md 참고.

GitHub Actions: deploy-pages.yml(Build Pages Apps)는 pnpm run lint:www-admin 후 www build, admin-web cf:build, pnpm run build:storybook 순으로 검증만 수행(Cloudflare 업로드 없음).

로컬: 루트에서 pnpm installpnpm --filter prego-www run dev(3001) 또는 pnpm --filter prego-admin-web run dev(3002). 푸시 전 CI와 맞추려면 pnpm run lint:www-admin. 상세는 apps/www/README.md, apps/admin-web/README.md, www & admin-web 배포, Build Pages Apps, (선택) Deploy admin-web (Cloudflare Worker) 참고.


2. Control Plane 연동 요약

용도메서드/경로비고
무료 테넌트 생성POST /v1/tenantstier, region, subdomain_slug, subdomain_name, company_name(최대 60자), abbr(2~5자 선택), admin_email, admin_name, admin_phone(선택), additional_users. 202 + job_id.
유료 CheckoutPOST /v1/checkoutplan_tier, region, subdomain_slug, subdomain_name, company_name(최대 60자), abbr, success_url, cancel_url. STRIPE_SECRET_KEY·STRIPE_PRICE_ID 필요.
작업 상태GET /v1/jobs/:idorigin_url, trace_id가 있으면 origin_url_with_trace(prego_trace). 클라이언트는 Zuplo·게이트웨이 로그와 맞추기 위해 x-trace-id 전송 가능.
프로비저닝 작업 목록(운영자 JSON)GET /internal/provision-jobsBearer INTERNAL_API_KEY; 항목마다 작업 상태 API와 동일한 origin_url / origin_url_with_trace.
서브도메인 중복GET /v1/subdomain/check?slug=, optional subdomain_name, use_same_as_slug.
테넌트 결제(내부)GET /internal/billing?tenant_id=Bearer INTERNAL_API_KEY. company_name, abbr, admin_email, admin_name, admin_phone, additional_users, stripe_* 등.
관리자 테스트GET /internal/billing-testHTML 껍데기; 표는 Bearer로 GET /internal/billing-test-data (브라우저는 cp_internal_key).

마이그레이션: 0008_tenant_subdomain_billing.sql, 0009_additional_users.sql, 0010_abbr.sql, 0012_admin_phone.sql, 0013_workflow_dispatch_log.sql 적용 필요.
온보딩 플로우: www에서 패키지 선택 → admin-web Step 2~6 (로그인 → 결제 → 테넌트 정보(서브도메인·회사명·관리자·팀원) → 확인 → 프로비저닝). 기획: www-admin-web-folder-restructure-plan, tenant-onboarding-demo-www-plan §16.

Option B (Queue): Stripe webhook → Control Plane가 prego-provision-queue로 메시지 전송 → 동일 Worker의 Queue consumer가 D1 workflow_dispatch_log로 중복 방지 후 workflow_dispatch 호출.
필요: wrangler에 [[queues.producers]] / [[queues.consumers]] (queue = prego-provision-queue), PROVISION_QUEUE 바인딩, Queue 생성(wrangler queues create prego-provision-queue 등). Consumer는 GITHUB_TOKEN, GITHUB_WORKFLOW_DISPATCH_URL 사용.

2.1 Stripe 테스트 모드 연동

Step 3 결제 플로우를 로컬/스테이징에서 검증하려면 Stripe 테스트 모드를 사용한다.

항목설정
Control Planewrangler secret put STRIPE_SECRET_KEY (sk_test_…), STRIPE_PRICE_ID (price_xxx 테스트)
Stripe DashboardTest mode 활성화 → Products → Prices에서 테스트 가격 생성
admin-webNEXT_PUBLIC_PREGO_CONTROL_PLANE_URL = Control Plane Worker URL
테스트 카드4242 4242 4242 4242 (기타: Stripe Testing)

플로우: Step 2 → Step 3 → Pay 클릭 → Stripe Checkout → 테스트 카드 결제 → success_url 리다이렉트 → Step 4.


3. 워크플로 입력(workflow_dispatch)

Control Plane: Stripe Webhook 수신 시 Option B면 Queue에 메시지 전송; Queue consumer가 workflow_dispatch_log로 idempotent하게 GitHub Actions workflow_dispatch 호출. (Option A는 Webhook에서 직접 workflow_dispatch 호출.) 전달되는 입력:

  • job_id, tenant_id, region, target_server_id, create_new_server
  • subdomain_slug, canonical_hostname (전달 시 DNS·콜백에서 사용)
  • 콜백 시 origin_url = https://{subdomain_slug}.pregoi.com 전달 시 tenant_runtime.origin_url 저장.

4. 장애 시 확인 순서

  1. admin-web에서 “사용 가능” 안 나옴 → Control Plane GET /v1/subdomain/check, admin-web의 PREGO_CONTROL_PLANE_URL 설정 확인.
  2. 유료 결제 후 프로비저닝 안 됨 → Stripe Webhook 수신 여부, Control Plane D1 provider_events·provision_jobs·tenants_master, GITHUB_WORKFLOW_DISPATCH_URL·GITHUB_TOKEN.
  3. 프로비저닝 완료 후 링크 안 나옴 → 워크플로 콜백의 origin_url, GET /v1/jobs/:id의 origin_url / origin_url_with_trace; trace_id와 x-trace-id 로그 상관관계 확인.
  4. 결제 정보 페이지 빈 화면 → PREGO_BILLING_PROXY_URL, 프록시가 GET /internal/billing (Bearer) 호출하는지, tenant_id(localStorage 또는 URL).
  5. 팀원(additional_users) 활용provision-tenant-pipeline §3.5 참고. GET /internal/billing?tenant_id= 로 조회 후 Ansible 등에 전달.
  6. 프로비저닝 실패·단계별 확인 → Control Plane GET /internal/onboarding-dashboard 에서 job_id 또는 tenant_id 입력 후, 단계별(done/pending/failed) 진행 확인. prego-control-plane-dashboard 참고.
  7. 리소스 할당·플랜 한도·포화 검증 → 배포 후 R1–R8 동작 확인은 prego-control-plane-dashboard#배포 후 검증 R1–R8 참고. 구현·배포 전 체크리스트는 tenant-onboard-resource-allocation-flow-plan §10 참고.
  8. 브라우저에서 교차 출처 API 차단(CORS·프리플라이트)prego-zuplo Portal ALLOWED_ORIGINS·라우트 CORS allowedHeaders 설정(x-trace-id 전송 시 목록에 포함). Prego monorepo docs/runbook/(인프라)과 다름 — README (색인) · 폴더 · 테넌트 신뢰 경계.

5. 관리자 페이지 URL (Control Plane Worker 기준)

테넌트·온보딩·결제 확인용 내부 URL. 실제 Worker 도메인은 배포 환경에 따라 다름.

용도경로비고
내부 콘솔GET /internal/consoleHTML. 허브: 스냅샷·최근 잡(빠른 열기)·테넌트·trace. Bearer 입력; 비어 있으면 sessionStorage cp_internal_key 로 요청.
대시보드 (메트릭)GET /internal/dashboardHTML. Bearer로 메트릭 로드; cp_internal_key·레거시 prego_dashboard_apikey 프리필.
메트릭 APIGET /internal/metrics/summaryBearer. JSON.
테넌트·결제 목록GET /internal/billing-test (HTML) / GET /internal/billing-test-data (JSON)데이터는 Bearer. 브라우저: billing-test에서 불러오기 시 sessionStorage cp_internal_key.
단일 테넌트 결제GET /internal/billing?tenant_id=Bearer. JSON.
온보딩 단계별 상태GET /internal/onboarding-status?job_id= 또는 ?tenant_id=Bearer. JSON. 단계별 진행/에러; origin_url / origin_url_with_trace, trace_id(조회 가능 시). 대시보드 HTML에서 링크 제공.
온보딩 단계별 대시보드GET /internal/onboarding-dashboardHTML. 단계 시각화; 상태 JSON에 URL 있으면 테넌트 열기 링크.
트레이스GET /internal/trace/:trace_idBearer.
이메일 플로우 검증GET /internal/email-flow-dashboardHTML.
Help