KB // DOC-0042 MSSP UNIFIED SECURITY DASHBOARD REV 1.1  ·  2026-03-22
01 // Purpose & Audience
7
Integrated Platforms
1,312
Endpoints Monitored
37
API Endpoints Wired
100%
Self-Contained HTML

The MSSP Unified Security Dashboard is a single-file HTML demo interface that presents a consolidated view of security posture, infrastructure health, email threat data, and backup status across a managed client portfolio. It is pre-wired with exact API references for every displayed metric — every number on screen traces back to a real vendor endpoint, HTTP method, authentication pattern, and response field.

The primary audience is MSSP sales and engineering staff conducting client briefings, QBRs, or new prospect demonstrations. The dashboard communicates the breadth of visibility an MSSP provides at a glance, while the clickable API detail modals let technical stakeholders validate that real data can back every metric shown.

It is not a live operations tool in its current state — all displayed values are demo data. The architecture is intentionally designed to allow direct swap to live fetch() calls once backend proxy infrastructure is in place.

Target environment: Standalone HTML file. No build tools, no npm, no server required. Drop it in any static host, SharePoint page, or open directly in a browser. The only external dependencies are Google Fonts (decorative — the dashboard degrades gracefully if offline).
02 // Dashboard Architecture

The dashboard is organized as a vertical stack of sections within a fixed-height scrollable container (#scroll). A fixed topbar holds global KPIs and controls. Below it, a live ticker scrolls real-time alert events. The main body is divided into four visual sections plus a two-column panel row layout used for side-by-side platform stats.

Layer
Description
#ktc-demo-bar
Fixed demo banner at very top. Contains HOME link back to command.html and a "DEMO VERSION" warning label. 36px tall — shifts entire body down via padding-top:36px.
#topbar
Sticky 52px bar containing the brand hex logo, brand name, global KPI strip (Clients · Devices · Active Alerts · Critical), refresh controls, and live clock.
#ticker
21px scrolling alert ticker. Populated by buildTicker() at init. Items are duplicated for seamless looping. 60s animation cycle.
#scroll
Main scrollable content area. Contains all four sections plus the two-column stat panel rows. Uses flex:1; overflow-y:auto.
Section 1: Threat Radar
Full-width sortable/filterable threat table (#radar-tbl). Sources: SentinelOne, Mimecast, Ninja RMM, Auvik, Backup platforms.
Row 2: Security + Infra
.two-col grid. Left: SentinelOne 2×2 stat panel. Right: Ninja RMM + N-able 2×2 stat panel.
Row 3: Network + Backup
.two-col grid. Left: Auvik 2×2 stat panel. Right: Datto / Acronis / Axcient 2×2 stat panel.
Section 4: Email Security
Four-column .email-grid. Sources: Mimecast, Proofpoint. Metrics: Phishing, Malware, Impersonation, Suspicious Domains.
#modal
Full-screen overlay modal. Fixed position, z-index 800. Populated dynamically by setModal(title, html). Clicking the backdrop closes it.
#toasts
Fixed bottom-right toast notification stack. Each toast auto-removes after 4500ms.
Compact mode: A second CSS block (#ktc-compact) is pre-injected with overrides that tighten padding across the scroll area, section headers, KPI cells, and table rows. This allows the entire dashboard to fit within a typical 1080p browser window without scrolling the outer page.
03 // Integrated Platforms
Platform
Role in Dashboard
Base URL
Panel
SentinelOne
Primary EDR/XDR source. Drives Active Threats, Quarantined Hosts, Lateral Movement, Exploit Attempts cells. Also populates majority of Threat Radar rows.
YOUR-TENANT.sentinelone.net
Security
Ninja RMM
RMM platform. Drives Offline Devices, Agent Errors, Reboot Pending, Patch Failures. Also used for Threat Radar events and global device count.
api.ninjarmm.com
Infra
N-able
Secondary RMM. Used as aggregate source alongside Ninja for total device count and offline device detection.
api.n-able.com
Infra
Auvik
Network monitoring. Drives Devices Down, Network Alerts, Interface Errors, High CPU Switches panels. Also populates Threat Radar network events.
auvikapi.us1.my.auvik.com
Network
Datto BCDR
Primary backup/DR platform. Drives Failed Backups, Backup Age >24h, Storage Capacity Warning panels.
api.datto.com
Backup
Acronis
Secondary backup. Drives Unprotected Devices metric and supplements Failed Backups count.
api.acronis.com
Backup
Axcient
Tertiary backup. Aggregated with Datto and Acronis for backup failure count.
axcient.com/api/v2
Backup
Mimecast
Email security. Drives Phishing Attempts, Malware Attachments Blocked, Impersonation Attempts, Suspicious Domains panels. Largest email data source.
api.mimecast.com
Email
Proofpoint
Secondary email security. Aggregates with Mimecast for phishing click-through and malware attachment counts.
tap-api-us.proofpoint.com
Email
ConnectWise PSA
PSA system. Drives global client count (KPI strip). Referenced in modal action buttons for ticket creation and client mapping.
api.connectwise.com
PSA
04 // API Reference

Every metric cell in the dashboard is backed by an entry in the APIS JavaScript object (approximately line 934 in the source). Clicking any stat cell opens a modal showing the exact endpoint, HTTP method, auth header, parameters, field mapping, and a generated example fetch() call. The following tables document all wired endpoints.

SentinelOne EDR/XDR · YOUR-TENANT.sentinelone.net/web/api/v2.1
Auth: Authorization: ApiToken YOUR_TOKEN — generate in Settings → Users → API Token Integrations.
Dashboard Metric
Endpoint + Parameters
Response Field
Key
Active Threats
GET /threats?resolved=false&limit=100
pagination.totalItems
s1_threats
Quarantined Hosts
GET /agents?networkStatus=disconnected
data[].networkStatus == "disconnected" → count
s1_quar
Lateral Movement
GET /threats?classification=Lateral+Movement&resolved=false
pagination.totalItems
s1_lateral
Exploit Attempts
GET /threats?classification=Exploit&resolved=false
pagination.totalItems
s1_exploit
Ninja RMM · api.ninjarmm.com · N-able supplement · api.n-able.com/v1
Ninja Auth: Authorization: Bearer YOUR_ACCESS_TOKEN (OAuth2). N-able Auth: Basic base64(user:apiKey).
Dashboard Metric
Endpoint + Parameters
Response Field
Key
Offline Devices
GET /v2/devices?df=status%20eq%20OFFLINE
[].status == "OFFLINE" → count results
rmm_off
Agent Errors
GET /v2/devices?df=agentStatus%20eq%20ERROR
[].agentStatus == "ERROR" → count
rmm_err
Reboot Pending
GET /v2/devices?df=rebootRequired%20eq%20true
[].rebootRequired == true → count
rmm_reboot
Patch Failures
GET /v2/jobs?status=FAILED&type=PATCH_MANAGEMENT&pageSize=100
results[].jobStatus == "FAILED" → count
rmm_patch
Auvik · auvikapi.us1.my.auvik.com/v1
Auth: Authorization: Basic base64(username:apiKey) — generate at My Profile → API. Tenant filter required per client for MSP use: include tenantId param.
Dashboard Metric
Endpoint + Parameters
Response Field
Key
Devices Down
GET /inventory/device/info?filter[deviceStatus]=offline&page[size]=100
data[].attributes.deviceStatus == "offline" → data.length
net_down
Network Alerts
GET /alert/history/info?filter[resolved]=false&page[size]=100
data[].attributes.severity → count by level
net_alerts
Interface Errors
GET /statistics/interface/detail?filter[errorRate]=gt:0&page[size]=50
data[].attributes.inErrorRate + outErrorRate → interfaces > 0
net_iface
High CPU Switches
GET /statistics/device/detail?filter[cpuUsage]=gte:80&page[size]=50
data[].attributes.cpuUtilization → count ≥ 80%
net_cpu
Datto / Acronis / Axcient Backup · Multi-platform aggregate
Datto Auth: Basic base64(apiKey:secretKey). Acronis/Axcient Auth: OAuth2 Bearer token. Map Datto deviceId to client via /v1/bcdr/device. Acronis uses tenantId in the URL path.
Dashboard Metric
Endpoint + Parameters
Response Field
Key
Failed Backups
Datto: GET /v1/bcdr/device/{id}/alert?alertType=backupFailure · Acronis: GET /api/2/activities?status=error&type=backup_machine
Aggregate both platforms. Datto: items[].alertSeverity. Acronis: items[].status.
bkp_fail
Unprotected Devices
Acronis: GET /api/2/resources?hasActiveProtectionPlan=false&type=machine
items[].id → count (no active plan)
bkp_unprot
Backup Age >24h
Datto: GET /v1/bcdr/device (iterate all)
items[].lastOffsite → if (now − lastOffsite) > 86400s → count
bkp_age
Storage Capacity Warning
Datto: GET /v1/bcdr/device/{id}/local (per device)
storageUsed / storageTotalMB × 100 → flag if >80%
bkp_stor
Mimecast + Proofpoint · Email Security
Mimecast Auth: HMAC-SHA1 — requires x-mc-date header + Authorization: MC accessKey:base64(HMAC). Proofpoint Auth: Basic base64(principal:secret). Route all requests through a backend proxy to keep credentials server-side.
Dashboard Metric
Endpoint + Parameters
Response Field
Key
Phishing Attempts
Mimecast: POST /api/ttp/url/get-logs body:{from,to,route:"inbound"} · Proofpoint: GET /v2/siem/clicks/permitted?format=json&sinceSeconds=86400
Sum both. Mimecast: data[].url + scanResult. Proofpoint: clicksPermitted[].threatStatus.
em_phish
Malware Attachments Blocked
Mimecast: POST /api/ttp/attachment/get-logs · Proofpoint: GET /v2/siem/threats?threatType=attachment&sinceSeconds=86400
Mimecast: data[].result == "held". Proofpoint: messagesBlocked[].threatsInfoMap[].threatType.
em_malw
Impersonation Attempts
Mimecast: POST /api/ttp/impersonation/get-logs body:{identityAlerts:true,from,to}
data[].action + taggedExternal + taggedMaliciousDomain → count non-allow
em_imp
Suspicious Domains Blocked
Mimecast: POST /api/dns/get-managed-sender · Proofpoint: GET /v2/siem/threats?threatType=url&sinceSeconds=86400
Extract unique domains from url field → deduplicate → count. Mimecast: data[].domain.
em_dom
05 // Auth Patterns
CORS restriction: All vendor APIs reject direct browser-origin requests. Every fetch() call must be routed through a thin backend proxy (Node.js, Python, Azure Function, etc.) that adds credentials server-side and forwards the response. Never embed API keys or tokens in the client-side HTML file.
SentinelOne · ApiToken
Single static header. Generate in Settings → Users → API Token Integrations. Scope to read-only threats, agents, alerts. Token does not expire by default but should be rotated quarterly.

Authorization: ApiToken <token>
Ninja RMM · OAuth2 Bearer
Standard OAuth2 client credentials flow. Register an API application in the Ninja portal to get client_id and client_secret. Access tokens expire — implement refresh logic in your proxy.

Authorization: Bearer <access_token>
Auvik · Basic Auth
Simple HTTP Basic. Concatenate username:apiKey, base64 encode, pass as Authorization header. API key generated at My Profile → API. Include tenantId query param for MSP multi-tenant isolation.

Authorization: Basic base64(user:key)
Datto BCDR · Basic Auth
Concatenate apiKey:secretKey (not username — it's the API key pair). The apiKey acts as username and the secretKey as password in the Basic credential.

Authorization: Basic base64(apiKey:secretKey)
Mimecast · HMAC-SHA1
Most complex auth pattern. Requires x-mc-date (RFC 1123), x-mc-req-id (UUID), plus a signed Authorization header composed of accessKey:base64(HMAC-SHA1(signingKey, sigData)). Use Mimecast's official SDK or reference implementation for your proxy.
Proofpoint TAP · Basic Auth
Standard Basic auth using TAP principal and secret. Generated in the Threat Insight Portal → Settings. The principal is distinct from your Proofpoint login.

Authorization: Basic base64(principal:secret)
06 // Interactive Elements
Element
Behavior on Click / Interaction
Function
Global KPI: Clients
Fires a toast with client count and CW PSA endpoint reference.
toast()
Global KPI: Devices
Fires a toast noting Ninja + N-able device count and both API paths.
toast()
Global KPI: Active Alerts
Fires a warn-type toast with aggregate alert count across all platforms.
toast()
Global KPI: Critical
Opens the critical events modal listing all 4 critical events with severity badges, client, and time. Each row is clickable to drill into the individual threat modal.
openCritModal()
↻ REFRESH button
Calls refreshAll() which re-renders the radar table, resets the 30s countdown, and fires an "ok" toast confirming refresh.
refreshAll()
Threat Radar Row
Opens the threat detail modal for that specific event. Shows severity, source, client, asset, timestamp, and the API endpoint that would surface this event in production.
openThreatModal(i)
TRIAGE button (inline)
Also opens the threat modal for that row. Uses event.stopPropagation() to prevent double-firing from the row click handler.
openThreatModal(i)
Severity ↕ / Client ↕ / Time ↕ column headers
Sorts the visible threat list by the selected field and re-renders the table body.
sortRadar(field)
Search input
Live filters the threat table on any column value (client, asset, event, source, status). Case-insensitive. Fires on every keystroke.
filterRadar(v)
ALL SEVERITY dropdown
Filters table to show only the selected severity tier. Selecting the blank option restores all events.
filterSev(v)
Stat panel cells (sp-cell)
Each 2×2 cell in Security / Infra / Network / Backup panels opens the API detail modal showing the full endpoint, auth, params, field path, and generated fetch() example for that specific metric.
openApiModal(key)
Panel footer buttons
Each platform panel has 1–2 footer buttons. Primary button opens the platform overview modal (openPlatModal) with all endpoints for that platform. Secondary buttons fire contextual toasts.
openPlatModal(key)
Email Security cells
Clicking any of the four email metric cells (Phishing, Malware, Impersonation, Suspicious Domains) opens the API detail modal with Mimecast and Proofpoint endpoint details.
openApiModal(key)
07 // Modal System

All modals share a single HTML structure: #modal (overlay) → .mbox (container) → .mhdr (header with title + close ✕) → #m-body (dynamic innerHTML). The setModal(title, html) helper populates both the title and body then adds the .open class to #modal, which switches its display from none to flex. closeModal() removes the class.

Clicking the dark overlay backdrop also closes the modal (v1.1 fix). Clicking inside the .mbox stops propagation to prevent accidental close.

Modal Type
Content + Action Buttons
Threat Detail Modal
openThreatModal(i)
Shows severity + source + status badges, a 4-cell event detail grid (Client · Asset · Event · Detected), the API source block showing how this data is pulled in production, and 6 action buttons: OPEN INCIDENT, ASSIGN ENGINEER, ISOLATE ENDPOINT, BLOCK SENDER, CREATE TICKET, OPEN IN PORTAL.
API Detail Modal
openApiModal(key)
Shows the full API definition for the clicked metric: platform, base URL, method, endpoint, params, auth header, field mapping, note. Also includes a generated JavaScript fetch() example. Action buttons: TEST CONNECTION, PORTAL, CLOSE.
Platform Overview Modal
openPlatModal(key)
Shows all endpoints for a given platform (S1, RMM, Auvik, Backup, Email) in a reference block format. Platform name, base URL, auth pattern, CORS tip, and a list of all endpoints powering the dashboard with their parameters and descriptions. Buttons: TEST CONNECTION, OPEN PORTAL, CLOSE.
Critical Events Modal
openCritModal()
Lists all 4 CRITICAL severity events from ALL_THREATS. Each row is clickable to chain-open the threat detail modal. Buttons: BULK ESCALATE, ASSIGN ON-CALL, CLOSE.
Open Incident Modal
openIncidentModal()
Lists all CRITICAL and HIGH events as selectable source events for a new incident. Clicking a row highlights it with a cyan border. Buttons: CREATE INCIDENT (fires INC-2042 toast), CREATE PSA TICKET, CANCEL.
08 // Demo Mode

In demo mode all displayed metric values are static constants defined directly in the HTML source. The ALL_THREATS array (line ~1114) defines 15 threat events across four severity tiers representing seven clients and five platforms. Stat cell numbers are hardcoded in their id elements.

The auto-refresh counter (#rtimer, 30s countdown) does call refreshAll() when it reaches zero, which re-renders the radar table and fires an "ok" toast — but no actual API fetch occurs. This is intentional: it demonstrates refresh UX to demo audiences without requiring live credentials.

Switching to live data: Replace the static values in each id element and in ALL_THREATS with the result of fetch() calls to your backend proxy. The refreshAll() function is the correct hook — add your fetch logic there. Each API key in the APIS object already maps to exactly the endpoint and field path your proxy should consume.
Demo Data Location
What It Controls
ALL_THREATS array (~line 1114)
All 15 rows in the Threat Radar table. Each object: {sev, src, client, asset, event, time, status}. The o field is a sort-order integer (0=CRIT, 1=HIGH, 2=MED, 3=LOW).
id="g-clients" etc.
Global KPI strip numbers. IDs: g-clients, g-devices, g-alerts, g-crit.
id="s1-thr", "s1-quar" etc.
SentinelOne stat cell numbers. IDs: s1-thr, s1-quar, s1-lat, s1-exp.
id="rmm-off", "rmm-err" etc.
RMM stat cell numbers: rmm-off, rmm-err, rmm-rbt, rmm-pat.
id="net-dn", "net-alt" etc.
Auvik stat cell numbers: net-dn, net-alt, net-if, net-cpu.
id="bkp-fail", "bkp-up" etc.
Backup stat cell numbers: bkp-fail, bkp-up, bkp-age, bkp-stor.
id="em-phish", "em-malw" etc.
Email stat numbers: em-phish, em-malw, em-imp, em-dom.
Progress bar widths
Each .pf element has an inline style="width:X%". These are purely visual and do not auto-calculate from the stat number — update manually to match.
09 // Design Tokens

All visual variables are declared in a single :root block at the top of the <style> section. Changing a token propagates instantly to every component that references it. The dashboard uses no external CSS frameworks.

Token
Value
Used For
--void
#03070f
Page background (deepest layer)
--deep
#050d1a
Section header bars, modal header
--panel
#07111f
Primary card/section background
--card
#091525
Nested card background, code blocks
--raised
#0c1d30
Source chip background
--cyan / --b4 / --b5
#00c8ff / #00e5ff / #00f5ff
Primary accent, glow, scan line highlight
--green
#00e676
Resolved status, ok indicators
--amber
#ffab00
Medium severity, warnings
--red
#ff2d55
Critical severity, active threats
--orange
#ff9100
High severity, network alerts
--purple
#bf6fff
ConnectWise PSA chip, backup status
--border / --border2
#0c2d50 / #153d62
Component borders (rest / hover)
--txt / --txt2 / --txt3
#deeeff / #6a9abf / #2d567a
Primary text / secondary text / muted labels
--mono
'Share Tech Mono', monospace
API annotations, labels, clock, ticker
--display
'Barlow Condensed', sans-serif
All large stat numbers and heading text
--body
'Barlow', sans-serif
General body text throughout
10 // Updating Data

For demo customization — adjusting numbers to match a specific prospect's environment, for example — all values can be updated by text-editing the HTML source. No compilation step is required.

Updating the Global KPI Strip
Find the elements with IDs g-clients, g-devices, g-alerts, g-crit in the topbar section and change their text content. Also update the matching onclick toast message strings on the parent .gkpi elements to keep them consistent.
Updating Stat Panel Numbers
Each panel uses simple id attributes. Search for the ID (e.g. id="s1-thr") and update the inner number. If updating progress bars, also find the .pf div inside the same .sp-cell and adjust the inline width percentage to match.
Updating or Adding Threat Radar Events
Edit the ALL_THREATS array in the script block. Each entry uses: {o:0-3, sev:'CRITICAL|HIGH|MEDIUM|LOW', src:'PlatformName', client:'Client Name', asset:'Asset', event:'Description', time:'Xm ago', status:'ACTIVE|INVESTIGATING|OPEN|RESOLVED'}. The SRC_CLS object maps source names to chip color classes.
Updating Ticker Events
The buildTicker() function (~line 1416) contains an items array of HTML strings. Edit or add entries following the existing pattern: <span class="tc|th|tm|tg|ti"> for CRIT / HIGH / MED / RESOLVED / INFO coloring respectively.
Updating API Reference Entries
The APIS object (~line 934) and PLAT_INFO object (~line 1280) drive all modal content. To update endpoint details, change the relevant key's endpoint, params, auth, field, or note properties. No changes to HTML structure are needed.
Changing Client Name / Branding
The brand name (MSSP SECURE) is in the .brand-name element inside #topbar. The subtitle (UNIFIED SECURITY DASHBOARD · MANAGED CLIENTS) is in .brand-sub. The page <title> tag should also be updated to match.
Tip for prospect-specific demos: Before a client meeting, update the five client names in ALL_THREATS (ACME Corp, Beta Inc, Delta LLC, Gamma Corp, Omega Co) to match names relevant to the prospect's industry vertical. This significantly increases demo realism without any structural changes.
11 // Deployment
Method
Notes
Direct file open Simplest
Open the HTML file directly in Chrome/Edge. Fully functional — all JS runs, all interactions work. Font loading requires internet access; degrades to system sans-serif if offline.
Static host (S3, Cloudflare Pages, GitHub Pages, Netlify)
Drop the single HTML file into any static host. No configuration needed. The #ktc-demo-bar HOME link points to command.html — ensure that file exists in the same directory or update the href.
SharePoint Embed (SPFx or iFrame web part)
Embeds cleanly as an iFrame web part. Compact mode CSS is pre-included. Test localStorage behavior if adding any stateful features later — SharePoint sandboxed iFrames may restrict it.
NinjaOne Docs / internal wiki
For teams using NinjaOne's documentation module, the file can be uploaded as an attachment. Link to it from a runbook or client-facing page rather than embedding inline (iFrame CSP restrictions may apply).
Local demo machine
For field sales or QBR use, keep the file on a local drive. Open in browser fullscreen mode (F11) for a clean presentation view. The compact CSS mode ensures the dashboard fits a 1080p screen without outer scroll.
The HOME link: The #ktc-demo-bar at the top of the page contains a link to command.html. This is a reference to a broader command center portal. If the dashboard is being used as a standalone file outside that portal, update the href to # or remove the bar entirely by deleting the <div id="ktc-demo-bar"> block and the associated <style id="ktc-home-bar-style"> block. Also remove body { padding-top: 36px !important; } from that style block.
12 // Fixes Applied (v1.1)

The following issues were identified through code review and corrected in the v1.1 build released 2026-03-22. The original file (v1.0) was delivered with all five issues present.

Critical Fix · Truncated Script Block
Root cause: The source file was truncated mid-byte in the third setTimeout() toast call at the end of the <script> block. The script tag was never closed. The browser discarded the entire JavaScript payload, leaving every interactive element completely non-functional — no modals, no toasts, no KPI clicks, no radar table rendering.

Fix: The partial byte sequence was removed. The incomplete setTimeout call was reconstructed, the script was properly closed with </script>, and the </body></html> closing tags were appended.
Fix · Cloudflare Email Obfuscation
Root cause: The email address finance@omega.com in the CEO impersonation Threat Radar event had been processed by Cloudflare's email obfuscation system, replacing it with an encoded anchor tag that required Cloudflare's external decode script to render. The script reference was to /cdn-cgi/scripts/.../email-decode.min.js, which does not exist in a standalone HTML context.

Fix: The Cloudflare script tag was removed. The obfuscated anchor element was replaced with the plain text string finance@omega.com.
Fix · Modal Backdrop Non-Dismissable
Root cause: The modal overlay (#modal) had no click handler. Clicking the dark backdrop had no effect, requiring users to click the ✕ button or a CLOSE/CANCEL button — disruptive during live demos.

Fix: Added onclick="closeModal()" to the #modal overlay div. Added onclick="event.stopPropagation()" to the inner .mbox container so clicks within the modal content do not bubble up and trigger an accidental close.
Fix · Device Count Mismatch
Root cause: Device counts throughout the dashboard referenced 5,482 total devices and 3,241 agents, which did not align with the client's actual ~1,300-endpoint environment.

Fix: Global device count updated to 1,312, agent count updated to 1,247, and all matching references in toast strings and footer notes updated for internal consistency.
Minor · Missing Closing Tags
Root cause: As a consequence of the truncation, </body> and </html> closing tags were absent. Browsers tolerate this but it is invalid HTML and can cause subtle rendering inconsistencies in certain embedding contexts.

Fix: Both tags appended as part of the script closure fix.
13 // Known Limitations
No Live Data · Demo Only
All displayed numbers are static demo values. The refreshAll() function re-renders the radar table from the same ALL_THREATS array but does not call any API. Making this dashboard live requires a backend proxy layer and replacement of static values with fetch() calls inside refreshAll().
CORS · All Vendor APIs Block Browser-Origin Requests
SentinelOne, Ninja RMM, Auvik, Datto, Mimecast, and Proofpoint all enforce CORS policies that reject direct fetch requests from a browser page. A server-side proxy is mandatory for production use. Options include: Azure Function (recommended for MSP Azure environments), AWS Lambda, Node.js/Express on a small VPS, or a Cloudflare Worker.
Mimecast HMAC-SHA1 Auth Complexity
Mimecast's authentication signature requires server-side implementation. The signed headers (x-mc-date, x-mc-req-id, Authorization: MC) cannot be safely computed in client-side JavaScript without exposing the signing key. Use Mimecast's official Python or Node SDK in your proxy, or reference their developer documentation for the exact signing algorithm.
Ninja RMM · OAuth2 Token Refresh Required
Ninja access tokens have a limited lifetime. Your proxy must implement the OAuth2 refresh token flow. The dashboard's refreshAll() 30-second cycle will exhaust a static access token over time without a refresh mechanism.
Auvik · Tenant Scoping for Multi-Client MSP Use
Auvik's API requires a tenantId parameter to scope results to a specific client. When aggregating across all clients (as the dashboard implies), your proxy must iterate all tenants and aggregate the results. A single top-level call will not return cross-tenant data.
command.html Dependency
The #ktc-demo-bar HOME link references command.html. If this dashboard is deployed without the parent portal, that link will result in a 404. Update the href or remove the bar as described in the Deployment section.
No Mobile Optimization
The dashboard is designed for 1280px+ desktop viewports. The compact CSS mode is tuned for 1080p display. The layout does not reflow gracefully for tablet or mobile screen widths. Not intended for mobile use.
Threat Modal Index Uses visThreats, Not ALL_THREATS
openThreatModal(i) resolves the event using visThreats[i], the current filtered/sorted view. If the table is filtered when a modal opens and then the modal chains to openCritModal drilldown, index alignment may shift. This is cosmetic in demo mode but should be addressed (e.g. by using an event ID rather than array index) before production use.