Onboarding Lifecycle Events
choco intermediate 5 min read
ELI5
The onboarding flow is a tour bus with stops. Every time the bus pulls in to a stop, leaves a stop, skips a stop, gets stuck at a stop, or restarts the route, it radios the dispatcher. The dispatcher is the analytics service.
Technical Deep Dive
Defined in proto/events/onboarding/v1/lifecycle.proto. Stream choco:events:onboarding, ordering causally_ordered by session_id.
Happy-Path Sequence
sequenceDiagram participant U as User participant W as cho-co-web participant G as choco-gateway participant N as NATS (onboarding) participant C as choco-consumers U->>W: visit /onboarding W->>G: POST /onboarding/start G->>N: OnboardingStarted (session_id, user_id) loop steps U->>W: complete step W->>G: POST /onboarding/step G->>N: OnboardingStepCompleted (step_id, ordinal) end U->>W: pick path W->>G: POST /onboarding/path G->>N: OnboardingPathSelected (path_id) G->>N: SiteProvisionRequested (site_id) G-->>N: SiteProvisionStateChanged * 6 G->>N: SiteProvisionCompleted OR WelcomeSiteProvisioned G->>N: OnboardingCompleted (total_steps, total_duration_ms) N->>C: fan-out to analytics + observabilitySkipped vs Abandoned
| Trigger | Field | Source | |
|---|---|---|---|
| Skipped | user explicitly clicks “skip” | skip_reason (string) | lifecycle.proto:48-54 |
| Abandoned | timeout-based heuristic, no user action | idle_duration_ms (int32) | lifecycle.proto:67-73 |
Different consumers care about different things: skip drives funnel analytics; abandon drives reactivation campaigns.
Aggregate Identity
For lifecycle events the aggregate is session_id; for the provisioning saga events the aggregate is site_id (lifecycle.proto:159). Two-aggregate flow: a single onboarding session can spawn one or more sites, and SiteProvisionRequested.workspace_id ties them back to the session’s user/workspace.
Site Provisioning Sub-Saga
The terminal step of onboarding is provisioning a documentation site (lifecycle.proto:81-99). Two terminal events depending on hosting mode:
SiteProvisionCompleted— user_git path; ships once the saga reacheslive. Carriesvercel_project_id,deploy_url,total_duration_ms.WelcomeSiteProvisioned— platform_template path; emitted synchronously from the onboarding final step, no saga.
SiteProvisionFailed distinguishes failure from awaiting_github (lifecycle.proto:203-205); the latter is a non-terminal pause and does NOT emit Failed.
Reset Semantics
OnboardingReset (lifecycle.proto:77) carries initiated_by to distinguish self-reset from admin reset, both of which return the session to step 0 but log differently.
Key Terms
- session_id → primary aggregate for the lifecycle events; one row in the gateway’s onboarding sessions table.
- causally_ordered → events for the same
session_idarrive in publish order; cross-session order is not preserved. - terminal pause →
awaiting_github; saga stops emitting state-changed events but is not failed.
Q&A
Q: Does OnboardingResumed reset session_id?
A: No — it reuses the existing session_id and reports gap_duration_ms (lifecycle.proto:60-64). Reset is the event that mints a new session.
Q: Which consumers subscribe to this stream?
A: The proto comment for the saga states “consumed by choco-consumers (analytics, observability) and the cho-co-web SSE status endpoint” (lifecycle.proto:91-93).
Q: Are SiteProvisionStateChanged events high frequency?
A: Yes — ~6 per happy-path provision (lifecycle.proto:175-176). Consumers should subscribe selectively (e.g. only to_state IN (live, failed)) unless they’re driving the SSE stream.
Examples
A user starts onboarding, completes 3 steps, picks the “blog” path, doesn’t have GitHub linked, and the saga parks in awaiting_github. Wire trace: OnboardingStarted → 3× OnboardingStepCompleted → OnboardingPathSelected → SiteProvisionRequested(has_github_link=false) → SiteProvisionStateChanged(requested → source_resolving → awaiting_github). No Completed or Failed is emitted. The user later links GitHub and a fresh Start() resumes the saga.
neighbors on the map
- EventEnvelope Wire Wrapper publishing a new domain event proto
- Site Hosting Modes & Lifecycle Stages adding a new fork branching on platform vs user_git
- CI Transition Event Schema vendoring kahn_emit.py into a CI producer
- Agent Transition Event Schema vendoring kahn_agent_emit.py into an agent loop