Operational Risk Intelligence & Optimization Network Energy Supply Chain Resilience & Geopolitical Intelligence Platform
- Project Overview
- Technology Stack
- Project Directory Structure
- How Everything is Linked Together
- Frontend Architecture
- Backend Architecture
- Database Schema & Data Layer
- API Endpoints & Service Domains
- Authentication & Authorization
- Caching Strategy
- Real-Time Systems
- Map Rendering & Geospatial Stack
- Machine Learning Pipeline
- Internationalization (i18n)
- Dashboard
- Panel System (160+ Panels)
- Data Pipeline & Seed Scripts
- External Data Sources (30+)
- Payment & Subscription System
- MCP Server (AI Tool Protocol)
- Notification System
- Security Architecture
- Build & Deployment
- Testing Strategy
- Development Setup
- Environment Variables
- Configuration Files Reference
- Key Design Patterns
- Feature Flags & Beta Features
- Embed System
- Notification Channels
- Broadcast System
- Referral System
- Circuit Breaker & Resilience
- Storage Architecture
- Event System
- Web Workers
- Progressive Web App (PWA)
- OAuth 2.0 System
- Data Freshness & Staleness
- Entitlement & Gating System
- Usage Telemetry
- Error Handling
- Protocol Buffers & Code Generation
- Scripts & Tooling
- Static Assets & Public Directory
- Consumer Prices Core Module
- Railway Relay System
- Cloudflare Worker
- Linting & Code Quality
- Version Management & Changelog
- Known Issues & Technical Debt
- Glossary
ORION (Operational Risk Intelligence & Optimization Network) is a large-scale, real-time global intelligence dashboard platform focused on energy supply chain resilience and geopolitical risk monitoring. It aggregates data from 30+ external APIs, processes it through 34 service domains, and displays it across 160+ dashboard panels — all from a single codebase.
- Real-time monitoring of global events: conflicts, earthquakes, wildfires, disease outbreaks, cyber threats, supply chain disruptions
- Energy supply chain resilience: tracking oil inventories, pipeline status, fuel prices, chokepoint risks (Strait of Hormuz, Suez Canal, etc.)
- Financial market intelligence: stock quotes, commodities, crypto, yield curves, ETF flows, sentiment analysis
- Geopolitical analysis: country briefs, escalation correlation, sanctions tracking, military posture
- AI-powered insights: LLM summarization, scenario simulation, predictive modeling, anomaly detection
- Multi-format delivery: Web dashboard (orion.app), PWA, embeddable widgets, MCP server for AI tools
- 160+ panels across 8 categories (map, signals, markets, energy, defense, climate, analysis, reports)
- 34 service domains with proto-first RPC contracts
- 30+ external data sources (ACLED, USGS, Yahoo Finance, CoinGecko, NASA FIRMS, etc.)
- 24 supported languages with RTL support
- 21 cron seed jobs running on Railway
- 60+ Vercel Edge Functions
| Technology | Purpose |
|---|---|
| TypeScript (ES2020) | Primary language — vanilla TS, no framework |
| Vite (v6.0.7+) | Build tool, dev server, HMR |
| Preact (v10.25+) | Lightweight UI rendering (minimal use — most UI is imperative DOM) |
| MapLibre GL (v5.16+) | 2D map rendering with vector tiles |
| deck.gl (v9.2+) | 3D geospatial visualization (ScatterplotLayer, ArcLayer, HeatmapLayer) |
| globe.gl (v2.45+) | 3D globe visualization |
| ONNX Runtime Web (v1.26+) | Browser-side ML inference (WebGPU → WebGL → WASM cascade) |
| i18next (v25.8+) | Internationalization (24 languages) |
| Tailwind CSS (CDN) | Utility-first CSS framework |
| DOMPurify (v3.4+) | HTML sanitization |
| marked (v17+) | Markdown rendering |
| d3 (v7.9+) | Data visualization |
| papaparse (v5.5+) | CSV parsing |
| h3-js (v4.4+) | H3 hexagonal grid system |
| satellite.js (v6.0+) | Satellite orbit calculations |
| hls.js (v1.6+) | HLS video streaming |
| PMTiles (v4.4+) | Cloud-optimized geospatial tiles |
| Protomaps (v5.7+) | Basemap tile source |
| canvas-confetti (v1.9+) | Celebration animations |
| JMESPath (v0.16+) | JSON query expressions |
| Zod (v4.3+) | Schema validation |
| Technology | Purpose |
|---|---|
| Vercel Edge Functions | Serverless API endpoints (60+) |
| Convex (v1.32+) | Realtime database, serverless functions, cron jobs |
| Upstash Redis | Distributed caching, rate limiting |
| Railway | Cron seed jobs, AIS WebSocket relay, RSS relay |
| Cloudflare Workers | CORS preflight at api.orion.app |
| Protocol Buffers | API contract definitions (34 domains) |
| sebuf (v0.11+) | Proto → TypeScript code generator |
| Technology | Purpose |
|---|---|
| Clerk (v6.13+) | User authentication, JWT validation |
| Dodo Payments (v1.8+) | Subscription/payment processing |
| HMAC-SHA256 | Internal service-to-service auth |
| OAuth 2.0 | MCP server authorization (PKCE S256) |
| Technology | Purpose |
|---|---|
| Groq API | Primary LLM provider (14,400 req/day free) |
| OpenRouter | Fallback LLM provider |
| Ollama | Self-hosted local LLM |
| Anthropic SDK (v0.91+) | Claude API integration |
| Xenova Transformers (v2.17+) | Browser-side NER, embeddings, sentiment |
| ONNX Runtime Web | ML model inference in browser |
| Technology | Purpose |
|---|---|
| Sentry (v10.39+) | Error tracking (edge + browser) |
| Axiom | Usage telemetry |
| Vercel Analytics | Page analytics |
| Web Vitals | Performance metrics |
ORION/
├── api/ # Vercel Edge Functions (60+ endpoints)
│ ├── _api-key.js # API key validation
│ ├── _cors.js # CORS headers
│ ├── _rate-limit.js # Rate limiting
│ ├── _session.js # Session token management
│ ├── _crypto.js # Cryptographic utilities
│ ├── _sentry-edge.js # Sentry error capture
│ ├── _upstash-json.js # Redis pipeline helper
│ ├── _relay.js # Railway relay client
│ ├── _oauth-token.js # OAuth token resolution
│ ├── _mcp-grant-hmac.ts # MCP HMAC signing
│ ├── _rss-allowed-domains.js # RSS domain allowlist
│ ├── bootstrap.js # Bootstrap hydration endpoint (38 keys)
│ ├── health.js # Health monitoring (100+ checks)
│ ├── rss-proxy.js # Domain-allowlisted RSS proxy
│ ├── og-story.js # Social card image generation
│ ├── story.js # Story/OG endpoint
│ ├── version.js # Version endpoint
│ ├── orion-session.js # Anonymous session minting
│ ├── opensky.js # OpenSky aircraft proxy
│ ├── gpsjam.js # GPS interference data
│ ├── oref-alerts.js # Israeli Home Front alerts
│ ├── polymarket.js # Polymarket predictions
│ ├── telegram-feed.js # Telegram feed proxy
│ ├── reverse-geocode.js # Reverse geocoding
│ ├── geo.js # Geolocation
│ ├── seed-health.js # Seed health probe
│ ├── seed-contract-probe.ts # Contract verification
│ ├── product-catalog.js # Product catalog
│ ├── user-prefs.ts # User preferences CRUD
│ ├── notify.ts # Notification dispatch
│ ├── notification-channels.ts # Channel management
│ ├── symbol-search.ts # Financial symbol search
│ ├── cache-purge.js # Cache purge
│ ├── download.js # Data download
│ ├── latest-brief.ts # Latest brief retrieval
│ ├── chat-analyst.ts # AI chat analyst
│ ├── customer-portal.ts # Customer portal
│ ├── create-checkout.ts # Dodo Payments checkout
│ ├── [domain]/v1/[rpc].ts # 34 proto-first RPC endpoints
│ │ ├── aviation/v1/
│ │ ├── climate/v1/
│ │ ├── conflict/v1/
│ │ ├── consumer-prices/v1/
│ │ ├── cyber/v1/
│ │ ├── displacement/v1/
│ │ ├── economic/v1/
│ │ ├── forecast/v1/
│ │ ├── giving/v1/
│ │ ├── health/v1/
│ │ ├── imagery/v1/
│ │ ├── infrastructure/v1/
│ │ ├── intelligence/v1/
│ │ ├── leads/v1/
│ │ ├── maritime/v1/
│ │ ├── market/v1/
│ │ ├── military/v1/
│ │ ├── natural/v1/
│ │ ├── news/v1/
│ │ ├── positive-events/v1/
│ │ ├── prediction/v1/
│ │ ├── radiation/v1/
│ │ ├── research/v1/
│ │ ├── resilience/v1/
│ │ ├── sanctions/v1/
│ │ ├── scenario/v1/
│ │ ├── seismology/v1/
│ │ ├── supply-chain/v1/
│ │ ├── thermal/v1/
│ │ ├── trade/v1/
│ │ ├── unrest/v1/
│ │ ├── webcam/v1/
│ │ └── wildfire/v1/
│ ├── mcp.ts # MCP server entry point
│ ├── mcp/ # MCP protocol implementation
│ │ ├── handler.ts # JSON-RPC over HTTP+SSE
│ │ ├── auth.ts # MCP authentication
│ │ ├── dispatch.ts # Tool dispatch
│ │ ├── registry/ # Tool registry
│ │ ├── resources/ # Resource definitions
│ │ ├── prompts/ # Prompt definitions
│ │ ├── quota.ts # Daily quota enforcement
│ │ └── telemetry.ts # MCP telemetry
│ ├── mcp-proxy.ts # MCP proxy endpoint
│ ├── oauth/ # OAuth 2.0 endpoints
│ │ ├── authorize.js # Authorization endpoint
│ │ ├── authorize-pro.ts # Pro-tier authorization
│ │ ├── register.js # Client registration
│ │ └── token.ts # Token endpoint
│ ├── oauth-protected-resource.ts # RFC 9728 metadata
│ ├── slack/oauth/ # Slack OAuth integration
│ ├── discord/oauth/ # Discord OAuth integration
│ ├── user/ # User management endpoints
│ ├── me/ # User entitlement check
│ ├── referral/ # Referral system
│ ├── brief/ # Digest brief system
│ ├── internal/ # Internal-only endpoints
│ ├── skills/ # Agent skills index
│ ├── data/ # Static data endpoints
│ ├── security/ # Security report receiver
│ ├── youtube/ # YouTube integration
│ └── v2/shipping/ # Shipping API v2
│
├── server/ # Shared server logic
│ ├── gateway.ts # Central gateway (auth, rate limit, cache, telemetry)
│ ├── router.ts # Map-based route matcher (O(1) static, linear dynamic)
│ ├── cors.ts # CORS origin allowlist
│ ├── auth-session.ts # Clerk JWT validation with cached JWKS
│ ├── error-mapper.ts # Error → HTTP response mapper
│ ├── alias-rewrite.ts # URL rewrite helper for legacy v1 paths
│ ├── env.d.ts # Environment type declarations
│ ├── _shared/ # Shared utilities (52 files)
│ │ ├── auth-session.ts # Gateway-level Clerk JWT verification
│ │ ├── internal-auth.ts # Timing-safe HMAC comparison
│ │ ├── mcp-internal-hmac.ts # Internal MCP HMAC service auth
│ │ ├── premium-check.ts # Premium caller detection
│ │ ├── entitlement-check.ts # Tier enforcement
│ │ ├── user-api-key.ts # User API key validation
│ │ ├── pro-mcp-token.ts # Pro MCP token validation
│ │ ├── turnstile.ts # Cloudflare Turnstile CAPTCHA
│ │ ├── rate-limit.ts # Three-tier rate limiting (Upstash Redis)
│ │ ├── redis.ts # Upstash Redis client (cache, pipeline, coalescing)
│ │ ├── cache-keys.ts # Cache key patterns
│ │ ├── llm.ts # Multi-provider LLM client (Ollama/Groq/OpenRouter)
│ │ ├── llm-health.ts # LLM provider health gate
│ │ ├── acled.ts # ACLED conflict data client
│ │ ├── airline-codes.ts # IATA/ICAO airline codes
│ │ ├── chokepoint-registry.ts # Strategic chokepoint data
│ │ ├── country-normalize.ts # Country name normalization
│ │ ├── source-tiers.ts # Source credibility tiers
│ │ ├── fetch-json.ts # Upstream JSON fetch with timeout
│ │ ├── relay.ts # Railway relay base URL + auth
│ │ ├── usage.ts # Axiom-based API usage telemetry
│ │ ├── response-headers.ts # WeakMap-based response header attachment
│ │ ├── seed-envelope.ts # Seed-envelope aware reading
│ │ ├── resilience-freshness.ts # Resilience data freshness
│ │ └── simulation-queue.ts # Simulation queue management
│ └── orion/ # 34 domain handler modules
│ ├── aviation/v1/handler.ts
│ ├── climate/v1/handler.ts
│ ├── conflict/v1/handler.ts
│ ├── consumer-prices/v1/handler.ts
│ ├── cyber/v1/handler.ts
│ ├── displacement/v1/handler.ts
│ ├── economic/v1/handler.ts
│ ├── forecast/v1/handler.ts
│ ├── giving/v1/handler.ts
│ ├── health/v1/handler.ts
│ ├── imagery/v1/handler.ts
│ ├── infrastructure/v1/handler.ts
│ ├── intelligence/v1/handler.ts
│ ├── leads/v1/handler.ts
│ ├── maritime/v1/handler.ts
│ ├── market/v1/handler.ts
│ ├── military/v1/handler.ts
│ ├── natural/v1/handler.ts
│ ├── news/v1/handler.ts
│ ├── positive-events/v1/handler.ts
│ ├── prediction/v1/handler.ts
│ ├── radiation/v1/handler.ts
│ ├── research/v1/handler.ts
│ ├── resilience/v1/handler.ts
│ ├── sanctions/v1/handler.ts
│ ├── scenario/v1/handler.ts
│ ├── seismology/v1/handler.ts
│ ├── supply-chain/v1/handler.ts # Largest: ~20 RPC methods
│ ├── thermal/v1/handler.ts
│ ├── trade/v1/handler.ts
│ ├── unrest/v1/handler.ts
│ ├── webcam/v1/handler.ts
│ └── wildfire/v1/handler.ts
│
├── convex/ # Convex realtime database
│ ├── schema.ts # Database schema (24 tables)
│ ├── users.ts # User mutations/queries
│ ├── userPreferences.ts # User settings CRUD
│ ├── entitlements.ts # Feature gating
│ ├── subscriptions.ts # Dodo Payments subscriptions
│ ├── customers.ts # Paid customer records
│ ├── registrations.ts # Waitlist registrations
│ ├── contactMessages.ts # Contact form messages
│ ├── alertRules.ts # Configurable alert triggers
│ ├── followedCountries.ts # Country watchlist
│ ├── notificationChannels.ts # Telegram/Slack/Discord/Email/Webhook/Web Push
│ ├── userApiKeys.ts # User-owned API keys (wm_ prefix)
│ ├── mcpProTokens.ts # OAuth tokens for MCP
│ ├── broadcastRampConfig.ts # Email broadcast ramp config
│ ├── broadcast/ # Broadcast pipeline
│ ├── payments/ # Dodo Payments integration
│ ├── http.ts # HTTP route handlers (18 routes)
│ ├── crons.ts # Cron job definitions (7 jobs)
│ └── lib/ # Shared utilities
│
├── src/ # Frontend (Vanilla TypeScript)
│ ├── main.ts # Entry point → App.init()
│ ├── App.ts # Main application class
│ ├── settings-main.ts # Settings window entry point
│ ├── vite-env.d.ts # Vite client types
│ ├── pwa.d.ts # PWA types
│ ├── app/ # Application core (13 files)
│ │ ├── app-context.ts # Central state container
│ │ ├── country-intel.ts # Country intelligence briefing
│ │ ├── data-loader.ts # Central data loading orchestration
│ │ ├── event-handlers.ts # Global event handler setup
│ │ ├── panel-layout.ts # Panel grid layout management
│ │ ├── refresh-scheduler.ts # Periodic data refresh
│ │ ├── search-manager.ts # Global search
│ │ └── agent-bus-applier.ts # Agent bus event application
│ ├── bootstrap/ # Startup tasks (6 files)
│ │ ├── secondary-startup.ts # Deferred font loading, analytics
│ │ ├── sentry-init.ts # Sentry initialization
│ │ ├── stale-bundle-check.ts # Stale bundle detection
│ │ └── sw-update.ts # Service worker updates
│ ├── components/ # UI components
│ │ ├── PanelFactory.ts # Central panel factory (maps IDs → classes)
│ │ ├── ResizablePanel.ts # Drag-to-resize/reorder panels
│ │ ├── MapContainer.ts # Geospatial map container
│ │ ├── IntelTicker.ts # Scrolling intelligence ticker
│ │ ├── MarketsPanel.ts # Markets overview
│ │ ├── ChokepointsPanel.ts # Chokepoints display
│ │ ├── EnergySupplyPanel.ts # Energy supply network
│ │ └── panels/ # 118+ panel component files
│ ├── config/ # Configuration & data (36+ files)
│ │ ├── index.ts # Barrel exports
│ │ ├── panel-registry.ts # 161 panels in 8 categories
│ │ ├── panels.ts # Panel default configs, entitlements
│ │ ├── variant.ts # Variant selector (hardcoded 'full')
│ │ ├── variant-meta.ts # Variant metadata
│ │ ├── variants/ # Per-variant configs
│ │ ├── feeds.ts # RSS feed URLs, source tiers
│ │ ├── geo.ts # Geopolitical hotspots
│ │ ├── markets.ts # Stock sectors, commodities
│ │ ├── military.ts # Military data
│ │ ├── ports.ts # Global port database
│ │ ├── pipelines.ts # Oil/gas pipelines
│ │ ├── entities.ts # Entity registry
│ │ ├── countries.ts # Country data
│ │ ├── tech-geo.ts # Tech HQs, cloud regions
│ │ ├── ai-datacenters.ts # AI data centers
│ │ ├── finance-geo.ts # Stock exchanges, financial centers
│ │ ├── ml-config.ts # ML configuration
│ │ └── push.ts # Push notification config
│ ├── services/ # Business logic (130+ files, 18 domains)
│ │ ├── index.ts # Barrel exports (~50 modules)
│ │ ├── i18n.ts # Internationalization (i18next)
│ │ ├── rss.ts # RSS feed fetching/parsing
│ │ ├── live-news.ts # Real-time news aggregation
│ │ ├── live-data-service.ts # Unified live data streaming
│ │ ├── storage.ts # LocalStorage abstraction
│ │ ├── settings-manager.ts # API key management
│ │ ├── runtime.ts # Runtime detection
│ │ ├── clerk.ts # Authentication (Clerk)
│ │ ├── auth-state.ts # Auth state management
│ │ ├── billing.ts # Payment/subscription
│ │ ├── checkout.ts # Checkout flow
│ │ ├── entitlements.ts # Feature gating
│ │ ├── alert-engine.ts # Alert rule engine
│ │ ├── llm-service.ts # LLM service integration
│ │ ├── summarization.ts # Text summarization
│ │ ├── predictive-models.ts # ML predictions
│ │ ├── correlation.ts # Cross-domain correlation
│ │ ├── clustering.ts # News event clustering
│ │ ├── entity-extraction.ts # Named entity recognition
│ │ ├── threat-classifier.ts # Threat level classification
│ │ ├── geopolitical-risk-agent.ts # Risk scoring agent
│ │ ├── scenario-engine.ts # What-if scenario modeling
│ │ ├── procurement-optimizer.ts # Procurement optimization
│ │ ├── signal-aggregator.ts # Multi-source signal aggregation
│ │ ├── convex-client.ts # Convex database client
│ │ ├── rpc-client.ts # RPC client for sidecar API
│ │ ├── mcp-clients.ts # MCP client integration
│ │ ├── smart-poll-loop.ts # Adaptive polling with backoff
│ │ ├── tab-store.ts # Multi-tab state sync
│ │ ├── panel-data-loader.ts # Panel-specific data loading
│ │ ├── persistent-cache.ts # IndexedDB persistent cache
│ │ ├── aviation/ # Flight tracking, airline intel
│ │ ├── climate/ # Climate data, ocean monitoring
│ │ ├── conflict/ # Armed conflict data (ACLED, UCDP)
│ │ ├── consumer-prices/ # CPI and inflation data
│ │ ├── correlation-engine/ # Cross-domain correlation
│ │ ├── cyber/ # Cyber threat intelligence
│ │ ├── displacement/ # Population displacement tracking
│ │ ├── economic/ # Economic indicators (FRED, BLS)
│ │ ├── infrastructure/ # Infrastructure monitoring
│ │ ├── intelligence/ # Intelligence aggregation
│ │ ├── maritime/ # AIS shipping, vessel tracking
│ │ ├── market/ # Market data, crypto, stocks
│ │ ├── military/ # Military flights, vessels, bases
│ │ ├── news/ # News aggregation
│ │ ├── prediction/ # Prediction markets (Polymarket)
│ │ ├── research/ # Research data
│ │ ├── scenario/ # Scenario modeling
│ │ ├── supply-chain/ # Supply chain disruption monitoring
│ │ ├── trade/ # WTO trade data
│ │ ├── unrest/ # Social unrest monitoring
│ │ ├── webcams/ # Live webcam feeds
│ │ └── wildfires/ # Wildfire monitoring (NASA FIRMS)
│ ├── shared/ # Cross-cutting data stores (9 files)
│ │ ├── pipeline-registry-store.ts
│ │ ├── pipeline-evidence.ts
│ │ ├── storage-facility-registry-store.ts
│ │ ├── fuel-shortage-registry-store.ts
│ │ └── disruption-timeline.ts
│ ├── types/ # TypeScript types
│ │ ├── index.ts # 1,230 lines of shared types
│ │ ├── globe-gl.d.ts
│ │ └── uqr.d.ts
│ ├── utils/ # Utility functions (40+ files)
│ │ ├── index.ts # Barrel exports
│ │ ├── theme-manager.ts # Theme management (dark/light/auto)
│ │ ├── circuit-breaker.ts # Circuit breaker pattern
│ │ ├── with-timeout.ts # Fetch with timeout
│ │ ├── sanitize.ts # HTML sanitization
│ │ ├── proxy.ts # CORS proxy URL generation
│ │ ├── urlState.ts # URL state serialization
│ │ ├── country-flag.ts # Country code → flag emoji
│ │ ├── toast.ts # Toast notifications
│ │ ├── sparkline.ts # Sparkline charts
│ │ ├── export.ts # Export to JSON/CSV
│ │ ├── reverse-geocode.ts # Reverse geocoding
│ │ └── ... (30+ more)
│ ├── workers/ # Web Workers
│ │ ├── analysis.worker.ts # Clustering, correlation (off main thread)
│ │ ├── ml.worker.ts # ML inference (off main thread)
│ │ └── vector-db.ts # Client-side vector database
│ ├── generated/ # Auto-generated API clients
│ │ ├── client/ # 33 domain client stubs
│ │ └── server/ # 33 domain server handlers
│ ├── locales/ # 24 language translation files
│ │ ├── en.json # English (3,157 lines)
│ │ ├── ar.json # Arabic
│ │ ├── zh.json # Chinese
│ │ └── ... (21 more)
│ ├── embed/ # Embeddable widget
│ │ ├── embed-url.ts
│ │ └── embed-data-loader.ts
│ ├── data/ # Static JSON data
│ │ ├── world-happiness.json
│ │ ├── renewable-installations.json
│ │ └── conservation-wins.json
│ ├── styles/ # CSS
│ │ └── base.css # Base styles (glass-panel, glow, animations)
│ ├── shims/ # Module shims
│ │ ├── child-process.ts
│ │ └── child-process-proxy.ts
│ └── e2e/ # E2E test harnesses
│ ├── map-harness.ts
│ ├── mobile-map-harness.ts
│ └── mobile-map-integration-harness.ts
│
├── shared/ # Isomorphic shared code (47 files)
│ ├── source-tiers.json # Source credibility tiers
│ ├── country-bboxes.json # Country bounding boxes
│ └── ... (45 more reference data files)
│
├── proto/ # Protocol Buffer definitions (100+ .proto files)
│ ├── buf.gen.yaml # Code generation config
│ └── orion/*/v1/*.proto # Domain service definitions
│
├── scripts/ # Build & seed scripts (100+ files)
│ ├── seed-*.mjs # Railway seed scripts (21 cron jobs)
│ ├── ais-relay.cjs # AIS vessel WebSocket relay
│ ├── validate-rss-feeds.mjs # RSS feed validation
│ ├── lint-*.mjs # Custom lint scripts
│ └── ... (90+ more)
│
├── workers/ # Cloudflare Worker
│ └── api-cors-preflight/ # CORS preflight at api.orion.app
│ ├── src/index.js
│ └── wrangler.toml
│
├── consumer-prices-core/ # Standalone price scraping pipeline (90 files)
│
├── data/ # Static reference data
│ ├── telegram-channels.json # Telegram OSINT channels
│ ├── gamma-irradiators.json # Gamma irradiator facilities
│ ├── israeli-localities.json # Israeli localities
│ └── oref-translations.json # Oref alert translations
│
├── tests/ # Unit/integration tests
├── e2e/ # Playwright E2E tests
├── docs/ # Documentation
├── claude/ # AI assistant documentation
├── deploy/ # Nginx deployment config
├── public/ # Static assets (90+ files)
│
├── index.html # SPA entry HTML (landing page + dashboard shell)
├── middleware.ts # Vercel Edge Middleware (bot filtering)
├── vite.config.ts # Vite configuration (2,118 lines)
├── tsconfig.json # TypeScript config (frontend)
├── tsconfig.api.json # TypeScript config (API/server)
├── vercel.json # Vercel deployment (500 lines)
├── biome.json # Biome linter config
├── playwright.config.ts # Playwright E2E config
├── vitest.config.mts # Vitest unit test config
├── Makefile # Proto code generation toolchain
├── nixpacks.toml # Railway build config
├── package.json # Dependencies & scripts
├── .env.example # 150+ environment variables
├── .env.local # Local environment overrides
├── .nvmrc # Node.js 22
├── .npmrc # npm loglevel=error
├── .gitignore # node_modules, dist, .env
├── ARCHITECTURE.md # System architecture documentation
├── PLAN.md # Implementation plan for panel updates
└── PROJECT_DOCUMENTATION.md # This file
External APIs (30+)
↓
Railway Seed Jobs (21 crons, every 5min-6hr)
↓
Upstash Redis Cache (38 bootstrap keys + per-domain RPC keys)
↓
┌─────────────────────────────────────────────────────────┐
│ Vercel Edge Functions (60+) │
│ ├── /api/bootstrap → Single pipeline call, 38 keys │
│ ├── /api/{domain}/v1/{rpc} → Proto-first RPC handlers │
│ ├── /api/rss-proxy → Domain-allowlisted RSS │
│ └── /api/mcp → MCP protocol handler │
│ │
│ Gateway Pipeline (per-request): │
│ 1. Strip client headers │
│ 2. Origin check │
│ 3. CORS headers │
│ 4. OPTIONS preflight │
│ 5. Internal-MCP HMAC verify │
│ 6. Session resolution (Clerk JWT) │
│ 7. API key validation │
│ 8. Entitlement check │
│ 9. Rate limiting │
│ 10. Route match (O(1) static Map) │
│ 11. Handler execution │
│ 12. Cache tier headers │
│ 13. Usage telemetry │
└─────────────────────────────────────────────────────────┘
↓
Frontend (Vanilla TypeScript SPA)
├── Bootstrap Hydration (38 keys in 1 HTTP round-trip)
├── SmartPollLoop (adaptive polling per data source)
├── PanelFactory → 160+ panels in 8 categories
├── MapContainer (MapLibre + deck.gl + globe.gl)
├── Web Workers (ML, clustering, RSS parsing)
└── Event Bus (CustomEvent dispatch)
- Page Load:
index.html→src/main.ts→App.init() - Bootstrap:
GET /api/bootstrap?tier=fast→ 38 Redis keys in 1 pipeline call - Category Navigation: User clicks category →
App.showCategory()destroys current panels → creates new panel grid - Panel Initialization:
PanelFactorymaps panel ID → class → creates DOM → callsinit()in parallel batches (6 concurrent, 80ms stagger) - Data Fetching: Each panel calls its service function →
SmartPollLooporfetch()→ Edge Function → Redis cache → Upstream API - Real-time Updates: WebSocket (AIS vessels) + SmartPollLoop (adaptive polling) + Event Bus (CustomEvent)
- State Persistence: Panel positions/sizes → localStorage → restored on next visit
| From | To | Mechanism |
|---|---|---|
index.html |
src/main.ts |
<script type="module"> |
src/main.ts |
src/App.ts |
new App().init() |
src/App.ts |
src/components/PanelFactory.ts |
Panel creation |
src/components/PanelFactory.ts |
src/components/panels/*.ts |
ID → class mapping |
src/components/panels/*.ts |
src/services/*.ts |
Data fetching |
src/services/*.ts |
api/{domain}/v1/{rpc} |
HTTP POST to Edge Functions |
api/{domain}/v1/{rpc} |
server/gateway.ts |
Gateway pipeline |
server/gateway.ts |
server/orion/{domain}/v1/handler.ts |
Route matching |
server/orion/{domain}/v1/handler.ts |
server/_shared/redis.ts |
Cache read/write |
server/_shared/redis.ts |
Upstash Redis | HTTP REST API |
server/orion/{domain}/v1/handler.ts |
External APIs | Upstream fetch |
scripts/seed-*.mjs |
Upstash Redis | Write cached data |
convex/schema.ts |
Convex Cloud | Realtime database |
src/services/convex-client.ts |
Convex | Client queries/mutations |
middleware.ts |
vercel.json rewrite rules |
Request routing |
workers/api-cors-preflight/ |
api.orion.app/* |
CORS preflight at CF edge |
- Main Dashboard:
index.html→src/main.ts→src/App.ts - Settings Window: Separate HTML →
src/settings-main.ts - Embed Widget:
embed.html→src/embed/embed-url.ts - Live Channels:
live-channels.html - MCP Grant:
mcp-grant.html
The App class is the central orchestrator:
- Creates
PanelFactoryfor panel management - Sets up category-based navigation (8 categories: map, signals, markets, energy, defense, climate, analysis, reports)
- Manages the intel ticker
- Opens country brief overlays
- No traditional SPA router — navigation is category-based, not URL-based
Every data view is a panel — a TypeScript class that:
- Receives a container
HTMLElementin the constructor - Calls
async init()to fetch data and render - Implements
destroy()for cleanup - Uses event delegation on stable containers (survives innerHTML replacement)
Panel Factory (src/components/PanelFactory.ts):
- Maps 161 panel IDs to component classes
- Creates panel DOM elements with drag-and-drop reordering
- Initializes panels in parallel batches (6 concurrent, 80ms stagger)
- Handles panel persistence (position, size in localStorage)
Panel Categories (8):
| Category | Panel Count | Example Panels |
|---|---|---|
| Map | 1 | MapContainer (DeckGL + MapLibre + globe.gl) |
| Signals | 10 | LiveNewsPanel, BreakingNewsPanel, AIS Shipping, Airline Intel |
| Markets | 22 | MarketOverview, FearGreed, YieldCurve, ETF Flows, WSB Tickers |
| Energy | 26+ | EnergyCrisis, OilInventories, HormuzTracker, PipelineStatus |
| Defense | 9 | StrategicPosture, CyberThreats, Sanctions, RadiationWatch |
| Climate | 7 | ClimateAnomaly, Earthquakes, WeatherAlerts, Displacement |
| Analysis | 22+ | CountryBrief, CorrelationPanel, ScenarioSimulator, ChatAnalyst |
| Reports | 5 | ExecutiveReports, OrionDecisionDesk, AlternativeRoutes |
- AppContext (
src/app/app-context.ts): Central state container holding map reference, news data, market data, panel settings, map layers, cyber threats cache - localStorage: Panel positions, user preferences, theme, language
- IndexedDB: Persistent cache for large datasets
- URL State: Map state serialized in URL (lat, lon, zoom, layers)
- Convex: Server-side user preferences, entitlements, subscriptions
- CustomEvent Bus: Cross-component communication (wm:breaking-news, theme-changed, etc.)
class MyPanel {
private container: HTMLElement;
private data: MyData[] = [];
constructor(container: HTMLElement) {
this.container = container;
}
async init(): Promise<void> {
this.container.innerHTML = '<div class="loading">...</div>';
try {
this.data = await fetchMyData();
this.render();
} catch (e) {
this.container.innerHTML = '<div class="error">Failed to load</div>';
}
}
private render(): void {
this.container.innerHTML = `...`;
// Event delegation on this.container
}
destroy(): void {
this.container.innerHTML = '';
}
}┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Vercel │ │ Railway │ │ Convex │
│ │ │ │ │ │
│ • SPA (CDN) │ │ • 21 Cron │ │ • Realtime │
│ • Edge Funcs │ │ seed jobs │ │ Database │
│ • Edge MW │ │ • AIS Relay │ │ • Functions │
│ • Analytics │ │ (WebSocket)│ │ • Cron Jobs │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└───────────────────┼───────────────────┘
│
┌────────┴────────┐
│ Upstash Redis │
│ (Cache Layer) │
└─────────────────┘
Each domain has its own edge function entry point (tree-shaken for cold-start optimization):
// api/{domain}/v1/[rpc].ts
export const config = { runtime: 'edge' };
import { createDomainGateway, serverOptions } from '../../../server/gateway';
import { createXServiceRoutes } from '../../../src/generated/server/orion/x/v1/service_server';
import { xHandler } from '../../../server/orion/x/v1/handler';
export default createDomainGateway(createXServiceRoutes(xHandler, serverOptions));Every request passes through this pipeline:
- Header stripping: Remove client-controlled
x-user-id,x-orion-mcp-internal-verified - Origin check: Reject disallowed origins
- CORS headers: Generate per-origin
- OPTIONS preflight: Short-circuit
- Internal-MCP HMAC verify: If
X-ORION-MCP-Internalpresent - Session resolution: Clerk JWT for tier-gated endpoints
- API key validation: Enterprise/user/session keys
- Entitlement check: Tier enforcement
- Rate limiting: Global + per-endpoint
- Route match: O(1) static Map lookup, linear scan for dynamic routes
- Handler execution: Domain-specific business logic
- Cache tier headers: Applied from
RPC_CACHE_TIERmap - Usage telemetry: Axiom event emission (fire-and-forget)
8 cache tiers with different TTL strategies:
| Tier | s-maxage | stale-while-revalidate | Use Case |
|---|---|---|---|
fast |
60s | 300s | Breaking news, live events |
medium |
120s | 600s | Market data, weather |
slow |
300s | 1800s | Climate, conflict statistics |
slow-browser |
300s | 1800s | Browser-cached slow data |
static |
600s | 3600s | Port data, pipeline routes |
daily |
3600s | 14400s | Daily aggregations |
no-store |
— | — | Auth-sensitive data |
live |
30s | 60s | Real-time feeds |
34 domain handler modules, each containing:
v1/handler.ts— RPC method implementations- Individual method files for each RPC operation
- Reads from Redis cache (
getCachedJson/cachedFetchJson) - Falls back to upstream API on cache miss
| Table | Purpose | Key Fields |
|---|---|---|
users |
All Clerk-authenticated users | clerkUserId, email, createdAt |
userPreferences |
Per-user settings | userId, theme, language, mapLayers |
entitlements |
Feature gating | userId, tier (0-3), features[] |
subscriptions |
Dodo Payments subscriptions | userId, planId, status, expiresAt |
customers |
Paid user records | userId, dodoCustomerId, email |
registrations |
Waitlist entries | email, name, company, status |
contactMessages |
Contact form submissions | name, email, message, createdAt |
alertRules |
Configurable alert triggers | userId, condition, action, enabled |
followedCountries |
Country watchlist | userId, countryCode, addedAt |
notificationChannels |
Notification targets | userId, type (telegram/slack/email/discord/webhook/webpush), config |
userApiKeys |
User-owned API keys | userId, keyHash, prefix, createdAt |
mcpProTokens |
OAuth tokens for MCP | userId, tokenHash, scopes[], expiresAt |
broadcastRampConfig |
Email broadcast config | rampPercentage, maxPerWave, intervalMs |
broadcastCampaigns |
Broadcast campaign records | name, templateId, status, stats |
broadcastWaves |
Broadcast wave tracking | campaignId, waveNumber, recipientCount |
broadcastRecipients |
Per-recipient tracking | campaignId, userId, status, sentAt |
broadcastTemplates |
Email templates | name, subject, htmlContent, variables |
referralCodes |
Referral code registry | userId, code, space, createdAt |
referralAttributions |
Conversion tracking | referrerId, referredId, convertedAt |
usageEvents |
API usage tracking | domain, route, status, duration, timestamp |
webhookSubscriptions |
Shipping API webhooks | subscriberId, url, events[] |
productCatalog |
Product catalog | id, name, price, features[] |
featureFlags |
Runtime feature toggles | flag, enabled, rolloutPercentage |
auditLogs |
Security audit trail | userId, action, resource, timestamp |
- Queries (read-only):
users.ts,userPreferences.ts,entitlements.ts,subscriptions.ts,alertRules.ts,followedCountries.ts,notificationChannels.ts - Mutations (write, transactional): CRUD for all tables above
- Actions (side effects, external I/O): Payment webhooks, email dispatch, notification sending, broadcast campaign execution
- HTTP Routes (18): Webhook receivers for Dodo Payments, Stripe, Telegram bot
- Cron Jobs (7): Broadcast ramp runner, wave cleanup, shard seeding
- User preferences sync across tabs
- Entitlement changes reflected instantly
- Subscription status updates in real-time
- Alert rule triggers fire immediately
- Broadcast campaign progress live updates
Each domain has a .proto definition, generated TypeScript client/server, and edge function entry point:
| Domain | Description | Example RPCs |
|---|---|---|
aviation |
Flight tracking, airline intel | listFlights, getAirlineIntel, getAirportDelays |
climate |
Climate data, ocean monitoring | listClimateAnomalies, getCo2Monitoring |
conflict |
Armed conflict data | listAcledEvents, listUcdpEvents |
consumer-prices |
CPI and inflation | listConsumerPrices, getInflationTrend |
cyber |
Cyber threat intelligence | listCyberThreats, getThreatActors |
displacement |
Population displacement | getUnhcrPopulation, listDisplacementFlows |
economic |
Economic indicators | getEconomicIndicators, listFredSeries |
forecast |
Predictive modeling | triggerSimulation, getForecast |
giving |
Charitable giving data | listGivingTrends |
health |
Health data | listDiseaseOutbreaks, getHealthAirQuality |
imagery |
Satellite imagery | getSatelliteImagery |
infrastructure |
Infrastructure monitoring | listInfrastructureEvents |
intelligence |
Intelligence aggregation | classifyEvent, getInsights |
leads |
Lead capture | submitContact, registerInterest |
maritime |
AIS shipping, vessel tracking | getVesselSnapshot, listShippingRoutes |
market |
Market data, crypto, stocks | getMarketQuotes, getCryptoPrices |
military |
Military flights, vessels | listMilitaryFlights, getMilitaryPosture |
natural |
Natural disasters | listNaturalEvents, listEarthquakes |
news |
News aggregation | summarizeArticleCache, listNewsFeeds |
positive-events |
Good news tracking | listPositiveEvents |
prediction |
Prediction markets | listPolymarketData |
radiation |
Radiation monitoring | listRadiationData |
research |
Research papers | listResearchPapers |
resilience |
Energy resilience scoring | getResilienceRanking, getRuntimeManifest |
sanctions |
Sanctions tracking | lookupSanctionEntity, listSanctions |
scenario |
What-if scenario modeling | runScenario, listTemplates |
seismology |
Earthquake monitoring | listEarthquakes |
supply-chain |
Supply chain disruption | getShippingRates, getChokepointStatus, getPipelineDetail (~20 RPCs) |
thermal |
Thermal imaging | listThermalData |
trade |
WTO trade data | listTradeData |
unrest |
Social unrest monitoring | listUnrestEvents |
webcam |
Live webcam feeds | listWebcams |
wildfire |
Wildfire monitoring | listWildfires |
| Endpoint | Method | Description |
|---|---|---|
/api/bootstrap |
GET | Bootstrap hydration (38 Redis keys in 1 pipeline call) |
/api/health |
GET | Health monitoring (100+ seed freshness checks) |
/api/rss-proxy |
GET | Domain-allowlisted RSS proxy with SSRF protection |
/api/mcp |
POST | MCP protocol handler (JSON-RPC over HTTP+SSE) |
/api/oauth/* |
Various | OAuth 2.0 authorization, token, registration |
/api/orion-session |
POST | Anonymous session token minting |
/api/og-story |
GET | Social card image generation (Vercel OG) |
/api/chat-analyst |
POST | AI chat analyst with SSE streaming |
/api/create-checkout |
POST | Dodo Payments checkout creation |
/api/user-prefs |
GET/PUT | User preferences CRUD |
/api/notify |
POST | Notification dispatch |
/api/version |
GET | Version endpoint (no auth required) |
/api/security/report |
POST | CSP/COOP/COEP violation reports |
These endpoints bypass bot filtering and authentication:
/api/conflict/v1/list-acled-events/api/natural/v1/list-natural-events/api/resilience/v1/get-runtime-manifest/api/seismology/v1/list-earthquakes/api/unrest/v1/list-unrest-events/api/leads/v1/submit-contact/api/leads/v1/register-interest
- Prefix:
ors_ - Mechanism: HMAC-signed tokens, freely mintable by any browser
- Purpose: Satisfies basic API key gate; NOT proof of identity
- Endpoint:
POST /api/orion-session - Rejected: When
forceKey=true(premium endpoints)
- Source:
ORION_VALID_KEYSenvironment variable (comma-separated) - Mechanism: Operator-issued keys
- Purpose: Bypasses entitlement checks
- Auth kind:
enterprise
- Prefix:
wm_+ 40 hex chars - Mechanism: SHA-256 hashed, validated against Convex
userApiKeystable - Purpose: API access without Clerk JWT
- Auth kind:
user - Validation: 60s Redis cache TTL
- Mechanism: RS256-verified via cached JWKS
- Fields:
userId(sub),role(fromplanclaim or Clerk API lookup) - Cache: 5-minute in-memory cache for plan lookups
- Purpose: User-specific features, tier-gated endpoints
- Mechanism: HMAC-SHA-256 signing of
{ts}:{method}:{pathname}:{queryHash}:{bodyHash}:{userId} - Timestamp window: 30 seconds (replay defense)
- Nonce: Per-process-startup random nonce for verified marker
- Purpose: MCP edge → backend service-to-service auth
| Tier | Level | Features |
|---|---|---|
| Free | 0 | Basic panels, limited data sources |
| Pro | 1 | All panels, MCP access, priority support |
| API | 2 | API access, custom integrations |
| Enterprise | 3 | Unlimited access, custom deployment |
- Source: Convex
entitlementstable (synced from Dodo Payments webhook) - Caching: Redis with 15-minute TTL, Convex fallback on miss
- Enforcement:
server/_shared/entitlement-check.tswithENDPOINT_ENTITLEMENTSmap - Fail-closed: All error paths deny access
Tier 1: In-Memory (hydrationCache Map)
├── One-time read, then evicted
├── Used for bootstrap hydration
└── Eliminates 38 independent API calls
Tier 2: Upstash Redis
├── 38 bootstrap keys (fast/slow tiers)
├── Per-domain RPC cache keys
├── Negative sentinels (__ORION_NEG__)
└── In-flight promise coalescing
Tier 3: CDN (Vercel)
├── s-maxage directives per tier (60s-3600s)
├── stale-while-revalidate
└── stale-if-error fallback
Client-Side Cache:
├── IndexedDB (persistent, large datasets)
└── localStorage (preferences, panel state)
The cachedFetchJson() function in server/_shared/redis.ts implements:
- In-flight coalescing: Concurrent cache misses for the same key are merged into a single upstream fetch
- Negative sentinels: Cache
__ORION_NEG__to prevent repeated upstream calls for missing data - Local positive fallback: If Redis is unavailable, serve from in-memory cache
- Timeout protection: Upstream fetches have configurable timeouts
The most critical optimization:
GET /api/bootstrap?tier=fast
→ Single Redis pipeline call
→ Returns 38 keys in 1 HTTP round-trip
→ Eliminates 38 independent API calls
→ Saves 2-4 seconds first-meaningful-paint
Fast tier (s-maxage=1200s, 20 min): earthquakes, outages, macroSignals, chokepoints, marketQuotes, riskScores, predictions Slow tier (s-maxage=7200s, 2 hours): bisPolicy, minerals, cyberThreats, climate, naturalEvents, unrest, ucdpEvents
- Connection: WebSocket to AISStream.io
- Backpressure: 3 watermarks (1K/4K/8K messages)
- Capacity: 20,000 vessels (most recent per MMSI)
- Density: 5,000 cells (2°x2° grid)
- History: 30-point trail per vessel
- Auth: HMAC authentication
- Exponential backoff on failures
- 5x throttle when tab hidden
- Manual trigger support
- Circuit breaker integration
- Reason tagging (interval/resume/manual/startup)
wm:breaking-news— New breaking news eventswm:deduct-context— Context deduction eventstheme-changed— Theme toggleai-flow-changed— AI analysis flow state change
- AIS vessels: AISStream.io persistent connection
- Railway relay: AIS + OpenSky + RSS proxy
- Convex: Realtime database subscriptions
- Basemap: PMTiles with Protomaps vector tiles
- Overlays: GeoJSON layers, H3 hex grids
- Interactions: Click, hover, popup rendering
- Performance: Vector tiles, lazy-loaded styles
- ScatterplotLayer: Point data (conflicts, events)
- ArcLayer: Routes and connections
- PolygonLayer: Region boundaries
- HeatmapLayer: Density visualization
- BitmapLayer: Satellite imagery overlays
- Point markers: Global event visualization
- Flight trails: Aircraft paths
- Vessel positions: Ship tracking
- Heatmap overlay: Global density
type MapMarker =
| { _kind: 'conflict'; lat: number; lon: number; severity: number; ... }
| { _kind: 'flight'; lat: number; lon: number; callsign: string; ... }
| { _kind: 'vessel'; lat: number; lon: number; mmsi: string; ... }
| { _kind: 'earthquake'; lat: number; lon: number; magnitude: number; ... }
| ... // 15+ marker types with exhaustive switch matching- Conflict zones (ACLED/UCDP data)
- Military bases and movements
- Energy infrastructure (pipelines, refineries, ports)
- Supply chain routes and chokepoints
- Weather patterns and climate anomalies
- Cyber threat distribution
- Economic indicators by region
- Population density and displacement flows
Capability Detection Cascade:
WebGPU (fastest) → WebGL (fast) → WASM+SIMD (fallback)
Models:
├── Embeddings (384-dim float32)
├── Named Entity Recognition (NER)
├── Sentiment Analysis
└── Summarization
Execution:
├── Runs in Web Workers (off main thread)
├── Excluded on devices with <4GB RAM
└── Graceful degradation to server-side LLM
Multi-provider LLM client (server/_shared/llm.ts):
- Groq (primary, 14,400 req/day free)
- OpenRouter (fallback)
- Ollama (self-hosted, local)
- Generic OpenAI-compat (custom endpoints)
Use cases:
- Article summarization
- Event classification (threat level, sentiment)
- Geopolitical risk scoring
- Scenario simulation
- Chat analyst (AI Q&A with SSE streaming)
- Opinion vs fact classification
- Feel-good news classification
- Clustering: Jaccard similarity for news event grouping
- Correlation: Cross-domain signal correlation
- Entity Extraction: Named entity recognition (countries, organizations, persons)
- Vector Database: Semantic search via client-side vector DB
- Threat Classification: Threat level scoring
- Focal Point Detection: Events of interest identification
Arabic (ar), Bulgarian (bg), Czech (cs), German (de), Greek (el), Spanish (es), French (fr), Hindi (hi), Croatian (hr), Hungarian (hu), Italian (it), Japanese (ja), Korean (ko), Dutch (nl), Polish (pl), Portuguese (pt), Romanian (ro), Russian (ru), Swedish (sv), Thai (th), Turkish (tr), Vietnamese (vi), Chinese (zh), English (en)
- RTL Support: Automatic direction detection for Arabic
- Lazy Loading: Locale files loaded on demand
- Shell Subset:
en.shell.json(~3,157 lines) for first-paint English - Type-Safe: Some locales have
.d.tstype declarations - Key Healing:
i18n-raw-key-healer.tsheals untranslated raw keys that flash before locale loads
ORION is delivered as a single platform at orion.app with all 34 service domains and 160+ panels available to every user based on their entitlement tier.
- Build time: Standard Vite build produces the complete dashboard
- HTML customization:
htmlVariantPluginin vite.config.ts sets title, meta, theme-color, favicon - Shared assets: Identical SPA assets served from CDN cache
- Tree-shaking: Feature gating via entitlement system controls panel visibility at runtime
map-container— Geospatial map with DeckGL/MapLibre/globe.gl
live-news— Real-time news aggregationbreaking-news— Breaking news bannercross-source-signals— Multi-source signal correlationthreat-timeline— Threat event timelinegdelt-intel— GDELT intelligence feedais-shipping— AIS vessel trackingairline-intel— Airline intelligenceservice-status— Service availability statusgeopolitical-hubs— Geopolitical hub visualizationlive-intelligence— Live intelligence feed
market-overview— Market overview dashboardmarket-implications— Market impact analysismarket-breadth— Market breadth indicatorseconomic-indicators— Economic indicatorseconomic-calendar— Economic event calendarfear-greed— Fear & Greed Indexaaii-sentiment— AAII Sentiment Surveymacro-signals— Macroeconomic signalsmacro-tiles— Macro data tilesfinancial-stress— Financial Stress Indexyield-curve— Yield curve visualizationcot-positioning— Commitment of Tradersliquidity-shifts— Liquidity flow analysispositioning— Market positioninggold-intelligence— Gold market intelligenceetf-flows— ETF flow analysiswsb-tickers— WallStreetBets ticker trackingnational-debt— National debt visualizationgulf-economies— Gulf state economicsconsumer-prices— Consumer price indexdaily-market-brief— Daily market summarystablecoins— Stablecoin market data
energy-complex— Energy complex overviewenergy-crisis— Energy crisis monitoringenergy-disruptions— Energy disruption trackingenergy-risk— Energy risk assessmentenergy-supply— Energy supply networkoil-inventories— Oil inventory trackingfuel-prices— Fuel price monitoringfuel-shortages— Fuel shortage alertspipeline-status— Pipeline status monitoringstorage-facilities— Storage facility trackingchokepoint-strip— Chokepoint strip viewchokepoint-monitoring— Chokepoint monitoringchokepoints— Strategic chokepointshormuz-tracker— Strait of Hormuz trackersupply-chain— Supply chain disruptiontrade-policy— Trade policy trackingrenewable-energy— Renewable energy datainvestments— Energy investment trackingprocurement-advisor— Procurement optimizationreserve-optimization— Reserve managementalert-center— Energy alert centerindia-energy-hub— India energy focusindia-spr-timeline— India SPR timelinerefinery-compatibility— Refinery compatibilitycorridor-risk-monitor— Corridor risk monitoringai-scenario-simulator— AI scenario simulationprocurement-action-center— Procurement actionslive-disruption-probability— Live disruption probability
strategic-posture— Strategic military posturestrategic-risk— Strategic risk assessmentdefense-patents— Defense patent trackingucdp-events— UCDP conflict eventsoref-sirens— Israeli Home Front alertsthermal-escalation— Thermal escalation detectionsecurity-advisories— Security advisory feedsanctions— Sanctions trackingradiation— Radiation monitoringcyber-threats— Cyber threat intelligence
climate-anomaly— Climate anomaly trackingdisplacement— Population displacementdisease-outbreaks— Disease outbreak monitoringpopulation-exposure— Population exposure analysissocial-velocity— Social velocity trackingearthquakes— Earthquake monitoringweather-alerts— Weather alert feed
insights— AI-generated insightsdeduction— Analytical deductioncountry-brief— Country intelligence briefcountry-deep-dive— In-depth country analysiscountry-timeline— Country event timelinehistorical-intel— Historical intelligenceregional-intel— Regional intelligenceforecast— Predictive forecastinggeopolitical-risk— Geopolitical risk scoringchat-analyst— AI chat analystmcp-data— MCP data integrationcorrelation— Cross-domain correlationmilitary-correlation— Military correlationescalation-correlation— Escalation correlationeconomic-correlation— Economic correlationdisaster-correlation— Disaster correlationcountry-instability-index— Country instability indexcascade-analysis— Cascade failure analysisquantitative-risk— Quantitative risk scoringscenario-simulator— Scenario simulationhero-spotlight— Hero spotlightpositive-news— Positive news aggregationgood-things-digest— Good things digestbreakthroughs— Breakthroughs trackerspecies— Species conservation
executive-action— Executive action itemsexecutive-reports— Executive report generationorion-decision-desk— Decision deskalternative-routes— Alternative shipping routesmcp-data-report— MCP data report
| Seed Script | Source | Frequency |
|---|---|---|
seed-earthquakes |
USGS M4.5+ | 5 min |
seed-market-quotes |
Yahoo Finance | 5 min |
seed-commodity-qt |
Yahoo Finance | 5 min |
seed-crypto-qt |
CoinGecko | 5 min |
seed-cyber-threats |
Feodo/URLhaus/OTX | 2 hours |
seed-outages |
Cloudflare Radar | 5 min |
seed-fire-detect |
NASA FIRMS VIIRS | 10 min |
seed-climate |
Open-Meteo ERA5 | 15 min |
seed-airport-delay |
FAA/AviationStack | 10 min |
seed-insights |
Groq LLM | 10 min |
seed-predictions |
Polymarket | 10 min |
seed-etf-flows |
Yahoo Finance | 15 min |
seed-unrest |
ACLED + GDELT | 45 min |
seed-ucdp |
UCDP GED API | 6 hours |
seed-conflict |
ACLED + HAPI | 15 min |
seed-economy |
EIA + FRED | 15 min |
seed-supply-chain |
FRED + WTO | 6 hours |
seed-advisories |
24 RSS/Atom feeds | 1 hour |
seed-research |
arXiv + HN | 6 hours |
seed-correlation |
Cross-domain engine | 5 min |
seed-gpsjam |
GPSJam.org H3 | 6 hours |
Each seed script:
- Fetches data from external API
- Normalizes/transforms data
- Writes to Upstash Redis with appropriate TTL
- Optionally triggers downstream processing
| Category | Examples |
|---|---|
| Seed scripts | seed-earthquakes.mjs, seed-market-quotes.mjs, etc. |
| Shared helpers | redis-helpers.mjs, fetch-with-timeout.mjs, normalize-country.mjs |
| Lint scripts | lint-boundaries.mjs, enforce-safe-html.mjs, enforce-api-contract.mjs |
| Build scripts | build-agent-skills-index.mjs, bootstrap-worktree.mjs |
| Validation | validate-rss-feeds.mjs, audit-convex-string-calls.cjs |
| Relay | ais-relay.cjs (AIS vessel + OpenSky aircraft + RSS proxy) |
| Source | Data | Usage |
|---|---|---|
| ACLED | Armed conflict events | Conflict mapping, event analysis |
| UCDP GED | Conflict deaths | Fatality tracking, displacement proxy |
| GDELT | Global event database | Event monitoring, sentiment |
| LiveUAMap | Conflict visualization | Map overlays |
| BIS | Export controls | Sanctions tracking |
| WTO | Trade data | Trade flow analysis |
| Source | Data | Usage |
|---|---|---|
| Yahoo Finance | Stock quotes, ETFs | Market overview, sector analysis |
| CoinGecko | Cryptocurrency prices | Crypto market tracking |
| Polymarket | Prediction markets | Probability forecasting |
| FRED | Economic indicators | Macro analysis |
| Alpha Vantage | Financial data | Technical analysis |
| Source | Data | Usage |
|---|---|---|
| USGS | Earthquakes M4.5+ | Seismic monitoring |
| NASA FIRMS | Active fire detection | Wildfire tracking |
| GDACS | Disaster alerts | Disaster response |
| Open-Meteo | Weather/climate data | Weather forecasting |
| ECMWF | Climate reanalysis | Climate anomaly detection |
| Source | Data | Usage |
|---|---|---|
| Cloudflare Radar | DDoS/traffic data | Internet health monitoring |
| OpenSky | Aircraft tracking | Aviation intelligence |
| AISStream | Vessel tracking | Maritime intelligence |
| FAA | Airport delays | Aviation disruption |
| GPSJam | GPS interference | Navigation risk |
| Source | Data | Usage |
|---|---|---|
| Feodo Tracker | C&C server tracking | Cyber threat intel |
| URLhaus | Malware URLs | Cyber threat intel |
| OTX | Threat intelligence | Threat analysis |
| arXiv | Research papers | Research tracking |
| Hacker News | Tech news | Tech intelligence |
| Source | Data | Usage |
|---|---|---|
| EIA | Petroleum/electricity | Energy supply monitoring |
| IEA | Oil stocks | Energy reserve tracking |
| JODI | Gas/oil data | Global energy data |
| Ember | Electricity data | Power grid monitoring |
| GIE | Gas storage | Gas inventory tracking |
| ENTSO-E | European grid | European energy data |
- 24+ RSS/Atom feeds (BBC, Guardian, NPR, CNN, Al Jazeera, Reuters, etc.)
- Domain allowlist (500+ domains) for SSRF protection
- Fallback to Railway relay for blocked domains
Flow:
- User clicks "Upgrade" →
POST /api/create-checkout→ Dodo checkout session - User completes payment → Dodo webhook → Convex action
- Convex updates
subscriptions,entitlements,customerstables - Edge gateway reads entitlements from Redis (15-min TTL)
- User gains access to premium features
Subscription Lifecycle:
active→past_due→canceled→expiredtrialing→active→canceled- Webhook events:
checkout.completed,subscription.activated,subscription.canceled,invoice.paid,invoice.payment_failed
Entitlement Enforcement:
ENDPOINT_ENTITLEMENTSmap defines required tier per endpointgetEntitlements()reads from Redis, falls back to ConvexcheckEntitlement()verifies user tier against required tier- Fail-closed: All error paths deny access
Customer Portal: api/customer-portal.ts → Dodo Payments portal for subscription management
ORION implements an MCP server for AI tool integration:
Protocol: JSON-RPC over HTTP + Server-Sent Events (SSE)
Capabilities:
tools/list— List available toolstools/call— Execute a toolprompts/list— List available promptsprompts/get— Get a promptresources/list— List available resourcesresources/read— Read a resource
Authentication:
- Legacy: Environment API key (60/min rate limit)
- Pro: Clerk grant path (60/min per-user)
- Internal: HMAC-signed tool fetches
OAuth 2.0 Flow:
- Client registers at
/api/oauth/register - User authorizes at
/api/oauth/authorize(PKCE S256) - Client exchanges code at
/api/oauth/token - Token stored in Redis with TTL
- Token used for MCP API access
Daily Quota: Pro MCP users have daily usage quotas enforced via Redis INCR+EXPIRE
Tool Registry: 30+ tools for data access, analysis, and intelligence queries
| Channel | Configuration |
|---|---|
| Telegram | Bot token, chat ID, parse mode |
| Slack | Webhook URL, channel, username |
| Discord | Webhook URL, username, avatar |
| Resend API, from address, to addresses | |
| Webhook | URL, headers, method |
| Web Push | VAPID keys, subscription endpoint |
User-configurable alert rules:
- Condition: Threshold, pattern, or schedule
- Action: Send notification via configured channel
- Cooldown: Prevent alert fatigue
- Persistence: Rules stored in Convex
alertRulestable
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), bluetooth=()
Content-Security-Policy: [comprehensive policy with 25+ SHA256 hashes]
Cross-Origin-Opener-Policy-Report-Only: same-origin
Cross-Origin-Embedder-Policy-Report-Only: require-corp
Three regex patterns:
- BOT_UA: Blocks crawlers/bots from
/api/*and/favico/*(returns 403 JSON) - SOCIAL_PREVIEW_UA: Permits social bots (Twitter, Facebook, LinkedIn) on OG routes
- AI_CRAWLER_UA: Permits AI crawlers (GPTBot, ClaudeBot)
- Header stripping: Client-controlled
x-user-idandx-orion-mcp-internal-verifiedstripped at gateway entry - Body size cap: 256 KB max for internal-MCP requests
- Timing-safe comparisons: All HMAC and key comparisons use constant-time algorithms
- Fail-closed design: Missing configuration = deny (not allow)
- SSRF protection: RSS proxy uses domain allowlist, Google News feeds rejected
- API key validation: SHA-256 hashing with Convex lookup
- Rate limiting: Three-tier system (global, per-endpoint, scoped)
- CSP violation reporting:
/api/security/reportendpoint - Security report endpoint: CSP/COOP/COEP violation reports
Build Process:
npm run build:openapi— Copy OpenAPI spec to public/npm run build:agent-skills— Build agent skills indextsc— TypeScript type checkingvite build— Vite production build- Brotli precompression — All JS/CSS/HTML/SVG/JSON/WASM files >1KB compressed
- HTML plugin — Set title, meta, theme-color
- Dashboard HTML output — Rename
index.htmltodashboard.html
Build Outputs:
dashboard.html— Main SPA (renamed from index.html)embed.html— Embeddable widgetsettings.html— Settings windowlive-channels.html— Live channels viewmcp-grant.html— MCP authorizationassets/— JS/CSS chunks with content hashessw.js— Service worker
Chunk Splitting:
- 7 domain-specific panel chunks:
panels-markets,panels-energy,panels-defense,panels-news,panels-economy,panels-intel,panels-risk - Manual chunks: maplibre, deck-stack, protomaps, d3, topojson, i18next, Sentry, Clerk, transformers, onnxruntime
- Lazy HTML preload filtering for heavy chunks
Build: Nixpacks (nixpacks.toml)
- Installs curl via apt
npm cifor clean install- Installs scripts/ dependencies
Start: node scripts/ais-relay.cjs (AIS vessel tracking + OpenSky aircraft + RSS proxy relay)
Environment: NODE_OPTIONS="--dns-result-order=ipv4first"
- Schema changes auto-migrate
- Functions deployed via
npx convex deploy - Cron jobs defined in
convex/crons.ts - HTTP routes defined in
convex/http.ts
- Route:
api.orion.app/* - Purpose: CORS preflight short-circuit at CF edge
- Excludes public-cors paths (MCP, OAuth, security report)
| Tool | Config | Scope |
|---|---|---|
| tsx --test | package.json scripts |
tests/*.test.mjs, tests/*.test.mts |
| Vitest | vitest.config.mts |
convex/__tests__/, server/__tests__/ |
Test Commands:
npm run test:data— Data validation tests (16 workers)npm run test:convex— Convex function testsnpm run test:resilience-validation-smoke— Resilience validation tests
Config: playwright.config.ts
- Browser: Chromium with SwiftShader (software WebGL)
- Viewport: 1280x720
- Timeout: 90s per test
- Base URL:
http://127.0.0.1:4173 - Artifacts: Trace, screenshot, video on failure only
Test Commands:
npm run test:e2e:full— Full dashboard E2Enpm run test:e2e:visual— Visual regression tests
| Script | Purpose |
|---|---|
lint:boundaries |
Module boundary enforcement |
lint:safe-html |
HTML sanitization verification |
lint:api-contract |
API contract enforcement |
lint:rate-limit-policies |
Rate limit policy validation |
lint:premium-fetch |
Premium fetch pattern validation |
lint:mintlify-slugs |
Documentation slug validation |
lint:unicode |
Unicode safety checks |
security:local-env-dumps |
Local secret dump detection |
- Node.js 22 (
.nvmrc) - npm (
.npmrc:loglevel=error)
# 1. Clone the repository
git clone <repo-url>
# 2. Install dependencies
npm install
# 3. Copy environment variables
cp .env.example .env.local
# Edit .env.local with your API keys
# 4. Start dev server
npm run dev
# Runs at http://localhost:3000
# 5. Run tests
npm run test:data
npm run test:convex
# 6. Run linting
npm run lint| Command | Description |
|---|---|
npm run dev |
Start dev server (port 3000) |
npm run build |
Production build |
npm run preview |
Preview production build |
npm run typecheck |
TypeScript type checking |
npm run lint |
Run Biome linter |
npm run lint:fix |
Auto-fix lint issues |
# Install tools
make install
# Generate code
make generate
# Check for breaking changes
make breaking
# Format proto files
make format| Category | Key Variables |
|---|---|
| AI/LLM | GROQ_API_KEY, OPENROUTER_API_KEY, ANTHROPIC_API_KEY |
| Cache | UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN |
| Market Data | FINNHUB_API_KEY, ALPHA_VANTAGE_API_KEY, COINGECKO_API_KEY |
| Energy | EIA_API_KEY, GIE_API_KEY, ENTSO_E_TOKEN |
| Economic | FRED_API_KEY, IMF_API_KEY, COMTRADE_API_KEYS |
| Aviation | AVIATIONSTACK_API, ICAO_API_KEY, WINGBITS_API_KEY |
| Conflict | ACLED_EMAIL, ACLED_PASSWORD, UCDP_ACCESS_TOKEN |
| Infrastructure | CLOUDFLARE_API_TOKEN, CLOUDFLARE_R2_* (6 keys) |
| Satellite | NASA_FIRMS_API_KEY, RELIEFWEB_APPNAME |
| Relay | AISSTREAM_API_KEY, OPENSKY_CLIENT_ID, RELAY_SHARED_SECRET |
| Telegram | TELEGRAM_API_ID, TELEGRAM_API_HASH, TELEGRAM_BOT_TOKEN |
| Convex | CONVEX_URL, CONVEX_SERVER_SHARED_SECRET |
| Payments | DODO_API_KEY, DODO_WEBHOOK_SECRET, DODO_BUSINESS_ID |
| Auth | VITE_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY |
| MCP | MCP_PRO_GRANT_HMAC_SECRET, MCP_INTERNAL_HMAC_SECRET |
| Notifications | RESEND_API_KEY, VAPID_* |
| Site Config | VITE_VARIANT, VITE_WS_API_URL, VITE_SENTRY_DSN |
See .env.example (1,024 lines) for complete documentation.
| File | Lines | Purpose |
|---|---|---|
vite.config.ts |
2,118 | Vite build, dev server, plugins, chunk splitting |
vercel.json |
500 | Deployment rules, security headers, caching |
tsconfig.json |
28 | TypeScript frontend config |
tsconfig.api.json |
8 | TypeScript API/server config |
biome.json |
107 | Biome linter rules |
playwright.config.ts |
40 | Playwright E2E config |
vitest.config.mts |
9 | Vitest unit test config |
middleware.ts |
299 | Vercel Edge Middleware |
index.html |
562 | SPA entry HTML |
Makefile |
129 | Proto code generation |
nixpacks.toml |
26 | Railway build config |
.env.example |
1,024 | Environment variable docs |
ARCHITECTURE.md |
520 | System architecture |
| Pattern | Implementation | Purpose |
|---|---|---|
| No Framework | Vanilla TypeScript, direct DOM, CustomEvent bus | Zero framework overhead, full control |
| Panel Delegation | Event delegation on stable container | Survives innerHTML replacement |
| Discriminated Unions | _kind field on map markers |
Type-safe exhaustive switch matching |
| Circuit Breakers | Per-feed breakers, 5-min cooldown | Prevent cascading failures |
| Cache-First | In-memory → Redis → CDN → upstream | Minimize upstream calls |
| Adaptive Polling | SmartPollLoop with backoff | Reduce load on hidden tabs |
| Contract-First | .proto → generated client/server/OpenAPI | No schema drift |
| Graceful Degradation | Missing API keys skip sources, never crash | Resilient to config gaps |
| Multi-Signal Corroboration | Critical alerts require convergence | Reduce false positives |
| Browser-First Compute | ML, clustering, geolocation client-side | Reduce server load |
| Parallel Initialization | 6 concurrent panels, 80ms stagger | Fast page load |
| Negative Sentinels | Cache __ORION_NEG__ for missing data |
Prevent stampede on misses |
| In-Flight Coalescing | Concurrent misses merge into single fetch | Reduce duplicate requests |
| Fail-Closed | Missing config = deny (not allow) | Security by default |
| Two-Stage PATH Resolution | Proto plugin installation | Prevent stale plugin versions |
Runtime feature toggles via VITE_* environment variables and featureFlags Convex table:
- Map interaction mode:
VITE_MAP_INTERACTION_MODE - PMTiles URL:
VITE_PMTILES_URL - WebSocket API:
VITE_WS_API_URL - Sentry DSN:
VITE_SENTRY_DSN - 15+ resilience methodology gates
- Seed/forecast flags
- Feature gating for experimental panels
- Rollout percentage control
- User-level feature flags via Convex
Entry: embed.html → src/embed/embed-url.ts
Features:
- Configurable layers, theme, center, zoom
- External site embedding via iframe
- Responsive sizing
- Theme synchronization
URL Builder: src/embed/embed-url.ts generates embed URLs with query parameters for customization
| Channel | Config Fields |
|---|---|
| Telegram | botToken, chatId, parseMode |
| Slack | webhookUrl, channel, username |
| Discord | webhookUrl, username, avatarUrl |
resendApiKey, fromEmail, toAddresses |
|
| Webhook | url, headers, method |
| Web Push | vapidPublicKey, vapidPrivateKey, subscription |
- CRUD operations via
api/notification-channels.ts - Stored in Convex
notificationChannelstable - Per-user channel configuration
- Channel validation on creation
- Campaign Creation: Define template, audience, schedule
- Wave Execution: Process recipients in waves with ramp control
- Kill Gate: Safety mechanism to halt campaigns
- Progress Tracking: Per-recipient delivery status
- Ramp Percentage: Start with N% of recipients
- Max Per Wave: Limit recipients per wave
- Interval Ms: Delay between waves
- Purpose: Prevent email delivery issues at scale
- Broadcast ramp runner: Executes wave progression
- Wave cleanup: Removes stale wave data
- Shard seeding: Distributes recipients across shards
- Primary: Standard referral codes
- Premium: Premium-tier referral codes
- Referrer: User who shared the code
- Referred: User who signed up
- Conversion: When referred user becomes paid
- Credit: Attribution stored in Convex
referralAttributions
GET /api/referral/me— Get user's referral codePOST /api/leads/v1/register-interest— Register with referral code
- Per-feed breakers: Each data source has independent circuit breaker
- Cooldown: 5-minute cooldown after breaker trips
- States: Closed (normal) → Open (failing) → Half-Open (testing)
- Fallback: Stale data served when breaker is open
- Graceful degradation: Missing API keys skip sources, never crash
- Multi-signal corroboration: Critical alerts require convergence across independent streams
- Negative sentinels: Cache missing data to prevent stampede
- In-flight coalescing: Concurrent requests merged
- Timeout protection: All upstream fetches have configurable timeouts
- Retry logic: Exponential backoff with jitter
| Storage | Purpose | Size Limit |
|---|---|---|
| localStorage | Preferences, panel state, theme | 5-10 MB |
| IndexedDB | Persistent cache, large datasets | 50+ MB |
| Cache API | Service worker cache | Configurable |
| Storage | Purpose | TTL |
|---|---|---|
| In-Memory Map | Bootstrap hydration cache | One-time read |
| Upstash Redis | Distributed cache | 60s-14400s per tier |
| Convex | User data, entitlements, subscriptions | Persistent |
| CDN (Vercel) | Static assets | 3600s (immutable) |
tab-store.tssynchronizes state across browser tabscross-domain-storage.tshandles cross-domain storagecloud-prefs-sync.tssyncs preferences to cloud
| Event | Payload | Purpose |
|---|---|---|
wm:breaking-news |
NewsItem |
New breaking news |
wm:deduct-context |
{ country, context } |
Context deduction |
theme-changed |
{ theme } |
Theme toggle |
ai-flow-changed |
{ flow, state } |
AI analysis state |
- Event listeners attached to stable parent containers
- Events bubble up from child elements
- Survives innerHTML replacement
- Reduces memory consumption
| Worker | Purpose | Files |
|---|---|---|
| Analysis Worker | Jaccard clustering, correlation analysis | analysis.worker.ts |
| ML Worker | ONNX model inference | ml.worker.ts |
| Vector DB | Client-side vector database | vector-db.ts |
postMessage/onmessagefor data transferTransferableobjects for zero-copy transferSharedArrayBufferfor shared memory (when available)
- Service Worker: Workbox-based, auto-update
- Max Cached File: 4MB (for globe.gl/three.js)
- Precache: Excludes ML/WASM/locale/Clerk files
- Runtime Caching: Navigation, PMTiles, Google Fonts, locale files, images
- Push Notifications:
/push-handler.jsfor web push
- Offline mode with cached data
- Home screen installation
- Background sync
- Push notifications
| Endpoint | Method | Purpose |
|---|---|---|
/api/oauth/register |
POST | Client registration |
/api/oauth/authorize |
GET | Authorization (PKCE S256) |
/api/oauth/token |
POST | Token exchange |
authorization_code— User authorizationrefresh_token— Token refreshclient_credentials— Service-to-service
- Redis:
oauth:token:<uuid>,oauth:refresh:<uuid> - TTL: Configurable per grant type
- Revocation:
POST /api/user/mcp-revoke
- Clerk grant path stores
{kind:'pro', userId, mcpTokenId} - Pro tokens have higher rate limits and daily quotas
- Per-source staleness thresholds: Different data sources have different acceptable ages
- Health endpoint:
GET /api/healthchecks 100+ seed freshness checks - Status codes: OK / WARN / CRIT
- Staleness display: Panels show data age via
panel-freshness-display.ts
| Data Type | Fresh | Stale | Critical |
|---|---|---|---|
| Breaking news | <5 min | 5-30 min | >30 min |
| Market quotes | <1 min | 1-5 min | >5 min |
| Earthquakes | <10 min | 10-60 min | >60 min |
| Conflict events | <1 hr | 1-6 hr | >6 hr |
| Climate data | <15 min | 15-60 min | >60 min |
| Tier | Level | Monthly Price | Features |
|---|---|---|---|
| Free | 0 | $0 | Basic panels, limited data |
| Pro | 1 | $19.99 | All panels, MCP access, priority |
| API | 2 | $49.99 | API access, custom integrations |
| Enterprise | 3 | Custom | Unlimited, custom deployment |
| Feature | Free | Pro | API | Enterprise |
|---|---|---|---|---|
| Basic panels | ✅ | ✅ | ✅ | ✅ |
| All panels | ❌ | ✅ | ✅ | ✅ |
| MCP access | ❌ | ✅ | ✅ | ✅ |
| API access | ❌ | ❌ | ✅ | ✅ |
| Custom deployment | ❌ | ❌ | ❌ | ✅ |
| Priority support | ❌ | ❌ | ❌ | ✅ |
| Export formats | Limited | All | All | All |
- Client-side:
panel-gating.tschecks entitlement before panel mount - Server-side:
entitlement-check.tsverifies tier at gateway level - Fail-closed: Error paths deny access (never allow)
Events emitted per request:
domain— Service domainroute— RPC methodstatus— HTTP status codeduration— Request duration (ms)auth_kind— Authentication typetier— User tiercountry— User countryip— Client IP (anonymized)user-agent— Client user agentcache_tier— Cache tier used
Circuit breaker: 5% failure rate / 5-minute window → telemetry stops (never affects API availability)
| Error Type | HTTP Status | Client Message |
|---|---|---|
| ApiError | Custom statusCode | Error message |
| Network/Fetch | 502 | "Bad Gateway" |
| JSON Parse | 400 | "Bad Request" |
| Unknown | 500 | "Internal Server Error" |
| Rate Limit | 429 | "Too Many Requests" + Retry-After |
- Panel errors: Caught in
init(), displayed as error state - Fetch errors: Circuit breaker fallback to stale data
- ML errors: Graceful degradation to server-side LLM
- WebSocket errors: Auto-reconnect with exponential backoff
- buf (v1.64.0): Protocol Buffer compiler
- sebuf (v0.11+): Custom protoc plugins
protoc-gen-ts-client: TypeScript client stubsprotoc-gen-ts-server: TypeScript server handlersprotoc-gen-openapiv3: OpenAPI 3.1.0 specs
.proto files (100+)
↓
buf generate (via Makefile)
↓
src/generated/client/ — 33 domain client stubs
src/generated/server/ — 33 domain server handlers
docs/api/ — OpenAPI specs
service AviationService {
rpc ListFlights(ListFlightsRequest) returns (ListFlightsResponse);
rpc GetAirlineIntel(GetAirlineIntelRequest) returns (GetAirlineIntelResponse);
// ...
}Client (src/generated/client/orion/{domain}/v1/service_client.ts):
- Fetch-based RPC client
- Type-safe request/response
- Automatic URL construction
Server (src/generated/server/orion/{domain}/v1/service_server.ts):
- Server-side handler interface
- HTTP router generation
- Route descriptors for gateway
| Script | Purpose |
|---|---|
build-agent-skills-index.mjs |
Build agent skills index |
build-openapi.mjs |
Copy OpenAPI spec to public/ |
bootstrap-worktree.mjs |
Bootstrap new worktree |
| Script | Source | Frequency |
|---|---|---|
seed-earthquakes.mjs |
USGS M4.5+ | 5 min |
seed-market-quotes.mjs |
Yahoo Finance | 5 min |
seed-commodity-qt.mjs |
Yahoo Finance | 5 min |
seed-crypto-qt.mjs |
CoinGecko | 5 min |
seed-cyber-threats.mjs |
Feodo/URLhaus/OTX | 2 hr |
seed-outages.mjs |
Cloudflare Radar | 5 min |
seed-fire-detect.mjs |
NASA FIRMS VIIRS | 10 min |
seed-climate.mjs |
Open-Meteo ERA5 | 15 min |
seed-airport-delay.mjs |
FAA/AviationStack | 10 min |
seed-insights.mjs |
Groq LLM | 10 min |
seed-predictions.mjs |
Polymarket | 10 min |
seed-etf-flows.mjs |
Yahoo Finance | 15 min |
seed-unrest.mjs |
ACLED + GDELT | 45 min |
seed-ucdp.mjs |
UCDP GED API | 6 hr |
seed-conflict.mjs |
ACLED + HAPI | 15 min |
seed-economy.mjs |
EIA + FRED | 15 min |
seed-supply-chain.mjs |
FRED + WTO | 6 hr |
seed-advisories.mjs |
24 RSS/Atom feeds | 1 hr |
seed-research.mjs |
arXiv + HN | 6 hr |
seed-correlation.mjs |
Cross-domain engine | 5 min |
seed-gpsjam.mjs |
GPSJam.org H3 | 6 hr |
| Script | Purpose |
|---|---|
lint-boundaries.mjs |
Module boundary enforcement |
enforce-safe-html.mjs |
HTML sanitization verification |
enforce-sebuf-api-contract.mjs |
API contract enforcement |
enforce-rate-limit-policies.mjs |
Rate limit policy validation |
enforce-premium-fetch.mjs |
Premium fetch pattern validation |
enforce-mintlify-reserved-slugs.mjs |
Documentation slug validation |
check-unicode-safety.mjs |
Unicode safety checks |
check-local-secret-dumps.mjs |
Local secret dump detection |
| Script | Purpose |
|---|---|
validate-rss-feeds.mjs |
RSS feed URL validation |
audit-convex-string-calls.cjs |
Convex string call audit |
audit-dodo-catalog.cjs |
Dodo product catalog audit |
docs-stats.mjs |
Documentation statistics |
| Directory | Content |
|---|---|
favico/ |
Favicons |
map-styles/ |
MapLibre style definitions |
textures/ |
3D textures for globe.gl |
data/ |
Static JSON data files |
pro/ |
Pre-built pro tier assets |
icons/ |
UI icons |
fonts/ |
Custom fonts |
- Map styles loaded on demand
- Textures loaded when 3D view activated
- Large data tables loaded on demand
Location: consumer-prices-core/ (90 files)
Purpose: Scrapes, normalizes, and serves consumer price data (CPI, inflation)
Architecture:
- Independent module with its own build process
DATABASE_URLfor PostgreSQL storageCONSUMER_PRICES_CORE_API_KEY/CONSUMER_PRICES_CORE_BASE_URLfor API access
Purpose: WebSocket relay for AIS vessel tracking + OpenSky aircraft + RSS proxy
Features:
- Persistent WebSocket connection to AISStream.io
- AIS vessel position processing
- OpenSky aircraft tracking
- RSS feed proxy for blocked domains
- Backpressure management (3 watermarks)
- HMAC authentication
Environment Variables:
AISSTREAM_API_KEY— AISStream.io API keyOPENSKY_CLIENT_ID/OPENSKY_CLIENT_SECRET— OpenSky credentialsRELAY_SHARED_SECRET— Shared secret for relay authWS_RELAY_URL— WebSocket relay URL
Location: workers/api-cors-preflight/
Purpose: Short-circuits OPTIONS preflight requests at Cloudflare edge (skips Vercel)
Route: api.orion.app/*
Features:
- Immediate CORS header stamping
- Excludes public-cors paths (MCP, OAuth, security report)
- Observability enabled
Configuration: biome.json
Rules:
- Disabled:
noUnusedVariables,noUnusedImports,noExplicitAny,noConsole - Errors:
noFallthroughSwitchClause,noGlobalAssign,noRedeclare,noVar - Warnings:
noDoubleEquals,useConst,useDefaultParameterLast
Overrides:
src/generated/**: Linter disabled (generated code)public/**: Linter disabled (static assets)*.html: a11y rules disabled
| Script | Purpose |
|---|---|
lint:boundaries |
Module boundary enforcement |
lint:safe-html |
HTML sanitization verification |
lint:api-contract |
API contract enforcement |
lint:rate-limit-policies |
Rate limit policy validation |
lint:premium-fetch |
Premium fetch pattern validation |
lint:mintlify-slugs |
Documentation slug validation |
lint:unicode |
Unicode safety checks |
security:local-env-dumps |
Local secret dump detection |
__APP_VERSION__ // package.json version (1.0.0)
__CLERK_JS_VERSION__ // @clerk/clerk-js version (6.x)
__BUILD_HASH__ // Vercel commit SHA or 'dev'GET /api/version — Returns current version (no auth required)
- Nixpacks curl install: Occasional Ubuntu mirror hash mismatches (2026-04-17 incident)
- Chunk size warning: 1200 KB (raised from 500 KB due to large geospatial bundles)
- Non-critical warning: Dependency re-optimization on fresh install
- No SPA router: Category-based navigation limits deep linking
- Vanilla TypeScript: No framework means more boilerplate
- Large data tables: Some config files are 60+ KB (tech-geo.ts, ai-datacenters.ts)
- 160+ panels: High maintenance surface area
- 150+ env vars: Complex configuration surface
| Term | Definition |
|---|---|
| AIS | Automatic Identification System — ship tracking |
| ACLED | Armed Conflict Location & Event Data |
| Bootstrap Hydration | Single Redis pipeline call returning 38 keys |
| Circuit Breaker | Pattern to prevent cascading failures |
| Convex | Realtime database platform |
| deck.gl | 3D geospatial visualization library |
| Discriminated Union | TypeScript pattern with _kind field |
| Edge Function | Serverless function running at CDN edge |
| globe.gl | 3D globe visualization library |
| H3 | Hexagonal hierarchical spatial index |
| MapLibre GL | Open-source map rendering library |
| MCP | Model Context Protocol — AI tool integration |
| Negative Sentinel | Cache marker for missing data (__ORION_NEG__) |
| PMTiles | Cloud-optimized geospatial tile format |
| Proto/Protobuf | Protocol Buffers — API contract definitions |
| sebuf | Custom protoc plugins for TypeScript generation |
| Seed Script | Cron job that fetches and caches external data |
| SmartPollLoop | Adaptive polling with exponential backoff |
This document covers every aspect of the ORION project as of the current codebase. It is intended to be a complete reference for developers, contributors, and stakeholders.