Onboarding — Data Model
Onboarding does not own its own table. It composes writes across existing tables. See parent feature docs for column-level detail; this file maps the effect of the wizard on the schema.
Rows created by a successful wizard run
| Order | Table | Row | Source step |
|---|---|---|---|
| 1 | users | (if not yet created by webhook) — findOrCreateFromClerk inside OrganizationsService.create. | implicit |
| 2 | Clerk-side | new organization | org step → handleFinish |
| 3 | organizations | new row with name, type, platform_tier='lite', clerk_organization_id. | org step → handleFinish |
| 4 | memberships | new row, role='owner', status='active'. | org step → handleFinish (in OrganizationsService.create) |
| 5 | legal_consents | 3 rows (terms_of_use, privacy_policy, fitness_waiver), context='owner_onboarding'. | legal step → handleFinish |
| 6 | (none required; current wizard sends {}) | If onboarding-complete had classTypeName → class_types row. If inviteEmails[] → invitations + memberships(pending_invitation). | done step → handleFinish |
Persistence of in-progress wizard state
- LocalStorage — key
fitkit:setup-wizard-v2, value JSON-serializedOnboardingState<SetupWizardContext>(thecurrentStepId,flowData, internal OnboardJS fields). TTL 7 days. No server-side copy. - No DB row persists wizard progress. The org row exists only after
handleFinishruns.
Tour completion
- Column:
users.guided_tour_completed_at(timestamptz). - Set by
PATCH /users/me { guidedTourCompletedAt: <ISO> }. The dashboard reads this and skips the tour if non-null.
Multi-org isolation pattern
Onboarding writes that bootstrap a new org are all scoped to the org being created. The owner row in memberships is the first credential that lets the caller read/write the new org’s data through the standard requireMembership path on subsequent requests.
Soft-delete vs hard-delete
N/A — no onboarding-owned data. Org soft-delete is not exposed; legal consents are immutable (revocation creates a new row).