10 KiB
Pulse Account Portal Spec
Last updated: 2026-03-26 Status: ACTIVE
Purpose
Define the canonical customer and operator account surface for Pulse once the current fragmented cloud, licensing, billing, recovery, and MSP account surfaces are promoted into a dedicated governed lane.
This spec exists to stop three kinds of drift:
- Cloud and MSP account work growing as a control-plane-only portal with no coherent self-hosted account story.
- Self-hosted commercial support accreting as one-off utility pages instead of a real account surface.
- Relay, Mobile, Cloud, and licensing account actions being presented as separate portals rather than one Pulse account model with product-specific areas.
Current Product Truth
Pulse already has real customer-account and operator-account surfaces, but they are split across different products and repos:
internal/cloudcp/portal/page.goandinternal/cloudcp/portal/handlers.goprovide a real hosted browser portal for Cloud and MSP accounts.internal/cloudcp/account/tenant_handlers.goandinternal/cloudcp/routes.goprovide authenticated account-member, workspace, and billing actions.pulse-pro/landing-page/manage.html,pulse-pro/landing-page/retrieve-license.html,pulse-pro/landing-page/refund.html,pulse-pro/landing-page/data.html, andpulse-pro/landing-page/thanks.htmlprovide public commercial utility surfaces for the current self-hosted track.- Hosted Cloud and MSP now have public explanatory pages, but those pages are not themselves the account surface.
That means Pulse has account plumbing, not yet one coherent Pulse account product surface.
Canonical Product Definition
Pulse Account is the single authenticated commercial and lifecycle control
surface for Pulse customers and operators.
It owns:
- identity for commercial/account actions
- billing and subscription state
- self-hosted licenses, activations, and recovery
- hosted Cloud tenant access and lifecycle
- MSP workspace and membership administration
- support and compliance actions that belong to the commercial account, not to one Pulse runtime instance
It does not own:
- in-product Pulse runtime settings
- relay pairing or mobile device state as a standalone portal
- tenant-local monitoring, AI, alerting, storage, or other runtime product workflows that belong inside Pulse itself
Canonical User Model
The canonical commercial identity hierarchy is:
userOne human identity that can sign in to account-scoped commercial surfaces.accountThe commercial ownership unit. An account can be a Cloud customer, an MSP, or another commercial owner shape that holds billing and memberships.workspace/tenantA hosted Pulse runtime owned by an account.licenseA self-hosted commercial entitlement owned by an account.membershipA role binding between a user and an account.
One user may belong to multiple accounts. One account may own multiple hosted workspaces and multiple self-hosted licenses. MSP is therefore an account kind with stronger workspace-management needs, not a completely separate portal.
Canonical Information Architecture
The future Pulse account surface should be one shell with product-aware areas, not separate portals for each commercial motion.
Primary areas:
OverviewAccount identity, current plan state, high-level service status, and next actions.CloudHosted tenant list, health summary, open-workspace handoff, tenant lifecycle, invites, and account-scoped hosted billing actions.LicensesSelf-hosted license retrieval, activation context, entitlement status, renewal state, and recovery actions.BillingSubscription state, invoices, payment method, usage-facing commercial facts, and Stripe billing portal handoff when still needed.PeopleMemberships, roles, invitations, and account access.Recovery & SupportRefund, data request, recovery-email, and commercial support actions.
Conditional areas:
MSP WorkspacesOnly when the account kind is MSP or otherwise multi-workspace by contract.Organization / Tenant AdminOnly for hosted accounts that need browser-side workspace lifecycle actions.
Product-Specific Boundaries
Self-hosted Pulse
Self-hosted Pulse keeps runtime settings, activation notices, and local billing status inside the product instance, but the durable customer-account actions move toward Pulse Account:
- license retrieval
- subscription management
- refunds and data requests
- account-level billing history
- future license inventory and seat/entitlement visibility
Pulse Cloud
Pulse Cloud uses Pulse Account as its primary customer control surface.
It owns:
- hosted tenant list
- billing state
- workspace open/handoff
- tenant create/delete/suspend lifecycle
- account membership and invites
The hosted tenant Pulse runtime remains the product runtime, not the account portal.
MSP
MSP is not a separate portal brand. It is a Pulse Account shape with stronger multi-workspace and operator controls.
It adds:
- customer workspace lifecycle
- workspace switching
- per-workspace health summary
- account roles suitable for owner/admin/tech/read-only workflows
Pulse Relay and Pulse Mobile
Pulse Relay does not get a standalone portal. Relay is a capability inside Pulse Mobile, self-hosted Pulse, and Pulse Cloud.
Pulse Account may show:
- whether a plan includes relay/mobile capability
- hosted billing or upgrade implications for relay/mobile usage
It must not become a separate Relay administration product unless Relay is later sold as a standalone service.
Transition Rules
The current public utility pages remain valid transitional surfaces while v5 is the live public commercial track, but they are not the desired steady-state shape.
Transition rule:
- existing utility pages may remain as entry points or compatibility shims
- new commercial/account workflows should prefer the Pulse Account shell
- utility pages should shrink toward redirects or lightweight recovery handoffs once equivalent Pulse Account areas exist
Forbidden Drift
Do not:
- build a separate Relay portal
- build separate Cloud, MSP, and self-hosted account shells that duplicate billing, identity, and recovery logic
- add new one-off commercial utility pages when the workflow belongs in Pulse Account
- let the hosted control-plane portal evolve without a self-hosted license and recovery story
- move runtime product settings out of Pulse and into the account portal just because the account shell exists
v6 Scope And Phasing
The full Pulse Account portal is not an RC or GA floor gate for v6. That matches the current resolved decision that full hosted MSP portal expansion is post-GA.
But it is the canonical next product-shaping lane for commercial coherence.
Current v6 floor
Accepted as sufficient for RC and GA:
- Cloud/MSP control-plane portal exists
- self-hosted recovery and billing utilities exist
- commercial surfaces are functional but fragmented
Candidate lane target
The customer-account-portal lane should deliver:
- one named
Pulse Accountshell and IA - shared identity and navigation across hosted account actions and self-hosted commercial actions
- canonical ownership boundaries for billing, licenses, hosted tenants, memberships, and recovery
- de-duplication of fragmented public utility flows where a real authenticated account area is the better product shape
- a renderer-owned frontend bootstrap contract for the account shell, so a maintained frontend can consume canonical account state without scraping ad-hoc DOM attributes or hardcoded production URLs
- a maintained bundled frontend source tree and sync-proof path inside
internal/cloudcp/portal, so the account shell does not regress into handwritten embedded asset drift
Current frontend seam
The current /portal surface now renders one machine-owned application shell
for both signed-out and signed-in users. That shell emits a
pulse-account-bootstrap JSON script tag, and the authenticated runtime can
refresh from /api/portal/bootstrap. Together, those two surfaces are the
canonical frontend state seam for:
- account identity context
- hosted account and workspace summaries
- public/commercial edge URLs needed by the account shell
- signed-out versus signed-in shell state, so login, session expiry, and authenticated account runtime all inherit one owned page contract instead of separate server-rendered templates
- the canonical bootstrap route path and stable workspace summary fields, so the frontend can render and refresh account/workspace state from one owned contract instead of depending on server-rendered DOM structure
The portal package also owns a dedicated bootstrap JSON handler shape for the same contract, so route wiring can promote the shell toward a maintained frontend/API split without inventing a second state model.
New frontend work should extend that contract deliberately instead of adding
one-off data attributes or baking production hostnames into static assets. The
maintained frontend source now lives under internal/cloudcp/portal/frontend/,
is embedded from internal/cloudcp/portal/dist/, and is guarded by
internal/cloudcp/portal/frontend_sync_test.go, so Pulse Account frontend work
should extend that source tree and rebuild the committed bundle instead of
editing embedded script or CSS blobs directly.
Post-lane follow-on
Reasonable later expansions include:
- richer invoice/history views
- support case history
- broader audit/compliance export surfaces
- deeper MSP customer/customer-contact management
Ownership
The owning governed subsystem is cloud-paid.
Why:
- the portal is a commercial/account boundary first
- it spans Cloud, MSP, billing, licensing, and recovery
- the existing control-plane portal and self-hosted utility surfaces already sit inside cloud-paid-adjacent ownership
This is a lane-expansion / new-lane shape above current L3 and L4, not a
reason to fork commercial governance into another subsystem.