목적 : 클라이언트가 **www.pregoi.com**에 접속해 Gmail SSO 또는 이메일로 가입하고, 패키지(무료/유료)를 선택·결제한 뒤 리소스가 할당되기까지의 구체적인 로직 , 초기 인프라 설정 자동화 를 단계별로 정리한다.
코드 생성 없음 — 플로우·요건·현재 구현 상태만 기술.
참조 : tenant-provisioning-flow.md , provision-tenant-workflow-design.md , api-control-plane-implementation-plan.md , prego-saas-app-implementation-plan.md .
1. 개요
항목 내용 진입 URL https://www.pregoi.com (마케팅·가입·패키지 선택·결제 포털)가입 방식 Gmail SSO 또는 이메일 계정 생성 패키지 무료(Free), 유료(Basic / Professional / Enterprise 등) 결제 유료 선택 시 Stripe Checkout 또는 Subscription 리소스 할당 Control Plane이 큐(provision_jobs) 적재 → 배치 결정 → Pulumi/Ansible/Zuplo 순차 실행 초기 인프라 Hetzner 서버(필요 시), Docker·Frappe·테넌트 사이트, API Key, Zuplo·KV·DNS
2. 전체 플로우 요약
[2] 회원가입 (Gmail SSO 또는 이메일)
[6] 초기 인프라 자동화 (Pulumi → Ansible → Zuplo → 콜백)
3. 단계별 플로우 및 현재 구현 상태
목표
사용자가 **www.pregoi.com**에 접속했을 때 랜딩/마케팅 페이지 또는 로그인·가입 진입점을 제공한다.
(선택) 테넌트 서비스 접속은 {subdomain}.pregoi.com (예: acme.pregoi.com)으로 구분한다. 랜딩·가입은 www 또는 app.pregoi.com 등으로 분리할 수 있다.
구체적 로직
순서 동작 비고 1 DNS: www.pregoi.com → Cloudflare Proxy 또는 정적 호스팅/SPA Pages, Workers, 또는 외부 호스팅 2 HTTPS 제공 (Edge SSL 또는 Origin 인증서) Cloudflare 기본 3 랜딩: 제품 소개, 가격(무료/유료), CTA(시작하기·가입) 프론트엔드 구현 4 ”시작하기” 클릭 시 → 로그인/가입 선택 (Gmail SSO 또는 이메일) 2단계로 진입
현재 구현 상태
항목 상태 비고 www.pregoi.com 도메인·DNS기획/설정 의존 pregoi.com·테넌트 서브도메인(subdomain.pregoi.com) 설계는 tenant-subdomain-dns-design.md 에 있음. www 전용 랜딩은 별도 문서화·구현 여부 불명. 랜딩·마케팅 페이지 미구현 client-web 또는 마케팅 사이트는 기획서에서 “웹에서 가입”으로만 언급. 코드베이스에 별도 client-web 레포/경로 미확인. 테넌트 접속 URL 설계 완료 사용자용 {subdomain_slug}.pregoi.com CNAME → 내부 canonical tenant-{short_id}.pregoi.com.
3.2 2단계: 회원가입 (Gmail SSO 또는 이메일)
목표
Gmail SSO : Google OAuth 2.0으로 로그인/가입 한 번에 처리.
이메일 계정 : 이메일·비밀번호로 계정 생성, (선택) 이메일 검증 링크.
구체적 로직
순서 동작 비고 1 ”Google로 시작하기” 선택 시 → Google OAuth consent 화면 → redirect_uri로 복귀 client_id, client_secret, redirect_uri 설정 필요 2 OAuth 성공 시 백엔드에서 사용자 식별자(Google sub 또는 email) 저장. 신규면 “회원” 생성, 기존이면 로그인 처리 사용자 DB/테이블 설계 필요 3 ”이메일로 가입” 선택 시 → 이메일·비밀번호 입력 → 유효성 검사 → 계정 생성 이메일 중복 검사, 비밀번호 정책 4 (선택) 이메일 인증: 가입 후 검증 링크 발송, 클릭 시 계정 활성화 발송 서비스(SendGrid 등) 연동 5 가입 완료 후 → “패키지 선택” 화면으로 이동(또는 대시보드) 세션·JWT 등 인증 유지
현재 구현 상태
항목 상태 비고 Gmail SSO 미구현 기획서·Control Plane·prego-saas-app에 OAuth/Google 로그인 구현 없음. 랜딩·가입 담당 클라이언트 앱(client-web)이 별도일 경우 해당 앱에서 구현 대상. 이메일 가입 미구현 동일. Frappe 쪽은 테넌트 사이트별 User/Administrator가 있으며, 포털(www) 사용자 와 테넌트 사용자는 레이어가 다를 수 있음(포털 = 계정·결제·테넌트 목록, 테넌트 = ERPNext 사용). 사용자·계정 저장소 기획 수준 Control Plane D1에는 tenants_master, billing_customers, provision_jobs 등이 있으나 포털 사용자(이메일·Google id) 저장 스키마는 명시되지 않음. 별도 B2C User DB 또는 Auth0/Clerk 등 IdP 연동 시 정의 필요.
3.3 3단계: 패키지 선택 (무료 / 유료)
목표
사용자가 무료(Free) 또는 유료(Basic / Professional / Enterprise) 패키지 중 하나를 선택한다.
선택 결과는 다음 단계(결제 또는 바로 프로비저닝)로 전달된다.
구체적 로직
순서 동작 비고 1 화면에 플랜 목록 표시: Free, Basic, Professional, Enterprise 등. 가격·기능·리전(Enterprise 시 us/eu 등) 안내 플랜 메타는 Control Plane PLAN_TIERS 또는 별도 설정에서 관리 2 사용자가 플랜 선택 후 “다음” 또는 “결제하기” 클릭 Free 선택 시 결제 단계 스킵 가능 3 (유료) 결제 단계로 이동; (무료) 즉시 테넌트 생성 요청으로 진행 가능 4단계와 연동 4 선택값 정리: plan_tier, requested_region(선택), tenant_name(회사/서브도메인 slug) Stripe Checkout metadata 및 Control Plane API body와 동일 필드로 매핑
현재 구현 상태
항목 상태 비고 플랜 정의 부분 구현 prego-control-plane: PLAN_TIERS env, tenants.ts에서 basic | professional | enterprise 검증. 무료(Free) tier는 코드에 명시적 없을 수 있음. 패키지 선택 UI 미구현 www/client-web 쪽 화면. 기획서에는 “패키지(플랜) 선택” 단계만 기술. plan_tier·region 전달 구현됨 Stripe metadata(plan_tier, requested_region) 및 POST /v1/tenants body(tier, region)로 전달 구조 있음.
3.4 4단계: 결제
목표
유료 패키지 선택 시 Stripe Checkout 또는 Stripe Customer + Subscription으로 결제를 완료한다.
무료 선택 시 결제 없이 테넌트 생성 요청만 수행한다.
구체적 로직
순서 동작 비고 1 유료 선택 시: 백엔드 또는 클라이언트에서 Stripe Checkout Session 생성. metadata에 tenant_id(선택), plan_tier, requested_region 포함 Stripe API 호출 주체는 포털 백엔드 또는 Control Plane 연동 API 2 사용자를 Stripe Checkout 페이지로 리다이렉트 → 결제 완료 후 success_url으로 복귀 success_url/cancel_url 설정 3 결제 완료 시 Stripe가 Webhook 발송: checkout.session.completed (및 구독 시 customer.subscription.created 등) Control Plane이 수신 4 무료 선택 시: Stripe 없이 Control Plane POST /v1/tenants 직접 호출. body: tenant_name, tier=free(또는 basic), region 202 + job_id 반환 후 5단계로 진행
현재 구현 상태
항목 상태 비고 Stripe Webhook 수신 구현됨 prego-control-plane: POST /webhooks/stripe. 서명 검증(STRIPE_WEBHOOK_SECRET), 멱등(provider_events), checkout.session.completed 처리. Webhook 후처리 구현됨 D1: provider_events 삽입, tenants_master(Pending), provision_jobs(Pending), billing_customers, subscriptions. metadata에서 plan_tier, requested_region 파싱. workflow_dispatch 트리거 구현됨 GITHUB_WORKFLOW_DISPATCH_URL + GITHUB_TOKEN 설정 시 Stripe Webhook 처리 후 GitHub Actions workflow_dispatch 호출(job_id, tenant_id, region, create_new_server, target_server_id). 무료 플로우(Stripe 없이) 부분 구현 POST /v1/tenants로 직접 job 적재 가능. “Free” tier가 PLAN_TIERS에 포함되어 있으면 동일 경로로 처리 가능. Checkout Session 생성 UI/API 미구현(포털) prego-saas-app 기획서에 create_checkout_session(plan, tenant_name) API 명세 있음(Phase 6). 실제 Stripe Session 생성은 포털 백엔드 또는 별도 Billing API에서 구현 대상.
3.5 5단계: 리소스 할당 로직 (배치·큐)
목표
결제 완료(또는 무료 신청) 직후 어디에 테넌트를 올릴지 결정하고, 프로비저닝 작업을 큐에 넣는다.
리소스 = 서버(노드) + DB·Frappe 사이트 + API Key·라우팅 등. “할당”은 “기존 서버에 배치” 또는 “신규 서버 생성” 결정까지 포함.
구체적 로직
순서 동작 비고 1 큐 적재 : D1 provision_jobs에 1행 삽입. status=Pending, tenant_id, job_id, trace_id, region, plan_tier, infra_mode(create_new_server | use_existing)Stripe Webhook 또는 POST /v1/tenants에서 수행 2 배치 결정(Placement) : 기존 서버에 넣을지, 신규 서버를 만들지 결정. 입력: tenant_id, plan_tier, requested_region. 출력: target_server_id(기존 노드) 또는 create_new_server=trueCPU/메모리/테넌트 수 등 server_metrics 기반 규칙 또는 AI 엔진 3 region 결정 : resolveRegion(plan_tier, requested_region) → sg | us | eu. Enterprise는 requested_region 존중webhooks-stripe.ts에 resolveRegion 있음 4 트리거 : workflow_dispatch(또는 Provision Worker) 호출 시 입력으로 job_id, tenant_id, region, target_server_id, create_new_server 전달다음 단계(6) 실행 주체가 사용
현재 구현 상태
항목 상태 비고 provision_jobs 큐 구현됨 D1 테이블, Stripe Webhook 및 POST /v1/tenants에서 삽입. decidePlacement 구현됨 prego-control-plane placement.js: D1·server_metrics(또는 nodes) 조회, create_new_server 또는 target_server_id 반환. workflow_dispatch 입력 구현됨 Stripe Webhook 처리 후 GitHub API로 job_id, tenant_id, region, create_new_server, target_server_id 전달. Idempotency 구현됨 POST /v1/tenants 시 Idempotency-Key 헤더로 24시간 내 중복 요청 시 기존 job_id 반환. Free tier 배치 동일 로직 무료도 동일 placement·큐 적재. plan_limits 등은 plan_tier에 따라 6단계 Ansible에서 적용.
3.6 6단계: 초기 인프라 설정 자동화
목표
큐에 넣어진 한 건의 프로비저닝 job 에 대해, Pulumi(필요 시) → Ansible → Zuplo Sync → Control Plane 콜백 까지 사람 개입 없이 실행한다.
초기 인프라 = 서버(VM), Docker·Frappe·테넌트 사이트, API Key, 게이트웨이·라우팅·DNS·상태 갱신.
구체적 로직
순서 담당 동작 6.1 실행 주체 job 입력 확보: workflow_dispatch inputs 또는 D1에서 Pending job 1건 조회. 6.2 Pulumi(조건부) target_server_id 없고 create_new_server 시: region 스택 선택 → pulumi up → server_ip 획득. 있으면 D1 nodes에서 해당 서버 host 조회. 6.3 Ansible server_ip, tenant_id, plan_tier·plan_limits 전달. Docker 설치, Frappe bench, bench new-site, API Key 발급. 결과: api_key 파일/변수. 6.4 Cloudflare DNS 테넌트 canonical tenant-{short_id}.pregoi.com 및 사용자 URL {subdomain_slug}.pregoi.com CNAME 등록. 6.5 Zuplo Sync tenant_id, api_key로 Zuplo Consumer·API Key 등록. 6.6 Control Plane 콜백 POST /internal/provision-complete. D1: provision_jobs.status=Completed, tenants_master.status=Active, tenant_runtime 갱신. TENANT_ORIGINS(KV) 갱신.
현재 구현 상태
항목 상태 비고 provision-complete 콜백 구현됨 prego-control-plane: POST /internal/provision-complete. Bearer INTERNAL_API_KEY. D1 갱신, TENANT_ORIGINS KV 쓰기. Pulumi 구현됨 prego-pulumi 레포, 스택(sg/us/eu), Hetzner 서버·방화벽·Cloudflare DNS(node-01.pregoi.com 등). workflow에서 호출 시 동작. Ansible 구현됨 prego-ansible: Docker, Frappe, bench new-site, API Key. plan_tier·plan_limits 전달은 기획 반영 중(resource-optimization-safe-adoption-plan). Zuplo Sync 구현됨 infra/zuplo_sync.ts 또는 동등. tenant_id, api_key 등록. provision-tenant 워크플로 기획/부분 provision-tenant-workflow-design.md에 상세. 실제 .github/workflows/provision-tenant.yml 존재 여부·연동은 레포별 확인 필요. 테넌트 DNS 자동 등록 기획 tenant-provisioning-flow §5.1: 프로비저닝 단계에서 Cloudflare API로 canonical·CNAME. 구현은 워크플로 또는 Worker에서 수행.
3.7 7단계: 테넌트 활성화 및 사용자 안내
목표
프로비저닝이 완료되면 사용자에게 테넌트 접속 URL (예: acme.pregoi.com) 및 (선택) 초대 메일·비밀번호 설정 링크를 안내한다.
구체적 로직
순서 동작 비고 1 provision-complete 수신 시 tenant_runtime에 site_name, host, 사용자 URL 저장 D1·KV에 이미 반영됨 2 (선택) 웹훅 또는 이메일: “테넌트가 준비되었습니다. 접속 URL: https://{subdomain_slug}.pregoi.com” 기획서에 선택 구현으로 명시 3 포털(www) 대시보드에서 “내 테넌트” 목록·상태(job_id로 GET /v1/jobs/:id) 표시. Completed 시 “열기” 링크 제공 client-web 구현 대상
현재 구현 상태
항목 상태 비고 job 상태 조회 구현됨 GET /v1/jobs/:id. job_id, tenant_id, status 등 반환. 완료 시 알림(이메일/웹훅) 미구현 api-control-plane-implementation-plan §2 ⑤ 선택 구현. 포털 “내 테넌트” UI 미구현 client-web·www 전제.
4. 단계별 구현 상태 요약표
단계 내용 구현 상태 1 www.pregoi.com 접속·랜딩미구현(www/랜딩 페이지) 2 Gmail SSO·이메일 가입 미구현 3 패키지 선택(무료/유료) 플랜 정의·API 연동 부분 구현, UI 미구현 4 결제(Stripe·무료) Stripe Webhook·큐 적재·workflow_dispatch 구현됨; Checkout 생성·무료 UI 미구현 5 리소스 할당(배치·큐) 구현됨(placement, provision_jobs, Idempotency) 6 초기 인프라 자동화 Pulumi·Ansible·Zuplo·provision-complete 구현됨; provision-tenant 워크플로·DNS 자동 등록은 기획/부분 7 테넌트 활성화·안내 GET /v1/jobs/:id 구현됨; 알림·포털 UI 미구현
5. 의존성 및 권장 구현 순서
www.pregoi.com 랜딩·도메인 : 랜딩 페이지 또는 SPA 배포, DNS 설정.
가입·인증 : Gmail SSO + 이메일 가입, 사용자 저장소(또는 IdP) 결정 후 구현.
패키지 선택 UI : 플랜 목록·가격 노출, 선택 시 tier·region·tenant_name 수집.
결제 연동 : 유료 시 Stripe Checkout Session 생성 API·success/cancel 리다이렉트; 무료 시 POST /v1/tenants 호출.
프로비저닝 파이프라인 : provision-tenant 워크플로 또는 Provision Worker가 6단계 전 구간 실행·DNS·알림까지 연결.
사용자 안내 : job 상태 폴링·완료 시 이메일/대시보드 “내 테넌트” 링크.
6. 참조 문서