Skip to content

World Monitor Architecture: TypeScript SPA with Edge Functions, Web Workers, and Proto/RPC

Purpose

This post explores the technical architecture of World Monitor, a real-time intelligence dashboard that aggregates data from 30+ sources. I was curious about how such a complex application handles data flow, performance optimization, and cross-platform deployment.

Let me walk through the key architectural decisions and patterns that make this system work.

System Overview

World Monitor is built as a TypeScript single-page application with several interesting components:

System architecture diagram
┌─────────────────────────────────────────────────────────────────┐
│ Browser / Desktop │
│ ┌──────────┐ ┌──────────┐ ┌────────────┐ ┌──────────────┐ │
│ │ DeckGLMap│ │ GlobeMap │ │ Panels │ │ Workers │ │
│ │(deck.gl) │ │(globe.gl)│ │(86 classes)│ │(ML, analysis)│ │
│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ └──────────────┘ │
│ └──────────────┴──────────────┘ │
│ │ fetch /api/* │
└─────────────────────────┼───────────────────────────────────────┘
┌──────────────┼──────────────┐
│ │ │
┌──────▼──────┐ ┌─────▼─────┐ ┌─────▼──────┐
│ Vercel │ │ Railway │ │ Tauri │
│ Edge Funcs │ │ AIS Relay │ │ Sidecar │
└──────┬──────┘ └─────┬─────┘ └─────┬──────┘
│ │ │
└──────────────┼──────────────┘
┌──────▼──────┐
│ Upstash │
│ Redis │
└─────────────┘

The application runs in three deployment modes:

  • Browser: Direct access via Vercel Edge Functions
  • Desktop: Tauri shell with local Node.js sidecar
  • Hybrid: Both cloud and local API access

8-Phase Initialization

When the app starts, App.init() runs through 8 phases to get everything ready:

App.init() 8-phase initialization
Phase 1: Storage + i18n
→ IndexedDB setup, language detection, locale loading
Phase 2: ML Worker
→ ONNX model preparation (embeddings, sentiment, summarization)
Phase 3: Sidecar
→ Wait for desktop sidecar readiness (desktop only)
Phase 4: Bootstrap
→ Two-tier concurrent hydration from /api/bootstrap
Phase 5: Layout
→ PanelLayoutManager renders map and panels
Phase 6: UI
→ SignalModal, IntelligenceGapBadge, BreakingNewsBanner
Phase 7: Data
→ Parallel loadAllData() + viewport-conditional priming
Phase 8: Refresh
→ Variant-specific polling via startSmartPollLoop()

This phased approach ensures critical components load first while deferring non-essential initialization.

Frontend Architecture

Component Model

All panels extend a Panel base class with consistent patterns:

  • Render via setContent(html) with 150ms debounce
  • Event delegation on stable this.content element
  • Resizable row/col spans persisted to localStorage

This means each panel is self-contained and manages its own rendering lifecycle.

State Management

There’s no external state library. Instead:

  • AppContext serves as the central mutable object
  • URL state syncs bidirectionally via urlState.ts with 250ms debounce

I think this approach makes sense for an application where most state is local to panels and doesn’t need complex cross-component synchronization.

Web Workers

Three workers handle CPU-intensive tasks:

WorkerPurpose
analysis.worker.tsNews clustering, cross-domain correlation
ml.worker.tsONNX inference (MiniLM-L6, sentiment, NER)
vector-db.tsIndexedDB-backed vector store

By offloading ML inference and analysis to workers, the main thread stays responsive for UI interactions.

API Layer

Edge Functions

All API endpoints live in api/ as self-contained JavaScript files. The key constraint:

  • Cannot import from ../src/ or ../server/
  • Only same-directory _*.js helpers and npm packages
  • Enforced by tests/edge-functions.test.mjs

This isolation ensures edge functions remain portable and don’t accidentally pull in browser-specific code.

Gateway Factory

server/gateway.ts provides createDomainGateway(routes) with a 10-step pipeline:

Gateway request pipeline
1. Origin check
2. CORS headers
3. OPTIONS preflight
4. API key validation
5. Rate limiting
6. Route matching
7. POST-to-GET compatibility
8. Handler execution with error boundary
9. ETag generation + 304 Not Modified
10. Cache header application

Each route goes through the same validation and error handling, which keeps the codebase consistent.

Proto/RPC Contract System

One interesting pattern is the Protocol Buffers-based API contracts:

Proto code generation flow
proto/ definitions
↓ buf generate
src/generated/client/ (TypeScript RPC client stubs)
src/generated/server/ (TypeScript server message types)
docs/api/ (OpenAPI v3 specs)

Service definitions use (sebuf.http.config) annotations, and GET fields require (sebuf.http.query) annotation. CI enforces generated code freshness, so you can’t accidentally deploy outdated client stubs.

This approach gives you:

  • Type-safe client-server communication
  • Automatic OpenAPI documentation
  • Contract-first API development

Data Pipeline

Bootstrap Hydration

The /api/bootstrap endpoint reads cached keys in a single batch. It uses two tiers concurrently:

Bootstrap loading strategy
Fast tier: Critical data (events, alerts) - 2s timeout
Slow tier: Secondary data (feeds, stats) - 5s timeout

Data is consumed on-demand via getHydratedData(key), so the UI doesn’t wait for everything to load.

Seed Scripts

scripts/seed-*.mjs files handle data ingestion:

  • Fetch upstream sources
  • Transform to internal format
  • Write to Redis

The atomicPublish() function acquires a lock, validates, writes, and releases to ensure atomic updates.

Desktop Architecture

Tauri Shell (Rust)

The desktop app uses Tauri 2.x with:

  • Secret management via platform keyring
  • Sidecar control (spawn, probe, env injection)
  • Window management

Node.js Sidecar

The sidecar enables local API access:

  • Dynamic port allocation
  • Loads Edge Function handler modules
  • Monkey-patches globalThis.fetch for IPv4
  • Token-authenticated API access

Fetch Patching

installRuntimeFetchPatch() replaces window.fetch to route /api/* requests:

Desktop fetch routing
/api/* → sidecar with Bearer token
→ fallback to cloud on failure

This gives desktop users offline capability while maintaining cloud fallback.

Security Model

Trust Boundaries

Trust boundaries
Browser ↔ Vercel Edge ↔ Upstream APIs
Desktop ↔ Sidecar ↔ Cloud API / Upstream APIs

Authentication

  • API keys required for non-browser origins
  • Trusted browser origins exempt
  • Premium RPC paths always require key

This layered approach allows public browser access while protecting programmatic API access.

Testing Strategy

Unit and Integration

  • node:test runner
  • Tests for handlers, cache keying, circuit breakers, validation

End-to-End

Playwright specs in e2e/ cover:

  • Theme toggling
  • Circuit breaker persistence
  • Visual regression

Pre-Push Hook

Before pushing, the CI runs:

Pre-push validation
1. TypeScript check
2. CJS syntax validation
3. Edge function esbuild bundle check
4. Edge function import guardrail test
5. Markdown lint
6. MDX lint
7. Version sync check

Directory Reference

Project structure
.
├── api/ # Vercel Edge Functions
├── server/ # Server-side code
├── src/ # Browser SPA (TypeScript)
│ ├── components/ # 86 panel classes + maps
│ ├── config/ # Variant, panel, layer configs
│ ├── services/ # Business logic by domain
│ └── workers/ # Web Workers (analysis, ML)
├── src-tauri/ # Tauri desktop shell (Rust)
└── tests/ # Unit/integration tests

Key Takeaways

I found several patterns worth noting:

  1. Edge Functions isolation: Self-contained API handlers prevent accidental coupling with frontend code
  2. Phased initialization: Critical resources load first, non-essential deferred
  3. Web Workers for ML: Keeps the main thread responsive during inference
  4. Proto-based contracts: Type safety from API definition to client code
  5. Dual deployment: Cloud-first with local sidecar for desktop offline support

Summary

In this post, I explored World Monitor’s architecture from frontend components to deployment strategies. The key patterns are edge computing for low latency, Protocol Buffers for type-safe APIs, Web Workers for heavy computation, and Tauri for cross-platform desktop. These patterns can inform other complex single-page applications that need real-time data, offline support, and multi-platform deployment.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments