From 7d2f01e40242160d34bacaacef63154552532a51 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Tue, 21 Jul 2026 15:05:11 +0400 Subject: [PATCH] feat(whatsapp): unify embedded signup feature gating (#15106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WhatsApp embedded signup now uses `whatsapp_embedded_signup_inbox_creation` as the single Chatwoot Cloud rollout gate for inbox creation, proactive reconfiguration, and disconnected inbox reauthorization. The authorization endpoint enforces the same gate, so the UI and backend remain consistent. Self-hosted installations keep their existing behavior. ## Things to know - This reuses the existing feature flag; there is no migration or schema change. - The feature is shown as “WhatsApp Embedded Signup Flow” in feature management. - `whatsapp_reconfigure` remains visible and honored for self-hosted proactive reconfiguration to preserve existing accounts. It can be deprecated after the self-hosted dependency is removed or migrated. ## How to test 1. On Chatwoot Cloud, enable `whatsapp_embedded_signup_inbox_creation` for an account. 2. Confirm that new WhatsApp inbox creation, proactive reconfiguration, and disconnected inbox reauthorization are available. 3. Disable the flag and confirm those entry points are hidden and authorization requests are rejected. 4. On self-hosted, confirm proactive reconfiguration remains controlled by the existing `whatsapp_reconfigure` account setting. --------- Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com> --- .../v1/accounts/whatsapp/authorizations_controller.rb | 11 +++++++++-- app/javascript/dashboard/featureFlags.js | 3 +-- .../onboarding/inbox-setup/useChannelConfig.js | 4 +--- .../routes/dashboard/settings/inbox/Settings.vue | 5 +++++ .../dashboard/settings/inbox/channels/Whatsapp.vue | 4 +--- .../settings/inbox/settingsPage/ConfigurationPage.vue | 5 ++++- config/features.yml | 2 +- 7 files changed, 22 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb b/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb index 580ae77c6..46d89a1ba 100644 --- a/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb +++ b/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb @@ -1,4 +1,5 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts::BaseController + before_action :ensure_embedded_signup_enabled # Reconfiguring/reauthorizing a live inbox swaps its credentials, so restrict it to admins. before_action :check_admin_authorization?, if: -> { params[:inbox_id].present? } before_action :fetch_and_validate_inbox, if: -> { params[:inbox_id].present? } @@ -18,6 +19,13 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts: private + def ensure_embedded_signup_enabled + return unless ChatwootApp.chatwoot_cloud? + return if Current.account.feature_enabled?('whatsapp_embedded_signup_inbox_creation') + + raise Pundit::NotAuthorizedError + end + def process_embedded_signup service = Whatsapp::EmbeddedSignupService.new( account: Current.account, @@ -44,8 +52,7 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts: def can_reconfigure_channel? channel = @inbox.channel return false unless channel.provider == 'whatsapp_cloud' - - # Reconfiguring a live embedded-signup channel requires the feature flag. + return true if ChatwootApp.chatwoot_cloud? return Current.account.feature_enabled?('whatsapp_reconfigure') if channel.provider_config['source'] == 'embedded_signup' true diff --git a/app/javascript/dashboard/featureFlags.js b/app/javascript/dashboard/featureFlags.js index e707284cb..04f46890e 100644 --- a/app/javascript/dashboard/featureFlags.js +++ b/app/javascript/dashboard/featureFlags.js @@ -7,8 +7,7 @@ export const FEATURE_FLAGS = { AUTOMATIONS: 'automations', CAMPAIGNS: 'campaigns', WHATSAPP_CAMPAIGNS: 'whatsapp_campaign', - WHATSAPP_EMBEDDED_SIGNUP_INBOX_CREATION: - 'whatsapp_embedded_signup_inbox_creation', + WHATSAPP_EMBEDDED_SIGNUP_FLOW: 'whatsapp_embedded_signup_inbox_creation', WHATSAPP_MANUAL_TRANSFER: 'whatsapp_manual_transfer', WHATSAPP_RECONFIGURE: 'whatsapp_reconfigure', CANNED_RESPONSES: 'canned_responses', diff --git a/app/javascript/dashboard/routes/dashboard/onboarding/inbox-setup/useChannelConfig.js b/app/javascript/dashboard/routes/dashboard/onboarding/inbox-setup/useChannelConfig.js index 36a78dcbe..6dedbe894 100644 --- a/app/javascript/dashboard/routes/dashboard/onboarding/inbox-setup/useChannelConfig.js +++ b/app/javascript/dashboard/routes/dashboard/onboarding/inbox-setup/useChannelConfig.js @@ -18,9 +18,7 @@ export function useChannelConfig() { // app id (not the 'none' sentinel) and the signup configuration id. whatsapp: () => (!isOnChatwootCloud.value || - isCloudFeatureEnabled( - FEATURE_FLAGS.WHATSAPP_EMBEDDED_SIGNUP_INBOX_CREATION - )) && + isCloudFeatureEnabled(FEATURE_FLAGS.WHATSAPP_EMBEDDED_SIGNUP_FLOW)) && Boolean(installationConfig.whatsappAppId) && installationConfig.whatsappAppId !== 'none' && Boolean(installationConfig.whatsappConfigurationId), diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue index 222d238a8..5e7f320f3 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue @@ -390,6 +390,11 @@ export default { return ( this.isAWhatsAppCloudChannel && this.isEmbeddedSignupWhatsApp && + (!this.isOnChatwootCloud || + this.isFeatureEnabledonAccount( + this.accountId, + FEATURE_FLAGS.WHATSAPP_EMBEDDED_SIGNUP_FLOW + )) && this.inbox.reauthorization_required ); }, diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue index b4e0c58af..6a4a361b0 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue @@ -42,9 +42,7 @@ const shouldShowWhatsappEmbeddedSignup = computed(() => { selectedProvider.value === PROVIDER_TYPES.WHATSAPP && hasWhatsappAppId.value && (!isOnChatwootCloud.value || - isCloudFeatureEnabled( - FEATURE_FLAGS.WHATSAPP_EMBEDDED_SIGNUP_INBOX_CREATION - )) + isCloudFeatureEnabled(FEATURE_FLAGS.WHATSAPP_EMBEDDED_SIGNUP_FLOW)) ); }); diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue index 61038cec1..1e9e2f704 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue @@ -56,6 +56,7 @@ export default { ...mapGetters({ accountId: 'getCurrentAccountId', isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount', + isOnChatwootCloud: 'globalConfig/isOnChatwootCloud', }), isEmbeddedSignupWhatsApp() { return this.inbox.provider_config?.source === 'embedded_signup'; @@ -65,7 +66,9 @@ export default { this.isEmbeddedSignupWhatsApp && this.isFeatureEnabledonAccount( this.accountId, - FEATURE_FLAGS.WHATSAPP_RECONFIGURE + this.isOnChatwootCloud + ? FEATURE_FLAGS.WHATSAPP_EMBEDDED_SIGNUP_FLOW + : FEATURE_FLAGS.WHATSAPP_RECONFIGURE ) ); }, diff --git a/config/features.yml b/config/features.yml index 590f28814..950d6e7c5 100644 --- a/config/features.yml +++ b/config/features.yml @@ -265,6 +265,6 @@ enabled: false column: feature_flags_ext_1 - name: whatsapp_embedded_signup_inbox_creation - display_name: WhatsApp Embedded Signup Inbox Creation + display_name: WhatsApp Embedded Signup Flow enabled: false column: feature_flags_ext_1