Skip to content

[TAN-8197] Make manual sms campaign's consent false by default - #14325

Merged
AchrafGoVocal merged 26 commits into
masterfrom
TAN-8197-improve-sms-campaigns-consent
Aug 5, 2026
Merged

AchrafGoVocal merged 26 commits into
masterfrom
TAN-8197-improve-sms-campaigns-consent

Conversation

@AchrafGoVocal

@AchrafGoVocal AchrafGoVocal commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Changelog

Added

  • On the phone number page in profile settings, users now confirm two things when saving a number: a required agreement to receive one-time confirmation codes by SMS, and an optional opt-in to receive updates and campaign messages by SMS.

Changed

  • Manual SMS campaigns are now opt-in. Only users who explicitly ticked the opt-in box receive them.

Technical

  • Consentable now supports opt-in campaigns via a consented_by_default? class method; email campaigns keep the existing opt-out behaviour.

For translators

@notion-workspace

Copy link
Copy Markdown

@cl-dev-bot

cl-dev-bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Collaborator
Messages
📖 Changelog provided 🎉
📖 Notion issue: TAN-8197
📖

Run the e2e tests

📖 Check translation progress

Generated by 🚫 dangerJS against 3b50197

@AchrafGoVocal
AchrafGoVocal marked this pull request as ready for review July 22, 2026 10:15

@jamesspeake jamesspeake left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, I just feel that clicking an additional box to agree to receive SMS OTP codes seems overkill if the text above the box is really clear that this is what is happening. Can't recall ever having to do this on a website personally.

In fact, take a look at Twilio's guidance. We do have to store that they have consented, but it does not need to be a checkbox: https://www.twilio.com/docs/verify/consent-opt-in

Comment on lines +305 to +310
example 'records the opt-out when the user does not opt in' do
do_request(confirmation: { code: user.new_phone_confirmation.code, sms_manual_campaign_consent: false })
assert_status 200
consent = EmailCampaigns::Consent.find_by(user: user, campaign_type: sms_manual_type)
expect(consent.consented).to be false
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely this is a route that should never be hit? If the user does not consent then we cannot send them a code and therefore we should not even be allowing the form to submit. Worth documenting in the test, if this is the case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely this is a route that should never be hit? If the user does not consent then we cannot send them a code and therefore we should not even be allowing the form to submit. Worth documenting in the test, if this is the case.

This is for the manual sms campaigns. This is for the case where the user had previously consented to receiving the manual sms campaigns and then they are submitting a new phone number without consenting to the manual sms campaigns.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the consent for OTP I agree! I changed it up and now there is only a text below the submit button like in the Twilio docs. Also I record the consent for that with an activity as I assume we need to record every time the user consents to receiving a phone. Like twilio says "Treat any recipient who has not opted in as opted out by default. You must store evidence of each consent event and provide it to Twilio on request."

@AchrafGoVocal

Copy link
Copy Markdown
Contributor Author

@jamesspeake I re-requested your review because I made some significant changes related to the consent, like a adding a new SideFxConsentService to centralize the logging. Also now the consent changes for email campaigns are also recorded.

@jamesspeake jamesspeake left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks generally good. The comment about code sharing is not a blocker, but take a look and see what you think (I've not fully thought through what's possible)

Comment on lines +83 to +90
def record_sms_confirmation_consent
consent = EmailCampaigns::Consent.find_or_initialize_by(
user_id: current_user.id,
campaign_type: EmailCampaigns::Campaigns::NewPhoneConfirmation.name
)
consent.update!(consented: true)
EmailCampaigns::SideFxConsentService.new.log_consent_event(consent, current_user)
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel like this has a lot of shared code with the confirmations controller and might be better as a single method in the sideFxService eg record_sms_consent which takes some parameters.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree! At first I moved it to the SideFxService (here) but then it didn't feel right because I think that SideFxServices are only for logging and shouldn't do any DB mutations. So, I have landed on another solution (here) which I think fits better. WDYT ? @jamesspeake

@AchrafGoVocal

Copy link
Copy Markdown
Contributor Author

Ran the failing e2e test locally and it passed

@AchrafGoVocal
AchrafGoVocal merged commit 07ee789 into master Aug 5, 2026
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants