Technical docs
Onboarding
Public reference generated from tech docs/onboarding.md.
Overview
Current bootstrap and invite-entry behavior for new users.
Self-serve bootstrap
* Trigger: * Google OAuth callback at `/api/auth/google/callback` * runs only for a brand-new user when there is no invite code in OAuth `state` * Backend builder: * `OrganizationBuilder.createDefaultOrganization()` * creates `My Organization` * seeds `available_tokens` with `DEFAULT_AVAILABLE_TOKENS` (`2000`) * sets the new org as the user's `current_organization_id`
Optional default AI teammate
* Builder reads system setting `onboarding_employee_id`. * If the setting points to a valid system AI teammate, that teammate is cloned into the new org.
Ally welcome bootstrap
* The builder resolves the new user's personal Ally employee in the new org with `AiEmployeeService.findUserAllyEmployee(organizationId, user.id)`. * If that personal Ally employee exists, the backend: * creates or restores the user's employee-chat-backed Ally conversation for the new org * inserts a completed AI welcome message * updates the conversation last-message summary so it appears immediately in history * The current seeded welcome starts with `Welcome — I’m Ally.`.
First redirect after signup
* `getOnboardingRedirectUrl(organizationId)` currently returns: * `/staff?onboarding=true` * The current onboarding redirect no longer targets a first-AI-teammate detail route. * If organization ID is missing, the fallback is `/`.
Frontend onboarding behavior
* `ViewModeManager` watches `?onboarding=true`. * After scoped internal-chat state is restored for the current `userId + organizationId`, it auto-opens Ally if Ally is not already visible. * The onboarding open path forces Ally into a floating window near the bottom-right corner: * margin: `20px` * width: `MIN_WINDOW_SIZE.width` * height: `60%` of viewport height * On mobile, floating chat is converted back into the docked panel.
Invite route (`/invite/[code]`)
* Page bootstrap: * loads invite metadata from `GET /api/invites/{code}` * shows one of: * guest invite view * authenticated accept view * already-in-organization view * not-found state * Guest behavior: * `Sign in with Google` starts OAuth with `state: { inviteCode: code }` * the guest view warns that sign-in will automatically accept the invite * OAuth callback behavior with an invite code: * backend tries `AcceptInviteProcessor` immediately * on success, callback returns redirect `/` * on handled invite failure, callback redirects back to `/invite/{code}` * Authenticated behavior on the invite page: * `Accept Invite` calls `GET /api/invites/{code}/accept` * accepted invites redirect to `/` * `already_in_organization` shows `Go to Dashboard`
Support notes
* Landing on `/` after self-serve signup usually means the onboarding redirect did not receive an organization ID. * Missing Ally welcome usually means the user's personal Ally employee was not created or could not be resolved in the new org. * If `?onboarding=true` is present and Ally does not auto-open after load, treat that as unexpected. * Invite acceptance always switches the user's current organization to the invited org.