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
| Site | Variable | Description |
|---|---|---|
| www | NEXT_PUBLIC_PREGO_ADMIN_BASE_URL | Redirect after package selection. Default https://m.pregoi.com in app code. |
| admin-web | NEXT_PUBLIC_PREGO_CONTROL_PLANE_URL | Zuplo (public gateway) base. Tenant APIs and trial handoff (/internal/* on this host) use this URL. |
| admin-web | NEXT_PUBLIC_PREGO_AUTH_URL | Zuplo Auth base (email OTP, Singpass, POST /auth/google/complete-session). |
| admin-web | GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | Server-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-web | PREGO_ZUPLO_INTERNAL_API_KEY | Same as Zuplo INTERNAL_API_KEY (server-only). |
| admin-web | PREGO_CONTROL_PLANE_INTERNAL_API_KEY | Same 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-web | PREGO_JWT_COOKIE_DOMAIN | Optional (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-web | NEXT_PUBLIC_PREGO_BILLING_PROXY_URL | Billing proxy URL. billing page GET with ?tenant_id=xxx, display JSON. |
| admin-web | NEXT_PUBLIC_PREGO_WWW_BASE_URL | Step 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 project | Build command | Build output / deploy |
|---|---|---|
| prego-www | pnpm install --frozen-lockfile && pnpm --filter prego-www run build | Static: apps/www/out (output: 'export'). |
| admin-web (Worker) | pnpm install --frozen-lockfile && pnpm --filter prego-admin-web run cf:build | Not 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
| Use | Method/Path | Notes |
|---|---|---|
| Free tenant create | POST /v1/tenants | tier, 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 Checkout | POST /v1/checkout | plan_tier, region, subdomain_slug, subdomain_name, company_name, abbr, success_url, cancel_url. STRIPE_SECRET_KEY, STRIPE_PRICE_ID. |
| Job status | GET /v1/jobs/:id | origin_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-jobs | Bearer INTERNAL_API_KEY; list items include the same origin_url / origin_url_with_trace fields as job status. |
| Subdomain check | GET /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 test | GET /internal/billing-test | HTML 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
- “Available” not shown in admin-web → Control Plane GET /v1/subdomain/check, admin-web PREGO_CONTROL_PLANE_URL.
- No provisioning after paid payment → Stripe Webhook received?, D1 provider_events, provision_jobs, tenants_master, GITHUB_WORKFLOW_DISPATCH_URL, GITHUB_TOKEN.
- 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.
- Billing page empty → PREGO_BILLING_PROXY_URL, proxy calls GET /internal/billing (Bearer), tenant_id (localStorage or URL).
- additional_users → provision-tenant-pipeline §3.5. GET /internal/billing?tenant_id= then pass to Ansible.
- Provisioning failure → Control Plane GET /internal/onboarding-dashboard, enter job_id or tenant_id, check step status. prego-control-plane-dashboard.
- Resource allocation, plan limits, saturation → prego-control-plane-dashboard#배포 후 검증 R1–R8. Pre-deploy checklist: tenant-onboard-resource-allocation-flow-plan §10.
- Browser blocks cross-origin API (CORS / preflight) → Configure prego-zuplo Portal
ALLOWED_ORIGINSand route CORSallowedHeaders(includex-trace-idwhen clients send it). Not the Prego monorepodocs/runbook/tree — README (index) · folder · Tenant & trust boundaries.
5. Admin page URLs (Control Plane Worker)
| Use | Path | Notes |
|---|---|---|
| Internal console | GET /internal/console | HTML. 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/dashboard | HTML. Bearer for metrics; cp_internal_key / legacy prego_dashboard_apikey prefill. |
| Metrics API | GET /internal/metrics/summary | Bearer. JSON. |
| Tenant·billing list | GET /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 billing | GET /internal/billing?tenant_id= | Bearer. JSON. |
| Onboarding step status | GET /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 dashboard | GET /internal/onboarding-dashboard | HTML. job_id/tenant_id steps; tenant open link when status JSON has origin_url / origin_url_with_trace. |
| Trace | GET /internal/trace/:trace_id | Bearer. |
| Email flow | GET /internal/email-flow-dashboard | HTML. |
한국어 {#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=®ion=| 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. 데모 웹 환경 변수
| 사이트 | 변수 | 설명 |
|---|---|---|
| www | NEXT_PUBLIC_PREGO_ADMIN_BASE_URL | 패키지 선택 후 리다이렉트 대상. 앱 코드 기본값 https://m.pregoi.com. |
| admin-web | NEXT_PUBLIC_PREGO_CONTROL_PLANE_URL | Control Plane Worker URL. 설정 시 createTenantFree, getJobStatus, checkSubdomainAvailable, createCheckoutSession이 실제 API 호출. |
| admin-web | NEXT_PUBLIC_PREGO_AUTH_URL | Zuplo Auth 베이스(이메일 OTP, Singpass, POST /auth/google/complete-session). |
| admin-web | GOOGLE_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-web | PREGO_ZUPLO_INTERNAL_API_KEY | Zuplo INTERNAL_API_KEY와 동일(서버 전용). |
| admin-web | PREGO_JWT_COOKIE_DOMAIN | (선택) 세션 쿠키를 AUTH_URL 출처에 보낼 때 예: .pregoi.com. Workers 배포 시 선택 변수 ADMIN_PREGO_JWT_COOKIE_DOMAIN (deploy-admin-web-worker.yml). |
| admin-web | NEXT_PUBLIC_PREGO_BILLING_PROXY_URL | 결제 정보 조회 프록시 URL. billing에서 ?tenant_id=xxx로 GET 후 JSON 표시. |
| admin-web | NEXT_PUBLIC_PREGO_WWW_BASE_URL | Step 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-www | pnpm 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 install 후 pnpm --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/tenants | tier, region, subdomain_slug, subdomain_name, company_name(최대 60자), abbr(2~5자 선택), admin_email, admin_name, admin_phone(선택), additional_users. 202 + job_id. |
| 유료 Checkout | POST /v1/checkout | plan_tier, region, subdomain_slug, subdomain_name, company_name(최대 60자), abbr, success_url, cancel_url. STRIPE_SECRET_KEY·STRIPE_PRICE_ID 필요. |
| 작업 상태 | GET /v1/jobs/:id | origin_url, trace_id가 있으면 origin_url_with_trace(prego_trace). 클라이언트는 Zuplo·게이트웨이 로그와 맞추기 위해 x-trace-id 전송 가능. |
| 프로비저닝 작업 목록(운영자 JSON) | GET /internal/provision-jobs | Bearer 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-test | HTML 껍데기; 표는 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 Plane | wrangler secret put STRIPE_SECRET_KEY (sk_test_…), STRIPE_PRICE_ID (price_xxx 테스트) |
| Stripe Dashboard | Test mode 활성화 → Products → Prices에서 테스트 가격 생성 |
| admin-web | NEXT_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. 장애 시 확인 순서
- admin-web에서 “사용 가능” 안 나옴 → Control Plane GET /v1/subdomain/check, admin-web의 PREGO_CONTROL_PLANE_URL 설정 확인.
- 유료 결제 후 프로비저닝 안 됨 → Stripe Webhook 수신 여부, Control Plane D1 provider_events·provision_jobs·tenants_master, GITHUB_WORKFLOW_DISPATCH_URL·GITHUB_TOKEN.
- 프로비저닝 완료 후 링크 안 나옴 → 워크플로 콜백의 origin_url, GET /v1/jobs/:id의 origin_url / origin_url_with_trace; trace_id와 x-trace-id 로그 상관관계 확인.
- 결제 정보 페이지 빈 화면 → PREGO_BILLING_PROXY_URL, 프록시가 GET /internal/billing (Bearer) 호출하는지, tenant_id(localStorage 또는 URL).
- 팀원(additional_users) 활용 → provision-tenant-pipeline §3.5 참고. GET /internal/billing?tenant_id= 로 조회 후 Ansible 등에 전달.
- 프로비저닝 실패·단계별 확인 → Control Plane GET /internal/onboarding-dashboard 에서 job_id 또는 tenant_id 입력 후, 단계별(done/pending/failed) 진행 확인. prego-control-plane-dashboard 참고.
- 리소스 할당·플랜 한도·포화 검증 → 배포 후 R1–R8 동작 확인은 prego-control-plane-dashboard#배포 후 검증 R1–R8 참고. 구현·배포 전 체크리스트는 tenant-onboard-resource-allocation-flow-plan §10 참고.
- 브라우저에서 교차 출처 API 차단(CORS·프리플라이트) → prego-zuplo Portal
ALLOWED_ORIGINS·라우트 CORSallowedHeaders설정(x-trace-id 전송 시 목록에 포함). Prego monorepodocs/runbook/(인프라)과 다름 — README (색인) · 폴더 · 테넌트 신뢰 경계.
5. 관리자 페이지 URL (Control Plane Worker 기준)
테넌트·온보딩·결제 확인용 내부 URL. 실제 Worker 도메인은 배포 환경에 따라 다름.
| 용도 | 경로 | 비고 |
|---|---|---|
| 내부 콘솔 | GET /internal/console | HTML. 허브: 스냅샷·최근 잡(빠른 열기)·테넌트·trace. Bearer 입력; 비어 있으면 sessionStorage cp_internal_key 로 요청. |
| 대시보드 (메트릭) | GET /internal/dashboard | HTML. Bearer로 메트릭 로드; cp_internal_key·레거시 prego_dashboard_apikey 프리필. |
| 메트릭 API | GET /internal/metrics/summary | Bearer. 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-dashboard | HTML. 단계 시각화; 상태 JSON에 URL 있으면 테넌트 열기 링크. |
| 트레이스 | GET /internal/trace/:trace_id | Bearer. |
| 이메일 플로우 검증 | GET /internal/email-flow-dashboard | HTML. |