feat: don't let onboarding write domain (#14442)

Stop the onboarding flow from writing the user's company website into
`accounts.domain`. That column is reserved for the inbound email domain
used to construct reply-to addresses (`reply+<uuid>@<domain>`), and
silently overloading it from onboarding was breaking email continuity
for accounts whose domain MX didn't point at Chatwoot's inbound —
customer replies were going to an unreachable address.

The website value now lives in `custom_attributes.website`, which is
what the rest of the app already treats as the "company website" field.
This commit is contained in:
Shivam Mishra
2026-05-13 20:09:48 +05:30
committed by GitHub
parent 379e28df1f
commit 05bda5f742
6 changed files with 10 additions and 5 deletions
@@ -111,7 +111,7 @@ class Api::V1::AccountsController < Api::BaseController
end
def custom_attributes_params
params.permit(:industry, :company_size, :timezone, :referral_source, :user_role)
params.permit(:industry, :company_size, :timezone, :referral_source, :user_role, :website)
end
def settings_params
@@ -134,7 +134,7 @@ const populateFormFields = () => {
if (!locale.value) locale.value = detectBestLocale();
if (!website.value) {
website.value = account?.domain || brandInfo?.domain || '';
website.value = attrs.website || brandInfo?.domain || '';
}
if (!timezone.value) {
timezone.value =
@@ -216,7 +216,7 @@ const handleSubmit = async () => {
await updateAccount({
name: accountName.value,
locale: locale.value,
domain: website.value,
website: website.value,
industry: industry.value,
company_size: companySize.value,
timezone: timezone.value,
+3
View File
@@ -38,6 +38,9 @@ class Account < ApplicationRecord
}.freeze
validates :name, presence: true
# `domain` is the inbound email domain used to construct reply addresses
# (see `inbound_email_domain`). Do not repurpose it for a website or any
# non-mail-related domain.
validates :domain, length: { maximum: 100 }
validates_with JsonSchemaValidator,
schema: SETTINGS_PARAMS_SCHEMA,
@@ -55,7 +55,7 @@ class Onboarding::WebWidgetCreationService
end
def website_url
@account.domain.presence || brand_info[:domain].presence
@account.custom_attributes['website'].presence || brand_info[:domain].presence
end
def widget_color
@@ -6,6 +6,7 @@ if resource.custom_attributes.present?
json.subscribed_quantity resource.custom_attributes['subscribed_quantity']
json.subscription_status resource.custom_attributes['subscription_status']
json.subscription_ends_on resource.custom_attributes['subscription_ends_on']
json.website resource.custom_attributes['website'] if resource.custom_attributes['website'].present?
json.industry resource.custom_attributes['industry'] if resource.custom_attributes['industry'].present?
json.company_size resource.custom_attributes['company_size'] if resource.custom_attributes['company_size'].present?
json.timezone resource.custom_attributes['timezone'] if resource.custom_attributes['timezone'].present?
@@ -7,7 +7,8 @@ end
RSpec.describe Enterprise::Onboarding::WebWidgetCreationService do
let(:account) do
create(:account, name: 'Acme Inc', domain: 'acme.com', custom_attributes: {
create(:account, name: 'Acme Inc', custom_attributes: {
'website' => 'acme.com',
'brand_info' => { 'slogan' => 'Fallback slogan', 'description' => 'Fallback description' }
})
end