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.