docs/Docs_To_Review/DATA_MODEL.md
Comprehensive data model documentation for World Monitor — an AI-powered real-time global intelligence dashboard. This reference covers all TypeScript interfaces, data structures, and their relationships across the system.
Source of truth:
src/types/index.ts(1,297 lines, 60+ interfaces)
The news pipeline ingests RSS feeds, parses individual items, clusters them into events, and scores each event for severity and velocity.
RSS feed configuration. Each feed defines a source to poll, with optional metadata for filtering and propaganda risk assessment.
interface Feed {
name: string;
url: string | Record<string, string>;
type?: string;
region?: string;
propagandaRisk?: PropagandaRisk; // 'low' | 'medium' | 'high'
stateAffiliated?: string; // e.g. "Russia", "China", "Iran"
lang?: string; // ISO 2-letter language code
}
A single parsed news article from an RSS feed. The minimal unit of intelligence in the pipeline.
interface NewsItem {
source: string;
title: string;
link: string;
pubDate: Date;
isAlert: boolean;
monitorColor?: string;
tier?: number;
threat?: ThreatClassification;
lat?: number;
lon?: number;
locationName?: string;
lang?: string;
}
Multiple NewsItems merged into a single event via Jaccard or hybrid semantic clustering. This is the primary unit displayed in news panels.
interface ClusteredEvent {
id: string;
primaryTitle: string;
primarySource: string;
primaryLink: string;
sourceCount: number;
topSources: Array<{ name: string; tier: number; url: string }>;
allItems: NewsItem[];
firstSeen: Date;
lastUpdated: Date;
isAlert: boolean;
monitorColor?: string;
velocity?: VelocityMetrics;
threat?: ThreatClassification;
lat?: number;
lon?: number;
lang?: string;
}
Measures how quickly a story is spreading across sources. Used to detect breaking news and surging stories.
type VelocityLevel = 'normal' | 'elevated' | 'spike';
type SentimentType = 'negative' | 'neutral' | 'positive';
interface VelocityMetrics {
sourcesPerHour: number;
level: VelocityLevel;
trend: 'rising' | 'stable' | 'falling';
sentiment: SentimentType;
sentimentScore: number;
}
Links a news event to a nearby physical asset (pipeline, cable, datacenter, military base, nuclear facility).
type AssetType = 'pipeline' | 'cable' | 'datacenter' | 'base' | 'nuclear';
interface RelatedAsset {
id: string;
name: string;
type: AssetType;
distanceKm: number;
}
interface RelatedAssetContext {
origin: { label: string; lat: number; lon: number };
types: AssetType[];
assets: RelatedAsset[];
}
A monitored geopolitical hotspot from the geo configuration. Includes static metadata and dynamic escalation tracking.
type EscalationTrend = 'escalating' | 'stable' | 'de-escalating';
interface Hotspot {
id: string;
name: string;
lat: number;
lon: number;
keywords: string[];
subtext?: string;
location?: string; // e.g. "Sahel Region, West Africa"
agencies?: string[];
level?: 'low' | 'elevated' | 'high';
description?: string;
status?: string;
escalationScore?: 1 | 2 | 3 | 4 | 5;
escalationTrend?: EscalationTrend;
escalationIndicators?: string[];
history?: HistoricalContext;
whyItMatters?: string;
}
interface HistoricalContext {
lastMajorEvent?: string;
lastMajorEventDate?: string;
precedentCount?: number;
precedentDescription?: string;
cyclicalRisk?: string;
}
Real-time escalation assessment combining static baselines with live signal data. Maintained in src/services/hotspot-escalation.ts.
interface DynamicEscalationScore {
hotspotId: string;
staticBaseline: number;
dynamicScore: number;
combinedScore: number;
trend: EscalationTrend;
components: {
newsActivity: number; // weight: 0.35
ciiContribution: number; // weight: 0.25
geoConvergence: number; // weight: 0.25
militaryActivity: number; // weight: 0.15
};
history: Array<{ timestamp: number; score: number }>;
lastUpdated: Date;
}
Active conflict zone with polygon boundaries and contextual metadata.
interface ConflictZone {
id: string;
name: string;
coords: [number, number][];
center: [number, number];
intensity?: 'high' | 'medium' | 'low';
parties?: string[];
casualties?: string;
displaced?: string;
keywords?: string[];
startDate?: string;
location?: string;
description?: string;
keyDevelopments?: string[];
}
Georeferenced events from the Uppsala Conflict Data Program.
type UcdpEventType = 'state-based' | 'non-state' | 'one-sided';
interface UcdpGeoEvent {
id: string;
date_start: string;
date_end: string;
latitude: number;
longitude: number;
country: string;
side_a: string;
side_b: string;
deaths_best: number;
deaths_low: number;
deaths_high: number;
type_of_violence: UcdpEventType;
source_original: string;
}
Foreign military installations and bases worldwide.
type MilitaryBaseType =
| 'us-nato' | 'china' | 'russia' | 'uk' | 'france'
| 'india' | 'italy' | 'uae' | 'turkey' | 'japan' | 'other';
interface MilitaryBase {
id: string;
name: string;
lat: number;
lon: number;
type: MilitaryBaseType;
description?: string;
country?: string; // Host country
arm?: string; // Armed forces branch
status?: 'active' | 'planned' | 'controversial' | 'closed';
source?: string;
}
Tracked military aircraft from ADS-B/OpenSky with classification metadata.
type MilitaryAircraftType =
| 'fighter' | 'bomber' | 'transport' | 'tanker' | 'awacs'
| 'reconnaissance' | 'helicopter' | 'drone' | 'patrol'
| 'special_ops' | 'vip' | 'unknown';
type MilitaryOperator =
| 'usaf' | 'usn' | 'usmc' | 'usa' | 'raf' | 'rn'
| 'faf' | 'gaf' | 'plaaf' | 'plan' | 'vks' | 'iaf'
| 'nato' | 'other';
interface MilitaryFlight {
id: string;
callsign: string;
hexCode: string;
registration?: string;
aircraftType: MilitaryAircraftType;
aircraftModel?: string;
operator: MilitaryOperator;
operatorCountry: string;
lat: number;
lon: number;
altitude: number;
heading: number;
speed: number;
verticalRate?: number;
onGround: boolean;
squawk?: string;
origin?: string;
destination?: string;
lastSeen: Date;
firstSeen?: Date;
track?: [number, number][];
confidence: 'high' | 'medium' | 'low';
isInteresting?: boolean;
note?: string;
enriched?: {
manufacturer?: string;
owner?: string;
operatorName?: string;
typeCode?: string;
builtYear?: string;
confirmedMilitary?: boolean;
militaryBranch?: string;
};
}
interface MilitaryFlightCluster {
id: string;
name: string;
lat: number;
lon: number;
flightCount: number;
flights: MilitaryFlight[];
dominantOperator?: MilitaryOperator;
activityType?: 'exercise' | 'patrol' | 'transport' | 'unknown';
}
Naval vessel tracking from AIS data with type classification.
type MilitaryVesselType =
| 'carrier' | 'destroyer' | 'frigate' | 'submarine'
| 'amphibious' | 'patrol' | 'auxiliary' | 'research'
| 'icebreaker' | 'special' | 'unknown';
interface MilitaryVessel {
id: string;
mmsi: string;
name: string;
vesselType: MilitaryVesselType;
aisShipType?: string;
hullNumber?: string;
operator: MilitaryOperator | 'other';
operatorCountry: string;
lat: number;
lon: number;
heading: number;
speed: number;
course?: number;
destination?: string;
lastAisUpdate: Date;
aisGapMinutes?: number;
isDark?: boolean;
nearChokepoint?: string;
nearBase?: string;
track?: [number, number][];
confidence: 'high' | 'medium' | 'low';
isInteresting?: boolean;
note?: string;
}
interface MilitaryVesselCluster {
id: string;
name: string;
lat: number;
lon: number;
vesselCount: number;
vessels: MilitaryVessel[];
region?: string;
activityType?: 'exercise' | 'deployment' | 'transit' | 'unknown';
}
Aggregated view of all tracked military assets.
interface MilitaryActivitySummary {
flights: MilitaryFlight[];
vessels: MilitaryVessel[];
flightClusters: MilitaryFlightCluster[];
vesselClusters: MilitaryVesselCluster[];
activeOperations: number;
lastUpdate: Date;
}
interface StrategicWaterway {
id: string;
name: string;
lat: number;
lon: number;
description?: string;
}
type AisDisruptionType = 'gap_spike' | 'chokepoint_congestion';
interface AisDisruptionEvent {
id: string;
name: string;
type: AisDisruptionType;
lat: number;
lon: number;
severity: 'low' | 'elevated' | 'high';
changePct: number;
windowHours: number;
darkShips?: number;
vesselCount?: number;
region?: string;
description: string;
}
interface AisDensityZone {
id: string;
name: string;
lat: number;
lon: number;
intensity: number;
deltaPct: number;
shipsPerDay?: number;
note?: string;
}
interface GdeltTensionPair {
id: string;
countries: [string, string];
label: string;
score: number;
trend: 'rising' | 'stable' | 'falling';
changePercent: number;
region: string;
}
// Pentagon Pizza Index (novelty OSINT indicator)
type PizzIntDefconLevel = 1 | 2 | 3 | 4 | 5;
type PizzIntDataFreshness = 'fresh' | 'stale';
interface PizzIntStatus {
defconLevel: PizzIntDefconLevel;
defconLabel: string;
aggregateActivity: number;
activeSpikes: number;
locationsMonitored: number;
locationsOpen: number;
lastUpdate: Date;
dataFreshness: PizzIntDataFreshness;
locations: PizzIntLocation[];
}
Cyber threat indicators sourced from threat intelligence feeds (Feodo, URLhaus, C2Intel, OTX, AbuseIPDB).
type CyberThreatType = 'c2_server' | 'malware_host' | 'phishing' | 'malicious_url';
type CyberThreatSource = 'feodo' | 'urlhaus' | 'c2intel' | 'otx' | 'abuseipdb';
type CyberThreatSeverity = 'low' | 'medium' | 'high' | 'critical';
type CyberThreatIndicatorType = 'ip' | 'domain' | 'url';
interface CyberThreat {
id: string;
type: CyberThreatType;
source: CyberThreatSource;
indicator: string;
indicatorType: CyberThreatIndicatorType;
lat: number;
lon: number;
country?: string;
severity: CyberThreatSeverity;
malwareFamily?: string;
tags: string[];
firstSeen?: string;
lastSeen?: string;
}
Known Advanced Persistent Threat group profiles, mapped to their attributed state sponsors.
interface APTGroup {
id: string;
name: string;
aka: string;
sponsor: string;
lat: number;
lon: number;
}
Three-tier model: global summary → country-level displacement → individual flow corridors.
interface DisplacementFlow {
originCode: string;
originName: string;
asylumCode: string;
asylumName: string;
refugees: number;
originLat?: number;
originLon?: number;
asylumLat?: number;
asylumLon?: number;
}
interface CountryDisplacement {
code: string;
name: string;
// Origin-country displacement outflow
refugees: number;
asylumSeekers: number;
idps: number;
stateless: number;
totalDisplaced: number;
// Host-country intake
hostRefugees: number;
hostAsylumSeekers: number;
hostTotal: number;
lat?: number;
lon?: number;
}
interface UnhcrSummary {
year: number;
globalTotals: {
refugees: number;
asylumSeekers: number;
idps: number;
stateless: number;
total: number;
};
countries: CountryDisplacement[];
topFlows: DisplacementFlow[];
}
Derived from Open-Meteo / ERA5 reanalysis data.
type AnomalySeverity = 'normal' | 'moderate' | 'extreme';
interface ClimateAnomaly {
zone: string;
lat: number;
lon: number;
tempDelta: number;
precipDelta: number;
severity: AnomalySeverity;
type: 'warm' | 'cold' | 'wet' | 'dry' | 'mixed';
period: string;
}
WorldPop-derived population density for impact assessment.
interface CountryPopulation {
code: string;
name: string;
population: number;
densityPerKm2: number;
}
interface PopulationExposure {
eventId: string;
eventName: string;
eventType: string;
lat: number;
lon: number;
exposedPopulation: number;
exposureRadiusKm: number;
}
Submarine cable routes with landing points and country-level capacity data.
interface CableLandingPoint {
country: string; // ISO code
countryName: string;
city?: string;
lat: number;
lon: number;
}
interface CountryCapacity {
country: string; // ISO code
capacityShare: number; // 0–1
isRedundant: boolean;
}
interface UnderseaCable {
id: string;
name: string;
points: [number, number][];
major?: boolean;
landingPoints?: CableLandingPoint[];
countriesServed?: CountryCapacity[];
capacityTbps?: number;
rfsYear?: number;
owners?: string[];
}
interface CableAdvisory {
id: string;
cableId: string;
title: string;
severity: 'fault' | 'degraded';
description: string;
reported: Date;
lat: number;
lon: number;
impact: string;
repairEta?: string;
}
interface RepairShip {
id: string;
name: string;
cableId: string;
status: 'enroute' | 'on-station';
lat: number;
lon: number;
eta: string;
operator?: string;
note?: string;
}
Oil and gas pipelines with terminal endpoints and capacity data.
type PipelineType = 'oil' | 'gas' | 'products';
type PipelineStatus = 'operating' | 'construction';
interface PipelineTerminal {
country: string;
name?: string;
portId?: string;
lat?: number;
lon?: number;
}
interface Pipeline {
id: string;
name: string;
type: PipelineType;
status: PipelineStatus;
points: [number, number][];
capacity?: string;
length?: string;
operator?: string;
countries?: string[];
origin?: PipelineTerminal;
destination?: PipelineTerminal;
transitCountries?: string[];
capacityMbpd?: number;
capacityBcmY?: number;
alternatives?: string[];
}
Real-time internet connectivity disruptions.
interface InternetOutage {
id: string;
title: string;
link: string;
description: string;
pubDate: Date;
country: string;
region?: string;
lat: number;
lon: number;
severity: 'partial' | 'major' | 'total';
categories: string[];
cause?: string;
outageType?: string;
endDate?: Date;
}
Graph-based dependency model for simulating cascading failures across infrastructure networks.
type InfrastructureNodeType = 'cable' | 'pipeline' | 'port' | 'chokepoint' | 'country' | 'route';
interface InfrastructureNode {
id: string;
type: InfrastructureNodeType;
name: string;
coordinates?: [number, number];
metadata?: Record<string, unknown>;
}
type DependencyType =
| 'serves' | 'terminates_at' | 'transits_through' | 'lands_at'
| 'depends_on' | 'shares_risk' | 'alternative_to'
| 'trade_route' | 'controls_access' | 'trade_dependency';
interface DependencyEdge {
from: string;
to: string;
type: DependencyType;
strength: number; // 0–1 criticality
redundancy?: number; // 0–1 replaceability
metadata?: {
capacityShare?: number;
alternativeRoutes?: number;
estimatedImpact?: string;
portType?: string;
relationship?: string;
};
}
type CascadeImpactLevel = 'critical' | 'high' | 'medium' | 'low';
interface CascadeAffectedNode {
node: InfrastructureNode;
impactLevel: CascadeImpactLevel;
pathLength: number;
dependencyChain: string[];
redundancyAvailable: boolean;
estimatedRecovery?: string;
}
interface CascadeResult {
source: InfrastructureNode;
affectedNodes: CascadeAffectedNode[];
countriesAffected: CascadeCountryImpact[];
economicImpact?: {
dailyTradeLoss?: number;
affectedThroughput?: number;
};
redundancies?: Array<{
id: string;
name: string;
capacityShare: number;
}>;
}
type NuclearFacilityType =
| 'plant' | 'enrichment' | 'reprocessing' | 'weapons'
| 'ssbn' | 'test-site' | 'icbm' | 'research';
interface NuclearFacility {
id: string;
name: string;
lat: number;
lon: number;
type: NuclearFacilityType;
status: 'active' | 'contested' | 'inactive' | 'decommissioned' | 'construction';
operator?: string;
}
interface GammaIrradiator {
id: string;
city: string;
country: string;
lat: number;
lon: number;
organization?: string;
}
USGS earthquake data.
interface Earthquake {
id: string;
place: string;
magnitude: number;
lat: number;
lon: number;
depth: number;
time: Date;
url: string;
}
type NaturalEventCategory =
| 'severeStorms' | 'wildfires' | 'volcanoes' | 'earthquakes'
| 'floods' | 'landslides' | 'drought' | 'dustHaze'
| 'snow' | 'tempExtremes' | 'seaLakeIce' | 'waterColor' | 'manmade';
interface NaturalEvent {
id: string;
title: string;
description?: string;
category: NaturalEventCategory;
categoryTitle: string;
lat: number;
lon: number;
date: Date;
magnitude?: number;
magnitudeUnit?: string;
sourceUrl?: string;
sourceName?: string;
closed: boolean;
}
Equities, indices, and commodities pricing.
interface MarketData {
symbol: string;
name: string;
display: string;
price: number | null;
change: number | null;
sparkline?: number[];
}
interface CryptoData {
name: string;
symbol: string;
price: number;
change: number;
sparkline?: number[];
}
interface Sector {
symbol: string;
name: string;
}
interface Commodity {
symbol: string;
name: string;
display: string;
}
Polymarket-sourced prediction contract data.
interface PredictionMarket {
title: string;
yesPrice: number;
volume?: number;
url?: string;
}
Tracks Saudi and UAE foreign direct investment in global infrastructure.
type GulfInvestorCountry = 'SA' | 'UAE';
type GulfInvestmentSector =
| 'ports' | 'pipelines' | 'energy' | 'datacenters' | 'airports'
| 'railways' | 'telecoms' | 'water' | 'logistics' | 'mining'
| 'real-estate' | 'manufacturing';
type GulfInvestmentStatus =
| 'operational' | 'under-construction' | 'announced'
| 'rumoured' | 'cancelled' | 'divested';
type GulfInvestingEntity =
| 'DP World' | 'AD Ports' | 'Mubadala' | 'ADIA' | 'ADNOC'
| 'Masdar' | 'PIF' | 'Saudi Aramco' | 'ACWA Power' | 'STC'
| 'Mawani' | 'NEOM' | 'Emirates Global Aluminium' | 'Other';
interface GulfInvestment {
id: string;
investingEntity: GulfInvestingEntity;
investingCountry: GulfInvestorCountry;
targetCountry: string;
targetCountryIso: string;
sector: GulfInvestmentSector;
assetType: string;
assetName: string;
lat: number;
lon: number;
investmentUSD?: number;
stakePercent?: number;
status: GulfInvestmentStatus;
yearAnnounced?: number;
yearOperational?: number;
description: string;
sourceUrl?: string;
tags?: string[];
}
type EconomicCenterType = 'exchange' | 'central-bank' | 'financial-hub';
interface EconomicCenter {
id: string;
name: string;
type: EconomicCenterType;
lat: number;
lon: number;
country: string;
marketHours?: { open: string; close: string; timezone: string };
description?: string;
}
Specialized types for the Tech variant dashboard.
interface AIDataCenter {
id: string;
name: string;
owner: string;
country: string;
lat: number;
lon: number;
status: 'existing' | 'planned' | 'decommissioned';
chipType: string;
chipCount: number;
powerMW?: number;
h100Equivalent?: number;
sector?: string;
note?: string;
}
type RegulationType = 'comprehensive' | 'sectoral' | 'voluntary' | 'proposed';
type ComplianceStatus = 'active' | 'proposed' | 'draft' | 'superseded';
type RegulationStance = 'strict' | 'moderate' | 'permissive' | 'undefined';
interface AIRegulation {
id: string;
name: string;
shortName: string;
country: string;
region?: string;
type: RegulationType;
status: ComplianceStatus;
announcedDate: string;
effectiveDate?: string;
complianceDeadline?: string;
scope: string[];
keyProvisions: string[];
penalties?: string;
link?: string;
description?: string;
}
interface RegulatoryAction {
id: string;
date: string;
country: string;
title: string;
type: 'law-passed' | 'executive-order' | 'guideline' | 'enforcement' | 'consultation';
regulationId?: string;
description: string;
impact: 'high' | 'medium' | 'low';
source?: string;
}
interface TechCompany {
id: string;
name: string;
lat: number;
lon: number;
country: string;
city?: string;
sector?: string;
officeType?: 'headquarters' | 'regional' | 'engineering' | 'research' | 'campus' | 'major office';
employees?: number;
foundedYear?: number;
keyProducts?: string[];
valuation?: number;
stockSymbol?: string;
description?: string;
}
interface AIResearchLab {
id: string;
name: string;
lat: number;
lon: number;
country: string;
city?: string;
type: 'corporate' | 'academic' | 'government' | 'nonprofit' | 'industry' | 'research institute';
parent?: string;
focusAreas?: string[];
description?: string;
foundedYear?: number;
notableWork?: string[];
publications?: number;
faculty?: number;
}
interface StartupEcosystem {
id: string;
name: string;
lat: number;
lon: number;
country: string;
city: string;
ecosystemTier?: 'tier1' | 'tier2' | 'tier3' | 'emerging';
totalFunding2024?: number;
activeStartups?: number;
unicorns?: number;
topSectors?: string[];
majorVCs?: string[];
notableStartups?: string[];
avgSeedRound?: number;
avgSeriesA?: number;
description?: string;
}
Per-panel toggle and priority for the variant system.
interface PanelConfig {
name: string;
enabled: boolean;
priority?: number;
}
35+ boolean layer toggles that control which data overlays appear on the map.
interface MapLayers {
// Geopolitical
conflicts: boolean;
bases: boolean;
hotspots: boolean;
military: boolean;
sanctions: boolean;
// Infrastructure
cables: boolean;
pipelines: boolean;
nuclear: boolean;
irradiators: boolean;
datacenters: boolean;
waterways: boolean;
spaceports: boolean;
minerals: boolean;
// Security
cyberThreats: boolean;
outages: boolean;
// Environmental
weather: boolean;
fires: boolean;
natural: boolean;
climate: boolean;
// Tracking
ais: boolean;
flights: boolean;
protests: boolean;
// Economic
economic: boolean;
gulfInvestments: boolean;
stockExchanges: boolean;
financialCenters: boolean;
centralBanks: boolean;
commodityHubs: boolean;
// Data sources
ucdpEvents: boolean;
displacement: boolean;
// Tech variant
startupHubs: boolean;
cloudRegions: boolean;
accelerators: boolean;
techHQs: boolean;
techEvents: boolean;
}
User-defined keyword monitors that highlight matching news items.
interface Monitor {
id: string;
keywords: string[];
color: string;
name?: string;
lat?: number;
lon?: number;
}
Top-level application state holding all active data and UI configuration.
interface AppState {
currentView: 'global' | 'us';
mapZoom: number;
mapPan: { x: number; y: number };
mapLayers: MapLayers;
panels: Record<string, PanelConfig>;
monitors: Monitor[];
allNews: NewsItem[];
isLoading: boolean;
}
Intelligence synthesis layer that detects entities (countries, companies) with converging news and signal activity.
type FocalPointUrgency = 'watch' | 'elevated' | 'critical';
interface HeadlineWithUrl {
title: string;
url: string;
}
interface EntityMention {
entityId: string;
entityType: 'country' | 'company' | 'index' | 'commodity' | 'crypto' | 'sector';
displayName: string;
mentionCount: number;
avgConfidence: number;
clusterIds: string[];
topHeadlines: HeadlineWithUrl[];
}
interface FocalPoint {
id: string;
entityId: string;
entityType: 'country' | 'company' | 'index' | 'commodity' | 'crypto' | 'sector';
displayName: string;
// News dimension
newsMentions: number;
newsVelocity: number;
topHeadlines: HeadlineWithUrl[];
// Signal dimension
signalTypes: string[];
signalCount: number;
highSeverityCount: number;
signalDescriptions: string[];
// Scoring
focalScore: number;
urgency: FocalPointUrgency;
// AI context
narrative: string;
correlationEvidence: string[];
}
interface FocalPointSummary {
timestamp: Date;
focalPoints: FocalPoint[];
aiContext: string;
topCountries: FocalPoint[];
topCompanies: FocalPoint[];
}
Individual protest, riot, or civil unrest event sourced from ACLED, GDELT, or RSS feeds.
type ProtestSeverity = 'low' | 'medium' | 'high';
type ProtestSource = 'acled' | 'gdelt' | 'rss';
type ProtestEventType = 'protest' | 'riot' | 'strike' | 'demonstration' | 'civil_unrest';
interface SocialUnrestEvent {
id: string;
title: string;
summary?: string;
eventType: ProtestEventType;
city?: string;
country: string;
region?: string;
lat: number;
lon: number;
time: Date;
severity: ProtestSeverity;
fatalities?: number;
sources: string[];
sourceType: ProtestSource;
tags?: string[];
actors?: string[];
relatedHotspots?: string[];
confidence: 'high' | 'medium' | 'low';
validated: boolean;
imageUrl?: string;
sentiment?: 'angry' | 'peaceful' | 'mixed';
}
Geographically grouped protest events.
interface ProtestCluster {
id: string;
country: string;
region?: string;
eventCount: number;
events: SocialUnrestEvent[];
severity: ProtestSeverity;
startDate: Date;
endDate: Date;
primaryCause?: string;
}
Compact cluster representations used for map rendering (protest, tech HQ, datacenter, tech event).
interface MapProtestCluster {
id: string;
lat: number;
lon: number;
count: number;
items: SocialUnrestEvent[];
country: string;
maxSeverity: 'low' | 'medium' | 'high';
hasRiot: boolean;
totalFatalities: number;
riotCount?: number;
highSeverityCount?: number;
verifiedCount?: number;
sampled?: boolean;
}
interface MapDatacenterCluster {
id: string;
lat: number;
lon: number;
count: number;
items: AIDataCenter[];
region: string;
country: string;
totalChips: number;
totalPowerMW: number;
majorityExisting: boolean;
sampled?: boolean;
}
Source: src/config/entities.ts (636 lines)
The entity system provides a registry of 600+ real-world entities (companies, indices, commodities, countries, crypto assets) used for news-to-asset linking.
type EntityType = 'company' | 'index' | 'commodity' | 'crypto' | 'sector' | 'country';
interface EntityEntry {
id: string; // Ticker symbol or code (e.g., "AAPL", "^GSPC", "BTC")
type: EntityType;
name: string; // Display name (e.g., "Apple Inc.")
aliases: string[]; // All recognized names/abbreviations
keywords: string[]; // Contextual keywords for matching
sector?: string; // Sector classification (e.g., "Technology")
related?: string[]; // Entity IDs of related entities
}
Multi-index lookup structure built from ENTITY_REGISTRY. Defined in src/services/entity-index.ts.
interface EntityIndex {
byId: Map<string, EntityEntry>; // Direct lookup by entity ID
byAlias: Map<string, string>; // alias → entity ID (lowercased)
byKeyword: Map<string, Set<string>>; // keyword → set of entity IDs
bySector: Map<string, Set<string>>; // sector → set of entity IDs
byType: Map<string, Set<string>>; // entity type → set of entity IDs
}
Lookup functions:
| Function | Signature | Description |
|---|---|---|
buildEntityIndex() | (entities: EntityEntry[]) → EntityIndex | Build all index maps |
getEntityIndex() | () → EntityIndex | Singleton accessor (lazy build) |
lookupEntityByAlias() | (alias: string) → EntityEntry | undefined | Find entity by any alias |
lookupEntitiesByKeyword() | (keyword: string) → EntityEntry[] | Find all entities matching keyword |
lookupEntitiesBySector() | (sector: string) → EntityEntry[] | Find all entities in a sector |
findRelatedEntities() | (entityId: string) → EntityEntry[] | Get related entities |
findEntitiesInText() | (text: string) → EntityMatch[] | NLP-style entity extraction from text |
Result of text-based entity extraction.
interface EntityMatch {
entityId: string;
matchedText: string;
matchType: 'alias' | 'keyword' | 'name';
confidence: number;
position: number;
}
flowchart LR
A[RSS Feed] --> B[Parsed NewsItem]
B --> C{Clustering}
C -->|Jaccard only| D[clusterNews]
C -->|Jaccard + semantic| E[clusterNewsHybrid]
D --> F[ClusteredEvent]
E --> F
F --> G[Threat Classification]
G --> H[Entity Extraction]
H --> I[Severity & Velocity Scoring]
I --> J[Panel Display]
Stages:
REFRESH_INTERVALS.feeds (5 min). Raw XML parsed into NewsItem objects.clusterNews() — Jaccard similarity on tokenized titles. Fast, no ML dependency.clusterNewsHybrid() — Jaccard + ML-based semantic similarity via Web Worker embedding model (cosine similarity). Produces higher-quality merges.ThreatClassification with category and severity level.findEntitiesInText() matches aliases/keywords from ENTITY_REGISTRY against titles.VelocityMetrics computed (sources/hour, acceleration). Sentiment scored.ClusteredEvent rendered in news panels with velocity badges, threat indicators, and entity links.Source: src/services/signal-aggregator.ts (495 lines)
The signal aggregator collects all map-layer signals and correlates them by country/region to feed the AI Insights engine.
type SignalType =
| 'internet_outage'
| 'military_flight'
| 'military_vessel'
| 'protest'
| 'ais_disruption'
| 'satellite_fire' // NASA FIRMS thermal anomalies
| 'temporal_anomaly'; // Baseline deviation alerts
flowchart TD
S1[Internet Outages] --> GS[GeoSignal]
S2[Military Flights] --> GS
S3[Military Vessels] --> GS
S4[Protests] --> GS
S5[AIS Disruptions] --> GS
S6[Satellite Fires] --> GS
S7[Temporal Anomalies] --> GS
GS --> CSC[CountrySignalCluster]
CSC --> RC[RegionalConvergence]
RC --> SS[SignalSummary]
SS --> AI[AI Insights Context]
interface GeoSignal {
type: SignalType;
country: string;
countryName: string;
lat: number;
lon: number;
severity: 'low' | 'medium' | 'high';
title: string;
timestamp: Date;
}
interface CountrySignalCluster {
country: string;
countryName: string;
signals: GeoSignal[];
signalTypes: Set<SignalType>;
totalCount: number;
highSeverityCount: number;
convergenceScore: number;
}
interface RegionalConvergence {
region: string;
countries: string[];
signalTypes: SignalType[];
totalSignals: number;
description: string;
}
interface SignalSummary {
timestamp: Date;
totalSignals: number;
byType: Record<SignalType, number>;
convergenceZones: RegionalConvergence[];
topCountries: CountrySignalCluster[];
aiContext: string; // Pre-formatted text for LLM prompts
}
Six monitored regions with their constituent country codes:
| Region | Countries |
|---|---|
| Middle East | IR, IL, SA, AE, IQ, SY, YE, JO, LB, KW, QA, OM, BH |
| East Asia | CN, TW, JP, KR, KP, HK, MN |
| South Asia | IN, PK, BD, AF, NP, LK, MM |
| Eastern Europe | UA, RU, BY, PL, RO, MD, HU, CZ, SK, BG |
| North Africa | EG, LY, DZ, TN, MA, SD, SS |
| Sahel | ML, NE, BF, TD, NG, CM, CF |
The map renders 35+ toggleable layers. Each layer is controlled by a boolean in MapLayers.
Defined in src/utils/urlState.ts, the LAYER_KEYS array lists all URL-serializable layer identifiers:
const LAYER_KEYS: (keyof MapLayers)[] = [
'conflicts', 'bases', 'cables', 'pipelines', 'hotspots', 'ais',
'nuclear', 'irradiators', 'sanctions', 'weather', 'economic',
'waterways', 'outages', 'cyberThreats', 'datacenters', 'protests',
'flights', 'military', 'natural', 'spaceports', 'minerals', 'fires',
'ucdpEvents', 'displacement', 'climate',
'startupHubs', 'cloudRegions', 'accelerators', 'techHQs', 'techEvents',
];
| Layer | Data Interface | Source |
|---|---|---|
conflicts | ConflictZone | Static config + UCDP |
bases | MilitaryBase | Static config |
cables | UnderseaCable | Static config |
pipelines | Pipeline | Static config |
hotspots | Hotspot | Static config + dynamic escalation |
ais | AisDisruptionEvent, AisDensityZone | API |
nuclear | NuclearFacility | Static config |
flights | MilitaryFlight | OpenSky / Wingbits |
military | MilitaryVessel | AIS data |
protests | MapProtestCluster | ACLED / GDELT |
fires | FIRMS data | NASA FIRMS API |
cyberThreats | CyberThreat | Multi-source threat feeds |
outages | InternetOutage | Cloudflare / IODA |
datacenters | MapDatacenterCluster | Static config |
ucdpEvents | UcdpGeoEvent | UCDP API |
displacement | CountryDisplacement | UNHCR API |
climate | ClimateAnomaly | Open-Meteo / ERA5 |
natural | NaturalEvent | NASA EONET |
economic | EconomicCenter | Static config |
gulfInvestments | GulfInvestment | Static config |
Source: src/components/Panel.ts
Constructor options for creating a panel widget.
interface PanelOptions {
id: string;
title: string;
showCount?: boolean;
className?: string;
trackActivity?: boolean;
infoTooltip?: string;
}
Panels persist their size and ordering in localStorage:
| Key | Constant | Value Schema |
|---|---|---|
worldmonitor-panel-spans | PANEL_SPANS_KEY | Record<string, number> — panel ID → grid span (1–4) |
panel-order | PANEL_ORDER_KEY | string[] — ordered panel IDs |
heightToSpan(height: number) → number converts a pixel height to a grid span:
| Pixel Height | Grid Span |
|---|---|
| < 250px | 1 |
| 250–349px | 2 |
| 350–499px | 3 |
| ≥ 500px | 4 |
Functions: loadPanelSpans() reads from localStorage, savePanelSpan(panelId, span) writes back.
Source: src/config/variants/base.ts
The variant system supports multiple dashboard configurations (full, tech, finance) via an override chain.
interface VariantConfig {
name: string;
description: string;
panels: Record<string, PanelConfig>;
mapLayers: MapLayers;
mobileMapLayers: MapLayers;
}
const API_URLS = {
finnhub: (symbols: string[]) => `/api/finnhub?symbols=...`,
yahooFinance: (symbol: string) => `/api/yahoo-finance?symbol=...`,
coingecko: '/api/coingecko?...',
polymarket: '/api/polymarket?...',
earthquakes: '/api/earthquakes',
arxiv: (category, maxResults) => `/api/arxiv?...`,
githubTrending: (language, since) => `/api/github-trending?...`,
hackernews: (type, limit) => `/api/hackernews?...`,
};
const REFRESH_INTERVALS = {
feeds: 5 * 60 * 1000, // 5 min
markets: 2 * 60 * 1000, // 2 min
crypto: 2 * 60 * 1000, // 2 min
predictions: 5 * 60 * 1000, // 5 min
ais: 10 * 60 * 1000, // 10 min
arxiv: 60 * 60 * 1000, // 1 hr
githubTrending: 30 * 60 * 1000, // 30 min
hackernews: 5 * 60 * 1000, // 5 min
};
const STORAGE_KEYS = {
panels: 'worldmonitor-panels',
monitors: 'worldmonitor-monitors',
mapLayers: 'worldmonitor-layers',
disabledFeeds: 'worldmonitor-disabled-feeds',
} as const;
base.ts (defaults) → full.ts / tech.ts / finance.ts (overrides)
Each variant file imports from base.ts and selectively overrides panels, mapLayers, and mobileMapLayers to tailor the dashboard for its domain.
Source: src/services/country-instability.ts (703 lines)
Computes a real-time instability score per country from four components.
interface CountryScore {
code: string;
name: string;
score: number;
level: 'low' | 'normal' | 'elevated' | 'high' | 'critical';
trend: 'rising' | 'stable' | 'falling';
change24h: number;
components: ComponentScores;
lastUpdated: Date;
}
interface ComponentScores {
unrest: number; // Protests, riots, civil unrest
conflict: number; // Armed conflict, UCDP events
security: number; // Military activity, internet outages
information: number; // News volume, velocity
}
Learning mode: 15-minute warmup period during which scores are unreliable. Bypassed when cached scores are available from the backend (setHasCachedScores(true)).
Input data per country: SocialUnrestEvent[], ConflictEvent[], UcdpConflictStatus, HapiConflictSummary, MilitaryFlight[], MilitaryVessel[], ClusteredEvent[], InternetOutage[], displacement outflow, climate stress.
Source: src/services/cached-risk-scores.ts
Pre-computed scores fetched from the backend to eliminate the learning mode delay.
interface CachedCIIScore {
code: string;
name: string;
score: number;
level: 'low' | 'normal' | 'elevated' | 'high' | 'critical';
trend: 'rising' | 'stable' | 'falling';
change24h: number;
components: ComponentScores;
lastUpdated: string;
}
interface CachedStrategicRisk {
score: number;
level: string;
trend: string;
lastUpdated: string;
contributors: Array<{
country: string;
code: string;
score: number;
level: string;
}>;
}
interface CachedRiskScores {
cii: CachedCIIScore[];
strategicRisk: CachedStrategicRisk;
protestCount: number;
computedAt: string;
cached: boolean;
}
Source: src/services/hotspot-escalation.ts (349 lines)
Combines a static baseline with four dynamic components to produce a real-time escalation score per hotspot.
Component weights:
| Component | Weight | Description |
|---|---|---|
newsActivity | 0.35 | Keyword matches, breaking news, velocity |
ciiContribution | 0.25 | Country instability score for hotspot's country |
geoConvergence | 0.25 | Nearby geospatial signal density |
militaryActivity | 0.15 | Military flights/vessels within radius |
Constraints:
Hotspot.escalationScore (default: 3)Source: api/_upstash-cache.js
Map with max 5,000 entries, disk-persisted to api-cache.jsonSource: src/services/storage.ts (230 lines)
Database: worldmonitor_db, version 1.
baselinesRolling window statistics for temporal anomaly detection.
// keyPath: 'key'
interface BaselineEntry {
key: string;
counts: number[]; // Historical count values
timestamps: number[]; // Corresponding timestamps (ms)
avg7d: number; // 7-day rolling average
avg30d: number; // 30-day rolling average
lastUpdated: number; // Timestamp (ms)
}
Deviation calculation:
function calculateDeviation(current: number, baseline: BaselineEntry): {
zScore: number;
percentChange: number;
level: 'normal' | 'elevated' | 'spike' | 'quiet';
}
| z-score | Level |
|---|---|
| > 2.5 | spike |
| > 1.5 | elevated |
| < −2.0 | quiet |
| otherwise | normal |
snapshotsPeriodic dashboard state captures for historical comparison.
// keyPath: 'timestamp', index: 'by_time'
interface DashboardSnapshot {
timestamp: number;
events: unknown[];
marketPrices: Record<string, number>;
predictions: Array<{ title: string; yesPrice: number }>;
hotspotLevels: Record<string, string>;
}
Retention: 7 days. Cleaned via cleanOldSnapshots().
Source: src/services/persistent-cache.ts
Cross-runtime cache with Tauri invoke → localStorage fallback.
type CacheEnvelope<T> = {
key: string;
updatedAt: number;
data: T;
};
worldmonitor-persistent-cache:read_cache_entry / write_cache_entry commandslocalStorage fallbackdescribeFreshness(updatedAt) → "just now" | "5m ago" | "2h ago" | "1d ago"erDiagram
Feed ||--o{ NewsItem : "parsed into"
NewsItem }o--|| ClusteredEvent : "clustered into"
ClusteredEvent ||--o| VelocityMetrics : "scored with"
ClusteredEvent ||--o| ThreatClassification : "classified as"
ClusteredEvent }o--o{ EntityEntry : "mentions"
Hotspot ||--|| DynamicEscalationScore : "scored by"
DynamicEscalationScore }o--|| CountryScore : "uses CII from"
GeoSignal }o--|| CountrySignalCluster : "grouped into"
CountrySignalCluster }o--|| RegionalConvergence : "aggregated into"
RegionalConvergence }o--|| SignalSummary : "summarized in"
FocalPoint }o--|| EntityEntry : "references"
FocalPoint }o--|| SignalSummary : "correlated with"
InfrastructureNode }o--o{ DependencyEdge : "connected by"
DependencyEdge }o--|| CascadeResult : "produces"
CountryScore }o--|| CachedRiskScores : "cached in"
BaselineEntry }o--|| DashboardSnapshot : "compared against"