feat: Premium Page CTA updates and form handling by untra · Pull Request #28226 · coder/coder · GitHub
Skip to content

feat: Premium Page CTA updates and form handling - #28226

Merged
jeremyruppel merged 24 commits into
mainfrom
feat/DEVEX-752-premium-page
Aug 21, 2026
Merged

feat: Premium Page CTA updates and form handling#28226
jeremyruppel merged 24 commits into
mainfrom
feat/DEVEX-752-premium-page

Conversation

@untra

@untra untra commented Aug 17, 2026

Copy link
Copy Markdown
Contributor
  • Premium page has form for signing up for a trial
  • Input validation and normalization for trial form fields
  • api endpoint definition to make this processes seamless
  • license page updates to access ?success=true queryparam and confetti
Screenshot 2026-08-17 at 10 08 41 PM Aug-17-2026 22-12-38
sequenceDiagram
    autonumber
    actor Owner
    participant UI as UI<br/>TrialRequestForm + PremiumPage
    participant API as API<br/>api.ts + coderd middleware
    participant Coderd as Coderd<br/>postTrialLicense + trialer
    participant Licensor as Licensor<br/>v2-licensor + Postgres + pubsub + cache

    Note over UI: mutation.status = "idle"

    Owner->>UI: fills 10 fields, checks acknowledgement
    UI->>UI: Yup validate, strip "acknowledged", submit
    UI->>API: POST /api/v2/licenses/trial<br/>cookie + X-CSRF-TOKEN
    Note over UI: mutation.status = "pending"

    API->>API: verify CSRF, apiRateLimiter,<br/>apiKeyMiddleware sets actor
    API->>Coderd: dispatch

    Coderd->>Coderd: audit.InitRequest, authorize license:create,<br/>httpapi.Read validates, HasLicense is false
    Coderd->>Licensor: POST trial request<br/>deployment_id unspoofable, 10s deadline
    Licensor-->>Coderd: 200, raw signed JWT

    Coderd->>Coderd: ParseClaimsIgnoreNbf, uuid.Parse
    Coderd->>Licensor: InsertLicense, updateEntitlements,<br/>publish PubsubEventLicense, commit audit log
    Licensor-->>Coderd: database.License
    Coderd-->>API: 201 codersdk.License
    API-->>UI: 201 codersdk.License

    Note over UI: mutation.status = "success"
    UI->>Licensor: invalidate entitlements + licenses keys
    UI->>Owner: navigate /deployment/premium?success=true
    Note over Owner: confetti fires on the success param
Loading

@linear-code

linear-code Bot commented Aug 17, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Docs preview

Check off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here.

@untra untra changed the title Premium Page updates and form handling Premium Page CTA updates and form handling Aug 17, 2026
@untra untra changed the title Premium Page CTA updates and form handling feat: Premium Page CTA updates and form handling Aug 17, 2026
@untra
untra force-pushed the feat/DEVEX-752-premium-page branch from 2bb446a to 525e204 Compare August 18, 2026 18:50
Comment thread codersdk/licenses.go
Comment thread site/src/pages/DeploymentSettingsPage/PremiumPage/TrialRequestForm.tsx Outdated
@untra
untra force-pushed the feat/DEVEX-752-premium-page branch from 861e8d2 to cd3f9f7 Compare August 19, 2026 14:23
@untra
untra marked this pull request as ready for review August 19, 2026 15:03
@coderagents

coderagents Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Documentation Check

Updates Needed

  • docs/admin/licensing/index.md - This PR adds an in-product trial flow: an Owner can request and activate a trial license directly from the Premium page in Admin settings > Deployment (backed by the new POST /api/v2/licenses/trial endpoint). The licensing page currently only tells users to request a trial via the external site and then upload the resulting .jwt. Add a section (or a tabs option alongside "Coder UI"/"Coder CLI") documenting the in-product trial request form, its required fields, and that no manual upload is needed.

Notes

  • The API reference (docs/reference/api/enterprise.md, docs/reference/api/schemas.md) for the new endpoint and CreateTrialLicenseRequest schema is auto-generated and already regenerated in this PR. No manual edits needed there.
  • No glossary change required: "trial" and "Premium" are already covered in docs/reference/glossary.md, and this PR introduces no new product/feature proper noun.

Automated review via Coder Agents

Comment thread site/src/pages/DeploymentSettingsPage/PremiumPage/PremiumPage.tsx

@aslilac aslilac left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this pr is waaaaaaaaay too big to review properly. it's at least three different changes rolled up into one. we target a pr size of +500 lines, with a max of +1000.

Comment thread codersdk/licenses.go
Comment thread enterprise/cli/server.go Outdated
ProxyHealthInterval: options.DeploymentValues.ProxyHealthStatusInterval.Value(),
DefaultQuietHoursSchedule: options.DeploymentValues.UserQuietHoursSchedule.DefaultSchedule.Value(),
ProvisionerDaemonPSK: options.DeploymentValues.Provisioner.DaemonPSK.Value(),
TrialLicenseRequester: trialer.NewLicenseRequester(trialer.LicenseRequestURL),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should not be a separate object, we should extend the existing TrialGenerator to have whatever functionality is needed.

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 extended TrialGenerator and refactored the copypasta paths of license.
This approach and removing the trialgenerator option made writing golang tests a bit harder. I removed a few tests around trial license success generation because I wanted to avoid golang tests mocks, and I added a playwright e2e test to verify this continues to work.

https://github.com/coder/coder/actions/runs/32324209039/job/96292052395?pr=28226

Please let me know any other feedback! I try to always write tests to enforce correctness, but my golang-fu isn't the strongest , I defer to your wisdom 🙇

Comment thread enterprise/coderd/licenses.go Outdated
Comment thread enterprise/coderd/licenses.go
Comment thread enterprise/coderd/licenses.go Outdated
Comment thread enterprise/trialer/trialer.go
Comment thread site/src/api/queries/licenses.ts Outdated
Comment thread site/src/components/SelectField/SelectField.tsx Outdated

// Keep in sync with cli/login.go. The values are forwarded to the Coder licensor,
// so changing them requires coordinating with the licensor service.
export const numberOfDevelopersOptions = [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

files that only contain consts are a huge code smell. who uses these consts? what functionality do they offer? are there multiple consumers? if they're really that important and useful why are there not any functions alongside them to help you utilize them properly?

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.

marketing wants to be able to have a say over copy, lots of little rich text coordinated strings and copy, and wants to be able to find and edit that copy.

With this premium upsell, there are a lot of small strings that need to be maintained and associated, as well as common links used in the SetupPage and LicensePage and the PremiumPage . It's rule of two going on three.

I did not know bulk consts are seen as a code smell in typescript. What defect does that smell suggest? Is there a better place to coordinate such strings or shared yup form validation?

@jeremyruppel jeremyruppel Aug 20, 2026

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.

hm, I do feel a few of these do belong closer to the component (for example PREMIUM_TRIAL_UPSELL appears in exactly one component), and the Yup schema is definitely coupled to the trial form. I understand the reason behind wanting to keep marketing copy etc in one file for easy editing, but since marketing will likely be using agents, I wonder if there's a different way we can indicate or direct them to what they should change (comments?).

Comment thread site/src/pages/DeploymentSettingsPage/PremiumPage/PremiumPageView.tsx Outdated
Comment thread .github/workflows/premium-trial-e2e.yaml Outdated
@untra
untra force-pushed the feat/DEVEX-752-premium-page branch from 6f7323c to 099884b Compare August 20, 2026 05:06
untra and others added 2 commits August 20, 2026 05:18
…Premium branding on trial page

Rework the trial signup page copy to lead with "Coder trial" language
instead of "Premium":
- headline now reads "Start an unlimited 30-day Coder trial"
- subheadline focuses on Coder Agents usage and enterprise AI governance
- page title/header changed from "Premium trial" to "Start a Coder trial"
- pricing link text simplified to "Learn more" and points to the
  pricing comparison anchor
- trial-active panel drops the "upgrade to Coder Premium" phrasing
- database load acknowledgement references "Coder trial features"
  instead of "Premium features"
- left nav item renamed from "Premium" to "Trial Upgrade"
Comment thread site/src/modules/management/DeploymentSidebarView.tsx Outdated
@untra
untra requested review from aslilac and jeremyruppel August 20, 2026 23:05
Comment thread enterprise/trialer/trialer.go Outdated
Comment thread site/src/components/FormField/FormField.tsx Outdated
Comment thread site/src/components/FormField/FormField.tsx Outdated

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.

nit, and for a future PR: wondering if we should use cva for this inside <Supergraphic>. if there are classes we supply again and again, that probably makes sense

@jeremyruppel jeremyruppel 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.

@untra the only comment I have left is perhaps breaking up site/src/modules/licenses/trialLicense.ts, but idk how far you want to take the cleanup, so I'm going to approve ahead of that. nice work!

@jeremyruppel
jeremyruppel dismissed aslilac’s stale review August 21, 2026 13:47

all feedback has been addressed, aside from the PR size, but this is about as small as we can make it. we have code freeze tonight, so I'm dismissing this review so we can move forward

@jeremyruppel
jeremyruppel merged commit f44a3b5 into main Aug 21, 2026
31 checks passed
@jeremyruppel
jeremyruppel deleted the feat/DEVEX-752-premium-page branch August 21, 2026 13:54
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants