Technical docs
Onboarding
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.