Skip to main content

frontend — Dashboard SPA

The customer-facing dashboard: live session monitoring, recordings replay, chats/ calls, leads, identity-graph admin, agency portal, billing, and the Nox surfaces.

  • Stack: Vue 3 (Composition API) + Vite, Pinia, vue-router, TanStack Vue Query, vee-validate + zod, Socket.IO client, Twilio Video, rrweb, PostHog, Tailwind.
  • Dev server: :4000. The same source is wrapped by desktop.

Build & release

scripts/bump-version.js drives build:release (patch), build:minor, build:major. Vite injects __APP_VERSION__, __BUILD_DATE__, __GIT_COMMIT__, __WHITE_LABEL__. Rollup splits ~14 manual chunks (vue, rrweb, twilio, charts, quill, …). Containerized via Dockerfile.azure (multi-stage → nginx).

App structure (src/)

main.js Pinia + VueQuery + router + axios interceptors
router/ index.js (50+ routes, guards), admin.js, agency.js
store/ Pinia stores (persisted)
repositories/ API layer — plain async axios fns, grouped by area
composables/ useLiveSocket, useLiveReplayer, useKnoxVoice, usePostHog, …
views/ page components
components/ SessionPlayer (rrweb), form/ (vee-validate wrappers), knox/, …
layouts/ AppLayout (sidebar/header)
config/ env.config.js (API URLs, Stripe, Firebase)
utils/ platform.js (isElectron), socketManager.js, twilioCall.js

State (Pinia)

Stores persist to local/session storage via pinia-plugin-persistedstate. Main ones: app (user/company/auth/theme/subscription/branding), sessions, chats, calls, knox, nox* (noxActions, noxInsights, noxSettings, noxRecentConversations), briefSession, notifications, onboarding, update (Electron auto-updater).

GHL OAuth flows store auth in sessionStorage instead of localStorage — see the dynamic storage wrapper in store/app.js.

Data layer

Repository functions in repositories/<area>/ call axios; TanStack Query wraps them with keys from @lukemorales/query-key-factory (queryKeys.js per area). QueryClient defaults: 5 min stale, 30 min gc, 1 retry, no refetch-on-focus. The IDE-open file repositories/admin/identity.js is the identity-graph admin API (persons, profiles, form submissions, maintenance, GHL reconcile) — note it uses NDJSON streaming responses with an onProgress callback for long maintenance jobs.

Routing & auth

router/index.js guards: requiresAuth → redirect to /login; role redirects (admin → /admin, agency → /agency, owner → /dashboard); meta.permission checked via memberHasPermission(); meta.feature gated against subscription (appStore.isAllowInPackage); meta.ownerOnly; onboarding redirect. Axios interceptors attach the bearer token and clear storage + redirect on 401. Electron uses hash history; web uses HTML5 history.

Realtime

Two sockets: window.main_socket (agent/internal notifications) and window.socket (calls/chats/sessions). Notable events: update-live-session, online-session/offline-session, twilio-webrtc-call-response, new-call-request, new-session-message, session-page-context; emits agent-available-for-call, call-accepted-by-agent, inbound-takeover events. useLiveSocket.js and LiveCallListener.vue own the wiring.

Feature areas

FeatureWhere
Live sessionsLiveSessionsView.vue + useLiveSocket/useLiveSessionDetails/useLiveReplayer
Recorded replayRecordedSessionsView.vue + components/SessionPlayer/ (rrweb)
Twilio videocall panel + utils/twilioCall.js + LiveCallListener.vue
Knox voiceviews/settings/nox/ + useKnoxVoice + store/knox
Identity graph admin/admin/identity-graph + repositories/admin/identity.js (super-admin)
Agency portal/agency/*
Billingviews/packages/* (Stripe)
Nox surfacessettings/nox/ + nox* stores

Recent additions (2026-07)

  • Dashboard restructure/dashboard and /reports render beta-gated switchers (DashboardHome.vue / ReportsHome.vue, keyed on company.agent_k_beta_enabled): beta gets the "Today on Knock Knock" command center (views/Dashboard/Index.vue, tabs Today/Impact/Visitors/Funnel/Campaigns) at /, with the six-tab analytics moved to views/Reports/Index.vue at /reports; non-beta keeps the old screens. /funnel redirects to /dashboard?tab=funnel.
  • Wallet UI — sidebar wallet pill (CompanyNavigationSidebar.vue), views/packages/Wallet.vue transactions page, PackagesTabs.vue (Wallet/Add-ons/Payment Methods), composables/useBalanceAccess.js (now grants full self-service to agency sub-accounts).
  • Members layoutviews/members/MembersLayout.vue with People/Teams/Branches tabs.
  • Playground — public views/playground/ + views/simple-playground/ (no-login demo sandbox, shareable), agency lists under views/agency/{playground,simple-playground}/, admin list with credits column.
  • PWA — installable with a per-tenant manifest (App.vue, public/sw.js).
  • Admin surfacesviews/admin/StorageMaintenance.vue, cost-tracking unit-economics cards, Nox funnel audit logs + contact trace, identity maintenance panels, visitor-watch History tab, playground credits column.
  • Startup perf — heavy chunks (charts, Knox tree) deferred out of startup; vite build warnings cleaned.

Analytics

PostHog (prod only, EU host) via usePostHog.js; pageview/pageleave on route change; start_trial / subscribe events. Meta Pixel on register/onboarding.

Relationship to desktop & widget

Same source as desktop (Electron) — utils/platform.js isElectron() toggles platform behavior. Widget setup/codegen lives in components/Widget/ and settings/widget/, but the actual visitor widget is the separate widget repo.