feat(onboarding): add PATCH /users/me/onboarding-step + dismiss-rest
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>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Literal, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class OnboardingStatus(BaseModel):
|
||||
@@ -10,3 +12,40 @@ class OnboardingStatus(BaseModel):
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user