Skip to content

Web Dashboard

The Procella web dashboard is a React 19 single-page application built with Vite 7, Tailwind CSS v4, and tRPC. In production it is served as static files by the Procella server. In development the Vite dev server handles it with hot module replacement.

RoutePageDescription
/Stack ListAll stacks for the authenticated organization
/stacks/:org/:project/:stackStack DetailStack info and full update history
/stacks/:org/:project/:stack/updates/:updateIdUpdate DetailEngine events for a single update
/tokensAPI TokensCreate/revoke API tokens and edit user profile (Descope mode only)
/settingsAdmin SettingsUser, role, audit, and tenant management (Descope admin only)
/cli-loginCLI AuthorizationBrowser-based pulumi login authorization flow
/loginLoginDescope sign-up-or-in flow or dev token entry

The sticky header contains:

  • Procella wordmark — links to /
  • “Pulumi Backend” badge — static label
  • Tokens link — shown in Descope mode for all authenticated users
  • Settings link — shown in Descope mode only for users with the admin role
  • User avatar dropdown (Descope mode) — displays initials, full name and email, with a sign-out action
  • Token input (dev mode) — password field saved to localStorage and sent as the API token on all tRPC requests

Role detection uses the JWT claims from the active Descope session. The admin check reads the roles array for the current tenant from the session token — no server round-trip required.

The header shows a password input. The entered token is stored in localStorage and attached to all tRPC requests. The CLI login page (/cli-login) shows a password form where the user types the static token directly.

The Descope React SDK manages the session. On load it restores any existing session from storage. The tRPC client reads the session token and sends it as Authorization: token <key> on every request. Role and tenant information is extracted from the JWT claims client-side.

Available in Descope mode for all authenticated users. Contains two tabs:

TabWidgetPurpose
API TokensAccessKeyManagementCreate and revoke Descope access keys used as Pulumi API tokens
ProfileUserProfileEdit name, email, password, MFA, and passkeys

Access keys created here are standard Descope access keys. The Pulumi CLI uses them as PULUMI_ACCESS_TOKEN values — the Procella server validates them via ExchangeAccessKey on every request.

Available in Descope mode only for users with the admin role. Contains four tabs:

TabWidgetPurpose
UsersUserManagementInvite, remove, and manage org members and their roles
RolesRoleManagementView and manage roles and permissions
Audit LogAuditManagementFull audit trail of authentication and management events
TenantTenantProfileEdit tenant name and other tenant-level settings

Tab state is stored in the URL hash (#users, #roles, #audit, #tenant) so links are shareable.

The Descope management widgets call Descope’s management API using the user’s session token. This requires the Tenant Admin built-in Descope role at the tenant level — the app-level admin role alone is not sufficient.

Procella’s sign-up-or-in flow automatically assigns Tenant Admin to every user who creates a new tenant (via the createTenant flow action). No manual configuration is needed. The role is declared in infra/descope.ts and managed by Pulumi, so it survives redeploys.

When pulumi login http://your-procella-host is run, the CLI starts a local HTTP server and opens the browser to /cli-login with three query parameters:

ParameterDescription
cliSessionPortPort of the CLI’s local callback server
cliSessionNonceCSRF nonce for the callback
cliSessionDescriptionHuman-readable description of the login request (optional)
  1. If the user is not authenticated, the Descope sign-up-or-in flow is shown inline.
  2. Once authenticated, the user sees a confirmation card showing their email/name and a “Continue” button.
  3. Clicking “Continue” calls POST /api/auth/cli-token with the session token. The server creates a Descope access key and returns it.
  4. The browser redirects to http://localhost:<cliSessionPort>/?accessToken=<token>&nonce=<nonce>, which the CLI picks up and stores in ~/.pulumi/credentials.json.

A password input is shown. The user enters the static dev token and clicks “Authorize”. The browser redirects directly to the CLI callback with that token — no server call is made.