From 9509c737e032ad6528ccadfce93dbe16fa434b2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?=
<71827178+bosiraphael@users.noreply.github.com>
Date: Tue, 28 Jul 2026 16:46:52 +0200
Subject: [PATCH] Replace the onboarding AI chat feature flag with an
environment variable (#23439)
Follow-up to #23199.
The AI-chat onboarding is an instance-level rollout decision, not a
per-workspace experiment, so `IS_ONBOARDING_AI_CHAT_ENABLED` becomes an
instance config variable (default `false`, editable from the admin
panel) exposed to the frontend through `ClientConfig`. The workspace
feature flag is deleted; leftover `featureFlag` rows are inert since the
column is plain text.
`IS_WORKSPACE_COMPANY_ENRICHMENT_ENABLED` is removed as redundant: the
PDL client already skips everything when no API key is set. Enrichment
now runs when the AI chat is on and `PEOPLE_DATA_LABS_API_KEY` is
configured.
---
.../src/metadata/generated/schema.graphql | 2 +-
.../src/metadata/generated/schema.ts | 5 ++-
.../src/metadata/generated/types.ts | 3 ++
.../src/generated-admin/graphql.ts | 1 -
.../src/generated-metadata/graphql.ts | 2 +-
.../client-config/hooks/useClientConfig.ts | 9 +++++
.../states/isOnboardingAiChatEnabledState.ts | 6 +++
.../client-config/types/ClientConfig.ts | 1 +
.../CompanyEnrichmentOnboardingEffect.tsx | 8 ++--
...CompanyEnrichmentOnboardingEffect.test.tsx | 10 ++---
.../useSetNextOnboardingStatus.test.ts | 18 ++++-----
.../hooks/useSetNextOnboardingStatus.ts | 8 ++--
...WelcomeAnimationAfterOnboardingCheckout.ts | 10 ++---
.../SidePanelExpandAiChatButton.tsx | 7 ++--
.../src/pages/onboarding/WorkspaceSetup.tsx | 7 ++--
.../__tests__/WorkspaceSetup.test.tsx | 21 ++++------
.../src/testing/mock-data/config.ts | 1 +
packages/twenty-server/.env.example | 9 +++--
.../client-config.controller.spec.ts | 1 +
.../client-config/client-config.entity.ts | 3 ++
.../services/client-config.service.spec.ts | 2 +
.../services/client-config.service.ts | 3 ++
.../company-enrichment.module.ts | 2 -
.../company-enrichment.service.spec.ts | 38 +++----------------
.../services/company-enrichment.service.ts | 15 +-------
.../twenty-config/config-variables.ts | 4 +-
.../twenty-config/twenty-config.service.ts | 4 --
.../workspace-entity-manager.spec.ts | 1 -
.../core/utils/seed-feature-flags.util.ts | 5 ---
.../twenty-shared/src/types/FeatureFlagKey.ts | 1 -
30 files changed, 85 insertions(+), 122 deletions(-)
create mode 100644 packages/twenty-front/src/modules/client-config/states/isOnboardingAiChatEnabledState.ts
diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql
index f23c43e0f4..ccab90f7d3 100644
--- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql
+++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql
@@ -1756,7 +1756,6 @@ enum FeatureFlagKey {
IS_JUNCTION_RELATIONS_ENABLED
IS_REST_METADATA_API_NEW_FORMAT_DIRECT
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED
- IS_ONBOARDING_AI_CHAT_ENABLED
IS_SETTINGS_DISCOVERY_HERO_ENABLED
IS_WORKFLOW_VERSION_IN_CORE_ENABLED
}
@@ -1960,6 +1959,7 @@ type ClientConfig {
isCloudflareIntegrationEnabled: Boolean!
isClickHouseConfigured: Boolean!
isWorkspaceSchemaDDLLocked: Boolean!
+ isOnboardingAiChatEnabled: Boolean!
enterpriseInstanceType: String!
maintenance: ClientConfigMaintenanceMode
}
diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts
index 2d9d6f9d2c..698d737246 100644
--- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts
+++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts
@@ -1406,7 +1406,7 @@ export interface FeatureFlag {
__typename: 'FeatureFlag'
}
-export type FeatureFlagKey = 'IS_APP_CLAIMING_ENABLED' | 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_CALENDAR_WEEK_VIEW_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_ONBOARDING_AI_CHAT_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_WORKFLOW_VERSION_IN_CORE_ENABLED'
+export type FeatureFlagKey = 'IS_APP_CLAIMING_ENABLED' | 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_CALENDAR_WEEK_VIEW_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_WORKFLOW_VERSION_IN_CORE_ENABLED'
export interface WorkspaceUrls {
customUrl?: Scalars['String']
@@ -1608,6 +1608,7 @@ export interface ClientConfig {
isCloudflareIntegrationEnabled: Scalars['Boolean']
isClickHouseConfigured: Scalars['Boolean']
isWorkspaceSchemaDDLLocked: Scalars['Boolean']
+ isOnboardingAiChatEnabled: Scalars['Boolean']
enterpriseInstanceType: Scalars['String']
maintenance?: ClientConfigMaintenanceMode
__typename: 'ClientConfig'
@@ -4786,6 +4787,7 @@ export interface ClientConfigGenqlSelection{
isCloudflareIntegrationEnabled?: boolean | number
isClickHouseConfigured?: boolean | number
isWorkspaceSchemaDDLLocked?: boolean | number
+ isOnboardingAiChatEnabled?: boolean | number
enterpriseInstanceType?: boolean | number
maintenance?: ClientConfigMaintenanceModeGenqlSelection
__typename?: boolean | number
@@ -9416,7 +9418,6 @@ export const enumFeatureFlagKey = {
IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const,
IS_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const,
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED: 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' as const,
- IS_ONBOARDING_AI_CHAT_ENABLED: 'IS_ONBOARDING_AI_CHAT_ENABLED' as const,
IS_SETTINGS_DISCOVERY_HERO_ENABLED: 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' as const,
IS_WORKFLOW_VERSION_IN_CORE_ENABLED: 'IS_WORKFLOW_VERSION_IN_CORE_ENABLED' as const
}
diff --git a/packages/twenty-client-sdk/src/metadata/generated/types.ts b/packages/twenty-client-sdk/src/metadata/generated/types.ts
index 4940e1a1eb..fa57af4f45 100644
--- a/packages/twenty-client-sdk/src/metadata/generated/types.ts
+++ b/packages/twenty-client-sdk/src/metadata/generated/types.ts
@@ -3802,6 +3802,9 @@ export default {
"isWorkspaceSchemaDDLLocked": [
3
],
+ "isOnboardingAiChatEnabled": [
+ 3
+ ],
"enterpriseInstanceType": [
1
],
diff --git a/packages/twenty-front/src/generated-admin/graphql.ts b/packages/twenty-front/src/generated-admin/graphql.ts
index 55d4107b18..9dee07bc19 100644
--- a/packages/twenty-front/src/generated-admin/graphql.ts
+++ b/packages/twenty-front/src/generated-admin/graphql.ts
@@ -326,7 +326,6 @@ export enum FeatureFlagKey {
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED = 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED',
- IS_ONBOARDING_AI_CHAT_ENABLED = 'IS_ONBOARDING_AI_CHAT_ENABLED',
IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
IS_SETTINGS_DISCOVERY_HERO_ENABLED = 'IS_SETTINGS_DISCOVERY_HERO_ENABLED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts
index 9e2d4e61fd..08e9f13914 100644
--- a/packages/twenty-front/src/generated-metadata/graphql.ts
+++ b/packages/twenty-front/src/generated-metadata/graphql.ts
@@ -956,6 +956,7 @@ export type ClientConfig = {
isMicrosoftCalendarEnabled: Scalars['Boolean']['output'];
isMicrosoftMessagingEnabled: Scalars['Boolean']['output'];
isMultiWorkspaceEnabled: Scalars['Boolean']['output'];
+ isOnboardingAiChatEnabled: Scalars['Boolean']['output'];
isWorkspaceSchemaDDLLocked: Scalars['Boolean']['output'];
maintenance?: Maybe;
publicFeatureFlags: Array;
@@ -1772,7 +1773,6 @@ export enum FeatureFlagKey {
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED = 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED',
- IS_ONBOARDING_AI_CHAT_ENABLED = 'IS_ONBOARDING_AI_CHAT_ENABLED',
IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
IS_SETTINGS_DISCOVERY_HERO_ENABLED = 'IS_SETTINGS_DISCOVERY_HERO_ENABLED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
diff --git a/packages/twenty-front/src/modules/client-config/hooks/useClientConfig.ts b/packages/twenty-front/src/modules/client-config/hooks/useClientConfig.ts
index 8bc1e25d54..f1b1c14c3a 100644
--- a/packages/twenty-front/src/modules/client-config/hooks/useClientConfig.ts
+++ b/packages/twenty-front/src/modules/client-config/hooks/useClientConfig.ts
@@ -24,6 +24,7 @@ import { maintenanceModeState } from '@/client-config/states/maintenanceModeStat
import { isMicrosoftCalendarEnabledState } from '@/client-config/states/isMicrosoftCalendarEnabledState';
import { isMicrosoftMessagingEnabledState } from '@/client-config/states/isMicrosoftMessagingEnabledState';
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState';
import { sentryConfigState } from '@/client-config/states/sentryConfigState';
import { supportChatState } from '@/client-config/states/supportChatState';
@@ -126,6 +127,10 @@ export const useClientConfig = (): UseClientConfigResult => {
const setIsDDLLocked = useSetAtomState(isDDLLockedState);
+ const setIsOnboardingAiChatEnabled = useSetAtomState(
+ isOnboardingAiChatEnabledState,
+ );
+
const setMaintenanceMode = useSetAtomState(maintenanceModeState);
const setEnterpriseInstanceType = useSetAtomState(
@@ -215,6 +220,9 @@ export const useClientConfig = (): UseClientConfigResult => {
);
setIsClickHouseConfigured(clientConfig?.isClickHouseConfigured ?? false);
setIsDDLLocked(clientConfig?.isWorkspaceSchemaDDLLocked ?? false);
+ setIsOnboardingAiChatEnabled(
+ clientConfig?.isOnboardingAiChatEnabled ?? false,
+ );
setMaintenanceMode(clientConfig?.maintenance ?? null);
setEnterpriseInstanceType(
clientConfig?.enterpriseInstanceType ??
@@ -256,6 +264,7 @@ export const useClientConfig = (): UseClientConfigResult => {
setIsClickHouseConfigured,
setIsCloudflareIntegrationEnabled,
setIsDDLLocked,
+ setIsOnboardingAiChatEnabled,
setLabPublicFeatureFlags,
setMaintenanceMode,
setEnterpriseInstanceType,
diff --git a/packages/twenty-front/src/modules/client-config/states/isOnboardingAiChatEnabledState.ts b/packages/twenty-front/src/modules/client-config/states/isOnboardingAiChatEnabledState.ts
new file mode 100644
index 0000000000..f0115e964d
--- /dev/null
+++ b/packages/twenty-front/src/modules/client-config/states/isOnboardingAiChatEnabledState.ts
@@ -0,0 +1,6 @@
+import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
+
+export const isOnboardingAiChatEnabledState = createAtomState({
+ key: 'isOnboardingAiChatEnabledState',
+ defaultValue: false,
+});
diff --git a/packages/twenty-front/src/modules/client-config/types/ClientConfig.ts b/packages/twenty-front/src/modules/client-config/types/ClientConfig.ts
index 33ce41b14f..c30f5189ca 100644
--- a/packages/twenty-front/src/modules/client-config/types/ClientConfig.ts
+++ b/packages/twenty-front/src/modules/client-config/types/ClientConfig.ts
@@ -38,6 +38,7 @@ export type ClientConfig = {
isCloudflareIntegrationEnabled: boolean;
isClickHouseConfigured: boolean;
isWorkspaceSchemaDDLLocked: boolean;
+ isOnboardingAiChatEnabled: boolean;
onboarding: OnboardingConfig;
publicFeatureFlags: Array;
sentry: Sentry;
diff --git a/packages/twenty-front/src/modules/onboarding/effect-components/CompanyEnrichmentOnboardingEffect.tsx b/packages/twenty-front/src/modules/onboarding/effect-components/CompanyEnrichmentOnboardingEffect.tsx
index 0577315f43..6b39d9a558 100644
--- a/packages/twenty-front/src/modules/onboarding/effect-components/CompanyEnrichmentOnboardingEffect.tsx
+++ b/packages/twenty-front/src/modules/onboarding/effect-components/CompanyEnrichmentOnboardingEffect.tsx
@@ -3,14 +3,14 @@ import { useEffect } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { type WorkspaceCompanyEnrichment } from 'twenty-shared/workspace';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
import { companyEnrichmentState } from '@/onboarding/states/companyEnrichmentState';
import { hasAttemptedCompanyEnrichmentFetchState } from '@/onboarding/states/hasAttemptedCompanyEnrichmentFetchState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
+import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import {
EnrichWorkspaceCompanyDocument,
- FeatureFlagKey,
OnboardingStatus,
WorkspaceCompanyEnrichmentOutcome,
} from '~/generated-metadata/graphql';
@@ -25,8 +25,8 @@ export const CompanyEnrichmentOnboardingEffect = () => {
setHasAttemptedCompanyEnrichmentFetch,
] = useAtomState(hasAttemptedCompanyEnrichmentFetchState);
const [enrichWorkspaceCompany] = useMutation(EnrichWorkspaceCompanyDocument);
- const isOnboardingAiChatEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
+ const isOnboardingAiChatEnabled = useAtomStateValue(
+ isOnboardingAiChatEnabledState,
);
const isOnboardingInProgress =
diff --git a/packages/twenty-front/src/modules/onboarding/effect-components/__tests__/CompanyEnrichmentOnboardingEffect.test.tsx b/packages/twenty-front/src/modules/onboarding/effect-components/__tests__/CompanyEnrichmentOnboardingEffect.test.tsx
index 501f17d931..cfc5fac0db 100644
--- a/packages/twenty-front/src/modules/onboarding/effect-components/__tests__/CompanyEnrichmentOnboardingEffect.test.tsx
+++ b/packages/twenty-front/src/modules/onboarding/effect-components/__tests__/CompanyEnrichmentOnboardingEffect.test.tsx
@@ -4,6 +4,7 @@ import { GraphQLError } from 'graphql';
import { Provider as JotaiProvider } from 'jotai';
import { type WorkspaceCompanyEnrichment } from 'twenty-shared/workspace';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { CompanyEnrichmentOnboardingEffect } from '@/onboarding/effect-components/CompanyEnrichmentOnboardingEffect';
import { companyEnrichmentState } from '@/onboarding/states/companyEnrichmentState';
import { hasAttemptedCompanyEnrichmentFetchState } from '@/onboarding/states/hasAttemptedCompanyEnrichmentFetchState';
@@ -17,16 +18,11 @@ import {
} from '~/generated-metadata/graphql';
const mockOnboardingStatus = jest.fn();
-const mockIsOnboardingAiChatEnabled = jest.fn();
jest.mock('@/onboarding/hooks/useOnboardingStatus', () => ({
useOnboardingStatus: () => mockOnboardingStatus(),
}));
-jest.mock('@/workspace/hooks/useIsFeatureEnabled', () => ({
- useIsFeatureEnabled: () => mockIsOnboardingAiChatEnabled(),
-}));
-
const enrichment: WorkspaceCompanyEnrichment = {
domain: 'acme.com',
enrichedAt: '2026-07-21T10:00:00.000Z',
@@ -89,7 +85,7 @@ describe('CompanyEnrichmentOnboardingEffect', () => {
resetJotaiStore();
localStorage.clear();
mockOnboardingStatus.mockReturnValue(OnboardingStatus.PROFILE_CREATION);
- mockIsOnboardingAiChatEnabled.mockReturnValue(true);
+ jotaiStore.set(isOnboardingAiChatEnabledState.atom, true);
});
afterEach(() => {
@@ -156,7 +152,7 @@ describe('CompanyEnrichmentOnboardingEffect', () => {
);
it('does not fetch when onboarding AI chat is disabled', async () => {
- mockIsOnboardingAiChatEnabled.mockReturnValue(false);
+ jotaiStore.set(isOnboardingAiChatEnabledState.atom, false);
let callCount = 0;
renderEffect([
diff --git a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts
index 30743c6181..276419e71b 100644
--- a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts
+++ b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts
@@ -6,6 +6,7 @@ import { currentUserState } from '@/auth/states/currentUserState';
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { billingState } from '@/client-config/states/billingState';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus';
import { isWelcomeAnimationVisibleState } from '@/onboarding/states/isWelcomeAnimationVisibleState';
import { shouldOpenAiChatAfterOnboardingState } from '@/onboarding/states/shouldOpenAiChatAfterOnboardingState';
@@ -17,7 +18,7 @@ import {
resetJotaiStore,
} from '@/ui/utilities/state/jotai/jotaiStore';
-import { FeatureFlagKey, OnboardingStatus } from '~/generated-metadata/graphql';
+import { OnboardingStatus } from '~/generated-metadata/graphql';
import {
mockCurrentWorkspace,
mockedUserData,
@@ -42,6 +43,11 @@ const renderHooks = (
isOnboardingAiChatEnabled = false,
}: RenderHooksOptions = {},
) => {
+ jotaiStore.set(
+ isOnboardingAiChatEnabledState.atom,
+ isOnboardingAiChatEnabled,
+ );
+
const { result } = renderHook(
() => {
const [currentUser, setCurrentUser] = useAtomState(currentUserState);
@@ -81,12 +87,6 @@ const renderHooks = (
? mockCurrentWorkspace.billingSubscriptions
: [],
workspaceMembersCount: withOneWorkspaceMember ? 1 : 2,
- featureFlags: [
- {
- key: FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
- value: isOnboardingAiChatEnabled,
- },
- ],
});
result.current.setBilling({
__typename: 'Billing',
@@ -257,7 +257,7 @@ describe('useSetNextOnboardingStatus', () => {
expect(shouldOpenAiChatAfterOnboarding).toBe(false);
});
- it('should open the ai chat after onboarding when the feature flag is enabled', () => {
+ it('should open the ai chat after onboarding when it is enabled', () => {
const { isWelcomeAnimationVisible, shouldOpenAiChatAfterOnboarding } =
renderHooks(OnboardingStatus.INVITE_TEAM, {
isOnboardingAiChatEnabled: true,
@@ -266,7 +266,7 @@ describe('useSetNextOnboardingStatus', () => {
expect(shouldOpenAiChatAfterOnboarding).toBe(true);
});
- it('should still show the welcome animation when the ai chat feature flag is disabled', () => {
+ it('should still show the welcome animation when the ai chat is disabled', () => {
const { isWelcomeAnimationVisible, shouldOpenAiChatAfterOnboarding } =
renderHooks(OnboardingStatus.INVITE_TEAM, {
isOnboardingAiChatEnabled: false,
diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts
index 227941b8e6..b1c4ffe298 100644
--- a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts
+++ b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts
@@ -9,15 +9,15 @@ import {
currentWorkspaceState,
} from '@/auth/states/currentWorkspaceState';
import { billingState } from '@/client-config/states/billingState';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { isWelcomeAnimationVisibleState } from '@/onboarding/states/isWelcomeAnimationVisibleState';
import { shouldOpenAiChatAfterOnboardingState } from '@/onboarding/states/shouldOpenAiChatAfterOnboardingState';
import { getHasJustCompletedOnboarding } from '@/onboarding/utils/getHasJustCompletedOnboarding';
import { getIsPlanRequired } from '@/onboarding/utils/getIsPlanRequired';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useCallback } from 'react';
-import { FeatureFlagKey, OnboardingStatus } from '~/generated-metadata/graphql';
+import { OnboardingStatus } from '~/generated-metadata/graphql';
import { useStore } from 'jotai';
type GetNextOnboardingStatusArgs = {
@@ -73,8 +73,8 @@ export const useSetNextOnboardingStatus = () => {
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
const billing = useAtomStateValue(billingState);
const isBillingEnabled = billing?.isBillingEnabled ?? false;
- const isOnboardingAiChatEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
+ const isOnboardingAiChatEnabled = useAtomStateValue(
+ isOnboardingAiChatEnabledState,
);
return useCallback(() => {
diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useShowWelcomeAnimationAfterOnboardingCheckout.ts b/packages/twenty-front/src/modules/onboarding/hooks/useShowWelcomeAnimationAfterOnboardingCheckout.ts
index fbde78ce97..52d2e3ffad 100644
--- a/packages/twenty-front/src/modules/onboarding/hooks/useShowWelcomeAnimationAfterOnboardingCheckout.ts
+++ b/packages/twenty-front/src/modules/onboarding/hooks/useShowWelcomeAnimationAfterOnboardingCheckout.ts
@@ -1,11 +1,10 @@
import { currentUserState } from '@/auth/states/currentUserState';
-import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
-import { checkIfFeatureFlagIsEnabledOnWorkspace } from '@/workspace/utils/checkIfFeatureFlagIsEnabledOnWorkspace';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { isOnboardingCheckoutPendingState } from '@/onboarding/states/isOnboardingCheckoutPendingState';
import { isWelcomeAnimationVisibleState } from '@/onboarding/states/isWelcomeAnimationVisibleState';
import { shouldOpenAiChatAfterOnboardingState } from '@/onboarding/states/shouldOpenAiChatAfterOnboardingState';
import { useStore } from 'jotai';
-import { FeatureFlagKey, OnboardingStatus } from '~/generated-metadata/graphql';
+import { OnboardingStatus } from '~/generated-metadata/graphql';
export const useShowWelcomeAnimationAfterOnboardingCheckout = () => {
const store = useStore();
@@ -21,9 +20,8 @@ export const useShowWelcomeAnimationAfterOnboardingCheckout = () => {
return;
}
- const isOnboardingAiChatEnabled = checkIfFeatureFlagIsEnabledOnWorkspace(
- FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
- store.get(currentWorkspaceState.atom),
+ const isOnboardingAiChatEnabled = store.get(
+ isOnboardingAiChatEnabledState.atom,
);
store.set(isOnboardingCheckoutPendingState.atom, false);
diff --git a/packages/twenty-front/src/modules/side-panel/components/SidePanelExpandAiChatButton.tsx b/packages/twenty-front/src/modules/side-panel/components/SidePanelExpandAiChatButton.tsx
index edc0c9b3c7..a4a1f642a5 100644
--- a/packages/twenty-front/src/modules/side-panel/components/SidePanelExpandAiChatButton.tsx
+++ b/packages/twenty-front/src/modules/side-panel/components/SidePanelExpandAiChatButton.tsx
@@ -6,11 +6,10 @@ import { IconButton } from 'twenty-ui/input';
import { useIsMobile } from 'twenty-ui/utilities';
import { aiChatExpandedReturnLocationState } from '@/ai/states/aiChatExpandedReturnLocationState';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { sidePanelPageState } from '@/side-panel/states/sidePanelPageState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
-import { FeatureFlagKey } from '~/generated-metadata/graphql';
export const SidePanelExpandAiChatButton = () => {
const { t } = useLingui();
@@ -18,8 +17,8 @@ export const SidePanelExpandAiChatButton = () => {
const location = useLocation();
const isMobile = useIsMobile();
const sidePanelPage = useAtomStateValue(sidePanelPageState);
- const isOnboardingAiChatEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
+ const isOnboardingAiChatEnabled = useAtomStateValue(
+ isOnboardingAiChatEnabledState,
);
const setAiChatExpandedReturnLocation = useSetAtomState(
aiChatExpandedReturnLocationState,
diff --git a/packages/twenty-front/src/pages/onboarding/WorkspaceSetup.tsx b/packages/twenty-front/src/pages/onboarding/WorkspaceSetup.tsx
index e640945a9f..84bb8d6ae8 100644
--- a/packages/twenty-front/src/pages/onboarding/WorkspaceSetup.tsx
+++ b/packages/twenty-front/src/pages/onboarding/WorkspaceSetup.tsx
@@ -5,13 +5,12 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
import { AiChatMessageListPreambleContext } from '@/ai/contexts/AiChatMessageListPreambleContext';
import { AiChatTab } from '@/ai/components/AiChatTab';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
import { WorkspaceSetupChatPreamble } from '@/onboarding/components/WorkspaceSetupChatPreamble';
import { WorkspaceSetupHeader } from '@/onboarding/components/WorkspaceSetupHeader';
import { shouldOpenAiChatAfterOnboardingState } from '@/onboarding/states/shouldOpenAiChatAfterOnboardingState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
-import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
-import { FeatureFlagKey } from '~/generated-metadata/graphql';
const PANEL_CORNER_RADIUS_DERIVED_FROM_THEME_SCALE = `calc(${themeCssVariables.border.radius.md} + ${themeCssVariables.spacing[1]})`;
@@ -39,8 +38,8 @@ const StyledContent = styled.div`
export const WorkspaceSetup = () => {
const { t } = useLingui();
const { defaultHomePagePath } = useDefaultHomePagePath();
- const isOnboardingAiChatEnabled = useIsFeatureEnabled(
- FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
+ const isOnboardingAiChatEnabled = useAtomStateValue(
+ isOnboardingAiChatEnabledState,
);
const shouldOpenAiChatAfterOnboarding = useAtomStateValue(
shouldOpenAiChatAfterOnboardingState,
diff --git a/packages/twenty-front/src/pages/onboarding/__tests__/WorkspaceSetup.test.tsx b/packages/twenty-front/src/pages/onboarding/__tests__/WorkspaceSetup.test.tsx
index 59b3998244..827a8b65ac 100644
--- a/packages/twenty-front/src/pages/onboarding/__tests__/WorkspaceSetup.test.tsx
+++ b/packages/twenty-front/src/pages/onboarding/__tests__/WorkspaceSetup.test.tsx
@@ -5,16 +5,14 @@ import { Provider as JotaiProvider } from 'jotai';
import { type ReactNode } from 'react';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
-import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
+import { isOnboardingAiChatEnabledState } from '@/client-config/states/isOnboardingAiChatEnabledState';
import { shouldOpenAiChatAfterOnboardingState } from '@/onboarding/states/shouldOpenAiChatAfterOnboardingState';
import {
jotaiStore,
resetJotaiStore,
} from '@/ui/utilities/state/jotai/jotaiStore';
-import { FeatureFlagKey } from '~/generated-metadata/graphql';
import { messages } from '~/locales/generated/en';
import { WorkspaceSetup } from '~/pages/onboarding/WorkspaceSetup';
-import { mockCurrentWorkspace } from '~/testing/mock-data/users';
i18n.load({ [SOURCE_LOCALE]: messages });
i18n.activate(SOURCE_LOCALE);
@@ -57,13 +55,8 @@ jest.mock('react-router-dom', () => ({
},
}));
-const setOnboardingAiChatFeatureFlag = (value: boolean) => {
- jotaiStore.set(currentWorkspaceState.atom, {
- ...mockCurrentWorkspace,
- featureFlags: [
- { key: FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED, value },
- ],
- });
+const setIsOnboardingAiChatEnabled = (value: boolean) => {
+ jotaiStore.set(isOnboardingAiChatEnabledState.atom, value);
};
const Wrapper = ({ children }: { children: ReactNode }) => (
@@ -80,7 +73,7 @@ describe('WorkspaceSetup', () => {
});
it('should dress the chat for onboarding when the post-onboarding hint is set', () => {
- setOnboardingAiChatFeatureFlag(true);
+ setIsOnboardingAiChatEnabled(true);
jotaiStore.set(shouldOpenAiChatAfterOnboardingState.atom, true);
const { getByTestId } = render(, { wrapper: Wrapper });
@@ -91,7 +84,7 @@ describe('WorkspaceSetup', () => {
});
it('should render a plain chat when the post-onboarding hint is not set', () => {
- setOnboardingAiChatFeatureFlag(true);
+ setIsOnboardingAiChatEnabled(true);
const { getByTestId, queryByTestId } = render(, {
wrapper: Wrapper,
@@ -102,8 +95,8 @@ describe('WorkspaceSetup', () => {
expect(getByTestId('header-title')).toHaveTextContent('Ask AI');
});
- it('should redirect home when the onboarding ai chat feature flag is disabled', () => {
- setOnboardingAiChatFeatureFlag(false);
+ it('should redirect home when the onboarding ai chat is disabled', () => {
+ setIsOnboardingAiChatEnabled(false);
const { queryByTestId } = render(, { wrapper: Wrapper });
diff --git a/packages/twenty-front/src/testing/mock-data/config.ts b/packages/twenty-front/src/testing/mock-data/config.ts
index 3bbe5494f4..f0046b9a18 100644
--- a/packages/twenty-front/src/testing/mock-data/config.ts
+++ b/packages/twenty-front/src/testing/mock-data/config.ts
@@ -66,4 +66,5 @@ export const mockedClientConfig: ClientConfig = {
isCloudflareIntegrationEnabled: false,
isClickHouseConfigured: false,
isWorkspaceSchemaDDLLocked: false,
+ isOnboardingAiChatEnabled: false,
};
diff --git a/packages/twenty-server/.env.example b/packages/twenty-server/.env.example
index 70ef8d259e..881eaa1bfc 100644
--- a/packages/twenty-server/.env.example
+++ b/packages/twenty-server/.env.example
@@ -86,10 +86,11 @@ FRONTEND_URL=http://localhost:3001
# HTTP_TOOL_SAFE_MODE_ENABLED=true
# ALLOW_REQUESTS_TO_TWENTY_ICONS=true
-# ———————— ENRICHMENT ————————
-# Enriches a new workspace with its own company data, used as AI chat context.
-# Disabled by default; requires both the flag and the API key.
-# IS_WORKSPACE_COMPANY_ENRICHMENT_ENABLED=true
+# ———————— ONBOARDING AI CHAT ————————
+# Opens an AI chat at the end of onboarding to help set up the workspace.
+# IS_ONBOARDING_AI_CHAT_ENABLED=true
+# Enriches the new workspace with its own company data, used as chat context.
+# Active as soon as the API key is set.
# PEOPLE_DATA_LABS_API_KEY=
# ———————— AI ————————
diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.controller.spec.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.controller.spec.ts
index 86dcfce567..49699e1948 100644
--- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.controller.spec.ts
+++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.controller.spec.ts
@@ -109,6 +109,7 @@ describe('ClientConfigController', () => {
isCloudflareIntegrationEnabled: false,
isClickHouseConfigured: false,
isWorkspaceSchemaDDLLocked: false,
+ isOnboardingAiChatEnabled: false,
enterpriseInstanceType: ENTERPRISE_INSTANCE_TYPE.PRODUCTION,
};
diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts
index 22f3e7113e..ab17464146 100644
--- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts
+++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts
@@ -345,6 +345,9 @@ export class ClientConfig {
@Field(() => Boolean)
isWorkspaceSchemaDDLLocked: boolean;
+ @Field(() => Boolean)
+ isOnboardingAiChatEnabled: boolean;
+
@Field(() => String)
enterpriseInstanceType: string;
diff --git a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts
index 5ad07bd1d6..4c809afe37 100644
--- a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts
+++ b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts
@@ -110,6 +110,7 @@ describe('ClientConfigService', () => {
CLOUDFLARE_ZONE_ID: undefined,
ALLOW_REQUESTS_TO_TWENTY_ICONS: false,
CLICKHOUSE_URL: undefined,
+ IS_ONBOARDING_AI_CHAT_ENABLED: false,
};
return mockValues[key];
@@ -191,6 +192,7 @@ describe('ClientConfigService', () => {
calendarBookingPageId: 'team/twenty/talk-to-us',
isCloudflareIntegrationEnabled: false,
isClickHouseConfigured: false,
+ isOnboardingAiChatEnabled: false,
enterpriseInstanceType: ENTERPRISE_INSTANCE_TYPE.PRODUCTION,
});
});
diff --git a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts
index ac735924b3..f63f6f93fb 100644
--- a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts
@@ -281,6 +281,9 @@ export class ClientConfigService {
isWorkspaceSchemaDDLLocked: this.twentyConfigService.get(
'WORKSPACE_SCHEMA_DDL_LOCKED',
),
+ isOnboardingAiChatEnabled: this.twentyConfigService.get(
+ 'IS_ONBOARDING_AI_CHAT_ENABLED',
+ ),
enterpriseInstanceType:
this.twentyConfigService.get('ENTERPRISE_INSTANCE_TYPE') ??
ENTERPRISE_INSTANCE_TYPE.PRODUCTION,
diff --git a/packages/twenty-server/src/engine/core-modules/company-enrichment/company-enrichment.module.ts b/packages/twenty-server/src/engine/core-modules/company-enrichment/company-enrichment.module.ts
index 94c8d8f745..ae7e7c7b05 100644
--- a/packages/twenty-server/src/engine/core-modules/company-enrichment/company-enrichment.module.ts
+++ b/packages/twenty-server/src/engine/core-modules/company-enrichment/company-enrichment.module.ts
@@ -4,7 +4,6 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { CompanyEnrichmentResolver } from 'src/engine/core-modules/company-enrichment/resolvers/company-enrichment.resolver';
import { CompanyEnrichmentService } from 'src/engine/core-modules/company-enrichment/services/company-enrichment.service';
import { PeopleDataLabsCompanyClientService } from 'src/engine/core-modules/company-enrichment/services/people-data-labs-company-client.service';
-import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { KeyValuePairModule } from 'src/engine/core-modules/key-value-pair/key-value-pair.module';
import { SecureHttpClientModule } from 'src/engine/core-modules/secure-http-client/secure-http-client.module';
import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module';
@@ -13,7 +12,6 @@ import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user
@Module({
imports: [
TypeOrmModule.forFeature([UserWorkspaceEntity]),
- FeatureFlagModule,
KeyValuePairModule,
SecureHttpClientModule,
ThrottlerModule,
diff --git a/packages/twenty-server/src/engine/core-modules/company-enrichment/services/__tests__/company-enrichment.service.spec.ts b/packages/twenty-server/src/engine/core-modules/company-enrichment/services/__tests__/company-enrichment.service.spec.ts
index 498c782d84..ce6a7d16fd 100644
--- a/packages/twenty-server/src/engine/core-modules/company-enrichment/services/__tests__/company-enrichment.service.spec.ts
+++ b/packages/twenty-server/src/engine/core-modules/company-enrichment/services/__tests__/company-enrichment.service.spec.ts
@@ -3,7 +3,6 @@ import { getRepositoryToken } from '@nestjs/typeorm';
import { CompanyEnrichmentService } from 'src/engine/core-modules/company-enrichment/services/company-enrichment.service';
import { PeopleDataLabsCompanyClientService } from 'src/engine/core-modules/company-enrichment/services/people-data-labs-company-client.service';
-import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { COMPANY_ENRICHMENT_ATTEMPT_KEY } from 'src/engine/core-modules/company-enrichment/types/company-enrichment-attempt-key-value.type';
import { KeyValuePairType } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
import { KeyValuePairService } from 'src/engine/core-modules/key-value-pair/key-value-pair.service';
@@ -24,8 +23,7 @@ describe('CompanyEnrichmentService', () => {
};
let throttlerService: { tokenBucketThrottleOrThrow: jest.Mock };
let keyValuePairService: { set: jest.Mock };
- let twentyConfigService: { isWorkspaceCompanyEnrichmentEnabled: jest.Mock };
- let featureFlagService: { isFeatureEnabled: jest.Mock };
+ let twentyConfigService: { get: jest.Mock };
const workspaceId = 'workspace-id';
const creatorUserId = 'creator-user-id';
@@ -41,10 +39,7 @@ describe('CompanyEnrichmentService', () => {
throttlerService = { tokenBucketThrottleOrThrow: jest.fn() };
keyValuePairService = { set: jest.fn() };
twentyConfigService = {
- isWorkspaceCompanyEnrichmentEnabled: jest.fn().mockReturnValue(true),
- };
- featureFlagService = {
- isFeatureEnabled: jest.fn().mockResolvedValue(true),
+ get: jest.fn().mockReturnValue(true),
};
const module: TestingModule = await Test.createTestingModule({
@@ -66,10 +61,6 @@ describe('CompanyEnrichmentService', () => {
provide: TwentyConfigService,
useValue: twentyConfigService,
},
- {
- provide: FeatureFlagService,
- useValue: featureFlagService,
- },
{
provide: KeyValuePairService,
useValue: keyValuePairService,
@@ -210,8 +201,8 @@ describe('CompanyEnrichmentService', () => {
);
});
- it('should return unavailable without enriching when onboarding AI chat is off', async () => {
- featureFlagService.isFeatureEnabled.mockResolvedValue(false);
+ it('should return unavailable without any lookup when onboarding AI chat is off', async () => {
+ twentyConfigService.get.mockReturnValue(false);
const result = await service.enrichCompanyForWorkspaceCreator({
userId: creatorUserId,
@@ -220,26 +211,9 @@ describe('CompanyEnrichmentService', () => {
});
expect(result).toEqual({ outcome: 'unavailable', enrichment: null });
- expect(userWorkspaceRepository.findOne).not.toHaveBeenCalled();
- expect(throttlerService.tokenBucketThrottleOrThrow).not.toHaveBeenCalled();
- expect(
- peopleDataLabsCompanyClientService.enrichCompanyByDomain,
- ).not.toHaveBeenCalled();
- expect(keyValuePairService.set).not.toHaveBeenCalled();
- });
-
- it('should return unavailable without any lookup when the enrichment flag is off', async () => {
- twentyConfigService.isWorkspaceCompanyEnrichmentEnabled.mockReturnValue(
- false,
+ expect(twentyConfigService.get).toHaveBeenCalledWith(
+ 'IS_ONBOARDING_AI_CHAT_ENABLED',
);
-
- const result = await service.enrichCompanyForWorkspaceCreator({
- userId: creatorUserId,
- email: 'foo@acme.com',
- workspaceId,
- });
-
- expect(result).toEqual({ outcome: 'unavailable', enrichment: null });
expect(userWorkspaceRepository.findOne).not.toHaveBeenCalled();
expect(throttlerService.tokenBucketThrottleOrThrow).not.toHaveBeenCalled();
expect(
diff --git a/packages/twenty-server/src/engine/core-modules/company-enrichment/services/company-enrichment.service.ts b/packages/twenty-server/src/engine/core-modules/company-enrichment/services/company-enrichment.service.ts
index 772f88e419..058fa3089e 100644
--- a/packages/twenty-server/src/engine/core-modules/company-enrichment/services/company-enrichment.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/company-enrichment/services/company-enrichment.service.ts
@@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { isNonEmptyString } from '@sniptt/guards';
-import { FeatureFlagKey } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type WorkspaceCompanyEnrichmentResult } from 'twenty-shared/workspace';
import { Repository } from 'typeorm';
@@ -10,7 +9,6 @@ import { Repository } from 'typeorm';
import { COMPANY_ENRICHMENT_THROTTLE_MAX_REQUESTS } from 'src/engine/core-modules/company-enrichment/constants/company-enrichment-throttle-max-requests.constant';
import { COMPANY_ENRICHMENT_THROTTLE_WINDOW_MS } from 'src/engine/core-modules/company-enrichment/constants/company-enrichment-throttle-window-ms.constant';
import { PeopleDataLabsCompanyClientService } from 'src/engine/core-modules/company-enrichment/services/people-data-labs-company-client.service';
-import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import {
COMPANY_ENRICHMENT_ATTEMPT_KEY,
type CompanyEnrichmentAttemptKeyValueTypeMap,
@@ -38,7 +36,6 @@ export class CompanyEnrichmentService {
private readonly userWorkspaceRepository: Repository,
private readonly peopleDataLabsCompanyClientService: PeopleDataLabsCompanyClientService,
private readonly twentyConfigService: TwentyConfigService,
- private readonly featureFlagService: FeatureFlagService,
private readonly throttlerService: ThrottlerService,
private readonly keyValuePairService: KeyValuePairService,
) {}
@@ -52,18 +49,8 @@ export class CompanyEnrichmentService {
email: string;
workspaceId: string;
}): Promise {
- if (!this.twentyConfigService.isWorkspaceCompanyEnrichmentEnabled()) {
- return { outcome: 'unavailable', enrichment: null };
- }
-
// The enrichment only feeds the AI-chat workspace setup, so it is pointless without it.
- const isOnboardingAiChatEnabled =
- await this.featureFlagService.isFeatureEnabled(
- FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
- workspaceId,
- );
-
- if (!isOnboardingAiChatEnabled) {
+ if (!this.twentyConfigService.get('IS_ONBOARDING_AI_CHAT_ENABLED')) {
return { outcome: 'unavailable', enrichment: null };
}
diff --git a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts
index b5769978a0..a5caf8dcd0 100644
--- a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts
+++ b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts
@@ -1953,11 +1953,11 @@ export class ConfigVariables {
@ConfigVariablesMetadata({
group: ConfigVariablesGroup.ADVANCED_SETTINGS,
description:
- 'Enable or disable workspace company enrichment during onboarding',
+ 'Enable or disable the AI chat that helps set up the workspace at the end of onboarding',
type: ConfigVariableType.BOOLEAN,
})
@IsOptional()
- IS_WORKSPACE_COMPANY_ENRICHMENT_ENABLED = false;
+ IS_ONBOARDING_AI_CHAT_ENABLED = false;
@ConfigVariablesMetadata({
group: ConfigVariablesGroup.ADVANCED_SETTINGS,
diff --git a/packages/twenty-server/src/engine/core-modules/twenty-config/twenty-config.service.ts b/packages/twenty-server/src/engine/core-modules/twenty-config/twenty-config.service.ts
index ce52e282bd..040bca6108 100644
--- a/packages/twenty-server/src/engine/core-modules/twenty-config/twenty-config.service.ts
+++ b/packages/twenty-server/src/engine/core-modules/twenty-config/twenty-config.service.ts
@@ -205,10 +205,6 @@ export class TwentyConfigService {
return this.get('IS_BILLING_ENABLED') === true;
}
- isWorkspaceCompanyEnrichmentEnabled(): boolean {
- return this.get('IS_WORKSPACE_COMPANY_ENRICHMENT_ENABLED') === true;
- }
-
private validateNotEnvOnly(
key: T,
operation: string,
diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts
index 4b4de3dc59..0c66c3bb01 100644
--- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts
+++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts
@@ -247,7 +247,6 @@ describe('WorkspaceEntityManager', () => {
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED: false,
IS_SETTINGS_DISCOVERY_HERO_ENABLED: false,
IS_WORKFLOW_VERSION_IN_CORE_ENABLED: false,
- IS_ONBOARDING_AI_CHAT_ENABLED: false,
},
userWorkspaceRoleMap: {},
apiKeyRoleMap: {},
diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts
index 88fa3e7399..13f94e9218 100644
--- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts
+++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts
@@ -50,11 +50,6 @@ export const seedFeatureFlags = async ({
workspaceId: workspaceId,
value: false,
},
- {
- key: FeatureFlagKey.IS_ONBOARDING_AI_CHAT_ENABLED,
- workspaceId: workspaceId,
- value: false,
- },
])
.execute();
};
diff --git a/packages/twenty-shared/src/types/FeatureFlagKey.ts b/packages/twenty-shared/src/types/FeatureFlagKey.ts
index 3ccc7d2707..2e441a870f 100644
--- a/packages/twenty-shared/src/types/FeatureFlagKey.ts
+++ b/packages/twenty-shared/src/types/FeatureFlagKey.ts
@@ -7,7 +7,6 @@ export enum FeatureFlagKey {
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',
IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED = 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED',
- IS_ONBOARDING_AI_CHAT_ENABLED = 'IS_ONBOARDING_AI_CHAT_ENABLED',
IS_SETTINGS_DISCOVERY_HERO_ENABLED = 'IS_SETTINGS_DISCOVERY_HERO_ENABLED',
IS_WORKFLOW_VERSION_IN_CORE_ENABLED = 'IS_WORKFLOW_VERSION_IN_CORE_ENABLED',
}