Een commando-en-controle-dashboard is geen business-intelligence-tool met een militair verflaagje. De architectuurbeslissingen die bepalen of een BI-dashboard adequaat presteert — pollingintervallen, pagina-herlaadcycli, synchrone API-aanroepen — zijn precies de beslissingen die een defensie-C2-dashboard in het veld laten falen. Het dreigingsmodel, de netwerkomgeving en de operationele inzet zijn fundamenteel anders.

Dit artikel behandelt de voornaamste architectuurbeslissingen waarmee een ontwikkelteam wordt geconfronteerd bij het bouwen van een C2-dashboard voor defensiegebruik: hoe de frontend van de backend te scheiden, hoe realtime data in te nemen zonder de gebruikersinterface te overweldigen, welke kaartweergavetechnologie te selecteren, hoe rolgebaseerde toegang te structureren voor verschillende commandoniveaus, en hoe de prestaties te handhaven wanneer het aantal sporen vijf of zes cijfers bereikt.

Frontend/Backend-Scheiding in Defensiedashboards

Het dominante patroon in moderne C2-dashboardontwikkeling is een React- of Vue-single-page-applicatie (SPA) die gegevens consumeert van een reeks backend-microservices via WebSocket-verbindingen voor live data en REST voor configuratie- en historische queries. Deze scheiding biedt een duidelijke scheiding van verantwoordelijkheden: de frontend is verantwoordelijk voor het weergeven van toestand, de backend voor het handhaven van de gezaghebbende toestand en het uitzenden van delta's.

De microservice-backend bestaat doorgaans uit minimaal vier services in een minimale uitrol: een spoorservice (onderhoudt de live-objectdatabase), een berichtendienst (verwerkt CoT- en NFFI-ingest), een alertservice (evalueert regels en publiceert meldingen) en een authenticatiedienst (valideert JWT-tokens en handhaaft RBAC-beleid). Elke service is gecontaineriseerd — doorgaans Docker op Kubernetes voor hoofdkwartieruitrollen, of Docker Compose op een geharde server voor vooruit-uitgerold configuraties.

Een kritische architectuurbeperking die defensiedashboards onderscheidt van commerciële SaaS is de vereiste om te werken in air-gapped of zwaar bandbreedte-beperkte omgevingen. Dit betekent dat het volledige frontend-bundle, alle kaarttiles en alle geospatiale bibliotheken lokaal beschikbaar moeten zijn. De frontend-build-pijplijn moet een volledig zelfstandig artefact produceren dat werkt zonder CDN-afhankelijkheden. In de praktijk betekent dit het inbouwen van Mapbox GL JS, Cesium en alle npm-afhankelijkheden in de build-uitvoer en alles serveren vanaf de lokale server.

Architecture Diagram
C2 Dashboard — Backend Services and Real-Time Data Flow
CoT / NFFI feeds Radar / sensor tracks Intel overlays Logistics data
Track Service
Live object DB · position states · track lifecycle
Messaging Service
CoT / NFFI ingest · normalization · feed validation
Alert Service
Rule engine · R-tree spatial index · INACTIVE → ACTIVE → COOLDOWN
Auth Service
JWT validation · RBAC policy · per-request scope check
Redis Pub/Sub or NATS JetStream
WebSocket Gateway
Fan-out to authenticated sessions · per-session AoI filter · backpressure + rate limiting · delta events only
↓ WebSocket — tracks + alerts, <200ms local  ·  REST — config, history, logistics
React SPA Frontend
WebGL track layer · map engine · RBAC-gated UI · Web Worker track state · self-contained bundle (no CDN, air-gap ready)
Read path (WebSocket) and write path (REST) are separated at the API layer — different infrastructure, different latency profiles, different failure modes.
C2-dashboard backend-architectuur — Corvus Intelligence. Docker Compose voor vooruitgestationeerde configuraties; Kubernetes voor het hoofdkwartier. Alle vier services draaien binnen de geclassificeerde netwerkperimeter.

Realtime Data-Ingest: WebSocket versus Polling

Voor spoorwijzigingen is WebSocket de enige haalbare keuze bij tactische latentievereisten. Een HTTP-pollingbenadering met een interval van 5 seconden introduceert een gemiddelde latentie van 2,5 seconden plus serververwerkingstijd, wat onaanvaardbaar is voor luchtsporen waarbij de verouderingsdrempel van 10 seconden geldt. WebSocket-verbindingen, correct beheerd, leveren een end-to-end latentie onder 200 ms op een lokaal netwerk en onder 500 ms via een tactische radioverbinding.

Het standaard implementatiepatroon is een fan-out WebSocket-gateway. De backend-spoorservice publiceert spoor-delta's (niet de volledige toestand) naar een interne berichtbus — Redis Pub/Sub of NATS JetStream zijn gangbare keuzes. De WebSocket-gateway abonneert zich op de bus, onderhoudt een verbindingspool van geverifieerde browsersessies en geeft relevante gebeurtenissen door aan elke sessie op basis van de rol en het interessegebiedfilter van de sessie.

Tegendruk is een kritieke zorg die veel vroege C2-implementaties over het hoofd zien. Wanneer de frontend gebeurtenissen niet zo snel kan verwerken als ze arriveren — bijvoorbeeld tijdens een intensief gevecht wanneer honderden sporen tegelijkertijd worden bijgewerkt — kan de WebSocket-buffer vollopen en de verbinding wegvallen. De oplossing is een clientzijdige gebeurteniswachtrij met instelbare diepte en een verwerpbeleid (oudste-eerst is standaard voor spoorwijzigingen, omdat de laatste positie de enige relevante is). De backend-gateway moet ook snelheidsbegrenzing per sessie implementeren om te voorkomen dat een trage client de berichtbus blokkeert.

Voor logistieke data en inlichtingenoverlays, die worden bijgewerkt op minuutschaal in plaats van secondenschaal, is REST-polling aanvaardbaar en eenvoudiger correct te implementeren. Het dashboard moet geen WebSocket gebruiken voor data die geen realtime levering vereist — overmatig gebruik van persistente verbindingen verhoogt het serverresourceverbruik zonder voordeel.

Kaartlaag-Technologieën

De kaartlaag is de meest visueel kritische component van een C2-dashboard en de component met de meest significante technologiekeuze-implicaties. Drie opties domineren defensie-C2-ontwikkeling: Mapbox GL JS, Cesium.js en aangepaste WebGL-weergave bovenop OpenLayers of Leaflet.

Mapbox GL JS is de meest gebruikte optie voor 2D-operationele-beelddashboards. Het geeft vectortiles weer met WebGL, ondersteunt aangepaste laagvolgorde en verwerkt dynamische styling efficiënt (de kleur van een spoorsymbool wijzigen op basis van zijn classificatie). Cruciaal voor geclassificeerde netwerkuitrollen kan Mapbox GL JS volledig zelf worden gehost: serveer uw eigen vectortileset vanuit een TileServer-GL- of MapTiler Server-instantie, en de bibliotheek heeft geen externe netwerkafhankelijkheden. De belangrijkste beperking is 2D-exclusieve weergave — Mapbox GL JS ondersteunt geen echte 3D-terrein of globusmodusprojectie, wat het nut ervan beperkt voor lucht- en raketverdedigingsscenario's waarbij hoogte operationeel significant is.

Cesium.js is de standaard voor 3D-aardweergave. Het ondersteunt ellipsoïdale globusmodus, nauwkeurig 3D-terrein met Cesium World Terrain of aangepaste terraintiles, en tijddynamische visualisatie — spoorhistorieken kunnen worden weergegeven als sporen op de globus met nauwkeurige tijdprogressie. De prestatiekosten zijn reëel: Cesium vereist een discrete GPU en een moderne CPU om soepel te renderen bij hoge spooraantallen, wat een beperking is voor sommige geharde hardwareprofielen. Het tileformaat van Cesium (3D Tiles) en het terrainformaat (quantized-mesh) zijn open standaarden, en een zelf gehoste Cesium ion-proxy kan worden gebruikt op geclassificeerde netwerken.

Aangepaste tileservers voor geclassificeerde netwerken zijn een vereiste in de meeste nationale defensieprogramma's. De geclassificeerde netwerkomgeving verbiedt externe dataoproepen, wat betekent dat alle achtergrondbeeldmateriaal, terreindata en vectorkaartdata moeten worden geserveerd vanuit de netwerkperimeter. MapTiler Server Enterprise en TileServer-GL zijn de twee meest gebruikte opties. Beide ondersteunen MBTiles (een SQLite-gebaseerd tilecontainerformaat) en kunnen zowel raster- als vectortiles serveren. Voor inzetgebied-uitrollen kan een GeoServer-instantie ondersteund door PostGIS dynamische featurelagen serveren — wegen, hydrografie, bestuurlijke grenzen — vanuit geclassificeerde geografische databases.

CMP — Comparison
Map Layer Technology Selector
Mapbox GL JS Cesium.js Custom Tile Server
Projection 2D only 2D + 3D globe Raster / vector
GPU requirement Integrated Discrete Server-side
Self-hostable ✓ Yes ✓ Yes (ion proxy) ✓ Required
3D terrain ✗ No ✓ Yes Raster only
Performance @ 5K tracks 60 fps 30–45 fps Tile-dependent
Best for Ground / surface COP Air & missile defense Classified network base layer
Vergelijking van kaartlaag-technologieën voor defensie-C2-dashboards — zelf-hosten is niet onderhandelbaar op geclassificeerde netwerken.

Rolgebaseerde Toegangscontrole voor Commandoniveaus

Een C2-dashboard dient personeel met fundamenteel verschillende informatiebehoefte en autorisatieniveaus. Een commandant op brigadeiveau heeft het volledige operationele beeld nodig met vuurbeheerautoriteit. Een operator op hetzelfde niveau heeft spoorbeheer- en rapportcapaciteit nodig maar geen vuurmissie-initiatie. Een analist heeft leestoegang tot alle spoordata plus inlichtingenoverlays, maar geen schrijftoegang tot de spoordatabase. Een logistiek officier heeft routeoverlays en logistiek-knooppuntstatus nodig, maar geen toegang tot inlichtingencompartimenten.

De standaard implementatie gebruikt JWT-tokens met ingebedde claims die zowel de rol van de gebruiker als zijn classificatieniveau coderen. De backend-API handhaaft toegang op resourceniveau: een verzoek voor een inlichtingenoverlay met GEHEIM-classificatie wordt afgewezen als de JWT-claim het juiste vrijgaveattribuut niet bevat. De frontend gebruikt dezelfde claims om UI-elementen conditioneel weer te geven — de knop "Vuurmissie" wordt niet weergegeven voor gebruikers zonder de FIRE_CONTROL-rol, niet alleen uitgeschakeld.

Een vierniveaus rolhiërarchie werkt goed voor brigade en daaronder: COMMANDANT (volledige toegang, taakuitgifte, vuurbeheer), OPERATOR (spoorbeheer, rapport indiening, overlaybewerking), ANALIST (lees-alles, geen schrijven), LOGISTIEK (logistieklaag lezen/schrijven, geen inlichtingentoegang). Elke rol wordt gekoppeld aan een set machtigingsomvangen in de JWT. De authenticatiedienst valideert de JWT-handtekening en vervaldatum bij elke API-aanroep; rolbereikvalidatie vindt plaats bij de API-gateway voordat verzoeken individuele microservices bereiken.

Prestaties op Schaal: 10.000+ Gelijktijdige Sporen

Schaalbaarheid van het spooraantal is de meest onderschatte uitdaging in C2-dashboardontwikkeling. Een systeem op brigadeiveau in een intensieve omgeving kan 500-2.000 gelijktijdige sporen hebben. Een systeem op inzetgebiedsniveau dat gelijktijdig lucht-, grond-, maritieme en ruimteobjecten volgt, kan 50.000 overschrijden. De browser-weergavepijplijn is de knelpunt bij hoge spooraantallen.

De sleutelarchitiectuursbeslissing is of sporen moeten worden weergegeven als DOM-elementen, SVG, Canvas 2D of WebGL. DOM- en SVG-weergave faalt boven ongeveer 1.000 elementen — de browser-layout-engine kan 30 FPS niet handhaven bij het elke seconde herberekenen van posities voor duizenden DOM-knooppunten. Canvas 2D schaalt beter maar is CPU-gebonden en kan GPU-versnelling voor compositing niet benutten. WebGL is de enige optie die schaalt tot 10.000+ sporen op 60 FPS, waarbij geïnstanceerde rendering wordt gebruikt om duizenden identieke symboolgeometrieën te tekenen met één enkele draw call.

Mapbox GL JS en Cesium gebruiken beiden intern WebGL en ondersteunen aangepaste lagen. Voor sporen is het aanbevolen patroon een aangepaste WebGL-laag die een Float32Array-buffer van spoorposities bijhoudt, bijgewerkt via de WebSocket-gebeurtenishandler. Elk frame wordt de buffer geüpload naar de GPU als een vertex buffer en getekend met één enkele geïnstanceerde draw call. Symboolrotatie (voor directionele sporen), kleur (voor classificatie) en grootte (voor nadruk) worden gecodeerd als per-instantie-attributen in de vertex buffer, zonder dat er CPU-zijdige iteratie per frame nodig is.

Bij 10.000+ sporen verschuift het knelpunt van weergave naar JavaScript-verwerking van binnenkomende WebSocket-gebeurtenissen. Een spoorwijzigingsgebeurtenis moet worden gedeserialiseerd vanuit JSON, gevalideerd, geschreven naar de in-memory spooropslag en in de wachtrij geplaatst voor het volgende weergaveframe. Bij 100 bijwerkingen per seconde over 10.000 sporen zijn dit één miljoen bewerkingen per seconde in de JavaScript-thread. De oplossing is spoortoestandsbeheer te verplaatsen naar een Web Worker: de hoofdthread ontvangt ruwe WebSocket-frames en draagt ze over (met behulp van overdraagbare ArrayBuffer-objecten, niet gestructureerde kloon) naar de worker, die bijwerkingen verwerkt en de bijgewerkte positiebuffer terugstuurt naar de hoofdthread voor GPU-upload. Dit patroon houdt de hoofdthread vrij voor gebruikersinteracties en handhaaft soepele weergave.

MTX — Matrix
Rendering Technology vs Track Count
Renderer Max smooth tracks FPS @ 1K Compute Verdict
DOM < 200 12–18 CPU (layout) Prototypes only
SVG < 500 20–28 CPU (paint) Small-scale COP
Canvas 2D ~3,000 55–60 CPU-bound Brigade-level
WebGL 10,000+ 60 (stable) GPU (instanced) Theater-level
WebGL instanced rendering draws thousands of symbols in a single GPU draw call. Move track state management to a Web Worker to keep the main thread free at 10K+ update rates.
Weergave-technologiematrix — DOM/SVG zijn uitgeput voor brigadeomvang; alleen WebGL verwerkt spooraantallen op inzetgebiedsniveau op 60 fps.

Architectuurprincipe: Scheid leespaden van schrijfpaden op de API-laag. Spoorlezingen zijn hoog-frequent en latentiegevoelig; spoorschrijvingen (operatorcorrecties, taakopdrachten) zijn laag-frequent en correctheidsgevoelig. Deze hebben verschillende infrastructuurvereisten en mogen niet dezelfde servicelaag delen.

Alertlogica-Architectuur

Alertlogica in een C2-dashboard moet deterministisch, auditeerbaar en snel zijn. Een alert die 30 seconden na de activerende omstandigheid afgaat is operationeel nutteloos; een alert die incorrect afgaat ondermijnt het vertrouwen van operators. De alertservice evalueert regels tegen de live spoortoestand bij elke bijwerkgebeurtenis van de berichtbus.

Regels worden opgeslagen als gestructureerde JSON-beleidsdocumenten: een voorwaarde (ruimtelijk — spoor betreedt een gedefinieerd veelhoek; attribuut — spoorsnelheid overschrijdt drempel; temporeel — spoor is N seconden niet bijgewerkt) en een actie (WebSocket-melding pushen, alertrecord aanmaken, externe integratie activeren). De regelengine evalueert ruimtelijke voorwaarden met een ruimtelijke index (R-tree is standaard) voor O(log n) veelhoekdoorsnijdingscontroles — elk spoor evalueren tegen elk veelhoek bij elke bijwerking is O(n·m) en schaalt niet voorbij een paar honderd regels.

Alertonderdrukkingslogica — voorkomen dat dezelfde alert herhaaldelijk afgaat voor dezelfde omstandigheid — is geïmplementeerd als een toestandsmachine per (regel, spoor) paar. Een alert gaat van INACTIEF naar ACTIEF over wanneer aan de voorwaarde voor het eerst wordt voldaan, blijft ACTIEF totdat de voorwaarde verdwijnt, en treedt een KOELTIJD-toestand in voordat het terugkeert naar INACTIEF. Dit voorkomt alertstormen tijdens perioden van snelle spoorbeweging.