diff --git a/docs/release-control/v6/internal/subsystems/cloud-paid.md b/docs/release-control/v6/internal/subsystems/cloud-paid.md index 014df4727..54c236564 100644 --- a/docs/release-control/v6/internal/subsystems/cloud-paid.md +++ b/docs/release-control/v6/internal/subsystems/cloud-paid.md @@ -234,6 +234,11 @@ Community limit enforcement. surfaces must describe the real commercial flow as secure checkout -> Pulse Account -> open workspace, not as an immediate workspace creation or trial-only shortcut. + Public hosted Cloud trial signup must state the trial duration and + checkout economics before Stripe handoff: Stripe may collect a payment + method, but the subscription starts with the configured trial period and no + upfront charge, then Pulse Account opens the provisioned workspace after + checkout completes. 20. Add contract tests where runtime and pricing need to stay aligned 21. Add or change hosted browser org-context bootstrap through `frontend-modern/src/App.tsx`, `frontend-modern/src/AppLayout.tsx`, `frontend-modern/src/useAppRuntimeState.ts`, and `frontend-modern/src/utils/apiClient.ts` That same hosted bootstrap boundary also owns the runtime-capability JSON diff --git a/frontend-modern/src/pages/CloudPricing.tsx b/frontend-modern/src/pages/CloudPricing.tsx index af8327c14..d009ff7da 100644 --- a/frontend-modern/src/pages/CloudPricing.tsx +++ b/frontend-modern/src/pages/CloudPricing.tsx @@ -69,7 +69,7 @@ function CloudTierCard(props: { tier: CloudPlanDefinition }) { href={`/cloud/signup?tier=${t.tier}`} class="w-full inline-flex items-center justify-center rounded-md bg-blue-600 px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-blue-700" > - {`Choose ${t.name}`} + {`Start ${t.name} Trial`} diff --git a/frontend-modern/src/pages/__tests__/CloudPricing.test.tsx b/frontend-modern/src/pages/__tests__/CloudPricing.test.tsx index a8129bd2a..fc1f9b45b 100644 --- a/frontend-modern/src/pages/__tests__/CloudPricing.test.tsx +++ b/frontend-modern/src/pages/__tests__/CloudPricing.test.tsx @@ -20,25 +20,27 @@ describe('CloudPricing', () => { )); - expect(await screen.findByRole('link', { name: 'Choose Starter' })).toHaveAttribute( + expect(await screen.findByRole('link', { name: 'Start Starter Trial' })).toHaveAttribute( 'href', '/cloud/signup?tier=starter', ); expect(screen.getByText('Founding rate')).toBeInTheDocument(); expect(screen.getByText('$19')).toBeInTheDocument(); expect(screen.getByText('$29/month')).toBeInTheDocument(); - expect(screen.getByRole('link', { name: 'Choose Power' })).toHaveAttribute( + expect(screen.getByRole('link', { name: 'Start Power Trial' })).toHaveAttribute( 'href', '/cloud/signup?tier=power', ); - expect(screen.getByRole('link', { name: 'Choose Max' })).toHaveAttribute( + expect(screen.getByRole('link', { name: 'Start Max Trial' })).toHaveAttribute( 'href', '/cloud/signup?tier=max', ); expect(screen.queryByText('Starter founding rate')).not.toBeInTheDocument(); expect(screen.getAllByText('All Pro features')).toHaveLength(1); expect(screen.getByText('Managed hosting')).toBeInTheDocument(); - expect(screen.getByText('Choose a Cloud plan and complete secure checkout.')).toBeInTheDocument(); + expect( + screen.getByText('Choose a Cloud plan and start the 14-day trial in secure checkout.'), + ).toBeInTheDocument(); expect(screen.getByText('How it works')).toBeInTheDocument(); expect(screen.getByRole('link', { name: 'Open Pulse Account' })).toHaveAttribute( 'href', diff --git a/frontend-modern/src/pages/__tests__/HostedSignup.test.tsx b/frontend-modern/src/pages/__tests__/HostedSignup.test.tsx index 309db6ed1..6e4c6192b 100644 --- a/frontend-modern/src/pages/__tests__/HostedSignup.test.tsx +++ b/frontend-modern/src/pages/__tests__/HostedSignup.test.tsx @@ -60,10 +60,14 @@ describe('HostedSignup', () => { )); expect(await screen.findByText('Workspace')).toBeInTheDocument(); - expect(screen.getByText('Create your Pulse Cloud account and hosted workspace.')).toBeInTheDocument(); + expect( + screen.getByText('Start your 14-day Pulse Cloud trial and hosted workspace.'), + ).toBeInTheDocument(); expect(screen.getByText('Plan')).toBeInTheDocument(); expect(screen.getByText('How it works')).toBeInTheDocument(); - expect(screen.getByText('Choose a Cloud plan and complete secure checkout.')).toBeInTheDocument(); + expect( + screen.getByText('Choose a Cloud plan and start the 14-day trial in secure checkout.'), + ).toBeInTheDocument(); expect(screen.getByText('Already signed up?')).toBeInTheDocument(); expect(screen.getByText('Request a fresh Pulse Account sign-in link.')).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Email Pulse Account Link' })).toBeInTheDocument(); @@ -74,7 +78,7 @@ describe('HostedSignup', () => { fireEvent.input(screen.getByLabelText('Organization Name'), { target: { value: 'Pulse Labs' }, }); - fireEvent.submit(screen.getByRole('button', { name: 'Continue to Checkout' }).closest('form')!); + fireEvent.submit(screen.getByRole('button', { name: 'Start Trial in Checkout' }).closest('form')!); await waitFor(() => { expect(signupMock).toHaveBeenCalledWith({ diff --git a/frontend-modern/src/utils/__tests__/cloudPlans.test.ts b/frontend-modern/src/utils/__tests__/cloudPlans.test.ts index 71796572c..5d4f1f6fe 100644 --- a/frontend-modern/src/utils/__tests__/cloudPlans.test.ts +++ b/frontend-modern/src/utils/__tests__/cloudPlans.test.ts @@ -32,7 +32,7 @@ describe('cloudPlans', () => { it('keeps shared cloud commercial copy in the common contract', () => { expect(CLOUD_COMMERCIAL_PRESENTATION).toEqual({ pageTitle: 'Pulse Cloud', - pageDescription: 'Managed Pulse hosting with Pro features included.', + pageDescription: 'Managed Pulse hosting with Pro features included. Start with a 14-day trial.', includedInAllHeading: 'Included in every Cloud plan', includedInAllItems: [ 'All Pro features', @@ -50,15 +50,15 @@ describe('cloudPlans', () => { it('keeps hosted signup commercial copy in the common contract', () => { expect(HOSTED_SIGNUP_PRESENTATION).toEqual({ pageTitlePrefix: 'Pulse Cloud', - pageDescription: 'Create your Pulse Cloud account and hosted workspace.', + pageDescription: 'Start your 14-day Pulse Cloud trial and hosted workspace.', workspaceHeading: 'Workspace', planHeading: 'Plan', nextHeading: 'How it works', nextSteps: CLOUD_ACCOUNT_FLOW_STEPS, existingAccountHeading: 'Already signed up?', existingAccountDescription: 'Request a fresh Pulse Account sign-in link.', - createWorkspaceLabel: 'Continue to Checkout', - creatingWorkspaceLabel: 'Preparing Checkout...', + createWorkspaceLabel: 'Start Trial in Checkout', + creatingWorkspaceLabel: 'Preparing Trial Checkout...', emailSignInLinkLabel: 'Email Pulse Account Link', sendingSignInLinkLabel: 'Sending...', }); diff --git a/frontend-modern/src/utils/cloudPlans.ts b/frontend-modern/src/utils/cloudPlans.ts index 8c6073f09..8f074e2aa 100644 --- a/frontend-modern/src/utils/cloudPlans.ts +++ b/frontend-modern/src/utils/cloudPlans.ts @@ -46,7 +46,7 @@ export interface HostedSignupPresentation { } export const CLOUD_ACCOUNT_FLOW_STEPS = [ - 'Choose a Cloud plan and complete secure checkout.', + 'Choose a Cloud plan and start the 14-day trial in secure checkout.', 'Use the email link to open Pulse Account.', 'Open your workspace and connect systems.', ] as const; @@ -104,7 +104,7 @@ export const CLOUD_PLAN_LABELS: Record = { export const CLOUD_COMMERCIAL_PRESENTATION: CloudCommercialPresentation = { pageTitle: 'Pulse Cloud', - pageDescription: 'Managed Pulse hosting with Pro features included.', + pageDescription: 'Managed Pulse hosting with Pro features included. Start with a 14-day trial.', includedInAllHeading: 'Included in every Cloud plan', includedInAllItems: [ 'All Pro features', @@ -120,15 +120,15 @@ export const CLOUD_COMMERCIAL_PRESENTATION: CloudCommercialPresentation = { export const HOSTED_SIGNUP_PRESENTATION: HostedSignupPresentation = { pageTitlePrefix: 'Pulse Cloud', - pageDescription: 'Create your Pulse Cloud account and hosted workspace.', + pageDescription: 'Start your 14-day Pulse Cloud trial and hosted workspace.', workspaceHeading: 'Workspace', planHeading: 'Plan', nextHeading: 'How it works', nextSteps: CLOUD_ACCOUNT_FLOW_STEPS, existingAccountHeading: 'Already signed up?', existingAccountDescription: 'Request a fresh Pulse Account sign-in link.', - createWorkspaceLabel: 'Continue to Checkout', - creatingWorkspaceLabel: 'Preparing Checkout...', + createWorkspaceLabel: 'Start Trial in Checkout', + creatingWorkspaceLabel: 'Preparing Trial Checkout...', emailSignInLinkLabel: 'Email Pulse Account Link', sendingSignInLinkLabel: 'Sending...', } as const; diff --git a/internal/cloudcp/public_cloud_signup_handlers.go b/internal/cloudcp/public_cloud_signup_handlers.go index 4eb79b03e..83153fd64 100644 --- a/internal/cloudcp/public_cloud_signup_handlers.go +++ b/internal/cloudcp/public_cloud_signup_handlers.go @@ -58,7 +58,7 @@ var publicCloudSignupPageTemplate = template.Must(template.New("public-cloud-sig - Start Pulse Cloud + Start Pulse Cloud Trial