pulse-account
Audience
PLANA staff. The customer-facing account portal at my.planapulse.ai.
pulse-account is the customer-facing account portal — the my.planapulse.ai web app where customers sign in, see their workspaces, manage their team, view invoices, and reach BOS. It is the entry point to everything except the tenant Odoo and the marketing site.
Stack
| Property | Value |
|---|---|
| Repo | git.planapulse.com/plana-pulse/pulse-account |
| Language | JavaScript ESM (no TypeScript) |
| Framework | Nuxt 3 on Vue 3.5 |
| State | Pinia |
| Functional utilities | Ramda |
| Image base | node:20-alpine build + nginxinc/nginx-unprivileged:1.27-alpine runtime |
| Namespace | pulse-account |
| Deployment | pulse-account (3 replicas, HPA on CPU) |
| Domain | my.planapulse.ai |
| Database | None directly — talks to pulse-account-api |
The frontend is a Nuxt 3 SSR app. Server-side rendering for the initial HTML; client-side hydration takes over for everything after that.
What it serves
| Route | Page |
|---|---|
/ | Marketing landing for signed-out visitors |
/login | PLANA SSO redirect |
/dashboard | Workspace overview |
/team | Team management (invite, remove, role) |
/billing | Plan + invoice list |
/integrations | Per-workspace integration catalog |
/{workspace-slug} | Catch-all → BOS (proxied to bos-portal) |
The Envoy Gateway HTTPRoute for my.planapulse.ai:
| Path prefix | Backend |
|---|---|
/api | pulse-account-api |
Known SPA paths (/dashboard, /login, /team, …) | pulse-account |
| Everything else | bos-portal-ext (ExternalName → BOS workspace slug) |
This is the trickiest route in the cluster — see Envoy Gateway → platform route example.
Authentication
pulse-account is not itself a session holder. Authentication lives in pulse-account-api: a server-set cookie called pa_token carrying a JWT (HS256, 15-minute access, 30-day refresh). The Nuxt app reads document.cookie on the client side and relies on the API to gate sensitive responses.
The "Sign in" button redirects to:
https://auth.planapulse.com/application/o/authorize/?
client_id=pulse-account&
redirect_uri=https://my.planapulse.ai/api/auth/oidc/callback&
response_type=code&
scope=openid+email+profileAfter successful auth, pulse-account-api's /api/auth/oidc/callback exchanges the code for tokens and sets the pa_token cookie.
Configuration
| Env var | Source | Purpose |
|---|---|---|
NUXT_API_BASE | ConfigMap | Base URL for pulse-account-api |
NUXT_PUBLIC_SITE_URL | ConfigMap | Public origin used in OG tags |
NUXT_PUBLIC_MATOMO_SITE_ID | ConfigMap | Matomo site ID for tracking |
There are no secrets in the frontend pod. All sensitive operations go through pulse-account-api.
Deployment
Standard build → image → kustomize → Flux → Deployment. Source of truth: infra/k8s/pulse-account/.
Image tag pattern: git.planapulse.com/plana-pulse/pulse-account:<sha>.
Health endpoint: GET /healthz → 200 OK. The nginx-unprivileged container serves a static healthz file at that path.
Liveness + readiness probes hit /healthz on port 8080.
What this service does NOT do
- No business logic — all business logic lives in
pulse-account-api - No direct PostgreSQL — only the API touches the DB
- No XML-RPC to Odoo — only the API calls Odoo
- No persistent session state — everything stateful is in cookies set by the API, or in the API's Redis cache
Common operational tasks
Roll a new version
# CI does this on push to main; manual override:
kubectl -n pulse-account set image deploy/pulse-account \
pulse-account=git.planapulse.com/plana-pulse/pulse-account:<sha>
kubectl -n pulse-account rollout status deploy/pulse-accountForce-clear a deployment from a bad image
kubectl -n pulse-account rollout undo deploy/pulse-accountThe previous ReplicaSet is automatically restored.
Diagnose a routing problem
If a path on my.planapulse.ai is hitting the wrong backend:
- Confirm the request reaches
pulse-accountand notbos-portal-ext:kubectl -n pulse-account logs deploy/pulse-account --tail=20 | grep <path> - If the request is going to
bos-portal-ext, the HTTPRoute SPA-path matcher is missing this prefix. Add it toinfra/k8s/platform-routes/httproutes.yaml, merge, Flux reconciles.
Where to read more
- pulse-account-api — the backend
- pulse-portal (BOS) — the BOS frontend
- Envoy Gateway — how
my.planapulse.airouting works