diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index d4bccc8c32..916a4e5a84 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -14586,9 +14586,6 @@ const docTemplate = `{ "codersdk.CreateFirstUserOnboardingInfo": { "type": "object", "properties": { - "is_business": { - "type": "boolean" - }, "newsletter_marketing": { "type": "boolean" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 711647d763..1fb7b92d03 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -13126,9 +13126,6 @@ "codersdk.CreateFirstUserOnboardingInfo": { "type": "object", "properties": { - "is_business": { - "type": "boolean" - }, "newsletter_marketing": { "type": "boolean" }, diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go index 1dac106cba..7478be3626 100644 --- a/coderd/telemetry/telemetry.go +++ b/coderd/telemetry/telemetry.go @@ -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 { diff --git a/coderd/users.go b/coderd/users.go index e226f769cf..07603e0b0e 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -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, } diff --git a/coderd/users_test.go b/coderd/users_test.go index 4df639c618..c47b1a5293 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -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) }) } diff --git a/codersdk/users.go b/codersdk/users.go index 5d245a39eb..90b3147c15 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -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. diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index d3036ceca9..b10bf485cb 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -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 }, diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index d40b5f2465..8987b0001b 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -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 }, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index a46c3a38d2..76b2eefdcd 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -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