Persists welcome-wizard Step 1/2/3 progress for self-serve signup Phase 2. PATCH validates step cannot decrease, ignores `data` on action="skip", and is idempotent on re-PATCH of the same step. POST /users/me/onboarding-dismiss-rest backs the wizard's "Skip the rest" button. Both routes added to _EMAIL_VERIFICATION_ALLOWLIST and _SUBSCRIPTION_GUARD_ALLOWLIST so the wizard runs before email verification and during the trial. 4 integration tests cover field writes, skip semantics, decrease guard, and dismiss-rest. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
from typing import Literal, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class OnboardingStatus(BaseModel):
|
|
created_flow: bool
|
|
ran_session: bool
|
|
exported_session: bool
|
|
tried_ai_assistant: bool
|
|
invited_teammate: bool
|
|
connected_psa: bool
|
|
is_team_user: bool
|
|
dismissed: bool
|
|
|
|
|
|
# --- Welcome wizard (Phase 2) ----------------------------------------------
|
|
|
|
|
|
TeamSizeBucket = Literal["1-2", "3-5", "6-10", "11-25", "26+"]
|
|
RoleAtSignup = Literal["owner", "lead_tech", "tech", "other"]
|
|
PrimaryPsa = Literal["connectwise", "autotask", "halopsa", "none"]
|
|
WizardStep = Literal[1, 2, 3]
|
|
WizardAction = Literal["complete", "skip"]
|
|
|
|
|
|
class OnboardingStepData(BaseModel):
|
|
"""Optional payload carried with `action="complete"` for steps 1 and 2.
|
|
|
|
Step 1 fields: company_name, team_size_bucket, role_at_signup
|
|
Step 2 fields: primary_psa
|
|
Step 3 has no data (invitations posted separately).
|
|
"""
|
|
|
|
# Step 1
|
|
company_name: Optional[str] = Field(default=None, max_length=255)
|
|
team_size_bucket: Optional[TeamSizeBucket] = None
|
|
role_at_signup: Optional[RoleAtSignup] = None
|
|
# Step 2
|
|
primary_psa: Optional[PrimaryPsa] = None
|
|
|
|
|
|
class OnboardingStepRequest(BaseModel):
|
|
step: WizardStep
|
|
action: WizardAction
|
|
data: Optional[OnboardingStepData] = None
|
|
|
|
|
|
class OnboardingStepResponse(BaseModel):
|
|
onboarding_step_completed: Optional[int]
|
|
onboarding_dismissed: bool
|