Skip to content

English {#english}

Tenant Onboarding Process and Demo Web (www) — Plan

Purpose: Document Prego’s tenant_id and tenant_slug model (Frappe multi-tenant), document the tenant onboarding flow from existing plans and current code, and define scope and requirements for a test demo user site (package choice → Sign-in → Stripe → Ansible/Pulumi/Zuplo).
No code generation — flow, planning, and requirements only.

References: tenant-provisioning-flow.md, provision-tenant-workflow-design.md, www-pregoi-com-signup-to-provisioning-flow.md, tenant-subdomain-dns-design.md, api-control-plane-implementation-plan.md Appendix C.


1. Prego Multi-Tenant Model Summary

ItemContent
ModelFrappe multi-tenant: Site = 1 Tenant, DB per site.
tenant_idInternal customer ID. Control Plane D1 tenants_master.tenant_id PK. UUID recommended; short_id = first 8 chars for tenant-{short_id}.pregoi.com.
tenant_slugUser-facing slug; same as subdomain_slug. 1:1 with {subdomain_slug}.pregoi.com.
Ownershiptenant_id, tenant_slug, canonical_hostname in Control Plane D1; after provisioning, Zuplo gets tenant_id, slug, subdomain.

2. Onboarding Flow Summary

Sequence: Demo www package (free/paid) → Sign-in → (paid) Stripe Checkout or (free) POST /v1/tenants → Webhook/API → Control Plane (tenant_id, D1 Pending, provision_jobs) → decidePlacement → workflow_dispatch → Pulumi → Ansible (Frappe site, API Key) → Cloudflare DNS (canonical + user CNAME) → Zuplo Sync → provision-complete → D1·KV updated, tenant Active.

Identifiers: tenant_id (UUID), short_id (first 8), canonical_hostname tenant-{short_id}.pregoi.com, subdomain_slug user subdomain {subdomain_slug}.pregoi.com. Slug and subdomain rules (§2.4): reserved names (www, app, api, …), length 3–63, blocklist, D1 UNIQUE, validation API.


3. Demo Web (apps/www) Requirements

  • Location: Prego/apps/www. Package selection, Sign-in, Stripe, (optional) job status. Deploy: Cloudflare Pages or static.
  • Packages: Free → POST /v1/tenants (subdomain_slug, tier=free). Paid → Stripe Checkout with metadata (plan_tier, requested_region, subdomain_slug).
  • Sign-in: After sign-in, create Checkout Session (paid) or call POST /v1/tenants (free). success_url/cancel_url to demo www.
  • User vs system subdomain: User = {subdomain_slug}.pregoi.com (CNAME to canonical). System = tenant-{short_id}.pregoi.com.
  • UI/Backend split (§3.5): Demo UI in separate layer; API/client layer for Control Plane, Stripe, validation; same flow reusable for production UI.

§§4–17 (Ansible multi-tenant input/output, Pulumi vs pipeline DNS, API Key, Zuplo metadata, D1 schema gaps, flow diagram, §10 implementation checklist, §11 Frappe required fields post-payment, §12 user registration/additional_users, §13 wizard steps 1–7, §14 App/DB/Redis separation and placement, §15 billing D1/KV and user/admin UI, §16 consolidated changes: 6 steps, Step 4 fields/limits, Step 6 admin URL, §17 references) — full tables, step-by-step mapping, and checklist are in the Korean section below.


한국어 {#korean}

테넌트 온보딩 프로세스 및 데모 웹(www) 기획서

목적: Frappe 멀티테넌트 모델 기반 Prego의 tenant_id·tenant_slug 관리 체계를 정리하고, 테넌트 온보딩 플로우를 기존 기획·현행 코드 분석에 따라 문서화한다. 이어서 테스트용 데모 사용자 웹사이트(패키지 선택 → Sign-in → Stripe 결제 → Ansible/Pulumi/Zuplo 연동) 구현 범위와 요건을 정의한다.
코드 생성 없음 — 플로우 정리·기획·요건만 포함.

참조: tenant-provisioning-flow.md, provision-tenant-workflow-design.md, www-pregoi-com-signup-to-provisioning-flow.md, tenant-subdomain-dns-design.md, api-control-plane-implementation-plan.md Appendix C.


1. Prego 멀티테넌트 모델 요약

항목내용
모델Frappe 멀티테넌트: Site 단위 DB 격리, 1 Site = 1 Tenant.
tenant_id내부 고객사 식별자. Control Plane D1 tenants_master.tenant_id PK. 현재 Stripe Webhook에서 미전달 시 tenant_${Date.now()}_${random} 생성(32자 절단). 권장: UUID로 통일 시 canonical tenant-{short_id}.pregoi.com에서 short_id = UUID 앞 8자로 일관 적용 가능.
tenant_slug사용자/노출용 슬러그. 기획서에서는 subdomain_slug와 동일 개념으로 사용 가능. {subdomain_slug}.pregoi.com 형태의 사용자 지정 서브도메인과 1:1.
관리 주체tenant_id·tenant_slug(subdomain_slug)·canonical_hostname은 Control Plane D1에 저장; 프로비저닝 완료 후 Zuplo에는 tenant_id, slug, subdomain(또는 origin) 정리하여 등록.

2. 현재 Prego 코드 기준 Tenant 온보딩 플로우 정리

기존 기획서(tenant-provisioning-flow, www-pregoi-com-signup-to-provisioning-flow, provision-tenant-workflow-design)와 현행 코드를 기준으로 한 단계별 플로우이다.

2.1 전체 시퀀스 (가입 → 패키지 → 결제 → 프로비저닝 → Zuplo)

[데모 웹 www] 패키지 선택 (무료 / 유료)
[Sign-in] 포털 사용자 인증 (Gmail SSO 또는 이메일)
[유료 시] Stripe Checkout → 결제 완료
[무료 시] Control Plane POST /v1/tenants 직접 호출
Stripe Webhook (checkout.session.completed) 또는 POST /v1/tenants
Control Plane: tenant_id 확정, D1 tenants_master(Pending), provision_jobs(Pending) 삽입
배치 결정 (decidePlacement) → target_server_id 또는 create_new_server
workflow_dispatch (job_id, tenant_id, region, ...)
[전 구간 자동화] Pulumi(필요 시) → Ansible(multi-tenant 생성, API Key 발급) → Cloudflare DNS(서브도메인) → Zuplo Sync → Control Plane 콜백
provision_jobs=Completed, tenants_master=Active, tenant_runtime·TENANT_ORIGINS(KV) 갱신

2.2 단계별 담당·입출력 (현행·기획 대조)

단계담당입력출력현행 코드/기획
1. 패키지 선택데모 웹 (apps/www)plan_tier (free | basic | professional | enterprise), (선택) requested_region, subdomain_slug기획: www-pregoi-com §3.3. 구현: 데모용 www 폴더 신규.
2. Sign-in데모 웹 + Auth이메일 또는 OAuth포털 사용자 세션, (선택) 사용자→tenant 소유권기획: §3.2. Gmail SSO·이메일 가입 미구현.
3. 결제(유료)Stripe Checkoutplan_tier, metadata(tenant_id, plan_tier, requested_region, subdomain_slug)checkout.session.completedControl Plane: webhooks-stripe.ts. metadata에 subdomain_slug 추가 시 D1·워크플로 전달 필요.
3’. 무료Control Plane APIPOST /v1/tenants { tier, region, subdomain_slug? }202 + job_idtenants.ts. subdomain_slug 수용 시 D1 저장.
4. Webhook·큐 적재Control PlaneStripe event / POST /v1/tenantstenant_id, job_id, provision_jobs(Pending)webhooks-stripe.ts: tenant_id 생성, tenants_master INSERT, provision_jobs INSERT. : tenants_master에 subdomain_slug·canonical_hostname 컬럼 없음 → 마이그레이션 필요.
5. 배치 결정decidePlacementtenant_id, plan_tier, regiontarget_server_id | create_new_server, regionplacement.js.
6. 트리거Control Planejob_id, tenant_id, region, target_server_id, create_new_serverworkflow_dispatch 호출webhooks-stripe.ts. 전달 보강: subdomain_slug, canonical_hostname(tenant_id 기반 계산) 전달 시 워크플로에서 DNS·Zuplo에 활용.
7. Pulumiprego-pulumi / 워크플로region, (선택) create_new_serverserver_ip, (노드용 DNS node-01.pregoi.com 등)테넌트별 DNS는 Pulumi가 아닌 **프로비저닝 단계(Cloudflare API)**에서 수행(tenant-subdomain-dns-design §9).
8. Ansibleprego-ansibleserver_ip, tenant_id, db_root_password, (선택) plan_tier·plan_limitsFrappe 사이트(canonical_hostname = tenant-{short_id}.pregoi.com), Administrator API Keyplaybook.yml: tenant_id, canonical_hostname, site_name. artifacts/tenant_api_key.txt.
9. Cloudflare DNS워크플로/스크립트/Workertenant_id, canonical_hostname, subdomain_slug① canonical A/CNAME: tenant-{short_id}.pregoi.com → 오리진 ② 사용자 CNAME: {subdomain_slug}.pregoi.com → canonicaltenant-subdomain-dns-design 방식 C. 현행: Pulumi는 노드용 DNS만. 테넌트 DNS는 프로비저닝 파이프라인 내 Cloudflare API 호출로 구현 필요.
10. Zuplo Syncinfra/zuplo_sync 또는 동등tenant_id, api_key, (선택) slug, subdomainZuplo Consumer·API Key 등록, metadata/tags에 tenantId·slug·subdomain 정리tenant-provisioning-flow §4. Zuplo에 tenant_id, slug(tenant_slug), subdomain(사용자 URL) 메타 반영 요건.
11. Control Plane 콜백provision-completejob_id, tenant_id, status, host, site_name, canonical_hostname, origin_url(사용자 URL)provision_jobs=Completed, tenants_master=Active, tenant_runtime, TENANT_ORIGINS KVinternal.ts. 이미 canonical_hostname·origin_url 수신 가능.

2.3 식별자·도메인 규칙 (기획서 반영)

식별자규칙용도
tenant_idUUID 권장(또는 현행 tenant_* 형식). D1 PK, Ansible·Frappe site·Zuplo 식별.내부 일관 식별.
short_idtenant_id(UUID) 앞 8자. 비-UUID면 tenant_id 앞 8자.canonical 서브도메인: tenant-{short_id}.pregoi.com.
canonical_hostnametenant-{short_id}.pregoi.com. Frappe site·라우팅·시스템 내부 고정.Ansible site_name, TENANT_ORIGINS 키.
subdomain_slug (tenant_slug)사용자 입력. 소문자·숫자·하이픈, 예약어 제외. D1 unique.사용자 노출 URL: {subdomain_slug}.pregoi.com (CNAME → canonical). Zuplo slug/subdomain 메타.

2.4 Slug·서브도메인 명 구분 및 Tenant 서브도메인 Rule

사용자는 slug서브도메인용 name구분해서 입력하며, 필요 시 둘 중 하나를 선택해 사용할 수 있게 한다.

구분의미입력·선택
slug (tenant_slug)내부·API·라우팅용 식별자. 예: acme-corp.사용자 입력. 서브도메인 명과 동일하게 쓸 수 있고, 다르게 둘 수도 있음.
서브도메인 명 (subdomain name)실제 노출 URL에 쓰이는 이름. {subdomain_name}.pregoi.com.사용자 입력. “slug와 동일하게 사용” 체크 시 slug 값을 그대로 서브도메인으로 사용.

Tenant 서브도메인 Rule — 등록 가능한 서브도메인(및 slug)에 대한 규칙을 정의한다.

규칙 유형내용
등록 불가 서브도메인 (예약어)www, app, api, admin, mail, staging, dev, prego, pregoi, support, help, status, login, signup, billing, dashboard, node-01, control, internal, portal 등. 운영·시스템에서 사용하는 이름 전부. 목록은 D1 또는 설정 파일로 관리하고, 검증 API에서 조회.
글자수 제한최소 3자, 최대 63자 (DNS 라벨 제한). 정규식 예: ^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$. 양 끝은 영숫자, 중간은 소문자·숫자·하이픈만.
불량단어 (Blocklist)부적절·상표·금지어 목록. 별도 테이블 또는 설정으로 관리. 입력값(또는 slug/서브도메인 명)이 목록에 포함되면 등록 불가.
중복D1 tenants_master.subdomain_slug(및 서브도메인 명이 slug와 다를 경우 해당 컬럼) UNIQUE. 가입·변경 시 중복 검사 필수.
저장가입 시 subdomain_slug(slug), subdomain_name(서브도메인용, 선택 시 slug와 동일) 컬럼에 저장. DNS에는 subdomain_name(또는 slug)으로 {name}.pregoi.com 생성.

3. 데모 사용자 웹사이트 (apps/www) 요건

테스트용 데모 사이트는 Prego 레포 내 apps/www 에 두고, 패키지 선택 → Sign-in → Stripe 결제 → (백엔드에서 프로비저닝 트리거) 까지의 흐름을 검증한다.

3.1 위치·스택

항목내용
경로Prego/apps/www (또는 Prego/apps/demo-www). 사용자 요청대로 apps 아래 www 폴더.
역할테스트용 데모 웹: 패키지 선택 페이지, Sign-in, Stripe 결제 연동, (선택) job 상태 조회.
배포Cloudflare Pages 또는 정적 호스팅. 도메인은 기존 www.pregoi.com 또는 별도 데모 서브도메인.

3.2 SaaS 무료·유료 패키지

패키지plan_tier결제비고
무료 (Free)free없음. 선택 시 바로 Control Plane POST /v1/tenants 호출.subdomain_slug 필수 입력, region 기본 sg.
유료 (Basic 등)basic | professional | enterpriseStripe Checkout Session 생성 후 리다이렉트, 완료 시 Webhook으로 프로비저닝.metadata에 plan_tier, requested_region, subdomain_slug, (선택) tenant_id.
  • 패키지 선택 페이지: 무료/유료 카드 UI, 플랜명·가격·요약 기능.
  • 선택 시: (유료) Sign-in 후 Checkout Session 생성 API 호출 → Stripe 리다이렉트; (무료) Sign-in 후 subdomain_slug 입력 → POST /v1/tenants.

3.3 Sign-in 후 Stripe 결제 연결

  • 유료 선택 시: Sign-in(또는 가입) 완료 후 백엔드에서 Stripe Checkout Session 생성.
    • metadata: plan_tier, requested_region, subdomain_slug (사용자 입력), tenant_id(선택, 없으면 Control Plane에서 생성).
    • success_url / cancel_url: 데모 www 경로.
  • 사용자가 Stripe에서 결제 완료 → Stripe → Control Plane Webhook → provision_jobs 삽입 → workflow_dispatch → Pulumi → Ansible → DNS → Zuplo → 콜백.

3.4 사용자 지정 subdomain vs 시스템 내부 subdomain

  • 사용자 지정 서브도메인: 가입/패키지 단계에서 입력한 subdomain_slug. 최종 URL: https://{subdomain_slug}.pregoi.com. DNS는 CNAME으로 canonical을 가리킴.
  • 시스템 내부 서브도메인: tenant-{short_id}.pregoi.com. short_id = tenant_id 앞 8자. Frappe site·라우팅·Ansible site_name으로만 사용.

데모 www에서 subdomain_slug 입력 필드 제공, 중복/예약어 검증은 Control Plane API 또는 전용 검증 엔드포인트로 수행.

3.5 데모 웹 구성 원칙 (UI·Backend 분리, 상용 전환 용이)

데모 웹은 기능 개발플로우 시뮬레이션을 위한 코드로, UI와 Backend를 분리하여 구성한다. 목표는 나중에 상용 웹 UI로 교체가 용이하도록 하는 것이다.

항목요건
UI 레이어데모 전용 UI 컴포넌트·페이지는 별도 디렉터리/모듈로 두고, API 호출·플로우 상태만 주입받도록 설계. 상용화 시 동일 API 스펙을 쓰는 새 UI로 교체만 하면 됨.
Backend 레이어Control Plane API 호출, Stripe Session 생성, 검증 API 등은 서비스/API 클라이언트 계층으로 분리. 데모용 Mock과 실서비스 엔드포인트를 설정으로 전환 가능하게.
플로우 시뮬레이션단계별 상태(패키지 선택 → 서브도메인 입력 → 결제/무료 신청 → 프로비저닝 대기)를 상태 머신 또는 단계 ID로 관리해, 상용 UI에서도 동일 플로우를 재사용하기 쉽게.
교체 시상용 웹 UI는 데모 UI를 교체하고, Backend/API 계층·Control Plane 연동은 그대로 두거나 환경 변수만 전환.

4. Ansible을 통한 Multi-Tenant 생성

  • 입력: server_ip, tenant_id, canonical_hostname (= tenant-{short_id}.pregoi.com), db_root_password, (선택) plan_tier·plan_limits.
  • 동작: prego-ansible playbook — Docker, Frappe, bench new-site <canonical_hostname>, Administrator API Key 발급, artifact에 api_key 기록.
  • 출력: artifacts/tenant_api_key.txt (다음 단계 Zuplo Sync·콜백에서 사용).

현행 playbook.yml은 이미 tenant_id, canonical_hostname, site_name 변수와 API Key artifact를 지원함. tenant_id는 UUID 또는 Control Plane이 부여한 값 그대로 전달.


5. Pulumi로 Cloudflare에 서브도메인 등록

  • 테넌트별 DNS는 Pulumi 리소스로 정적 정의하지 않고, 프로비저닝 파이프라인 내에서 Cloudflare API로 생성하는 구성을 기획서(tenant-subdomain-dns-design §9)가 권장함.
  • 등록 내용
    1. canonical: tenant-{short_id}.pregoi.com → A 또는 CNAME(오리진/Tunnel).
    2. 사용자 URL: {subdomain_slug}.pregoi.com → CNAME → tenant-{short_id}.pregoi.com.
  • 담당: GitHub Actions 워크플로 단계 또는 전용 Worker/스크립트. Pulumi는 노드(서버)·공통 인프라만 담당.

6. Ansible으로 tenant_id·Administrator API Key 발급

  • Ansible이 이미 수행: Frappe 사이트 생성 후 Administrator용 API Key 생성, artifacts/tenant_api_key.txt에 기록.
  • tenant_id: 워크플로 입력으로 전달되며, Ansible -e tenant_id=... 로 사용. Frappe site 식별은 canonical_hostname(site_name)으로만 하면 됨.

7. Zuplo에 tenant_id·slug·subdomain 정리

  • 동작: Zuplo Sync(infra/zuplo_sync.ts 또는 동등)에서 Consumer 생성·API Key 등록 시, metadata/tags에 아래를 정리해 두는 것을 요건으로 함.
    • tenant_id: 내부 식별자.
    • slug (tenant_slug): 사용자 서브도메인 slug. subdomain_slug와 동일.
    • subdomain: 사용자 노출 FQDN. {subdomain_slug}.pregoi.com.
  • 필요 시 canonical_hostname도 메타에 포함해 라우팅·정책에서 사용 가능.

8. 데이터·스키마 보강 (D1)

현행 D1 스키마와 기획서 간 갭 반영:

테이블/컬럼현행기획 반영
tenants_mastertenant_id, status, region, plan_tier, created_at, updated_atsubdomain_slug TEXT UNIQUE, canonical_hostname TEXT (또는 생성 규칙으로 런타임 계산). 마이그레이션 추가.
plan_tierbasic, professional, enterprisefree tier 추가. PLAN_TIERS/검증 로직에 free 포함.
provision_jobsjob_id, tenant_id, trace_id, region, status, plan_tier, infra_mode(선택) subdomain_slug, canonical_hostname 컬럼으로 워크플로 전달 보강.

9. Tenant Onboarding Process Flow (요약 다이어그램)

[데모 www] 패키지 선택(무료/유료) → Sign-in
유료: Stripe Checkout (metadata: plan_tier, subdomain_slug, requested_region)
무료: POST /v1/tenants (tier=free, subdomain_slug, region)
Control Plane: tenant_id 확정(UUID 권장), tenants_master(Pending)+subdomain_slug/canonical_hostname, provision_jobs(Pending)
decidePlacement → workflow_dispatch(job_id, tenant_id, region, subdomain_slug, canonical_hostname, ...)
Pulumi(필요 시) → server_ip
Ansible: tenant_id, canonical_hostname → Frappe site + Administrator API Key → artifact
Cloudflare API: canonical A/CNAME + subdomain_slug CNAME
Zuplo Sync: tenant_id, api_key, slug(=subdomain_slug), subdomain(=subdomain_slug.pregoi.com)
POST /internal/provision-complete: job_id, tenant_id, canonical_hostname, origin_url
D1·KV 갱신, 테넌트 Active

10. 구현 체크리스트 (데모 www·백엔드 연동)

  • apps/www 폴더 생성 및 패키지 선택 페이지 (무료/유료 카드).
  • 무료: subdomain_slug 입력, POST /v1/tenants 연동 (tier=free).
  • 유료: Stripe Checkout Session 생성 API 연동(POST /v1/checkout), metadata에 subdomain_slug·subdomain_name·plan_tier·requested_region.
  • Sign-in: PREGO_AUTH_URL 설정 시 3단계·헤더에서 로그인 리다이렉트(return_url·signin=success) 연동.
  • Control Plane: tenants_master에 subdomain_slug·canonical_hostname 등 컬럼 마이그레이션; Webhook·POST /v1/tenants에서 저장·워크플로 입력으로 전달.
  • 프로비저닝 워크플로: Cloudflare API 단계(canonical + 사용자 CNAME), canonical_hostname·origin_url 콜백 반영.
  • Zuplo Sync: Consumer metadata에 tenant_id, slug, subdomain 정리.
  • 데모 www에서 GET /v1/jobs/:id로 프로비저닝 상태 표시 및 완료 시 origin_url(https://{subdomain}.pregoi.com) 링크 안내.
  • §3.5 데모 웹 UI·Backend(api.js) 분리 구조로 구현해 상용 UI 교체 용이하게 구성.
  • §2.4 Slug·서브도메인 명 구분 입력·선택, Tenant 서브도메인 Rule(예약어·글자수·불량단어·중복·실시간 검사) 적용.
  • §11 결제 후 Frappe tenant 필수 정보(회사명, 관리자 이메일·이름 등) 입력 폼 및 전달.
  • §12 온보드 시 사용자 이메일·이름으로 등록·추가 플로우(팀원 초대). 데모 www 5단계 팀원 1명 입력 → POST /v1/tenants에 additional_users 전달, D1 tenants_master.additional_users(JSON) 저장. 프로비저닝·Ansible에서 해당 컬럼 읽어 사용자 생성 시 연동 가능.
  • §13 Tenant Onboard Wizard 단계별 UI·상태 관리.
  • §14 App/DB/Redis 분리, Control Plane 배치 로직에 따른 Pulumi·Ansible 서버·DB·Redis 바인딩, Cloudflare 서브도메인 자동 설정(워크플로·infra 반영).
  • §15 결제 정보 D1·KV 관리, Billing 사용자 UI(프록시 연동)·시스템 관리자용 테스트 페이지(GET /internal/billing-test, GET /internal/billing?tenant_id=).

11. Frappe Tenant 생성 필수 정보 (결제 후 입력)

Frappe 테넌트(사이트) 생성을 위해 필요한 필수 정보결제 완료 후 단계에서 사용자에게 입력받는다. 결제 전에는 패키지·서브도메인(slug/name)만 수집하고, 결제(또는 무료 신청) 확정 후 다음 정보를 추가 수집한다.

필수 항목설명저장·전달
회사명 (법인명 전체)공식 문서·송장용. Frappe Company 등에 원본 유지. 최대 30자.D1 tenants_master.company_name, Ansible/Frappe 전달.
서브도메인 / 호스트(Slug)2단계에서 입력한 값. 5단계에서는 읽기 전용 표시.tenants_master.subdomain_slug·subdomain_name, site_name과 동일.
약어(abbr)Frappe 계정과목 등에 사용. 2~5자, 선택. 비워두면 Frappe에서 자동 생성 가능.D1 tenants_master.abbr, GET /internal/billing·Ansible 연동.
관리자 이메일테넌트 최초 Administrator 계정 이메일.D1; Ansible에서 bench add-user·API Key 발급 시 사용.
관리자 이름Administrator 표시명.Ansible/Frappe 사용자 생성 시 전달.
리전(선택)패키지 단계에서 수집. 유료 시 requested_region.tenants_master.region, 워크플로 입력.

입력 시점: 결제 완료(또는 무료 신청 완료) 직후 “테넌트 설정” 또는 “사이트 정보 입력” 스텝에서 폼으로 수집. 수집 완료 후 provision_jobs 삽입·workflow_dispatch 트리거.


12. 온보드 시 사용자 등록 (이메일·이름)

온보딩 과정에서 테넌트 사용자이메일과 이름으로 쉽게 등록·추가할 수 있게 한다.

요건내용
최초 사용자결제 후 입력 단계에서 “관리자 이메일·이름” 수집. 해당 사용자가 테넌트의 첫 Administrator.
추가 사용자온보드 위저드 내 “팀원 초대” 또는 “사용자 추가” 스텝에서 이메일·이름만 입력해 추가. (비밀번호는 초대 메일·설정 링크로 나중에 설정.)
저장포털 측: D1 또는 별도 User 테이블에 포털 사용자(이메일·이름·tenant_id 소유권). Frappe 측: 프로비저닝 완료 후 해당 사이트에 User 생성(Ansible 또는 Control Plane→Frappe API).
간소화가입 시 최소 필드만: 이메일, 이름(표시명). 추가 필드(전화번호 등)는 선택 또는 사후 프로필에서.

이메일·이름만으로 “초대 목록”을 만들어 두고, 프로비저닝 완료 후 Frappe 사이트에 사용자 생성·초대 메일 발송하는 플로우로 정리.


13. Tenant Onboard Wizard (단계별)

테넌트 온보딩을 단계별 위저드로 정리해, 사용자가 한 번에 하나의 단계만 진행하도록 한다.

단계제목내용
1패키지 선택무료 / Basic / Professional / Enterprise 선택. (선택) 리전.
2서브도메인Slug·서브도메인 명 입력(또는 “slug와 동일” 선택). 실시간 유효성·중복·예약어·불량단어 검사.
3Sign-in / 가입포털 로그인 또는 회원가입(이메일·이름 등).
4결제(유료 시)Stripe Checkout 리다이렉트 → 결제 완료 후 return_url으로 복귀. 무료는 이 단계 스킵.
5테넌트 정보 입력회사명(법인명 전체, 최대 30자), 서브도메인/Slug 확인 표시, 약어(2~5자 선택), 관리자 이메일·이름. (선택) 추가 사용자(이메일·이름) 목록.
6확인 및 제출입력 내용 요약, “시작하기” 클릭 시 provision_jobs 등록·workflow_dispatch 트리거.
7프로비저닝 대기job_id로 GET /v1/jobs/:id 폴링. 완료 시 “테넌트 준비 완료”, https://{subdomain}.pregoi.com 링크 안내.

위저드 상태(현재 단계·입력값)는 클라이언트 상태 또는 세션/임시 저장으로 유지. 상용 UI로 교체 시 동일 단계 정의를 재사용.


14. Prego 인프라 분리 및 동적 할당 (Control Plane·Pulumi·Ansible·Cloudflare)

Prego는 Application 서버, DB, Redis분리되어 있으며, 자원의 동적 할당prego-control-plane 레포의 로직(배치 결정·노드·메트릭)에 따라 이뤄진다. Pulumi·Ansible이 특정 서버·DB·Redis 정보를 바인딩해 설치를 진행하고, Cloudflare 서브도메인 설정이 자동으로 수행되어야 한다.

구성 요소역할
Application 서버Frappe Bench·앱 실행. Pulumi로 VM 생성 또는 기존 노드(node_id) 지정.
DBMariaDB. 전용 DB 서버 또는 App 서버와 분리. Ansible 인벤토리에서 db_host, db_root_password 등으로 바인딩.
Redis캐시·세션. 전용 Redis 서버 또는 공유. Ansible에서 redis_host, redis_password 등 바인딩.
자원 동적 할당prego-control-plane의 배치 로직(예: decidePlacement, nodes, server_metrics)에 따라 기존 노드에 배치(target_server_id) 또는 신규 서버 생성(create_new_server). 워크플로 입력으로 job_id, tenant_id, region, target_server_id, create_new_server 전달.
Pulumiregion·create_new_server에 따라 Hetzner 등에 서버 생성, 노드 등록(POST /internal/nodes). 기존 노드 사용 시 스킵.
Ansible선정된 App 서버 IP, DB 호스트·비밀번호, Redis 호스트·비밀번호를 인벤토리/변수로 바인딩해 playbook 실행. Frappe·bench new-site·API Key 발급.
Cloudflare프로비저닝 파이프라인 내에서 서브도메인 설정 자동 수행: canonical tenant-{short_id}.pregoi.com, 사용자 URL {subdomain_name}.pregoi.com CNAME. API 호출로 레코드 생성·갱신.

정리: 단일 서버가 아닌 App / DB / Redis 분리 아키텍처를 전제로, Control Plane이 “어디에 올릴지” 결정하고, Pulumi·Ansible이 그에 맞는 서버·DB·Redis 바인딩으로 설치·설정하며, Cloudflare DNS는 파이프라인 단계에서 자동 반영된다.


15. 결제 정보·빌링·인보이스 관리 및 UI

사용자 결제 정보D1에서 관리하고, KV에 기본 정보를 연동해 두며, Billing·Payment·Invoice 발행 등을 이 기반으로 진행한다. 이에 맞는 사용자용 UI시스템 관리자용 테스트 페이지를 둔다.

항목내용
D1 관리결제·구독·고객 정보: billing_customers, subscriptions, invoices(또는 동일 목적 테이블). Stripe customer_id, subscription_id, plan_tier, 결제 수단 메타 등. tenants_master와 tenant_id로 연결.
KV 연동테넌트 기본 정보·상태·플랜 요약을 KV에 캐시(예: tenant:{tenant_id}:billing). 엣지·API에서 빠른 조회, D1이 Source of Truth.
Billing·Payment·InvoiceStripe Webhook으로 결제·구독·인보이스 이벤트 수신 → D1 갱신. 인보이스 발행·다운로드 링크는 D1·Stripe 기반으로 제공.
사용자 UI내 결제 정보: 등록된 결제 수단, 현재 플랜, 구독 상태. 결제 내역·인보이스: 목록·다운로드. 플랜 변경·해지: 업그레이드/다운그레이드/해지 신청. 데모 www 또는 상용 포털의 “Billing” 섹션으로 제공.
시스템 관리자용 테스트 페이지테스트·검증용: 테넌트별 결제 상태 조회, Stripe Webhook 재발송·테스트, 인보이스 목록·상태 확인, (선택) Mock 결제·테스트 구독 생성. prego-control-plane 대시보드 확장 또는 별도 /admin/billing-test 등 보호된 경로.

요약: 결제·빌링·인보이스는 D1 + KV로 관리하고, 사용자용 Billing UI관리자용 테스트 페이지를 기획에 포함한다.


16. 온보딩 상세 변경 사항 (통합)

아래는 onboarding-plan-limits-team-invite-step6-admin-plan, onboarding-step2-removal-step5-changes-plan, onboarding-step4-company-subdomain-abbr-admin-name-plan 3개 기획서를 통합한 요건 요약이다.

16.1 Step 2 제거 및 6단계 전환

변경 전변경 후
Step 2 서브도메인 별도 단계삭제 — Step 4(테넌트 정보)에 통합
7단계6단계: 1 패키지 → 2 로그인 → 3 결제 → 4 테넌트 정보 → 5 확인 → 6 프로비저닝

16.2 Step 4(테넌트 정보) 필드·UI

항목요건
회사명placeholder “company pte ltd”. 최대 60자. 소문자 저장.
서브도메인초기 빈 값. 회사명 입력 시 첫 단어 기반 자동 채움(소문자). 수정 가능.
약어초기 빈 값. 회사명 첫 2글자 대문자 자동 채움. 2~5자.
관리자First name / Last name 분리. 전화번호(선택).
팀원 추가”팀원 추가” 버튼(회색). 최대 인원 도달 시 버튼 숨김.

16.3 플랜별 팀원 초대 한도

패키지최대 팀원
Free, Basic5
Professional, Enterprise10

16.4 Step 6 프로비저닝 대기·관리자

  • GET /v1/jobs/:id 폴링, Completed 시 origin_url 표시. Failed 시 에러 메시지·관리자 안내.
  • 관리자 URL: /internal/dashboard, /internal/billing-test, /internal/onboarding-status, /internal/onboarding-dashboard (Runbook 참조).

17. 참조 문서

문서용도
tenant-provisioning-flow.mdStripe→큐→배치→전 구간 자동화 흐름.
provision-tenant-workflow-design.md워크플로 입출력·Ansible·Zuplo·콜백 스펙.
www-pregoi-com-signup-to-provisioning-flow.mdwww 접속→가입→패키지→결제→리소스 할당 단계별 구현 상태.
tenant-subdomain-dns-design.md방식 C(canonical + 사용자 CNAME), 검증 규칙, DNS 담당.
api-control-plane-implementation-plan.md Appendix C테넌트 생애주기·상태 전이.
Help