Skip to content

pulse-portal

Audience

PLANA staff. The BOS frontend codebase. Customers using BOS read /bos/ instead.

pulse-portal is the BOS frontend — the Vue 3 SPA at my.planapulse.ai/{workspace-slug}. It is the screen customers actually open to use PLANA Pulse.

Stack

PropertyValue
Repogit.planapulse.com/plana-pulse/pulse-portal
LanguageJavaScript ESM (no TypeScript)
FrameworkVue 3.5 with Vite (SPA mode; NOT Nuxt)
RouterNone — in-memory view switching via useAppState
StatePinia
StreamingNative EventSource for SSE
Functional utilitiesRamda
Image baseBuilt static, served by nginx-unprivileged
Namespacepulse-account (prod) or bos-demo (dev)
Deploymentbos-portal
Domainmy.planapulse.ai/{slug} (catch-all routes here)

What it serves

The eight views described in BOS user manual:

  • Dashboard (KPIs + cashflow + alerts summary + quick links)
  • Chat (4 agents, SSE streaming)
  • Alerts (master/detail)
  • Banking (PSD2 accounts + transactions)
  • Billing (plan + invoices)
  • Execution log (tool call audit)
  • Integrations (catalog with status)
  • Settings (workspace / team / API keys / alert thresholds)

How it differs from pulse-account

pulse-accountpulse-portal (BOS)
FrameworkNuxt 3 SSRVue 3 + Vite SPA
RoutingNuxt file-basedIn-memory tab switching
URLmy.planapulse.ai SPA pathsmy.planapulse.ai/{workspace-slug}
PurposeCustomer account portalWorkspace operating screen

The two coexist on my.planapulse.ai; the Envoy Gateway routes between them based on path. See Architecture → Envoy Gateway.

Auth

pulse-portal does not maintain its own session. It reads the pa_token cookie set by pulse-account-api and includes it in every /api/* request. If the cookie is missing or expired, the API returns 401 and the frontend redirects to login.

SSE streaming

The Chat panel uses native EventSource:

js
const es = new EventSource(`/api/agents/${agentId}/chat/stream?...`)
es.addEventListener('text_delta', e => { ... })
es.addEventListener('tool_call', e => { ... })
es.addEventListener('done', () => es.close())

pulse-account-api proxies the EventSource to ai-agents via reply.hijack(). See ai-agents for the downstream.

Configuration

Env var (build-time)Purpose
VITE_API_BASE/api (relative)
VITE_SSE_BASESame
VITE_MATOMO_SITE_IDMatomo tracking

There are no runtime secrets in the frontend pod. All sensitive operations go through the API.

Known surface that does NOT belong to BOS

Some code paths in pulse-portal are no longer used and should not be relied on (also documented in BOS → Known issues):

  • useFinanceAgent.js — superseded by generic useAgent.js
  • BottomPanel LOG, TERMINAL, PROBLEMS tabs — hardcoded demo data; not wired to real backends
  • Settings → "Domain" tab — empty placeholder
  • StatusBar Excel ⚠ indicator — static, not dynamic
  • AppSidebar "New dashboard" / "New session" buttons — no handlers
  • Hardcoded "Techno OOD" in AppSidebar footer
  • Hardcoded "CM" avatar initials in TitleBar
  • Hardcoded "Apr 2026" period badge in TabBar

These are cleanup tasks. Do not document them as features in /bos/.

Mobile

pulse-portal is mobile-responsive but not a native app. A native companion (Ionic Vue + Capacitor 7) is on the roadmap — see BOS → Mobile status.

Deployment

PathWhat
BuildVite → dist/ (static)
Imagenginx-unprivileged serving the static dist
DeployCurrently kubectl set image from CI (migration to Flux pending)
Source of truthinfra/k8s/pulse-account/bos-portal.yaml

Where to read more

© PLANA Digital Ltd.