fix: remove work/personal onboarding telemetry (#24021)

Following on from #23989 #24018 

- We also no longer want to collect `IsBusiness` demographic data
- Newsletter fields no longer allow `nil` as a value, instead default to
false

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeremy Ruppel
2026-04-03 14:26:35 -04:00
committed by GitHub
parent ec83065b59
commit 01b8cdb00d
9 changed files with 19 additions and 52 deletions
-3
View File
@@ -14586,9 +14586,6 @@ const docTemplate = `{
"codersdk.CreateFirstUserOnboardingInfo": {
"type": "object",
"properties": {
"is_business": {
"type": "boolean"
},
"newsletter_marketing": {
"type": "boolean"
},
-3
View File
@@ -13126,9 +13126,6 @@
"codersdk.CreateFirstUserOnboardingInfo": {
"type": "object",
"properties": {
"is_business": {
"type": "boolean"
},
"newsletter_marketing": {
"type": "boolean"
},
+5 -7
View File
@@ -1552,14 +1552,12 @@ type User struct {
LoginType string `json:"login_type,omitempty"`
}
// FirstUserOnboarding contains optional demographic and newsletter
// preference data collected during first user setup. This is sent
// once when the first user is created. Pointer fields distinguish an
// explicit answer from a skipped question.
// FirstUserOnboarding contains optional newsletter preference data
// collected during first user setup. This is sent once when the first
// user is created.
type FirstUserOnboarding struct {
IsBusiness *bool `json:"is_business"`
NewsletterMarketing *bool `json:"newsletter_marketing"`
NewsletterReleases *bool `json:"newsletter_releases"`
NewsletterMarketing bool `json:"newsletter_marketing"`
NewsletterReleases bool `json:"newsletter_releases"`
}
type Group struct {
-5
View File
@@ -284,14 +284,9 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) {
// Only populate onboarding data when the client actually sent it. A nil
// OnboardingInfo means the request came from an older client, the CLI, or
// the OIDC flow — not from a user who answered "no" to every question.
//
// Note: newsletter consent (NewsletterMarketing) is bundled here alongside
// product-analytics fields. These may have different legal bases under GDPR
// and should be separated in a follow-up once the legal posture is clarified.
var onboarding *telemetry.FirstUserOnboarding
if createUser.OnboardingInfo != nil {
onboarding = &telemetry.FirstUserOnboarding{
IsBusiness: createUser.OnboardingInfo.IsBusiness,
NewsletterMarketing: createUser.OnboardingInfo.NewsletterMarketing,
NewsletterReleases: createUser.OnboardingInfo.NewsletterReleases,
}
+6 -16
View File
@@ -128,29 +128,21 @@ func TestFirstUser_OnboardingTelemetry(t *testing.T) {
TelemetryReporter: fTelemetry,
})
isBusiness := true
wantMarketing := false
wantReleases := true
_, err := client.CreateFirstUser(ctx, codersdk.CreateFirstUserRequest{
Email: "admin@coder.com",
Username: "admin",
Password: "SomeSecurePassword!",
OnboardingInfo: &codersdk.CreateFirstUserOnboardingInfo{
IsBusiness: &isBusiness,
NewsletterMarketing: &wantMarketing,
NewsletterReleases: &wantReleases,
NewsletterMarketing: false,
NewsletterReleases: true,
},
})
require.NoError(t, err)
snapshot := testutil.TryReceive(ctx, t, fTelemetry.snapshots)
require.NotNil(t, snapshot.FirstUserOnboarding)
require.NotNil(t, snapshot.FirstUserOnboarding.IsBusiness)
require.True(t, *snapshot.FirstUserOnboarding.IsBusiness)
require.NotNil(t, snapshot.FirstUserOnboarding.NewsletterMarketing)
require.False(t, *snapshot.FirstUserOnboarding.NewsletterMarketing)
require.NotNil(t, snapshot.FirstUserOnboarding.NewsletterReleases)
require.True(t, *snapshot.FirstUserOnboarding.NewsletterReleases)
require.False(t, snapshot.FirstUserOnboarding.NewsletterMarketing)
require.True(t, snapshot.FirstUserOnboarding.NewsletterReleases)
})
t.Run("NilWhenOnboardingInfoOmitted", func(t *testing.T) {
@@ -190,10 +182,8 @@ func TestFirstUser_OnboardingTelemetry(t *testing.T) {
snapshot := testutil.TryReceive(ctx, t, fTelemetry.snapshots)
require.NotNil(t, snapshot.FirstUserOnboarding,
"non-nil OnboardingInfo must produce non-nil telemetry")
require.Nil(t, snapshot.FirstUserOnboarding.IsBusiness,
"nil *bool must stay nil, not become false")
require.Nil(t, snapshot.FirstUserOnboarding.NewsletterMarketing)
require.Nil(t, snapshot.FirstUserOnboarding.NewsletterReleases)
require.False(t, snapshot.FirstUserOnboarding.NewsletterMarketing)
require.False(t, snapshot.FirstUserOnboarding.NewsletterReleases)
})
}
+4 -7
View File
@@ -144,14 +144,11 @@ type CreateFirstUserTrialInfo struct {
Developers string `json:"developers"`
}
// CreateFirstUserOnboardingInfo contains optional demographic and
// newsletter preference data collected during first user setup.
// Pointer fields allow an explicit "no" answer to be distinguished
// from a skipped question, which matters for the telemetry schema.
// CreateFirstUserOnboardingInfo contains optional newsletter preference
// data collected during first user setup.
type CreateFirstUserOnboardingInfo struct {
IsBusiness *bool `json:"is_business"`
NewsletterMarketing *bool `json:"newsletter_marketing"`
NewsletterReleases *bool `json:"newsletter_releases"`
NewsletterMarketing bool `json:"newsletter_marketing"`
NewsletterReleases bool `json:"newsletter_releases"`
}
// CreateFirstUserResponse contains IDs for newly created user info.
-3
View File
@@ -2282,7 +2282,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
```json
{
"is_business": true,
"newsletter_marketing": true,
"newsletter_releases": true
}
@@ -2292,7 +2291,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
| Name | Type | Required | Restrictions | Description |
|------------------------|---------|----------|--------------|-------------|
| `is_business` | boolean | false | | |
| `newsletter_marketing` | boolean | false | | |
| `newsletter_releases` | boolean | false | | |
@@ -2303,7 +2301,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
"email": "string",
"name": "string",
"onboarding_info": {
"is_business": true,
"newsletter_marketing": true,
"newsletter_releases": true
},
-1
View File
@@ -246,7 +246,6 @@ curl -X POST http://coder-server:8080/api/v2/users/first \
"email": "string",
"name": "string",
"onboarding_info": {
"is_business": true,
"newsletter_marketing": true,
"newsletter_releases": true
},
+4 -7
View File
@@ -2390,15 +2390,12 @@ export interface CreateChatRequest {
// From codersdk/users.go
/**
* CreateFirstUserOnboardingInfo contains optional demographic and
* newsletter preference data collected during first user setup.
* Pointer fields allow an explicit "no" answer to be distinguished
* from a skipped question, which matters for the telemetry schema.
* CreateFirstUserOnboardingInfo contains optional newsletter preference
* data collected during first user setup.
*/
export interface CreateFirstUserOnboardingInfo {
readonly is_business: boolean | null;
readonly newsletter_marketing: boolean | null;
readonly newsletter_releases: boolean | null;
readonly newsletter_marketing: boolean;
readonly newsletter_releases: boolean;
}
// From codersdk/users.go