Present Relay as annual-first support tier

This commit is contained in:
rcourtman
2026-04-29 12:49:20 +01:00
parent 87b9e6dd62
commit f060f261cd
26 changed files with 94 additions and 90 deletions
+2 -2
View File
@@ -160,8 +160,8 @@ Self-hosted tiers:
| Plan | Price | Core monitoring | Metric history | Main value |
|---|---:|---|---:|---|
| Community | Free | Included | 7 days | Full self-hosted monitoring |
| Relay | $4.99/mo or $39/yr | Included | 14 days | Remote access, mobile, and push notifications |
| Pro | $8.99/mo or $79/yr | Included | 90 days | Root-cause analysis, safe remediation workflows, and operations tooling |
| Relay | $39/yr or $4.99/mo | Included | 14 days | Remote web access, mobile app pairing, and push notifications |
| Pro | $79/yr or $8.99/mo | Included | 90 days | Root-cause analysis, safe remediation workflows, and operations tooling |
Pulse still counts top-level monitored systems once no matter how they are
collected. VMs, containers, pods, disks, backups, and other child resources
+1 -1
View File
@@ -32,7 +32,7 @@ If a setting is disabled with an amber warning, it's being overridden by an envi
## 🔍 Monitoring & Metrics
### What do Relay, Pro, and Cloud unlock?
Relay adds remote access, mobile access, push notifications, and 14-day history. Pro and Cloud unlock **alert-triggered root-cause analysis and safe remediation workflows** along with the broader operations feature set. Existing legacy Pro+ holders keep their current continuity, but self-hosted pricing no longer sells more monitoring volume. Pulse Patrol is available to everyone on Community with BYOK and provides scheduled, cross-system analysis that correlates real-time state, recent metrics history, and diagnostics to surface actionable findings.
Relay adds secure remote access to the Pulse web UI, mobile app pairing, push notifications, and 14-day history. Pro and Cloud unlock **alert-triggered root-cause analysis and safe remediation workflows** along with the broader operations feature set. Existing legacy Pro+ holders keep their current continuity, but self-hosted pricing no longer sells more monitoring volume. Pulse Patrol is available to everyone on Community with BYOK and provides scheduled, cross-system analysis that correlates real-time state, recent metrics history, and diagnostics to surface actionable findings.
Example output includes trend-based capacity warnings, backup regressions, Kubernetes cluster analysis, and correlated container failures that simple threshold alerts miss.
See [Pulse AI](AI.md), [Plans and entitlements](PULSE_PRO.md), and <https://pulserelay.pro>.
+1 -1
View File
@@ -96,7 +96,7 @@ The telemetry implementation is in [`internal/telemetry/telemetry.go`](../intern
Pulse can make outbound connections when you enable specific features:
- **AI providers**: when AI features are configured, Pulse sends only the context required for your request to the provider you chose. Local providers stay on your network; non-local providers such as OpenAI or Anthropic receive provider-bound context directly from your Pulse instance. AI prompts from self-managed installs do not transit Pulse infrastructure. Before non-local model requests leave the instance, governed resource details use the same resource-policy redaction shown in Data Handling: local-only resource details are omitted from detailed prompt sections or replaced with policy-safe summaries, and known restricted resource identifiers are redacted where they appear in provider-bound context. See `docs/AI.md`.
- **Relay / Remote Access**: when relay is enabled, Pulse connects to the configured relay endpoint to enable mobile access. See Settings → Remote Access.
- **Relay / Remote Access**: when relay is enabled, Pulse connects to the configured relay endpoint to enable secure remote web access, mobile app pairing, and push notifications. See Settings → Remote Access.
- **Update checks**: Pulse can check for new releases/updates (for example via GitHub release metadata) depending on your deployment and configuration.
### Local-only commercial handoff events
+2 -2
View File
@@ -32,8 +32,8 @@ Self-hosted pricing is:
| Plan | Price | Core monitoring | Metric history | Purpose |
|---|---:|---|---:|---|
| Community | Free | Included | 7 days | Full self-hosted monitoring for normal homelab use |
| Relay | $4.99/mo or $39/yr | Included | 14 days | Remote access, mobile, push, and convenience |
| Pro | $8.99/mo or $79/yr | Included | 90 days | AI operations and advanced admin features |
| Relay | $39/yr or $4.99/mo | Included | 14 days | Remote web access, mobile pairing, push, and convenience |
| Pro | $79/yr or $8.99/mo | Included | 90 days | AI operations and advanced admin features |
Counted examples:
- Proxmox PVE node
+1 -1
View File
@@ -85,7 +85,7 @@ All other documents are supporting references unless explicitly required for evi
Pulse is available in three self-hosted tiers plus hosted Cloud:
- **Community**: Free self-hosted monitoring with core monitoring included and 7-day history.
- **Relay**: Adds remote access, mobile, push notifications, and 14-day history.
- **Relay**: Adds secure remote access to the Pulse web UI, mobile app pairing, push notifications, and 14-day history.
- **Pro**: Adds alert-triggered root-cause analysis, safe remediation workflows, operations tooling, governance features, and 90-day history.
- **Cloud**: Hosted Pulse with Pro-level capabilities; hosted pricing is unchanged by the self-hosted model lock.
@@ -5,6 +5,12 @@ Target: `v6-rc-stabilization`
Lanes: `L2`, `L13`
Status: Superseded on 2026-04-16 by `self-hosted-core-monitoring-free`; this record now preserves the capped RC1 self-hosted model as historical context only and is not the final GA pricing direction.
Current replacement: Pulse v6 GA treats self-hosted core monitoring as included
for Community, Relay, and Pro. Relay is presented annual-first at `$39/year` with
`$4.99/month` as the secondary option, and it sells secure remote access to the
Pulse web UI, mobile app pairing, push notifications, and 14-day history rather
than monitored-system headroom or native mobile monitoring.
## Historical Decision
On 2026-03-17, Pulse v6 self-hosted commercial packaging was locked to this capped RC1 model:
@@ -56,20 +62,11 @@ Rules:
## User-Facing Copy
Counted-unit explainer:
> Pulse counts monitored systems, not everything underneath them. Each top-level machine or cluster counts once, no matter how Pulse collects it. VMs, containers, pods, disks, backups, and services under that system are included.
Plan taglines:
- Community: Monitor up to 5 systems for free.
- Relay: Get a bit more room and monitor from anywhere.
- Pro: Pulse does not just watch your infrastructure. It helps operate it.
- Pro+: Everything in Pro, with more room for larger labs.
Boundary-upgrade copy:
- Community to Relay: Need a little more room? Upgrade to Relay for 3 extra monitored systems plus remote access, mobile, and push notifications.
- Relay to Pro: Want Pulse to do more than alert? Upgrade to Pro for AI investigation, auto-fix, and 90-day history.
- Grace copy: Your existing monitoring will keep working for now, but new systems will not be added until you remove one or upgrade.
The capped RC1 copy that originally lived here is intentionally not retained as
reusable wording. Current user-facing copy must come from the replacement policy
above and from the shared self-hosted plan definitions, where self-hosted core
monitoring is included and Relay is positioned around remote web access, mobile
app pairing, push notifications, and 14-day history.
## Implementation Slices
@@ -222,6 +222,13 @@ rather than legacy Community limit enforcement.
Community as included core monitoring plus paid Relay/Pro extras. It must
not frame self-hosted checkout as buying unlimited monitoring or monitored-
system volume.
Relay pricing presentation should be annual-first at the existing public
$39/year price, with $4.99/month as the secondary option, so Relay reads as
an optional support/convenience tier rather than a pressure upgrade. Relay
copy must describe secure remote access to the Pulse web UI, mobile app
pairing, push notifications, and 14-day history; it must not imply that the
native mobile app is a full monitoring dashboard until that product surface
exists.
7. Add or change Stripe provisioning plan resolution through `internal/cloudcp/stripe/provisioner.go`
8. Add or change activation/grant lifecycle, release build helper gating, or dev-mode capability widening through `pkg/licensing/dev_mode_features.go`, `pkg/licensing/service.go`, `pkg/licensing/testing_helpers.go`, `pkg/licensing/grant_refresh.go`, and `pkg/licensing/revocation_poll.go`
9. Add or change license-server transport through `pkg/licensing/license_server_client.go`
+1 -1
View File
@@ -47,7 +47,7 @@ current public v6 plans.
| Plan | Core monitoring | Metric history | Paid value |
|---|---|---:|---|
| Community | Included | 7 days | Full self-hosted monitoring |
| Relay | Included | 14 days | Remote access, mobile, push, and convenience |
| Relay | Included | 14 days | Remote web access, mobile app pairing, push, and convenience |
| Pro | Included | 90 days | Relay plus AI operations, automation, and advanced admin features |
Legacy `Pro+` remains continuity-only for existing holders. It is not a public
+1 -1
View File
@@ -36,7 +36,7 @@ Current self-hosted v6 packaging is:
| Plan | Core monitoring | Metric history | Paid value |
|---|---|---:|---|
| Community | Included | 7 days | Full self-hosted monitoring |
| Relay | Included | 14 days | Remote access, mobile, push, and convenience |
| Relay | Included | 14 days | Remote web access, mobile app pairing, push, and convenience |
| Pro | Included | 90 days | Relay plus AI operations, automation, and advanced admin features |
Legacy `Pro+` remains continuity-only for existing holders. It is not a public
+1 -1
View File
@@ -52,7 +52,7 @@ more monitored-system capacity.
Instead, the self-hosted paid story is now consistently:
- Relay:
remote access, mobile, push, and convenience
remote web access, mobile app pairing, push, and convenience
- Pro:
Relay plus AI operations, automation, governance, and longer history
@@ -40,7 +40,7 @@ inventory language, but they are no longer the self-hosted paid gate.
- Community:
core monitoring included, 7-day history
- Relay:
Community plus remote access, mobile, push notifications, and 14-day history
Community plus remote web access, mobile app pairing, push notifications, and 14-day history
- Pro:
Relay plus AI operations, automation, advanced admin features, and 90-day
history
+1 -1
View File
@@ -96,7 +96,7 @@ The telemetry implementation is in [`internal/telemetry/telemetry.go`](../intern
Pulse can make outbound connections when you enable specific features:
- **AI providers**: when AI features are configured, Pulse sends only the context required for your request to the provider you chose. Local providers stay on your network; non-local providers such as OpenAI or Anthropic receive provider-bound context directly from your Pulse instance. AI prompts from self-managed installs do not transit Pulse infrastructure. Before non-local model requests leave the instance, governed resource details use the same resource-policy redaction shown in Data Handling: local-only resource details are omitted from detailed prompt sections or replaced with policy-safe summaries, and known restricted resource identifiers are redacted where they appear in provider-bound context. See `docs/AI.md`.
- **Relay / Remote Access**: when relay is enabled, Pulse connects to the configured relay endpoint to enable mobile access. See Settings → Remote Access.
- **Relay / Remote Access**: when relay is enabled, Pulse connects to the configured relay endpoint to enable secure remote web access, mobile app pairing, and push notifications. See Settings → Remote Access.
- **Update checks**: Pulse can check for new releases/updates (for example via GitHub release metadata) depending on your deployment and configuration.
### Local-only commercial handoff events
+2 -2
View File
@@ -84,8 +84,8 @@ All other documents are supporting references unless explicitly required for evi
Pulse is available in three self-hosted tiers plus hosted Cloud:
- **Community**: Free self-hosted core monitoring with 7-day history.
- **Relay**: Adds remote access, mobile, push notifications, and 14-day history.
- **Community**: Free self-hosted monitoring with core monitoring included and 7-day history.
- **Relay**: Adds secure remote access to the Pulse web UI, mobile app pairing, push notifications, and 14-day history.
- **Pro**: Adds alert-triggered root-cause analysis, safe remediation workflows, operations tooling, governance features, and 90-day history.
- **Cloud**: Hosted Pulse with Pro-level capabilities; hosted pricing is unchanged by the self-hosted model lock.
@@ -270,7 +270,7 @@ describe('ProLicensePanel', () => {
expect(screen.getByText('What Relay adds')).toBeInTheDocument();
expect(screen.getByText('What Pulse Pro adds')).toBeInTheDocument();
expect(screen.getByText('Pulse Relay (Remote Access)')).toBeInTheDocument();
expect(screen.getByText('Mobile App Access')).toBeInTheDocument();
expect(screen.getByText('Mobile App Pairing')).toBeInTheDocument();
expect(screen.getByText('Push Notifications')).toBeInTheDocument();
expect(screen.getByText('Alert Root-Cause Analysis')).toBeInTheDocument();
expect(screen.getByText('Safe Remediation Workflows')).toBeInTheDocument();
@@ -546,7 +546,7 @@ describe('ProLicensePanel', () => {
expect(
screen.getByText(
'Relay is active on this instance. Remote access, mobile, push, and longer history are available right now.',
'Relay is active on this instance. Remote web access, mobile pairing, push notifications, and longer history are available right now.',
),
).toBeInTheDocument();
expect(screen.queryByText('Optional extras')).not.toBeInTheDocument();
@@ -554,7 +554,7 @@ describe('ProLicensePanel', () => {
expect(screen.queryByText('What Pulse Pro adds')).not.toBeInTheDocument();
expect(screen.queryByRole('link', { name: 'See all plans' })).not.toBeInTheDocument();
expect(screen.getByText('Pulse Relay (Remote Access)')).toBeInTheDocument();
expect(screen.getByText('Mobile App Access')).toBeInTheDocument();
expect(screen.getByText('Mobile App Pairing')).toBeInTheDocument();
expect(screen.getByText('Push Notifications')).toBeInTheDocument();
});
@@ -675,7 +675,9 @@ describe('ProLicensePanel', () => {
expect(screen.queryByText('Why is continuity still pending?')).not.toBeInTheDocument();
expect(screen.queryByRole('tab', { name: 'Usage' })).not.toBeInTheDocument();
expect(
screen.queryByText('New top-level additions are paused until this legacy continuity state is reviewed.'),
screen.queryByText(
'New top-level additions are paused until this legacy continuity state is reviewed.',
),
).not.toBeInTheDocument();
});
@@ -731,9 +733,7 @@ describe('ProLicensePanel', () => {
),
).toBeInTheDocument();
expect(screen.queryByText('Legacy monitoring continuity')).not.toBeInTheDocument();
expect(
screen.queryByText(/observed legacy estate available/i),
).not.toBeInTheDocument();
expect(screen.queryByText(/observed legacy estate available/i)).not.toBeInTheDocument();
expect(screen.queryByText('Legacy continuity')).not.toBeInTheDocument();
expect(screen.queryByText('23 monitored systems')).not.toBeInTheDocument();
expect(screen.queryByText('Monitored-system policy')).not.toBeInTheDocument();
@@ -793,7 +793,7 @@ describe('ProLicensePanel', () => {
expect(screen.getByText('PDF/CSV Reporting')).toBeInTheDocument();
expect(screen.getByText('Centralized Agent Profiles')).toBeInTheDocument();
expect(screen.getByText('Pulse Relay (Remote Access)')).toBeInTheDocument();
expect(screen.getByText('Mobile App Access')).toBeInTheDocument();
expect(screen.getByText('Mobile App Pairing')).toBeInTheDocument();
expect(screen.getByText('Push Notifications')).toBeInTheDocument();
expect(screen.getByText('Extended Metric History')).toBeInTheDocument();
expect(screen.queryByText('Multi-Tenant Mode')).not.toBeInTheDocument();
@@ -100,7 +100,7 @@ describe('licensePresentation', () => {
it('returns canonical feature labels', () => {
expect(getLicenseFeatureLabel('ai_patrol')).toBe('Pulse Patrol');
expect(getLicenseFeatureLabel('mobile_app')).toBe('Mobile App Access');
expect(getLicenseFeatureLabel('mobile_app')).toBe('Mobile App Pairing');
expect(getLicenseFeatureLabel('update_alerts')).toBe('Update Alerts');
expect(getLicenseFeatureLabel('relay')).toBe('Pulse Relay (Remote Access)');
expect(getLicenseFeatureLabel('custom_feature')).toBe('Custom Feature');
@@ -290,7 +290,7 @@ describe('licensePresentation', () => {
},
displayableCapabilities: [
'Pulse Relay (Remote Access)',
'Mobile App Access',
'Mobile App Pairing',
'Safe Remediation Workflows',
],
}),
@@ -393,10 +393,10 @@ describe('licensePresentation', () => {
cards: [
{
title: 'What Relay adds',
body: 'Reach this Pulse instance securely from anywhere, check it from mobile, get push notifications, and keep 14 days of history.',
body: 'Reach your Pulse web UI securely from anywhere, pair the mobile app for handoff and push notifications, and keep 14 days of history.',
highlights: [
'Pulse Relay (Remote Access)',
'Mobile App Access',
'Mobile App Pairing',
'Push Notifications',
'14-day metric history',
],
@@ -472,7 +472,7 @@ describe('licensePresentation', () => {
},
displayableCapabilities: [
'Pulse Relay (Remote Access)',
'Mobile App Access',
'Mobile App Pairing',
'Push Notifications',
'Safe Remediation Workflows',
],
@@ -506,7 +506,7 @@ describe('licensePresentation', () => {
},
displayableCapabilities: [
'Pulse Relay (Remote Access)',
'Mobile App Access',
'Mobile App Pairing',
'Push Notifications',
],
source: 'manual',
@@ -518,7 +518,7 @@ describe('licensePresentation', () => {
highlightsLabel: 'Available now on this instance',
highlights: [
'Pulse Relay (Remote Access)',
'Mobile App Access',
'Mobile App Pairing',
'Push Notifications',
'14-day metric history',
],
@@ -52,7 +52,7 @@ describe('selfHostedPlans', () => {
expect(SELF_HOSTED_COMMERCIAL_PRESENTATION).toEqual({
pageTitle: 'Pricing',
pageDescription:
'Self-hosted Pulse includes core monitoring for free. Relay adds secure remote access and mobile convenience, while Pro adds root-cause analysis, safe remediation workflows, 90-day history, and admin/reporting extras.',
'Self-hosted Pulse includes core monitoring for free. Relay adds secure remote access to the Pulse web UI, mobile pairing, and push notifications, while Pro adds root-cause analysis, safe remediation workflows, 90-day history, and admin/reporting extras.',
mostPopularBadge: 'Most Popular',
currentPlanLabel: 'Current Plan',
includedLabel: 'Included',
@@ -94,17 +94,17 @@ describe('selfHostedPlans', () => {
]);
expect(SELF_HOSTED_PLAN_BY_TIER.community.includedExtras).toEqual([]);
expect(SELF_HOSTED_PLAN_BY_TIER.relay.billingExtrasSummary).toBe(
'Remote access, mobile, and push',
'Remote web access, mobile pairing, and push',
);
expect(SELF_HOSTED_PLAN_BY_TIER.relay.entitlementSummary).toContain(
'Remote access, mobile, push, and longer history are available right now.',
'Remote web access, mobile pairing, push notifications, and longer history are available right now.',
);
expect(SELF_HOSTED_PLAN_BY_TIER.relay.comparisonSummary).toContain(
'Reach this Pulse instance securely from anywhere',
'Reach your Pulse web UI securely from anywhere',
);
expect(SELF_HOSTED_PLAN_BY_TIER.relay.entitlementHighlights).toEqual([
'Pulse Relay (Remote Access)',
'Mobile App Access',
'Mobile App Pairing',
'Push Notifications',
'14-day metric history',
]);
@@ -421,7 +421,7 @@ const getSelfHostedActivePlanSummary = (
case 'community':
return `${planLabel} is active on this instance. It includes self-hosted monitoring, 7-day metric history, Pulse Patrol (BYOK), and update alerts.`;
case 'relay':
return `${planLabel} is active on this instance. Remote access, mobile, push, and longer history are available right now.`;
return `${planLabel} is active on this instance. Remote web access, mobile pairing, push notifications, and longer history are available right now.`;
case 'pro':
return `${planLabel} is active on this instance. Root-cause analysis, safe remediation workflows, 90-day history, and admin/reporting extras are available right now.`;
default:
@@ -97,8 +97,8 @@ export const SELF_HOSTED_FEATURE_CATALOG: readonly GeneratedSelfHostedFeatureCat
},
{
"key": "mobile_app",
"displayName": "Mobile App Access",
"comparisonName": "Mobile App Access",
"displayName": "Mobile App Pairing",
"comparisonName": "Mobile App Pairing",
"showInComparisonTable": true,
"displayableInSelfHostedPlan": true,
"roles": {
+10 -10
View File
@@ -108,20 +108,20 @@ export const SELF_HOSTED_PLAN_DEFINITIONS: readonly SelfHostedPlanDefinition[] =
{
tier: 'relay',
name: 'Relay',
price: '$4.99/month',
subline: 'or $39/year',
price: '$39/year',
subline: 'or $4.99/month',
metricHistoryDays: 14,
billingExtrasSummary: 'Remote access, mobile, and push',
billingExtrasSummary: 'Remote web access, mobile pairing, and push',
entitlementSummary:
'Relay is active on this instance. Remote access, mobile, push, and longer history are available right now.',
'Relay is active on this instance. Remote web access, mobile pairing, push notifications, and longer history are available right now.',
entitlementHighlights: getTierEntitlementHighlights('relay', 14),
includedExtras: [],
comparisonSummary:
'Reach this Pulse instance securely from anywhere, check it from mobile, get push notifications, and keep 14 days of history.',
'Reach your Pulse web UI securely from anywhere, pair the mobile app for handoff and push notifications, and keep 14 days of history.',
highlights: [
'Everything in Community',
'Remote access via Relay',
'Mobile app access',
'Remote web access via Relay',
'Mobile app pairing',
'Push notifications',
'Custom URL (yourlab.pulserelay.pro)',
'14-day metric history',
@@ -130,8 +130,8 @@ export const SELF_HOSTED_PLAN_DEFINITIONS: readonly SelfHostedPlanDefinition[] =
{
tier: 'pro',
name: 'Pro',
price: '$8.99/month',
subline: 'or $79/year',
price: '$79/year',
subline: 'or $8.99/month',
metricHistoryDays: 90,
billingExtrasSummary: 'Analysis, remediation, and admin controls',
entitlementSummary:
@@ -179,7 +179,7 @@ export function getSelfHostedPlanDefinitionForBillingTier(
export const SELF_HOSTED_COMMERCIAL_PRESENTATION: SelfHostedCommercialPresentation = {
pageTitle: 'Pricing',
pageDescription:
'Self-hosted Pulse includes core monitoring for free. Relay adds secure remote access and mobile convenience, while Pro adds root-cause analysis, safe remediation workflows, 90-day history, and admin/reporting extras.',
'Self-hosted Pulse includes core monitoring for free. Relay adds secure remote access to the Pulse web UI, mobile pairing, and push notifications, while Pro adds root-cause analysis, safe remediation workflows, 90-day history, and admin/reporting extras.',
mostPopularBadge: 'Most Popular',
currentPlanLabel: 'Current Plan',
includedLabel: 'Included',
+1 -1
View File
@@ -1,5 +1,5 @@
{
"source_hash": "48a3ee0ab24faeac280a149c1dbe673accd83ea6073ecf17afc7fc57255c503f",
"source_hash": "ff1828403441d25373e005de762dcfe0486e438e6b360d59fe217cbb22302906",
"build_inputs": [
"package.json",
"tsconfig.json",
+11 -11
View File
@@ -482,34 +482,34 @@ function routeCommercialAPI(request, response, url, scenario) {
if (request.method === 'GET' && route === '/v1/public/pricing-model') {
sendJSON(response, 200, {
title: 'Simple self-hosted pricing for Pulse',
description: 'Community keeps core monitoring free. Relay lets you reach Pulse securely from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
description: 'Community keeps core monitoring free. Relay gives secure remote access to the Pulse web UI, mobile app pairing, push notifications, and 14-day history. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
explainer:
'Community keeps core monitoring free. Relay gets Pulse securely from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
'Community keeps core monitoring free. Relay gets your Pulse web UI securely reachable from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
plans: [
{
badge: 'Recommended',
highlight: true,
tierKicker: 'Relay',
title: 'Relay',
price: '$4.99',
period: '$39/year available too',
blurb: 'The reach-it-anywhere tier for secure remote access, mobile access, and push notifications.',
price: '$39/year',
period: 'or $4.99/month',
blurb: 'Secure remote access to your Pulse web UI, mobile app pairing, and push notifications.',
features: [
{ tone: 'check', html: 'Core <strong>self-hosted monitoring</strong> included' },
{ tone: 'check', html: 'Secure remote access' },
{ tone: 'check', html: 'Mobile access' },
{ tone: 'check', html: 'Secure remote web access' },
{ tone: 'check', html: 'Mobile app pairing' },
{ tone: 'check', html: 'Push notifications' },
],
buttons: [
{ kind: 'checkout', className: 'btn btn-secondary', tier: 'relay', planKey: 'price_relay_monthly', billingCycle: 'monthly', label: 'Buy Monthly' },
{ kind: 'checkout', className: 'btn btn-primary', tier: 'relay', planKey: 'price_relay_annual', billingCycle: 'annual', label: 'Buy Annual' },
{ kind: 'checkout', className: 'btn btn-secondary', tier: 'relay', planKey: 'price_relay_monthly', billingCycle: 'monthly', label: 'Buy Monthly' },
],
},
{
tierKicker: 'Pro',
title: 'Pro',
price: '$8.99',
period: '$79/year available too',
price: '$79/year',
period: 'or $8.99/month',
blurb: 'The operator tier for root-cause analysis, safe remediation workflows, and 90-day history.',
features: [
{ tone: 'check', html: 'Core <strong>self-hosted monitoring</strong> included' },
@@ -519,8 +519,8 @@ function routeCommercialAPI(request, response, url, scenario) {
{ tone: 'check', html: '90-day history' },
],
buttons: [
{ kind: 'checkout', className: 'btn btn-secondary', tier: 'pro', planKey: 'price_pro_monthly', billingCycle: 'monthly', label: 'Buy Monthly' },
{ kind: 'checkout', className: 'btn btn-primary', tier: 'pro', planKey: 'price_pro_annual', billingCycle: 'annual', label: 'Buy Annual' },
{ kind: 'checkout', className: 'btn btn-secondary', tier: 'pro', planKey: 'price_pro_monthly', billingCycle: 'monthly', label: 'Buy Monthly' },
],
},
],
@@ -240,13 +240,13 @@ describe('services view', function() {
title: 'Pricing',
description: 'Canonical pricing model',
explainer:
'Community keeps core monitoring free. Relay gets Pulse securely from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
'Community keeps core monitoring free. Relay gets your Pulse web UI securely reachable from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
plans: [
{
tierKicker: 'Pro',
title: 'Pro',
price: '$8.99',
period: '$79/year available too',
price: '$79/year',
period: 'or $8.99/month',
blurb: 'The operator tier for root-cause analysis, safe remediation workflows, and 90-day history.',
features: [{ tone: 'check', html: 'Core <strong>self-hosted monitoring</strong> included' }],
buttons: [
@@ -273,7 +273,7 @@ describe('services view', function() {
'Pulse Account keeps checkout tied to the Pulse instance that opened it, so completed Relay or Pro purchases return to the right Plans page automatically.',
);
expect(document.getElementById('upgrade-billing-root')?.innerHTML).toContain(
'Community keeps core monitoring free. Relay gets Pulse securely from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
'Community keeps core monitoring free. Relay gets your Pulse web UI securely reachable from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.',
);
expect(document.getElementById('upgrade-billing-root')?.innerHTML).not.toMatch(
/Unlimited[\s\S]{0,80}self-hosted monitoring/i,
@@ -300,9 +300,9 @@ describe('services view', function() {
{
tierKicker: 'Relay',
title: 'Relay',
price: '$4.99',
period: '$39/year available too',
blurb: 'Secure remote access and mobile access.',
price: '$39/year',
period: 'or $4.99/month',
blurb: 'Secure remote web access and mobile app pairing.',
features: [{ tone: 'check', html: 'Core <strong>self-hosted monitoring</strong> included' }],
buttons: [
{
+1 -1
View File
@@ -92,7 +92,7 @@ func TestGetFeatureDisplayNameCoversKnownFeaturesAndFallback(t *testing.T) {
{feature: FeatureSSO, want: "Basic SSO (OIDC)"},
{feature: FeatureAdvancedSSO, want: "Advanced SSO (SAML/Multi-Provider)"},
{feature: FeatureRelay, want: "Pulse Relay (Remote Access)"},
{feature: FeatureMobileApp, want: "Mobile App Access"},
{feature: FeatureMobileApp, want: "Mobile App Pairing"},
{feature: FeaturePushNotifications, want: "Push Notifications"},
{feature: FeatureAdvancedReporting, want: "PDF/CSV Reporting"},
{feature: FeatureLongTermMetrics, want: "Extended Metric History"},
+1 -1
View File
@@ -237,7 +237,7 @@ func TestGetFeatureDisplayName(t *testing.T) {
{FeatureSSO, "Basic SSO (OIDC)"},
{FeatureAdvancedSSO, "Advanced SSO (SAML/Multi-Provider)"},
{FeatureRelay, "Pulse Relay (Remote Access)"},
{FeatureMobileApp, "Mobile App Access"},
{FeatureMobileApp, "Mobile App Pairing"},
{FeaturePushNotifications, "Push Notifications"},
{FeatureAdvancedReporting, "PDF/CSV Reporting"},
{FeatureLongTermMetrics, "Extended Metric History"},
+3 -3
View File
@@ -105,8 +105,8 @@ var featureMetadataCatalog = map[string]FeatureMetadata{
},
FeatureMobileApp: {
Key: FeatureMobileApp,
DisplayName: "Mobile App Access",
ComparisonName: "Mobile App Access",
DisplayName: "Mobile App Pairing",
ComparisonName: "Mobile App Pairing",
ShowInComparisonTable: true,
DisplayableInPlanUI: true,
SelfHostedRoles: SelfHostedFeatureRoles{
@@ -114,7 +114,7 @@ var featureMetadataCatalog = map[string]FeatureMetadata{
Relay: SelfHostedFeatureRolePrimaryPillar,
Pro: SelfHostedFeatureRoleIncluded,
},
UpgradeReason: "Get Relay so you can check Pulse from your phone when you are away from the dashboard.",
UpgradeReason: "Get Relay so the mobile app can pair with this instance for secure handoff and notifications.",
UpgradePriority: 1,
},
FeaturePushNotifications: {
@@ -78,11 +78,11 @@ test.describe("Pulse Account upgrade bootstrap", () => {
"Pulse Account will return completed checkout directly to the Plans page in Pulse.",
),
).toBeVisible();
await expect(
page.getByText(
"Community keeps monitoring free and unlimited. Relay gets Pulse securely from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.",
),
).toBeVisible();
await expect(
page.getByText(
"Community keeps core monitoring free. Relay gets your Pulse web UI securely reachable from anywhere. Pro adds root-cause analysis, safe remediation workflows, and 90-day history.",
),
).toBeVisible();
await expect(
page.getByText(
"Pulse Account keeps checkout tied to the Pulse instance that opened it, so completed Relay or Pro purchases return to the right Plans page automatically.",