High-Density Gateway Observability Dashboard
Overview
Toron provides a high-density, real-time observability control plane served directly from /internal/dashboard/. Designed with pure vector SVG graphics, native ECMAScript Modules (ESM), and zero external JavaScript dependencies, it delivers instant visibility into traffic topologies, routing distributions, latency percentiles, upstream node health histories, and live request trace waterfalls.
The dashboard client engine (public/js/app.js) polls Toron’s internal management APIs (/internal/api/status, /internal/api/routes, and /internal/api/upstreams/health) on a 2-second interval, constructing an in-memory client data model with sub-millisecond execution overhead.
Key Dashboard Views
1. Overview
- Live Status Banner: Operational health status (
All systems operational,Degraded,Needs attention) and active incident alerts. - Sankey Traffic Flow: Vector ribbons visualizing throughput (RPS) flowing from listeners (
:443,:80) $\to$ route rules $\to$ backend upstream pools. - Key Signals Matrix: 5 core KPI tiles (Requests/s, p95 Latency, 5xx Rate, Active Connections, Egress Mb/s) with trend sparklines.
- Dual Time-Series Curves: Latency percentiles (p50, p95, p99) and stacked 4xx/5xx error volumes over 15m, 1h, 6h, and 24h ranges.
2. Routes & Route Detail Drawer
- Sortable and filterable route table showing live RPS sparklines, p95 latency, and error rates.
- Displays match hosts, path prefixes, proxy target destinations, and middleware chips.
- Clicking any route opens the Route Detail Drawer displaying latency vs. SLO target reference curves, error breakdowns, latency distribution histograms, and configured middlewares.
3. Upstreams & Node Health Histories
- Grouped into distinct upstream pool cards by route identity, showing load-balancing algorithms, summary RPS alongside cumulative traffic volume, p95 latency, and error rates.
- Requests tile renders dual metrics: real-time rate alongside cumulative total requests (e.g.
0.0/s (1.7k total)). - Per-instance cards featuring 48-tick visual health check history strips (green = passing, red = failed).
- Instance rows display real-time probe round-trip latency (
latency_ms), HTTP response code status, and circuit-breaker warnings.
4. Live Requests & Trace Waterfall Drawer
- Real-time tailing request stream with status code chips (
2xx,3xx,4xx,5xx), “Over SLO” toggle, and route filter. - Clicking a request opens the Trace Waterfall Drawer decomposing execution latency across listener parsing, TLS handshake, routing, token verification, rate limiting, upstream connect, and response streaming.
5. Certificates & Modules
- Certificates: Let’s Encrypt challenge types (HTTP-01, TLS-ALPN-01, DNS-01), days to expiration with progress bars, and renewal failure alerts.
- Modules & Runtime: Compiled engine reactors, event bus throughput, and Go runtime stats (Goroutines, Heap MB, GC pause p99, Open FDs).
6. API Console
- Interactive diagnostic probe tool calling
POST /internal/api/proxy-testto test endpoints and inspect response headers and bodies.
7. Alerts & Threat Defense Control Center
- Dual-Card UI Architecture: Structural bifurcation separating infrastructural Operational System Alerts (with 1-click resource jump links and zero-alert health checkmark banner) from the Security Incidents & Threat Defense Feed.
- 4-Card Security KPI Strip: Top-level executive metric cards displaying active alerts and unmitigated incidents, recent WAF-blocked attacks, Stage 1 temporary bans, and Stage 2 permanent firewall bans.
- Multi-Action Badging Taxonomy: 4 defense states (
Blocked,Banned,Throttled,Logged) with color-coded severity pills, status icons, and slide-out forensic drawer integration. - Real-Time Severity Facet Filtering: Interactive severity chips (
All,Critical,Warning) with dynamic categorization of dropped vs monitored/throttled events and automatic pagination reset. - Rate-Limiting Telemetry: Seamless capture of volumetric HTTP 429 rate drops as ‘Throttled’ security incidents with retry-after metadata and 1-click quarantine pre-fill.
- Decoupled Threat Actor Quarantine: Dedicated manual IP blocking toolbar with client-side IPv4/IPv6 syntax validation, duration presets (
15m,1h,6h,24h,7d,Permanent), custom interval inputs, and incident context reasons. - Slide-Out Forensic Incident Drawer: In-depth Layer 7 forensic audit telemetry with 9 structured attributes, raw payload inspection, and 1-click remediation shortcuts (“Ban Client IP”, “Filter Logs for IP”).
- Dynamic 2-Stage Auto-Ban Table: Sortable, paginated IP firewall table featuring deterministic IP tie-breaking, non-blocking in-app confirmation modal, and floating toast feedback for unban operations.
Disaggregated Upstream Route Pool Rendering
In microservice gateways and reverse proxy configurations, multiple distinct ingress routes frequently proxy to the same physical socket address or loopback container port (for example, /kite/callback, /kite/api, /kite/broker, and /kite/auth all forwarding to http://127.0.0.1:8080).
To avoid route collapse where multiple business routes are merged into a single backend pool card, the client data engine (public/app.js) implements a disaggregated route pooling architecture:
[ Ingress Routes ] [ Route-First Matching ] [ Upstream Pool Cards ]
/kite/callback --> 127.0.0.1:8080 ==> Match by u.route === prefix --> Pool Card: _kite_callback
/kite/api --> 127.0.0.1:8080 ==> Match by u.route === prefix --> Pool Card: _kite_api
/kite/broker --> 127.0.0.1:8080 ==> Match by u.route === prefix --> Pool Card: _kite_broker
/kite/auth --> 127.0.0.1:8080 ==> Match by u.route === prefix --> Pool Card: _kite_auth
1. Route-First Priority Matching
When processing health probe entries (rawApiUpstreams) from /internal/api/upstreams/health, buildDataModel() matches probe records against configured routes by prioritizing explicit route labels (u.route):
const routeMatches = routes.filter(r => {
if (!u.route) return false;
return r.short === u.route || r.path === u.route || (r.host + r.path) === u.route ||
r.short.includes(u.route) || (r.host + r.path).includes(u.route) ||
u.route.includes(r.path) || u.route.includes(r.short);
});
Generic target address matching (comparing targetAddr against r.pool or r.targets) is only executed as a secondary fallback when u.route is empty.
2. Deterministic Route-Scoped Pool Keys
Each route receives a unique, route-scoped pool identifier:
const primaryRoute = routeMatches.length > 0 ? routeMatches[0] : fallbackMatches[0];
const poolKey = primaryRoute ? primaryRoute.id : (u.route ? u.route.replace(/[^a-zA-Z0-9]/g, '_') : targetAddr.replace(/[^a-zA-Z0-9]/g, '_'));
Because poolKey is derived from the route ID rather than the backend host:port, each route generates an independent pool card in #/upstreams.
3. Instance Isolation per Route Pool
Each pool card maintains dedicated instance records (pool.insts) containing:
- Target address (
targetAddr, e.g.127.0.0.1:8080) - Route affiliation label
- Instance health state (
up,warn,down) - Real-time probe response latency (
latency_ms) - HTTP probe response status code (e.g.
200,502) - 48-tick visual health history array (
history)
Instances targeting the same backend server are isolated within their respective route pool, ensuring separate health history tracking and circuit-breaker alerts.
4. Guaranteed Fallback Route Instantiation
An exhaustive secondary registration loop evaluates all configured proxy routes (r.type !== 'static' with defined targets). Any route not yet present in poolMap is instantiated as an independent pool card, guaranteeing 100% upstream route coverage in the dashboard even when active probe records have not yet arrived.
5. Topology Parity Across Views
- Sankey Traffic Flow (
flow()): Connects route ribbons to their dedicated upstream pool nodes, displaying accurate throughput distribution without collapsing shared backend targets into a single node. - Routes Table (
rtUpdate()): Displays matching derived metrics (curRPS,p95,err5) consistent with the Upstreams view.
Live Telemetry Metric Derivations
The dashboard client engine dynamically derives throughput, latency percentiles, error rates, and health tones from live gateway telemetry exported by pkg/metrics/metrics.go and pkg/server/internal_api.go:
1. Telemetry Schema Alignment
The data model directly binds to the following backend telemetry fields:
rawApiStatus.metrics.requests_by_route: Cumulative request counter map keyed by individual route paths and subpaths.rawApiStatus.metrics.total_requests: Cumulative total request counter across all routes.rawApiStatus.timeseries.A.rps: Rolling requests-per-second array from the 60-bucket ring buffer.rawApiStatus.timeseries.A.p95: Rolling p95 latency percentiles from the 60-bucket ring buffer.rawApiStatus.timeseries.A.err: Rolling 5xx error rate from the 60-bucket ring buffer./internal/api/upstreams/health: Active probe measurements includinglatency_ms,http_code,status, andhistory.
2. Hierarchical Subpath Rollup in requests_by_route
In API gateways, clients query deep hierarchical endpoints (e.g., /kite/api/v1/business, /kite/api/v2/orders, or /kite/auth/refresh), which are recorded as granular path keys in requests_by_route.
To ensure child API requests are attributed to their configured parent route prefix (r.prefix), buildDataModel() executes a hierarchical subpath aggregation:
function getRouteTotalReqs(pfx) {
if (!pfx) return 0;
if (pfx === '/') {
return Object.entries(reqByRoute).reduce((acc, [k, count]) => {
if (!k.startsWith('/internal/')) return acc + (Number(count) || 0);
return acc;
}, 0);
}
return Object.entries(reqByRoute).reduce((acc, [k, count]) => {
if (k === pfx || k.startsWith(pfx + '/')) {
return acc + (Number(count) || 0);
}
return acc;
}, 0);
}
const routeCumulative = getRouteTotalReqs(prefix);
This ensures that any subpath falling under a configured prefix is automatically rolled up into that route’s cumulative volume (routeCumulative).
3. Internal Telemetry Polling Isolation
The dashboard client polls internal management endpoints (/internal/api/status, /internal/api/routes, /internal/api/upstreams/health, etc.) every second. Without filtering, these background management calls accumulate in requests_by_route under /internal/* and artificially inflate total gateway counts, thereby diluting the calculated traffic share of external user routes.
To eliminate this measurement distortion, the engine computes totalExternalRequests by explicitly excluding all /internal/ keys from the denominator:
const totalExternalRequests = Object.entries(reqByRoute).reduce((acc, [k, count]) => {
if (!k.startsWith('/internal/')) {
return acc + (Number(count) || 0);
}
return acc;
}, 0);
External traffic ratios are then evaluated against totalExternalRequests, isolating internal diagnostic polling from user-facing throughput statistics.
4. Moving Average Temporal Smoothing for Gateway RPS
Instantaneous throughput values from single-second telemetry snapshots can exhibit high variance or sampling discretisation spikes. To produce smooth and stable rate indications without sacrificing responsiveness to sustained traffic changes, buildDataModel() computes a trailing 5-point moving average over recent gateway RPS samples:
const recentRpsSamples = (tsA && tsA.rps && tsA.rps.length > 0) ? tsA.rps.slice(-5) : [];
const avgRecentRps = recentRpsSamples.length > 0 ? avg(recentRpsSamples) : 0;
const effectiveTotalRps = avgRecentRps > 0 ? avgRecentRps : totalRPS;
The resulting effectiveTotalRps is used to compute instantaneous route throughput:
5. Dual Rate and Cumulative Volume Display in Upstream Pool Cards
In #/upstreams, operators need to immediately differentiate between routes that are temporarily idle but have handled substantial traffic versus routes that are inactive or have never received requests.
Each upstream pool card aggregates cumulative request counts across its member routes (p.totalReqs = sum(rs.map(r => r.totalReqs))) and displays both real-time throughput and cumulative volume in the Requests KPI tile:
<dl class="pool-sum">
<div>
<dt>Requests</dt>
<dd>${fmt.n(p.rps)}/s ${p.totalReqs > 0 ? `<span class="mut">(${fmt.n(p.totalReqs)} total)</span>` : ''}</dd>
</div>
<div><dt>p95 Latency</dt><dd>${fmt.ms(p.p95)}</dd></div>
<div><dt>5xx Error Rate</dt><dd class="${p.err5 >= .02 ? 't-err' : ''}">${fmt.pct(p.err5, 1)}</dd></div>
</dl>
For example, a pool card with historical traffic that is currently quiescent displays 0.0/s (1.7k total), providing clear dual-dimension operational context.
6. Dynamic Health Probe Latency & p95 Percentile
Instance latency in poolCard(p) is bound directly to i.latency (from /internal/api/upstreams/health latency_ms).
The pool card header p95 latency (p.p95) is derived dynamically:
This ensures pool cards reflect real probe round-trip measurements rather than static initial fallbacks.
7. Multidimensional Health Classification & Error Rate
Each upstream instance is classified into a tri-state health status:
\[\text{state}(i) = \begin{cases} \text{"down"} & \text{if } u.\text{status} \in \{\text{"UNREACHABLE"}, \text{"DOWN"}\} \lor u.\text{http\_code} \ge 500 \\ \text{"up"} & \text{if } u.\text{status} \in \{\text{"HEALTHY"}, \text{"UP"}\} \land (u.\text{http\_code} < 400 \lor u.\text{http\_code} = \text{null}) \\ \text{"warn"} & \text{otherwise (e.g. 4xx responses or degraded state)} \end{cases}\]The pool card summary 5xx error rate (p.err5) combines route-level error averages and probe failure history:
where $\text{failed_ticks}$ is the count of failing checks in the 48-tick history strips.
8. Deterministic Visual Tone Escalation
Pool card tone is automatically escalated to alert operators to degradation:
\[\text{tone} = \begin{cases} \text{"err"} & \text{if } \text{down\_count} > 0 \lor \text{pool.err5} \ge 0.02 \\ \text{"warn"} & \text{if } \text{warn\_count} > 0 \lor \text{pool.err5} > 0 \\ \text{"ok"} & \text{otherwise} \end{cases}\]When an upstream returns errors or fails health probes, the pool card border, status pill, and metric badges update dynamically to reflect the incident state.
Live Request Tracing & Dynamic Upstream Target Fidelity
The Live Requests & Logs section (#/logs) and Trace Waterfall Drawer (openDrawer('log', id)) provide end-to-end telemetry on active gateway transactions:
1. Dynamic Upstream Socket Resolution
When a request is handled by a reverse proxy route, the active backend socket selected by the load balancer (e.g., 127.0.0.1:8080, 10.0.1.11:8080) is propagated from pkg/proxy/proxy.go via request context into server.GlobalTraceBuffer.
- Proxy Routes: Render the concrete upstream socket (
127.0.0.1:8080), eliminating ambiguous generic"gateway"strings. - Static Assets Routes: Tagged with destination
static. - In-Process Routes: Built-in engine endpoints (such as
/health,/metrics, and HTTPS redirects) are tagged asin-process.
2. Hierarchical Route Subpath Filtering
In public/app.js, the route dropdown filter (#lgRoute) matches both the canonical route prefix and all child subpaths. For example, filtering by /kite/api seamlessly displays requests to /kite/api/v1/trades, /kite/api/v1/business, and /kite/api/v1/auth.
3. Trace Waterfall & Security Isolation
Opening a request row renders execution spans across listener, router, WAF, and proxy phases. The resolved upstream node is displayed in the inspector drawer. In accordance with CWE-200 security requirements, internal upstream network sockets are recorded strictly within in-memory telemetry buffers and are never leaked to external client response headers.
Alerts & Threat Defense Control Center
The Alerts & Threat Defense Control Center (#/alerts) is Toron’s operational cockpit for edge security monitoring, threat analysis, and firewall policy management. Serving as the primary interface for the native Web Application Firewall (WAF) and dynamic 2-stage auto-ban engine (see OS-Level IP Blocking), this view combines high-density forensic analysis with zero-dependency native browser ECMAScript Modules (public/js/views/alerts.js).
The interface provides an executive security KPI strip, an ergonomically decoupled threat quarantine panel, a dual-card UI architecture separating infrastructural operational alerts from security incidents, a 4-state defense action badging taxonomy, real-time multi-attribute searching and severity facet filtering, client-side pagination, interactive table sorting with deterministic tie-breaking, non-blocking modal workflows, and a slide-out forensic incident investigation drawer.
+---------------------------------------------------------------------------------------------------------+
| SECURITY KPI METRICS STRIP |
| [ Active Alerts: 2 ] [ Recent WAF Blocks: 18 ] [ Stage 1 Temp Bans: 7 ] [ Stage 2 Perm: 3 ] |
+---------------------------------------------------------------------------------------------------------+
| MANUAL THREAT ACTOR QUARANTINE |
| [ IP Address ] [ Tier: 1h Temp v ] [ Context / Reason ] [ Ban Threat Actor ] |
+---------------------------------------------------------------------------------------------------------+
| CARD 1: OPERATIONAL SYSTEM ALERTS (#alOpsCard) |
| - [!] Upstream Degradation: api-pool · 2/3 instances unreachable [ Investigate -> upstreams ] |
| - [!] High 5xx Error Rate: /v1/auth · 5xx rate 4.2% > 2.0% SLO [ Investigate -> routes ] |
| - [!] Certificate Renewal Failed: example.com · ACME renewal failed [ Investigate -> certs ] |
| (Or Zero-Alert State: [✓] All upstream services, routes, and certificates operating normally.) |
+---------------------------------------------------------------------------------------------------------+
| CARD 2: SECURITY INCIDENTS & THREAT DEFENSE FEED (.al-inc-card) |
| [ Search incidents... ] [ All | Critical | Warning ] |
| - SQL Injection [Blocked] POST /v1/auth/login · Rule 942100 · IP 198.51.100.99 · Score: 15 |
| - Firewall Quarantine [Banned] CONNECT /admin · Rule auto_ban · IP 198.51.100.20 · Score: 25 |
| - Rate Limit Ingress [Throttled] POST /api/v1/orders · Rule rate_limit · IP 203.0.113.30 · Score: 0 |
| - Protocol Violation [Logged] GET /wp-login.php · Rule 920100 · IP 203.0.113.40 · Score: 3 |
| Showing 1–10 of 24 incidents | << < Page 1 / 3 > >> | [ 10 / page v ] |
+---------------------------------------------------------------------------------------------------------+
| DYNAMIC 2-STAGE AUTO-BAN & BLOCKED IPS |
| [ Search bans... ] [ All | Stage 1 (1h Temp) | Stage 2 (Permanent) ] |
| Table: Client IP ▲ | Ban Tier | Created At | Temp Bans | Reason / Category | TTL / Expiry | Action |
| Showing 1–10 of 10 banned IPs | << < Page 1 / 1 > >> | [ 25 / page v ] |
+---------------------------------------------------------------------------------------------------------+
1. Executive 4-Card Security KPI Metrics Strip
The top of the view renders a responsive 4-column metric grid (.al-kpi-grid) presenting immediate high-level situational awareness across edge threat activity:
| KPI Metric Card | Target Element | Derived Data Source | Tone Escalation | Description |
|---|---|---|---|---|
| Active Incidents / Alerts | #alKpiActive |
D.alerts.length + unmitigated D.incidents.length |
var(--err) if $> 0$, var(--ok) if 0 |
Total unresolved operational degradations and active Layer 7 security alerts requiring operator attention. |
| Recent WAF Blocks | #alKpiBlocks |
Count of D.incidents where action === 'blocked' |
var(--c5) (Indigo) |
Total malicious request payloads intercepted and rejected by OWASP inspection rules within the telemetry buffer. |
| Stage 1 Temp Bans | #alKpiTemp |
Count of D.bannedIps where type === 'temporary' |
var(--warn) (Amber) |
Malicious client IP addresses currently undergoing automated or manual temporary quarantine (default 1 hour). |
| Stage 2 Permanent Bans | #alKpiPerm |
Count of D.bannedIps where type === 'permanent' |
var(--err) (Red) |
Repeat offending IP addresses permanently dropped at the socket layer by the firewall. |
The KPI cards adapt responsively (repeat(auto-fit, minmax(200px, 1fr))) to varying screen widths, ensuring readability across tablet and multi-monitor operations screens.
2. Decoupled Manual Threat Actor Quarantine Toolbar
Rather than nesting input forms inside table headers, manual quarantine is decoupled into an independent action panel (.al-ban-box within .al-ban-card). Operators can manually isolate suspicious actors, automated vulnerability scanners, or abusive bots:
- Client-Side IP Syntax Validation (
isValidIP):- The client engine validates both IPv4 (
255.255.255.255dotted decimal format) and IPv6 (hexadecimal colon notation) before network transmission. - If an invalid address format is entered, an inline feedback warning (
#alBanError) immediately renders without dispatching invalid API traffic over the network.
- The client engine validates both IPv4 (
- Duration Presets & Custom Interval Selection:
- Presets:
15m(15 Minutes),1h(Stage 1: 1h Temp - default),6h(6 Hours),24h(24 Hours),7d(7 Days), andPermanent(Stage 2: Permanent). - Custom Duration: Selecting
customdynamically displays a duration text input (#alBanCustomDuration) accepting standard duration strings (e.g.30m,48h,72h).
- Presets:
- Context & Reason Attribution:
- An optional context input (
#alBanReason) captures audit justification (e.g.Credential stuffing against /v1/auth). If omitted, defaults toManually banned via dashboard.
- An optional context input (
- API Dispatch & State Sync:
- Clicking Ban Threat Actor submits
POST /internal/api/security/banwith JSON payload{ ip, type, duration, reason }. - On HTTP
200 OK, input fields clear, a floating toast confirms success, andfetchBackendData()immediately refreshes the dashboard data model.
- Clicking Ban Threat Actor submits
3. Dual-Card UI Architecture & Operational Alert Non-Suppression
To prevent operational alarms from being drowned out by high-frequency security attack chatter, the Alerts view implements a dual-card separation architecture dividing system health degradations from threat activity:
[ Telemetry Model D ]
|
+---> D.alerts (Operational Issues) ------> Card 1: Operational System Alerts (#alOpsCard)
| - Upstream pool degradation (unreachable nodes)
| - Route 5xx error rate spikes (> 2.0% threshold)
| - ACME SSL certificate renewal failures
| - 1-click resource jump links (data-go)
| - Zero-alert reassuring checkmark state
|
+---> D.incidents (Threat Audit Feed) -----> Card 2: Security Incidents & Threat Defense (.al-inc-card)
- WAF rule violations (SQLi, XSS, traversal)
- Volumetric rate drops (HTTP 429 Throttled)
- Dynamic auto-ban triggers (Banned)
- Passive inspection logs (Logged)
- Dedicated search & severity faceting
A. Dedicated Operational System Alerts Card (#alOpsCard)
Positioned prominently above the security feeds, the Operational System Alerts card renders unresolved infrastructure anomalies derived from D.alerts:
- Upstream Degradation (
upstream_<id>):- Triggers when active or passive health checks detect one or more failed backend instances in an upstream pool (
p.down > 0). - Title:
Upstream Degradation: <pool-name>. - Description: Displays the exact count of failing instances (e.g.
2 of 3 instances are failing health checks.). - Severity:
critical(rendered with red error tonet-errandi-xicon). - Resource Jump Link: Tagged with
data-go="upstreams". Clicking the row or the Investigate button navigates directly to#/upstreamsfocused on the affected pool.
- Triggers when active or passive health checks detect one or more failed backend instances in an upstream pool (
- High 5xx Error Rate (
route_<id>):- Triggers when a route’s 5xx error percentage reaches or exceeds the 2.0% SLO threshold (
r.cur.err5 >= 0.02). - Title:
High 5xx Error Rate: <route-path>. - Description: Formats the exact error percentage (e.g.
5xx error rate (4.2%) exceeds 2% threshold.). - Severity:
critical(t-err,i-x). - Resource Jump Link: Tagged with
data-go="routes". Clicking navigates directly to#/routes.
- Triggers when a route’s 5xx error percentage reaches or exceeds the 2.0% SLO threshold (
- Certificate Renewal Failure (
cert_<id>):- Triggers when an automated Let’s Encrypt ACME renewal attempt fails (
c.state === 'failing'). - Title:
Certificate Renewal Failed: <domain>. - Description: Details the failing domain and protocol challenge.
- Severity:
critical(t-err,i-x). - Resource Jump Link: Tagged with
data-go="certs". Clicking navigates directly to#/certs.
- Triggers when an automated Let’s Encrypt ACME renewal attempt fails (
- Zero-Alert Positive Health Summary:
- When all upstream pools, routes, and certificates operate normally (
D.alerts.length === 0), the list displays a reassuring positive health summary:<li class="empty"> <span class="t-ok">[ICON: i-check]</span> <span>All upstream services, routes, and certificates operating normally.</span> </li>
- When all upstream pools, routes, and certificates operate normally (
- Guaranteed Non-Suppression Invariant:
- Operational alerts reside in
#alOpsListcompletely decoupled from#alIncList. - Filtering security incidents via
#alIncSearchor changing severity facets (#alSevChips) has zero effect on operational alert rendering. - High volumes of Layer 7 security attacks (e.g. 50,000 WAF blocks during a DDoS attack) never displace, hide, or paginate operational system failures off-screen.
- Operational alerts reside in
4. Incidents Feed Multi-Action Badging Taxonomy
Toron classifies all defensive edge interventions and audit recordings into a standardized 4-state action taxonomy:
| Action State | Status Badge | Class | Color Tone | Status Icon | HTTP Response | Trigger Condition |
|---|---|---|---|---|---|---|
blocked |
Blocked |
st s5 |
t-err (Red) |
i-x |
403 Forbidden |
Malicious payload intercepted by active OWASP WAF inspection rules (e.g. SQLi, XSS, Path Traversal). |
banned |
Banned |
st s5 |
t-err (Red) |
i-x |
Connection Drop | Traffic originating from a client IP address subject to Stage 1 temporary quarantine or Stage 2 permanent firewall ban. |
throttled |
Throttled |
st s4 |
t-warn (Amber) |
i-alert |
429 Too Many Requests |
Request volume exceeded configured route-level or global token bucket limits (rate_limit_drop). |
logged |
Logged |
st s4 |
t-warn (Amber) |
i-alert |
Forwarded / Allowed | Passive WAF detection mode, anomaly score threshold warnings, or protocol violation audits. |
Visual Hierarchy & Tone Mapping
In public/js/views/alerts.js, the helper getActionMeta(action) maps each action state to deterministic visual styles:
- Critical Red Tones (
s5,t-err,i-x): Assigned to active request terminations (blocked,banned) representing hostile intrusion attempts or established threat actors. - Warning Amber Tones (
s4,t-warn,i-alert): Assigned to volumetric throttle drops (throttled) and non-blocking audit events (logged), highlighting anomalous behavior without implying an unmitigated compromise.
5. Rate-Limiting Telemetry & Audit Ingress Integration
Volumetric abuse protection enforced by Toron’s token-bucket rate limiter (pkg/router/rate_limiter.go) is integrated directly into the security audit pipeline:
- Telemetry Event Generation:
- When a client exhausts its token bucket quota,
rate_limiter.goissues an HTTP429 Too Many Requestsresponse with aRetry-After: <secs>header. - Concurrently, the rate limiter dispatches a structured audit event to the security audit buffer (
waf.AuditLogger):al.LogEvent(waf.SecurityEvent{ Event: "rate_limit_drop", Action: "throttled", Category: "rate_limit", ClientIP: clientIP, Method: method, Path: reqPath, AnomalyScore: 0, RuleID: "rate_limit", PayloadSnippet: fmt.Sprintf("Rate limit exceeded: retry after %d seconds", retrySecs), })
- When a client exhausts its token bucket quota,
- Feed Representation:
- Captured rate limit drops surface in the Security Incidents & Threat Defense Feed tagged with the amber
Throttledstatus pill (st s4,t-warn). - The category defaults to
Rate Limit Ingress, displaying the target route path and client IP.
- Captured rate limit drops surface in the Security Incidents & Threat Defense Feed tagged with the amber
- Forensic Correlation & Escalation:
- Clicking a throttled incident opens the slide-out investigation drawer, detailing the offending IP, request rate violation, and retry-after payload snippet.
- Clicking Ban Client IP inside the drawer automatically pre-populates the quarantine toolbar with the client’s IP and contextual justification (
Rate Limit Throttling: <path>), enabling rapid operator escalation from rate throttling to full firewall banishment.
6. Real-Time Multi-Attribute Search & Faceted Severity Filtering
Both the Security Incidents feed and the Banned IPs table feature real-time search inputs and categorical faceted filter chips:
A. Security Incidents Search & Severity Faceting
- Multi-Attribute Search (
#alIncSearch):- Executes instant case-insensitive substring matching against
client_ip,rule_id,path,category, andpayload_snippet. - Heuristic aliases support shorthand queries:
sqlimatches SQL injection (rule 942100).xssmatches cross-site scripting (rule 941100).lfiortraversalmatches directory traversal (rule 930100).throttle,rate, or429matches rate-limiting ingress drops.
- Executes instant case-insensitive substring matching against
- Severity Faceted Chips (
#alSevChips):- All: Renders all security incidents within the telemetry buffer.
- Critical: Intercepted high-severity threats where
action === 'blocked',action === 'banned',anomaly_score >= 10, orsev === 'critical'. - Warning: Monitored warnings and rate throttles where
action === 'throttled',action === 'logged',sev === 'warning', oranomaly_score < 10(strictly excluding blocked and banned actions). This ensures that throttled rate-limit events and passive audit logs are reliably surfaceable without returning empty sets.
- Pagination Index Reset:
- Typing into
#alIncSearchor selecting any severity chip automatically resetsstate.alIncPage = 1, preventing invalid out-of-bounds pagination slices.
- Typing into
- Empty State Feedback:
- When no records match active query or severity filters,
#alIncListdisplays:<li class="empty">[ICON: i-check] Zero security incidents match active filters.</li>
- When no records match active query or severity filters,
B. Banned IPs Filtering & Ban Tier Faceting
- Multi-Attribute Search (
#alBanSearch):- Matches across client IP address (
ip), justification reason (reason), and last violation category (last_category).
- Matches across client IP address (
- Ban Tier Faceted Chips (
#alTierChips):- All: All banned actors.
- Stage 1 (1h Temp): Temporary bans (
type === 'temporary'). - Stage 2 (Permanent): Permanent firewall bans (
type === 'permanent').
- Pagination Index Reset:
- Modifying
#alBanSearchor toggling tier chips resetsstate.alBanPage = 1.
- Modifying
7. Client-Side Non-Blocking Pagination
To prevent unbounded DOM growth, memory bloat, and excessive vertical scrolling when inspecting hundreds of security incidents or thousands of banned IP records, the view implements client-side pagination (.al-foot-bar):
- Configurable Page Sizes: Dropdown controls support
10,25, and50rows per page (defaulting to 10 for incidents and 25 for banned IPs). - Navigation Controls: First (
«), Previous (‹), Next (›), and Last (») buttons with boundary disabling (First and Previous are disabled on Page 1; Next and Last are disabled on the final page). - Status Indicators:
- Summary display:
Showing start–end of total(e.g.Showing 1–10 of 45). - Page indicator:
Page X / Y(e.g.Page 1 / 5).
- Summary display:
- Zero Server Overhead: Slicing occurs entirely in browser memory (
Array.prototype.slice) in $< 1\text{ ms}$, preserving high interactivity without server queries.
8. Deterministic Multi-Level Interactive Column Sorting
The Banned IPs table provides interactive sorting across 6 telemetry columns:
| Column Header | Field Key | Default Sorting Rule | Secondary Tie-Breaker |
|---|---|---|---|
| Client IP | ip |
Natural IP address collation | Collation direction |
| Ban Tier | type |
String comparison (permanent vs temporary) |
Deterministic IP ascending |
| Created At | created_at |
Epoch millisecond timestamp comparison | Deterministic IP ascending |
| Temp Bans | temp_ban_count |
Numeric strike count comparison | Deterministic IP ascending |
| Reason / Category | reason |
Lexicographical string comparison | Deterministic IP ascending |
| TTL / Expiry | remaining_seconds |
Numeric countdown seconds comparison | Deterministic IP ascending |
Deterministic Secondary IP Tie-Breaker
Clicking any column header toggles sort direction between ascending (▲) and descending (▼). When two records have identical values in the primary sort column (e.g. multiple IPs banned at the same second or sharing identical strike counts), the table breaks ties deterministically on client IP using numeric natural collation:
diff !== 0 ? diff * mult : (a.ip || '').localeCompare(b.ip || '', undefined, { numeric: true });
This mathematical tie-breaker ensures stable ordering across 2-second background telemetry polling refreshes, eliminating visual row jitter and preventing items from shifting between pagination pages.
9. Non-Blocking In-App Confirmation Modal & Toast Feedback
Earlier synchronous browser dialogs (window.confirm(), window.alert()) caused browser thread blocking, halting background telemetry polling, freezing animations, and breaking headless testing suites.
The redesigned control center replaces all native dialogs with an in-app confirmation workflow:
- In-App Modal Trigger (
#alConfirmModal):- Clicking the Unban button on any table row opens an in-app confirmation card overlay (
.modal-cardover.modal-scrim). - The modal explicitly displays the target client IP (
#alConfirmIp) and informs the operator that traffic filtering will be revoked. - The modal can be dismissed safely via the Cancel button, the top-right close icon (
#alConfirmClose), or by pressing Escape.
- Clicking the Unban button on any table row opens an in-app confirmation card overlay (
- Asynchronous Execution & Background Continuity:
- Confirming the unban initiates an asynchronous call (
POST /internal/api/security/unban) viaauthenticatedFetch. - The main browser event loop and 2-second telemetry polling cycles continue without interruption.
- Confirming the unban initiates an asynchronous call (
- Floating Toast Notifications (
#alToast):- Operation outcomes are surfaced via a non-blocking floating toast card positioned at
bottom: 20px; right: 20px(z-index: 100). - Success operations display green tone badges (
var(--ok)); server errors or network rejections display red tone badges (var(--err)). - Toasts automatically dismiss after 4,000 milliseconds without requiring manual user interaction.
- Operation outcomes are surfaced via a non-blocking floating toast card positioned at
10. Slide-Out Forensic Incident Investigation Drawer
Clicking any incident row in the Security Incidents & Threat Defense Feed activates Toron’s slide-out inspector drawer (openDrawer('incident', id)), rendering in-depth Layer 7 forensic audit telemetry:
Forensic Display Elements
- Header: Incident category, action tone pill (
Blocked,Banned,Throttled, orLogged), and full calendar timestamp (YYYY-MM-DD HH:MM:SS) with relative elapsed time (e.g.2m ago). - Forensic Attributes Table:
- OWASP Rule ID: The matched Core Rule Set or custom security rule identifier (e.g.
942100for SQL Injection,941100for XSS,930100for Path Traversal, orrate_limitfor rate drops). - Anomaly Score: Numerical severity score computed during rule evaluation (
0for volumetric rate drops). - Action Taken: Visual status pill indicating whether the transaction was dropped (
Blocked,Banned), throttled (Throttled), or recorded (Logged). - Parameter Location: Request segment where the malicious payload was identified (
query,header,body, orcookie). - HTTP Method & Path: Incoming verb and full URI endpoint (e.g.
POST /v1/auth/login?redirect=true). - Client IP: Offending client network address, paired with a 1-click Copy button (
#alDrawerCopyIp) for rapid external firewall or threat intelligence lookup. - Timestamp: High-precision calendar timestamp.
- OWASP Rule ID: The matched Core Rule Set or custom security rule identifier (e.g.
- Attack Payload Snippet:
- Rendered inside a horizontally scrollable code block (
<pre class="cs-pre">). - Raw attack vectors (e.g.
' OR '1'='1' --,<script>alert(1)</script>,../../../../etc/passwd) and rate limit drop notifications (e.g.Rate limit exceeded: retry after 2 seconds) are safely sanitized viaesc()to prevent DOM XSS execution while preserving exact byte sequences for forensic review.
- Rendered inside a horizontally scrollable code block (
Integrated 1-Click Remediation Actions
The drawer footer provides two immediate operational shortcuts:
- “Ban Client IP” (
#alDrawerBanBtn):- Closes the drawer and automatically pre-populates the Manual Threat Actor Quarantine toolbar with the offending client IP and context-derived reason:
- For rate limit drops:
Rate Limit Throttling: <path> - For WAF rule violations:
<category> (Rule <rule_id>)
- For rate limit drops:
- Places browser focus directly into the quarantine input form for single-keystroke ban enforcement.
- Closes the drawer and automatically pre-populates the Manual Threat Actor Quarantine toolbar with the offending client IP and context-derived reason:
- “Filter Logs for IP” (
#alDrawerLogBtn):- Closes the drawer, sets the log query filter state (
state.lq = client_ip), and navigates browser routing to the Live Requests view (#/logs). - Immediately displays all historical and streaming request traces associated with the malicious IP address across the gateway.
- Closes the drawer, sets the log query filter state (
11. Telemetry Data Model Deduplication & Badge Accuracy
In high-throughput environments, data model integrity is critical to avoid operator alarm fatigue. In public/js/model.js, telemetry collections are cleanly separated:
D.alerts: Strictly contains unresolved operational system issues, including upstream health check failures, route 5xx error spikes exceeding 2%, and failing ACME SSL certificate renewals.D.incidents: Dedicated collection of Layer 7 WAF security events and injection attempts.D.bannedIps: Dedicated collection of active Stage 1 temporary bans and Stage 2 permanent firewall bans.
By isolating bannedIps from alerts, quarantined threat actors no longer inflate the navigation alert badge (#nav button[data-nav="alerts"] .badge) or trigger misleading degraded health banners on the Overview screen. Mitigated threats remain visible in their designated threat table without obscuring actionable operational gateway incidents.
Native ECMAScript Modules Architecture
The dashboard is structured into a clean hierarchy of native browser ECMAScript Modules (ESM) under public/js/, delivering zero-build modularity, instantaneous development updates, and zero supply-chain vulnerabilities:
public/js/
├── app.js # Router, navigation, event dispatch & bootstrap entrypoint
├── state.js # Central reactive state store, time ranges & theme engine
├── utils.js # Core DOM helpers, HTML sanitizers & math/time formatters
├── api.js # Telemetry background polling adapter & authenticatedFetch interceptor
├── model.js # Telemetry data model builder, rollups & rate smoothing
├── components/
│ ├── icons.js # Vector SVG icon renderers & status tone badges
│ ├── charts.js # SVG sparklines, timeseries graphs & latency histograms
│ ├── sankey.js # Vector SVG Sankey traffic flow diagram generator
│ ├── drawer.js # Slide-over inspector drawer controller
│ └── authModal.js # Interactive in-page admin authentication modal & probe validator
└── views/
├── overview.js # View 1: Gateway health, Sankey flow & signal cards
├── routes.js # View 2: Route table, filtering, sorting & RPS sparklines
├── upstreams.js # View 3: Upstream pool cards & 48-tick probe strips
├── logs.js # View 4: Live request stream & tail pause controls
├── certs.js # View 5: ACME zero-touch TLS certificates & expiration
├── modules.js # View 6: Compiled engine reactors & Go runtime internals
├── alerts.js # View 7: Alerts & Threat Defense control center, ban management & search
└── console.js # View 8: Interactive API endpoint probe debugger
Key Architectural Invariants
- Zero External Dependencies: The client requires zero npm runtime libraries and zero build tools (no Webpack, Vite, or Rollup). The total uncompressed script footprint is under 100 KB.
- Strictly Relative Specifiers: All internal imports utilize relative paths (
./utils.js,../components/icons.js) with explicit.jsextensions, ensuring native compatibility across all modern browser module loaders. - Unidirectional Data Flow: The background poller in
public/js/api.jsupdates shared raw state and invalidatespublic/js/model.js. The active view controller’supdate()method re-renders the DOM using pure string templates and SVG elements.
Administrative Access & Defense-in-Depth Security
Control Center access and backing management endpoints (/internal/api/*) are secured via a hybrid defense-in-depth architecture:
1. Multi-Scheme Backend Access Controls
When administrative authentication is enabled via config.yaml or the TORON_ADMIN_KEY environment variable:
- Admin Token: Evaluated against
X-Toron-Admin-Key: <token>andAuthorization: Bearer <token>using constant-time comparison (crypto/subtle.ConstantTimeCompare). - Basic Authentication: Evaluated against standard
Authorization: Basic <base64(user:pass)>headers for configured administrative operators. - CIDR Subnet Filtering: Requests originating from client IPs outside configured
admin_subnetsreceive HTTP403 Forbidden. - Standardized 401 Challenges: Missing or rejected credentials return HTTP
401 UnauthorizedwithWWW-Authenticate: Bearer realm="Toron Management", Basic realm="Toron Management".
admin_auth_enabled: true
admin_token: "secret-admin-token"
admin_subnets:
- "127.0.0.1/32"
- "10.0.0.0/8"
2. Client Authentication Lifecycle & Interactive Modal
When an operator accesses /internal/dashboard/ against a secured gateway:
- 401 Response Interception: The HTTP client interceptor (
authenticatedFetchinpublic/js/api.js) pauses background polling and presents the in-page Admin Authentication Modal (public/js/components/authModal.js). - Direct Verification Probe: Submitting credentials triggers an immediate probe to
GET /internal/api/status. If valid, the modal dismisses and polling resumes. Invalid credentials render inline error feedback. - Session Scoping: Active credentials reside exclusively in volatile browser
sessionStorage(scoped to the active tab) and are never stored in persistentlocalStorage. - Session Lock Action: The top navigation toolbar contains a lock action button (
#authLockBtn), enabling instant session revocation and manual re-authentication.
For endpoint schemas and REST response structures, see the HTTP API Reference. For gateway configuration directives, see the Configuration Guide.