From 35c2a24afb41d56e5d9c677a7265e628435a3d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Tue, 16 Jun 2026 21:25:02 +0200 Subject: [PATCH] perf(onboarding): compute invite suggestions on-demand (#21696) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Follow-up to #21640. In production, invite suggestions took ~1 minute to appear because `FetchOnboardingInviteSuggestionsJob` ran on the shared `calendarQueue` behind heavy calendar-sync jobs. - **Drop the background job entirely.** `getInviteSuggestions` now resolves the connected account from the authenticated `@AuthUserWorkspaceId()` and computes suggestions on demand: cache-first, with a bounded calendar fetch + cache write on a miss. Removes the Google/Microsoft enqueues, the `shouldComputeInviteSuggestions` threading through the auth controllers, and the now-unused `shouldComputeInviteSuggestionsOnConnect` / `isOnboardingConnectAccountPending` helpers. - **Prefetch one step earlier.** New `usePrefetchInviteSuggestions` hook fires the query from `CreateProfile` so the server cache is warm by the time the invite step renders. `InviteTeam` switches from `network-only` → `cache-first`. If the profile step is skipped, the invite step still computes on-demand (~1–3s, no queue) — no more minute-long waits. No GraphQL schema change. ## Test plan - [ ] Connect Google calendar in onboarding → invite step renders prefilled teammates with no perceivable wait - [ ] Connect Microsoft calendar in onboarding → same - [ ] Onboard with workspace name already set so profile step is skipped → invite step still prefills (just with a brief on-demand fetch instead of 1 min) - [ ] Connect a non-work-email account → invite step renders empty form (no suggestions) - [ ] `npx nx typecheck twenty-server` ✅ - [ ] `npx nx lint:diff-with-main twenty-server` ✅ - [ ] `npx nx lint:diff-with-main twenty-front` ✅ (changed files clean) - [ ] `google-apis.service.spec.ts` + `microsoft-apis.service.spec.ts` pass https://claude.ai/code/session_019MyY3bfAEij4AwSXMCLtWY --- _Generated by [Claude Code](https://claude.ai/code/session_019MyY3bfAEij4AwSXMCLtWY)_ Review in cubic Co-authored-by: Claude --- .../hooks/usePrefetchInviteSuggestions.ts | 9 ++ .../src/pages/onboarding/CreateProfile.tsx | 4 + .../src/pages/onboarding/InviteTeam.tsx | 2 +- .../google-apis-auth.controller.ts | 7 -- .../microsoft-apis-auth.controller.ts | 7 -- .../auth/services/google-apis.service.ts | 23 ---- .../auth/services/microsoft-apis.service.ts | 22 ---- .../core-modules/message-queue/jobs.module.ts | 2 - .../onboarding/onboarding.resolver.ts | 5 +- .../onboarding/onboarding.service.ts | 37 ------- ...fetch-onboarding-invite-suggestions.job.ts | 26 ----- .../onboarding-invite-suggestions.module.ts | 2 - .../onboarding-invite-suggestions.service.ts | 100 +++++++++--------- 13 files changed, 66 insertions(+), 180 deletions(-) create mode 100644 packages/twenty-front/src/modules/onboarding/hooks/usePrefetchInviteSuggestions.ts delete mode 100644 packages/twenty-server/src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job.ts diff --git a/packages/twenty-front/src/modules/onboarding/hooks/usePrefetchInviteSuggestions.ts b/packages/twenty-front/src/modules/onboarding/hooks/usePrefetchInviteSuggestions.ts new file mode 100644 index 0000000000..f6b4c379c0 --- /dev/null +++ b/packages/twenty-front/src/modules/onboarding/hooks/usePrefetchInviteSuggestions.ts @@ -0,0 +1,9 @@ +import { useQuery } from '@apollo/client/react'; + +import { GetInviteSuggestionsDocument } from '~/generated-metadata/graphql'; + +export const usePrefetchInviteSuggestions = () => { + useQuery(GetInviteSuggestionsDocument, { + fetchPolicy: 'cache-first', + }); +}; diff --git a/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx b/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx index 19b711a2d2..21f9de0dce 100644 --- a/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx +++ b/packages/twenty-front/src/pages/onboarding/CreateProfile.tsx @@ -12,6 +12,7 @@ import { Title } from '@/auth/components/Title'; import { currentUserState } from '@/auth/states/currentUserState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersState'; +import { usePrefetchInviteSuggestions } from '@/onboarding/hooks/usePrefetchInviteSuggestions'; import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { useUpdateWorkspaceMemberSettings } from '@/settings/profile/hooks/useUpdateWorkspaceMemberSettings'; import { WorkspaceMemberPictureUploader } from '@/settings/workspace-member/components/WorkspaceMemberPictureUploader'; @@ -69,6 +70,9 @@ type Form = z.infer; export const CreateProfile = () => { const { t } = useLingui(); const setNextOnboardingStatus = useSetNextOnboardingStatus(); + + usePrefetchInviteSuggestions(); + const { enqueueErrorSnackBar } = useSnackBar(); const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState); const setCurrentUser = useSetAtomState(currentUserState); diff --git a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx index 4c6359f343..1969aa143c 100644 --- a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx +++ b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx @@ -96,7 +96,7 @@ export const InviteTeam = () => { const { data: inviteSuggestionsData } = useQuery( GetInviteSuggestionsDocument, { - fetchPolicy: 'network-only', + fetchPolicy: 'cache-first', }, ); diff --git a/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts b/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts index 94a74433d2..853b5ab960 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/controllers/google-apis-auth.controller.ts @@ -98,12 +98,6 @@ export class GoogleAPIsAuthController { const handle = emails[0].value.toLowerCase(); - const shouldComputeInviteSuggestions = - await this.onboardingService.shouldComputeInviteSuggestionsOnConnect({ - userId, - workspaceId, - }); - const connectedAccountId = await this.googleAPIsService.refreshGoogleRefreshToken({ handle, @@ -115,7 +109,6 @@ export class GoogleAPIsAuthController { calendarVisibility, messageVisibility, skipMessageChannelConfiguration, - shouldComputeInviteSuggestions, }); if (userId) { diff --git a/packages/twenty-server/src/engine/core-modules/auth/controllers/microsoft-apis-auth.controller.ts b/packages/twenty-server/src/engine/core-modules/auth/controllers/microsoft-apis-auth.controller.ts index 568709ef89..827666d0dc 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/controllers/microsoft-apis-auth.controller.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/controllers/microsoft-apis-auth.controller.ts @@ -105,12 +105,6 @@ export class MicrosoftAPIsAuthController { const handle = emails[0].value.toLowerCase(); - const shouldComputeInviteSuggestions = - await this.onboardingService.shouldComputeInviteSuggestionsOnConnect({ - userId, - workspaceId, - }); - const connectedAccountId = await this.microsoftAPIsService.refreshMicrosoftRefreshToken({ handle, @@ -122,7 +116,6 @@ export class MicrosoftAPIsAuthController { calendarVisibility, messageVisibility, skipMessageChannelConfiguration, - shouldComputeInviteSuggestions, }); if (userId) { diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts index 7f8dbc09d2..5af45f759b 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/google-apis.service.ts @@ -47,10 +47,6 @@ import { MessagingMessageListFetchJob, type MessagingMessageListFetchJobData, } from 'src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job'; -import { - FetchOnboardingInviteSuggestionsJob, - type FetchOnboardingInviteSuggestionsJobData, -} from 'src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job'; import { isDefined } from 'twenty-shared/utils'; @Injectable() @@ -93,7 +89,6 @@ export class GoogleAPIsService { calendarVisibility: CalendarChannelVisibility | undefined; messageVisibility: MessageChannelVisibility | undefined; skipMessageChannelConfiguration?: boolean; - shouldComputeInviteSuggestions?: boolean; }): Promise { const { handle, @@ -103,7 +98,6 @@ export class GoogleAPIsService { calendarVisibility, messageVisibility, skipMessageChannelConfiguration, - shouldComputeInviteSuggestions, } = input; const isCalendarEnabled = this.twentyConfigService.get( @@ -353,23 +347,6 @@ export class GoogleAPIsService { } } - if ( - shouldComputeInviteSuggestions && - isCalendarEnabled && - isCalendarAvailable - ) { - void this.calendarQueueService - .add( - FetchOnboardingInviteSuggestionsJob.name, - { - workspaceId, - userId, - connectedAccountId: newOrExistingConnectedAccountId, - }, - ) - .catch(() => undefined); - } - return newOrExistingConnectedAccountId; }, authContext, diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts index 734b0eebee..d705dc3d33 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/microsoft-apis.service.ts @@ -39,10 +39,6 @@ import { import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service'; import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service'; import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service'; -import { - FetchOnboardingInviteSuggestionsJob, - type FetchOnboardingInviteSuggestionsJobData, -} from 'src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job'; import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/services/message-channel-sync-status.service'; import { @@ -89,7 +85,6 @@ export class MicrosoftAPIsService { calendarVisibility: CalendarChannelVisibility | undefined; messageVisibility: MessageChannelVisibility | undefined; skipMessageChannelConfiguration?: boolean; - shouldComputeInviteSuggestions?: boolean; }): Promise { const { handle, @@ -99,7 +94,6 @@ export class MicrosoftAPIsService { calendarVisibility, messageVisibility, skipMessageChannelConfiguration, - shouldComputeInviteSuggestions, } = input; const scopes = getMicrosoftApisOauthScopes(); @@ -316,22 +310,6 @@ export class MicrosoftAPIsService { }, ); } - - if ( - shouldComputeInviteSuggestions && - syncableCalendarChannels.length > 0 - ) { - void this.calendarQueueService - .add( - FetchOnboardingInviteSuggestionsJob.name, - { - workspaceId, - userId, - connectedAccountId: newOrExistingConnectedAccountId, - }, - ) - .catch(() => undefined); - } } return newOrExistingConnectedAccountId; diff --git a/packages/twenty-server/src/engine/core-modules/message-queue/jobs.module.ts b/packages/twenty-server/src/engine/core-modules/message-queue/jobs.module.ts index 77cc7fa5b0..f1b0c88a20 100644 --- a/packages/twenty-server/src/engine/core-modules/message-queue/jobs.module.ts +++ b/packages/twenty-server/src/engine/core-modules/message-queue/jobs.module.ts @@ -42,7 +42,6 @@ import { CalendarEventParticipantManagerModule } from 'src/modules/calendar/cale import { CalendarModule } from 'src/modules/calendar/calendar.module'; import { AutoCompaniesAndContactsCreationJobModule } from 'src/modules/contact-creation-manager/jobs/auto-companies-and-contacts-creation-job.module'; import { MessagingModule } from 'src/modules/messaging/messaging.module'; -import { OnboardingInviteSuggestionsModule } from 'src/modules/onboarding-invite-suggestions/onboarding-invite-suggestions.module'; import { TimelineJobModule } from 'src/modules/timeline/jobs/timeline-job.module'; import { TimelineActivityModule } from 'src/modules/timeline/timeline-activity.module'; import { WorkflowModule } from 'src/modules/workflow/workflow.module'; @@ -67,7 +66,6 @@ import { WorkflowModule } from 'src/modules/workflow/workflow.module'; MessagingModule, CalendarModule, CalendarEventParticipantManagerModule, - OnboardingInviteSuggestionsModule, TimelineActivityModule, StripeModule, FeatureFlagModule, diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts index 2d73e94d2b..5c9a9b08dd 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.resolver.ts @@ -11,6 +11,7 @@ import { type AuthContextUser } from 'src/engine/core-modules/auth/types/auth-co import { OnboardingInviteSuggestionsService } from 'src/modules/onboarding-invite-suggestions/services/onboarding-invite-suggestions.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator'; +import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator'; import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard'; import { UserAuthGuard } from 'src/engine/guards/user-auth.guard'; @@ -31,10 +32,12 @@ export class OnboardingResolver { async getInviteSuggestions( @AuthUser() user: AuthContextUser, @AuthWorkspace() workspace: WorkspaceEntity, + @AuthUserWorkspaceId() userWorkspaceId: string, ): Promise { - return this.onboardingInviteSuggestionsService.getCachedSuggestions({ + return this.onboardingInviteSuggestionsService.getOrComputeSuggestions({ workspaceId: workspace.id, userId: user.id, + userWorkspaceId, }); } diff --git a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts index ea2d44ee9f..d5f415869b 100644 --- a/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts +++ b/packages/twenty-server/src/engine/core-modules/onboarding/onboarding.service.ts @@ -129,43 +129,6 @@ export class OnboardingService { return OnboardingStatus.COMPLETED; } - async isOnboardingConnectAccountPending({ - userId, - workspaceId, - }: { - userId: string; - workspaceId: string; - }): Promise { - const value = await this.userVarsService.get({ - userId, - workspaceId, - key: OnboardingStepKeys.ONBOARDING_CONNECT_ACCOUNT_PENDING, - }); - - return value === true; - } - - async shouldComputeInviteSuggestionsOnConnect({ - userId, - workspaceId, - }: { - userId?: string; - workspaceId: string; - }): Promise { - if (!isDefined(userId)) { - return false; - } - - try { - return await this.isOnboardingConnectAccountPending({ - userId, - workspaceId, - }); - } catch { - return false; - } - } - async setOnboardingConnectAccountPending( { userId, diff --git a/packages/twenty-server/src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job.ts b/packages/twenty-server/src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job.ts deleted file mode 100644 index 614721347a..0000000000 --- a/packages/twenty-server/src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator'; -import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; -import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; -import { OnboardingInviteSuggestionsService } from 'src/modules/onboarding-invite-suggestions/services/onboarding-invite-suggestions.service'; - -export type FetchOnboardingInviteSuggestionsJobData = { - workspaceId: string; - userId: string; - connectedAccountId: string; -}; - -@Processor({ - queueName: MessageQueue.calendarQueue, -}) -export class FetchOnboardingInviteSuggestionsJob { - constructor( - private readonly onboardingInviteSuggestionsService: OnboardingInviteSuggestionsService, - ) {} - - @Process(FetchOnboardingInviteSuggestionsJob.name) - async handle(data: FetchOnboardingInviteSuggestionsJobData): Promise { - await this.onboardingInviteSuggestionsService.computeAndCacheSuggestions( - data, - ); - } -} diff --git a/packages/twenty-server/src/modules/onboarding-invite-suggestions/onboarding-invite-suggestions.module.ts b/packages/twenty-server/src/modules/onboarding-invite-suggestions/onboarding-invite-suggestions.module.ts index 3a8757e1d2..54bde540f5 100644 --- a/packages/twenty-server/src/modules/onboarding-invite-suggestions/onboarding-invite-suggestions.module.ts +++ b/packages/twenty-server/src/modules/onboarding-invite-suggestions/onboarding-invite-suggestions.module.ts @@ -3,7 +3,6 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity'; import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module'; -import { FetchOnboardingInviteSuggestionsJob } from 'src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job'; import { CalendarAttendeesService } from 'src/modules/onboarding-invite-suggestions/services/calendar-attendees.service'; import { GoogleCalendarAttendeesService } from 'src/modules/onboarding-invite-suggestions/services/google-calendar-attendees.service'; import { MicrosoftCalendarAttendeesService } from 'src/modules/onboarding-invite-suggestions/services/microsoft-calendar-attendees.service'; @@ -19,7 +18,6 @@ import { OnboardingInviteSuggestionsService } from 'src/modules/onboarding-invit MicrosoftCalendarAttendeesService, CalendarAttendeesService, OnboardingInviteSuggestionsService, - FetchOnboardingInviteSuggestionsJob, ], exports: [OnboardingInviteSuggestionsService], }) diff --git a/packages/twenty-server/src/modules/onboarding-invite-suggestions/services/onboarding-invite-suggestions.service.ts b/packages/twenty-server/src/modules/onboarding-invite-suggestions/services/onboarding-invite-suggestions.service.ts index 83e13182f0..4f135fca98 100644 --- a/packages/twenty-server/src/modules/onboarding-invite-suggestions/services/onboarding-invite-suggestions.service.ts +++ b/packages/twenty-server/src/modules/onboarding-invite-suggestions/services/onboarding-invite-suggestions.service.ts @@ -9,20 +9,14 @@ import { CacheStorageService } from 'src/engine/core-modules/cache-storage/servi import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity'; import { getDomainNameFromHandle } from 'src/modules/contact-creation-manager/utils/get-domain-name-from-handle.util'; +import { isGroupEmail } from 'src/modules/messaging/message-import-manager/utils/is-group-email'; import { ONBOARDING_INVITE_SUGGESTIONS_CACHE_TTL_MS } from 'src/modules/onboarding-invite-suggestions/constants/onboarding-invite-suggestions-cache-ttl-ms.constant'; import { ONBOARDING_INVITE_SUGGESTIONS_MAX_COUNT } from 'src/modules/onboarding-invite-suggestions/constants/onboarding-invite-suggestions-max-count.constant'; -import { getOnboardingInviteSuggestionsCacheKey } from 'src/modules/onboarding-invite-suggestions/utils/get-onboarding-invite-suggestions-cache-key.util'; -import { isGroupEmail } from 'src/modules/messaging/message-import-manager/utils/is-group-email'; import { CalendarAttendeesService } from 'src/modules/onboarding-invite-suggestions/services/calendar-attendees.service'; import { type CalendarAttendee } from 'src/modules/onboarding-invite-suggestions/types/calendar-attendee.type'; +import { getOnboardingInviteSuggestionsCacheKey } from 'src/modules/onboarding-invite-suggestions/utils/get-onboarding-invite-suggestions-cache-key.util'; import { isWorkEmail } from 'src/utils/is-work-email'; -type ComputeAndCacheSuggestionsArgs = { - workspaceId: string; - userId: string; - connectedAccountId: string; -}; - @Injectable() export class OnboardingInviteSuggestionsService { private readonly logger = new Logger(OnboardingInviteSuggestionsService.name); @@ -35,54 +29,63 @@ export class OnboardingInviteSuggestionsService { private readonly cacheStorageService: CacheStorageService, ) {} - async getCachedSuggestions({ + async getOrComputeSuggestions({ workspaceId, userId, + userWorkspaceId, }: { workspaceId: string; userId: string; + userWorkspaceId: string; }): Promise { - const cachedSuggestions = await this.cacheStorageService.get< - CalendarAttendee[] - >(getOnboardingInviteSuggestionsCacheKey(workspaceId, userId)); - - return cachedSuggestions ?? []; - } - - async computeAndCacheSuggestions({ - workspaceId, - userId, - connectedAccountId, - }: ComputeAndCacheSuggestionsArgs): Promise { const cacheKey = getOnboardingInviteSuggestionsCacheKey( workspaceId, userId, ); - const connectedAccount = await this.connectedAccountRepository.findOne({ - where: { id: connectedAccountId, workspaceId }, - }); + const cachedSuggestions = + await this.cacheStorageService.get(cacheKey); - if (!isDefined(connectedAccount)) { - await this.cacheStorageService.set( - cacheKey, - [], - ONBOARDING_INVITE_SUGGESTIONS_CACHE_TTL_MS, - ); - - return; + if (isDefined(cachedSuggestions)) { + return cachedSuggestions; } - const connectedAccountHandle = connectedAccount.handle.toLowerCase(); + const suggestions = await this.computeSuggestionsFromConnectedAccount({ + workspaceId, + userWorkspaceId, + }); + + await this.cacheStorageService.set( + cacheKey, + suggestions, + ONBOARDING_INVITE_SUGGESTIONS_CACHE_TTL_MS, + ); + + return suggestions; + } + + private async computeSuggestionsFromConnectedAccount({ + workspaceId, + userWorkspaceId, + }: { + workspaceId: string; + userWorkspaceId: string; + }): Promise { + const mostRecentlyConnectedAccount = + await this.connectedAccountRepository.findOne({ + where: { userWorkspaceId, workspaceId }, + order: { createdAt: 'DESC' }, + }); + + if (!isDefined(mostRecentlyConnectedAccount)) { + return []; + } + + const connectedAccountHandle = + mostRecentlyConnectedAccount.handle.toLowerCase(); if (!isWorkEmail(connectedAccountHandle)) { - await this.cacheStorageService.set( - cacheKey, - [], - ONBOARDING_INVITE_SUGGESTIONS_CACHE_TTL_MS, - ); - - return; + return []; } const connectedAccountDomain = getDomainNameFromHandle( @@ -90,7 +93,7 @@ export class OnboardingInviteSuggestionsService { ); const ownEmailHandles = new Set([ connectedAccountHandle, - ...(connectedAccount.handleAliases ?? []).map((alias) => + ...(mostRecentlyConnectedAccount.handleAliases ?? []).map((alias) => alias.toLowerCase(), ), ]); @@ -98,10 +101,9 @@ export class OnboardingInviteSuggestionsService { let attendees: CalendarAttendee[] = []; try { - attendees = - await this.calendarAttendeesService.getRecentAttendees( - connectedAccount, - ); + attendees = await this.calendarAttendeesService.getRecentAttendees( + mostRecentlyConnectedAccount, + ); } catch (error) { this.logger.warn( `Could not compute invite suggestions for workspace ${workspaceId}: ${ @@ -150,14 +152,8 @@ export class OnboardingInviteSuggestionsService { eventCountByColleagueEmail.entries(), ).sort(([, left], [, right]) => right.eventCount - left.eventCount); - const suggestions: CalendarAttendee[] = mostFrequentColleaguesFirst + return mostFrequentColleaguesFirst .slice(0, ONBOARDING_INVITE_SUGGESTIONS_MAX_COUNT) .map(([email, { displayName }]) => ({ email, displayName })); - - await this.cacheStorageService.set( - cacheKey, - suggestions, - ONBOARDING_INVITE_SUGGESTIONS_CACHE_TTL_MS, - ); } }