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.

Recent additions (2026-08)

  • Agent K standalone page — Agent K moved from a dashboard tab to its own /agent-k page (views/agentk/Index.vue: Feed with channel sub-filters + Reports with drill-down; stage narrative via its STAGE_WORDS map; shared lead/stage formatting in common/helpers/agentK.js). Settings split into 7 URL-synced tabs (views/settings/ai/agents/AgentK/index.vue — overview / icp / traffic / outreach / channels / delivery / dnc, ?tab= + ?highlight=), plus a standalone setup route (agent-k-setupAgentK/Setup.vue) and a pricing modal (PricingModal.vue/PricingTable.vue + useAgentKPricing).
  • Nox Activityviews/NoxActivityView.vue (in-app history) and views/NoxActivityReportView.vue (authed print view — no share tokens).
  • Session details redesigncomponents/sessions/SessionMoreInfoPanel.vue + SessionAgentKOutreach.vue (Agent K outreach shown in the panel).
  • Engage live visitorcomponents/sessions/EngageVisitorModal.vue from the live session view; live sessions hide bot traffic by default. vitest is established (src/**/*.test.js): this window added AgentKInbox.test.js, AgentKPanes.test.js, useLiveSocket.test.js, useLiveReplayer.test.js (+ liveSessionTestKit.js), socketManager.reconnect.test.js, clipboard.test.js, ScheduleCallDialog.test.js, NoxTaskHistory.test.js, canvasOrder.test.js, and playground/integration tests.
  • 2026-08/09 — Calls screen rewritten as rail/thread/contact (components/calls/, useCallsFeed.js); Agent K three-pane inbox (views/agentk/); Nox Live standup mode, Task sheet, Scheduled overlay (components/knox/live/), KnoxConfigCard.vue; partner portal (views/partner/ — invites, listing editor, sign-up links) and onboarding PartnerStep.vue; admin identity repair screens, Integrations Maintenance, Identity Maintenance cards (CRM smoke, crm_links backfill), Call Duration Backfill; utils/clipboard.js; 20 admin views on reactive route-param query keys; version 1.7.0; Dockerfile.azure on node:24-alpine (npm 10.9.8 edgesOut crash on vitest 5 peers — there is no lockfile by design, so CI re-resolves every build).
  • Integrations screen splitviews/settings/integrations/ Index broken into ~24 per-card components in src/components/integrations/; the old dashboard Campaigns tab now lives on ManyReachCard.vue/ManyReachCampaigns.vue.
  • Platform APIs (agency)views/agency/settings/PlatformApis.vue, PlatformWebhookManager.vue + deliveries view, and views/auth/PlatformLoginView.vue at /platform-login/:code.
  • Partner certification — partner portal views/partner/ + admin suite views/admin/certification/ (Queue/Students/Tests/Settings, wallet rewards in dollars).
  • Push notifications — user push preferences + admin push tester; new components/form/FormSearchSelect.vue.
  • Misc UI — Wallet shows Agent K line items; shared components/DateRangeButton.vue; Quill rich-text standardized across Agent K drafts, Nox drafts, and the email signature editor.
  • Cross-tab session syncutils/sessionChannel.js (BroadcastChannel): stale tabs freeze when another tab switches user or logs out; app-store persist config fixed (field list was silently ignored); axios interceptors moved out of main.js.
  • GHL iframe silent re-auth — 401 inside the GHL iframe re-authenticates via the stored secret instead of logging out (views/auth/GoHighLevelAuthView.vue, store/app.js).
  • Dashboard tabsVALID_TABS = ['today', 'impact', 'visitors', 'funnel'] (views/Dashboard/Index.vue); Campaigns tab removed; Nox briefing strip removed from the dashboard (Reports still renders NoxStrip).
  • Traffic-source labelscommon/helpers/session.js: agent_k → "Agent K Outreach", manyreach → "ManyReach Campaign", ghl_backfill → "CRM Email Link".
  • Route gates are data-drivencompany.agent_k_beta_enabled, nox_activity_enabled, partner_certification_enabled (+ webOwnerOnly meta); the LINKEDIN_CHANNEL_UI build flag was removed.

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.