From 1c33404de4ef54db1dbab1731bcb22425ec3d876 Mon Sep 17 00:00:00 2001
From: Harlan Wilton
Date: Mon, 12 Oct 2026 23:27:38 +1100
Subject: [PATCH 1/4] fix(identity): default onboarding to one welcome email
---
COPY.md | 4 ++-
GLOSSARY.md | 4 +--
.../identity/app/pages/onboarding/email.vue | 15 +++++++----
layers/identity/server/utils/welcome-email.ts | 3 ++-
layers/identity/shared/contracts/account.ts | 4 +--
shared/welcome-email-copy.ts | 3 ++-
test/unit/email-form-submit.nuxt.test.ts | 26 ++++++++++++++-----
7 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/COPY.md b/COPY.md
index 404e06d9..97e6715d 100644
--- a/COPY.md
+++ b/COPY.md
@@ -19,7 +19,9 @@ After its main action, it says "Let me know if you’d like to see any changes :
Replies go to `harlan@harlanzw.com`.
Its one main action is "Open your account", linking to `/me`.
Its footer is "Stop welcome emails", linking to a signed welcome unsubscribe URL.
-Onboarding offers an unchecked choice: "Send me one welcome email with account tips."
+Onboarding checks the welcome choice for new accounts: "Send me one welcome email from Harlan."
+New accounts start with the weekly and digest choices unchecked. Saved choices stay as selected.
+Onboarding and the welcome email say "We’ll only send other emails if you’ve opted in."
The missing-address message is "Add an email address, or turn off all email choices."
Welcome unsubscribe says "You will not get welcome emails. Your weekly and digest settings are unchanged."
diff --git a/GLOSSARY.md b/GLOSSARY.md
index 7fa02240..64d3dd64 100644
--- a/GLOSSARY.md
+++ b/GLOSSARY.md
@@ -199,7 +199,7 @@ UI fixtures are labelled Example data. They are not recorded runs or evaluation
**Is:** the monthly email that summarises changes to watched Repositories. The user can turn it off.
-**Never:** newsletter, notification, alert. "the weekly" is the separate opt-out email.
+**Never:** newsletter, notification, alert. "the weekly" is the separate weekly email.
### trending
@@ -377,7 +377,7 @@ Existing route paths, table names, and protocol fields keep their identifiers.
### weekly
-**Is:** the one email everyone gets: Skills you liked that changed, plus what trended. Opt-out, on by default.
+**Is:** the weekly email with Skills you liked that changed, plus what trended. New accounts opt in during onboarding.
**Use for:** "the weekly", lowercase. It sits beside **digest**, which is the separate watched-Repository email. They are not the same send.
diff --git a/layers/identity/app/pages/onboarding/email.vue b/layers/identity/app/pages/onboarding/email.vue
index b176a863..7cbef657 100644
--- a/layers/identity/app/pages/onboarding/email.vue
+++ b/layers/identity/app/pages/onboarding/email.vue
@@ -14,14 +14,15 @@ onMounted(() => recordSignup({ stage: 'email', outcome: 'viewed', entry: 'onboar
const email = ref(me.value?.digest_email || me.value?.email || '')
// A stored address records a deliberate choice, including a previous opt-out.
const hasEmailChoices = computed(() => !!me.value?.onboarded_at || !!me.value?.digest_email)
-const optIn = ref(hasEmailChoices.value ? !!me.value?.email_opt_in : true)
-const weeklyOptIn = ref(hasEmailChoices.value ? !!me.value?.weekly_opt_in : true)
-const welcomeEmail = ref(false)
+const optIn = ref(hasEmailChoices.value ? !!me.value?.email_opt_in : false)
+const weeklyOptIn = ref(hasEmailChoices.value ? !!me.value?.weekly_opt_in : false)
+const welcomeEmail = ref(!hasEmailChoices.value)
watch(me, (account, previous) => {
if (account && !previous) {
email.value = account.digest_email || account.email || ''
- optIn.value = hasEmailChoices.value ? account.email_opt_in : true
- weeklyOptIn.value = hasEmailChoices.value ? account.weekly_opt_in : true
+ optIn.value = hasEmailChoices.value ? account.email_opt_in : false
+ weeklyOptIn.value = hasEmailChoices.value ? account.weekly_opt_in : false
+ welcomeEmail.value = !hasEmailChoices.value
}
})
@@ -132,6 +133,10 @@ useSeoMeta({ title: 'Email opt-in', robots: 'noindex' })
+
+ {{ WELCOME_EMAIL_COPY.emailChoices }}
+
+
You won't receive any emails. You can opt in later from your dashboard.
diff --git a/layers/identity/server/utils/welcome-email.ts b/layers/identity/server/utils/welcome-email.ts
index b27763f1..56f8db50 100644
--- a/layers/identity/server/utils/welcome-email.ts
+++ b/layers/identity/server/utils/welcome-email.ts
@@ -30,9 +30,10 @@ export function renderWelcomeEmail(unsubscribeUrl: string): Pick${copy.action}
${copy.feedback}
${copy.signature}
+${copy.emailChoices}
| ${copy.unsubscribe} |