Files
twenty/packages/twenty-server/src/modules/modules.module.ts
T
Félix Malfait 61309c45e6 feat(onboarding): prefill the invite step with teammates from the connected calendar (#21640)
## What & why

Implements core-team-issues#1414: move the calendar/email connection
earlier in onboarding and use the freshly connected calendar to prefill
the **Invite your team** step with likely teammates, so users don't
start from an empty form.

## Approach

Everything is behind the feature flag
`IS_ONBOARDING_INVITE_SUGGESTIONS_ENABLED` (off by default).

**Reorder** — onboarding becomes `Workspace activation → Connect account
→ Create profile → Invite team`. Connecting before profile gives the
calendar sync a head start; connecting *before* the workspace exists
isn't possible (a connected account requires an activated workspace +
workspace member + OAuth transient token). Gated in both
`OnboardingService.getOnboardingStatus` (backend) and
`useSetNextOnboardingStatus` (frontend) so the two agree.

**Fast teammate lookup** — on Google/Microsoft connect *during
onboarding*, a background job (`FetchOnboardingInviteSuggestionsJob`)
runs a single bounded calendar fetch (recent events, attendees inline),
keeps same-work-email-domain colleagues (excludes self + aliases;
personal mailboxes yield nothing), ranks by meeting frequency, and
caches the top 5. The invite step reads the cache via a new
`getInviteSuggestions` query and prefills the form — polling briefly
while the cache warms, and never overwriting input the user has already
typed.

Providers: **Google** (Calendar `events.list`) and **Microsoft** (Graph
`calendarView`), routed by a `CalendarAttendeesService` dispatcher
(mirrors the existing `CalendarGetCalendarEventsService`). Any fetch
failure (missing scope, API error) degrades to today's empty form via
the orchestrator's best-effort catch.

## How to enable

Turn on `IS_ONBOARDING_INVITE_SUGGESTIONS_ENABLED` for a workspace
(admin panel).

## Notes

- New-workspace creators only (invitees never see the connect/invite
steps). Skipping the connect step, or signing up with a personal email,
falls back to the current empty form.
- The "We found teammates from your calendar" subtitle only shows once
suggestions are actually prefilled.
- i18n: the new `<Trans>` strings are extracted on merge to `main` by
the existing Crowdin workflow.

## Testing

- Frontend unit tests for the reorder state machine (both flag states).
- `npx nx typecheck` and `npx nx lint:diff-with-main` green for
`twenty-front` and `twenty-server`.
- Server boots with the new DI wiring (no circular dependency);
`getInviteSuggestions` / `InviteSuggestion` present in the live metadata
schema.
- Not exercised in CI: live Google/Microsoft OAuth end-to-end (requires
real accounts + calendar data).

https://claude.ai/code/session_019MyY3bfAEij4AwSXMCLtWY

---
_Generated by [Claude
Code](https://claude.ai/code/session_019MyY3bfAEij4AwSXMCLtWY)_

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21640?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: neo773 <62795688+neo773@users.noreply.github.com>
Co-authored-by: neo773 <neo773@protonmail.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-06-16 15:45:11 +00:00

23 lines
830 B
TypeScript

import { Module } from '@nestjs/common';
import { CalendarModule } from 'src/modules/calendar/calendar.module';
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
import { MessagingModule } from 'src/modules/messaging/messaging.module';
import { OnboardingInviteSuggestionsModule } from 'src/modules/onboarding-invite-suggestions/onboarding-invite-suggestions.module';
import { WorkflowModule } from 'src/modules/workflow/workflow.module';
import { WorkspaceMemberModule } from 'src/modules/workspace-member/workspace-member.module';
@Module({
imports: [
MessagingModule,
CalendarModule,
ConnectedAccountModule,
OnboardingInviteSuggestionsModule,
WorkflowModule,
WorkspaceMemberModule,
],
providers: [],
exports: [],
})
export class ModulesModule {}