File size: 27,922 Bytes
3464008 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | # Architecture
> **Capability counts** (map layers, services, protos, locales, CI workflows, freshness sources) are derived from code and CI-verified by `npm run docs:check` (`scripts/docs-stats.mjs`, source of truth `docs/generated/stats.json`). Do not hand-edit those numbers β change the code, run `npm run docs:stats`.
>
> **Ownership rule**: When deployment topology, API surface, desktop runtime, or bootstrap keys change, this document must be updated in the same PR.
> **Design philosophy**: For the "why" behind architectural decisions, intelligence tradecraft, and algorithmic choices, see [Design Philosophy](docs/architecture.mdx).
World Monitor is a real-time global intelligence dashboard built as a TypeScript single-page application. It aggregates data from dozens of external sources covering geopolitics, military activity, financial markets, cyber threats, climate events, maritime tracking, and aviation into a unified operational picture rendered through an interactive map and a grid of specialized panels.
---
## 1. System Overview
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser / Desktop β
β ββββββββββββ ββββββββββββ ββββββββββββββ ββββββββββββββββ β
β β DeckGLMapβ β GlobeMap β β Panels β β Workers β β
β β(deck.gl) β β(globe.gl)β β(Panel base)β β(ML, analysis)β β
β ββββββ¬ββββββ ββββββ¬ββββββ βββββββ¬βββββββ ββββββββββββββββ β
β ββββββββββββββββ΄βββββββββββββββ β
β β fetch /api/* β
βββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββΌβββββββββββββββ
β β β
ββββββββΌβββββββ βββββββΌββββββ βββββββΌβββββββ
β Vercel β β Railway β β Tauri β
β Edge Funcs β β AIS Relay β β Sidecar β
β + Middlewareβ β + Seeds β β (Node.js) β
ββββββββ¬βββββββ βββββββ¬ββββββ βββββββ¬βββββββ
β β β
ββββββββββββββββΌβββββββββββββββ
β
ββββββββΌβββββββ
β Upstash β
β Redis β
ββββββββ¬βββββββ
β
βββββββββββββΌββββββββββββ
β β β
βββββββΌββββ βββββββΌββββ ββββββΌβββββ
β Finnhub β β Yahoo β β ACLED β
β OpenSky β β GDELT β β UCDP β
β CoinGeckβ β FRED β β FIRMS β
β ... β β ... β β ... β
βββββββββββ βββββββββββ βββββββββββ
65+ upstream providers and APIs
```
**Source files**: `package.json`, `vercel.json`
---
## 2. Deployment Topology
| Service | Platform | Role |
|---------|----------|------|
| SPA + Edge Functions | Vercel | Static files, API endpoints, middleware (bot filtering, social OG) |
| CORS Preflight Worker | Cloudflare | Edge CORS for `api.worldmonitor.app` β short-circuits OPTIONS, stamps CORS headers on responses |
| AIS Relay | Railway | WebSocket proxy (AIS stream), seed loops (market, aviation, GPSJAM, risk scores, UCDP, positive events), RSS proxy, OREF polling |
| Consumer Prices | Railway | Containerized price scrapers (Playwright, per-country baskets) + Redis publisher for the consumer-prices dataset |
| Redis | Upstash | Cache layer with stampede protection, seed-meta freshness tracking, rate limiting |
| Convex | Convex Cloud | Billing/entitlements (Dodo), user state and API keys, broadcast/email, contact + waitlist forms, historical intelligence memory (vector search) |
| Documentation | Mintlify | Public docs, proxied through Vercel at `/docs` |
| Desktop App | Tauri 2.x | macOS (ARM64, x64), Windows (x64), Linux (x64, ARM64) with bundled Node.js sidecar |
| Container Image | GHCR | Multi-arch Docker image (nginx serving built SPA, proxies API to upstream) |
**Source files**: `vercel.json`, `docker/Dockerfile`, `scripts/ais-relay.cjs`, `consumer-prices-core/Dockerfile`, `workers/api-cors-preflight/wrangler.toml`, `convex/schema.ts`, `src-tauri/tauri.conf.json`
**Cloudflare zone config (dashboard-managed, NOT in this repo):** the apex `worldmonitor.app` β `www` 301 is a Cloudflare Dynamic Redirect rule ("apex to www (exclude agent-discoverable paths)") whose exemption list is load-bearing: `/.well-known/*`, `/robots.txt`, `/security.txt`, `/mcp`, `/mcp/*`, and `/oauth/*` are served on the apex, never redirected. Dropping the `/mcp*` exemptions breaks every apex-URL MCP client; dropping `/oauth/*` re-breaks OAuth dynamic client registration β a redirected POST becomes a GET and dies with 405 (issue #4938). When editing the rule, mind expression precedence: `and` binds tighter than `or`, so a new exemption must be added as its own `or` term **inside** the `not (β¦)` group (appending `and not β¦` after the last term is a silent no-op). `mcp-live-smoke.yml` probes the MCP/OAuth members of this list (`/mcp`, `/.well-known/oauth-authorization-server`, and the OAuth endpoints it declares) every 6 hours and fails on the redirect fingerprint; the `robots.txt` / `security.txt` exemptions are crawler-facing and have no automated probe.
---
## 3. Frontend Architecture
### Entry and Initialization
`src/main.ts` initializes Sentry error tracking, Vercel analytics, dynamic meta tags, runtime fetch patches (desktop sidecar redirection), theme application, and creates the `App` instance.
`App.init()` runs in 8 phases:
1. **Storage + i18n**: IndexedDB, language detection, locale loading
2. **ML Worker**: ONNX model prep (embeddings, sentiment, summarization)
3. **Sidecar**: Wait for desktop sidecar readiness (desktop only)
4. **Bootstrap**: Two-tier concurrent hydration from `/api/bootstrap` (fast 3s + slow 5s timeouts)
5. **Layout**: PanelLayoutManager renders map and panels
6. **UI**: SignalModal, IntelligenceGapBadge, BreakingNewsBanner, correlation engine
7. **Data**: Parallel `loadAllData()` + viewport-conditional `primeVisiblePanelData()`
8. **Refresh**: Variant-specific polling intervals via `startSmartPollLoop()`
### Component Model
All panels extend the `Panel` base class (107 classes across `src/components`). Panels render via `setContent(html)` (debounced 150ms) and use event delegation on a stable `this.content` element. Panels support resizable row/col spans persisted to localStorage.
### Dual Map System
- **DeckGLMap**: WebGL rendering via deck.gl + maplibre-gl. Supports ScatterplotLayer, GeoJsonLayer, PathLayer, IconLayer, PolygonLayer, ArcLayer, HeatmapLayer, H3HexagonLayer. PMTiles protocol for self-hosted basemap tiles. Supercluster for marker clustering.
- **GlobeMap**: 3D interactive globe via globe.gl. Single merged `htmlElementsData` array with `_kind` discriminator. Earth texture, atmosphere shader, auto-rotate after idle.
Layer definitions live in `src/config/map-layer-definitions.ts`, each specifying renderer support (flat/globe), premium status, variant filtering, and i18n keys.
### State Management
No external state library. `AppContext` is a central mutable object holding: map references, panel instances, panel/layer settings, all cached data (news, markets, predictions, clusters, intelligence caches), in-flight request tracking, and UI component references. URL state syncs bidirectionally via `src/utils/urlState.ts` (debounced 250ms).
### Web Workers
- **analysis.worker.ts**: News clustering (Jaccard similarity), cross-domain correlation detection
- **ml.worker.ts**: ONNX inference via `@xenova/transformers` (MiniLM-L6 embeddings, sentiment, summarization, NER), in-worker vector store for headline memory
- **vector-db.ts**: IndexedDB-backed vector store for semantic search
### Variant System
Detected by hostname (`tech.worldmonitor.app` β tech, `finance.worldmonitor.app` β finance, etc.) or localStorage on desktop. Controls: default panels, map layers, refresh intervals, theme, UI text. Variant change resets all settings to defaults.
**Source files**: `src/main.ts`, `src/App.ts`, `src/app/`, `src/components/Panel.ts`, `src/components/DeckGLMap.ts`, `src/components/GlobeMap.ts`, `src/config/variant.ts`, `src/workers/`
---
## 4. API Layer
### Edge Functions
The `api/` directory holds two kinds of endpoints, both deployed as Vercel Edge Functions:
- **Domain intelligence gateways** β generated from proto contracts and backed by handlers under `server/worldmonitor/**`. The per-domain thin entry points (`api/<domain>/v<N>/[rpc].ts`) are produced via `createDomainGateway` (`server/gateway.ts`) and esbuild-bundled, so the *deployed* artifact is self-contained even though the source composes server-side modules.
- **Operational endpoints** β hand-written for concerns that don't fit the contract model: auth/session, checkout and customer portal, MCP, bootstrap/health, notifications, cache invalidation, and user workflows (e.g. `api/create-checkout.ts`, `api/customer-portal.ts`, `api/mcp.ts`, `api/user-prefs.ts`).
Edge functions are bundled per file: each deployed function may not pull in unrelated modules at runtime, a constraint enforced by `tests/edge-functions.test.mjs` and the pre-push esbuild bundle check. Hand-written endpoints that genuinely cannot be proto-defined are listed in `api/api-route-exceptions.json` and enforced by `npm run lint:api-contract`.
### Shared Helpers
| File | Purpose |
|------|---------|
| `_cors.js` | Origin allowlist (worldmonitor.app, Vercel previews, tauri://localhost, localhost) |
| `_rate-limit.js` | Upstash sliding window rate limiting, IP extraction |
| `_api-key.js` | Origin-aware API key validation (desktop requires key, trusted browser exempt) |
| `_relay.js` | Factory for proxying requests to Railway relay service |
### Gateway Factory
`server/gateway.ts` provides `createDomainGateway(routes)` for per-domain Edge Function bundles. Pipeline:
1. Origin check (403 if disallowed)
2. CORS headers
3. OPTIONS preflight
4. API key validation
5. Rate limiting (endpoint-specific, then global fallback)
6. Route matching (static Map lookup, then dynamic `{param}` scan)
7. POST-to-GET compatibility (for stale clients)
8. Handler execution with error boundary
9. ETag generation (FNV-1a hash) + 304 Not Modified
10. Cache header application
### Cache Tiers
| Tier | s-maxage | Use case |
|------|----------|----------|
| fast | 300s | Live event streams, flight status |
| medium | 600s | Market quotes, stock analysis |
| slow | 1800s | ACLED events, cyber threats |
| static | 7200s | Humanitarian summaries, ETF flows |
| daily | 86400s | Critical minerals, static reference data |
| no-store | 0 | Vessel snapshots, aircraft tracking |
### Domain Handlers
`server/worldmonitor/<domain>/v1/handler.ts` exports handler objects with per-RPC functions. Each RPC function uses `cachedFetchJson()` from `server/_shared/redis.ts` for cache-miss coalescing: concurrent requests for the same key share a single upstream fetch and Redis write.
**Source files**: `api/`, `server/gateway.ts`, `server/router.ts`, `server/_shared/redis.ts`, `server/worldmonitor/`
---
## 5. Proto/RPC Contract System
The project uses the **sebuf** framework built on Protocol Buffers:
```
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 to map RPCs to HTTP verbs and paths. GET fields require `(sebuf.http.query)` annotation. `repeated string` fields need `parseStringArray()` in the handler. `int64` maps to `string` in TypeScript.
CI enforces generated code freshness via `.github/workflows/proto-check.yml`: runs `make generate` and fails if output differs from committed files.
**Source files**: `proto/`, `Makefile`, `src/generated/`, `.github/workflows/proto-check.yml`
---
## 6. Data Pipeline
### Bootstrap Hydration
`/api/bootstrap` reads cached keys from Redis in a single batch call. The SPA fetches two tiers concurrently (fast + slow) with separate abort controllers and timeouts. Hydrated data is consumed on-demand by panels via `getHydratedData(key)`.
### Seed Scripts
`scripts/seed-*.mjs` fetch upstream data, transform it, and write to Redis via `atomicPublish()` from `scripts/_seed-utils.mjs`. Atomic publish acquires a Redis lock (SET NX), validates data, writes the cache key, writes `seed-meta:<key>` with `{ fetchedAt, recordCount }`, and releases the lock.
### AIS Relay Seed Loops
The Railway relay service (`scripts/ais-relay.cjs`) runs continuous seed loops:
- Market data (stocks, commodities, crypto, stablecoins, sectors, ETF flows, gulf quotes)
- Aviation (international delays)
- Positive events
- GPSJAM (GPS interference)
- Risk scores (CII)
- UCDP events
These are the primary seeders. Standalone `seed-*.mjs` scripts on Railway cron are secondary/backup.
### Refresh Scheduling
`startSmartPollLoop()` supports: exponential backoff (max 4x), viewport-conditional refresh (only if panel is near viewport), tab-pause (suspend when hidden), and staggered flush on tab visibility (150ms delays).
### Health Monitoring
`api/health.js` checks every bootstrap and standalone key. For each key it reads `seed-meta:<key>` and compares `fetchedAt` against `maxStaleMin`. Cascade groups handle fallback chains (e.g., theater-posture: live, stale, backup). Returns per-key status: OK, STALE, WARN, EMPTY.
**Source files**: `api/bootstrap.js`, `api/health.js`, `scripts/_seed-utils.mjs`, `scripts/seed-*.mjs`, `scripts/ais-relay.cjs`, `src/services/bootstrap.ts`, `src/app/refresh-scheduler.ts`
---
## 7. Desktop Architecture
### Tauri Shell
Tauri 2.x (Rust) manages the app lifecycle, system tray, and IPC commands:
- **Secret management**: Read/write platform keyring (macOS Keychain, Windows Credential Manager, Linux keyring)
- **Sidecar control**: Spawn Node.js process, probe port, inject environment variables
- **Window management**: Three trusted windows (main, settings, live-channels) with Edit menu for macOS clipboard shortcuts
### Node.js Sidecar
`src-tauri/sidecar/local-api-server.mjs` runs on a dynamic port. It dynamically loads Edge Function handler modules from `api/`, injects secrets from the keyring via environment variables, and monkey-patches `globalThis.fetch` to force IPv4 (Node.js tries IPv6 first, but many government APIs have broken IPv6).
### Fetch Patching
`installRuntimeFetchPatch()` in `src/services/runtime.ts` replaces `window.fetch` on the desktop renderer. All `/api/*` requests route to the sidecar with `Authorization: Bearer <token>` (5-min TTL from Tauri IPC). If the sidecar fails, requests fall back to the cloud API.
**Source files**: `src-tauri/src/main.rs`, `src-tauri/sidecar/local-api-server.mjs`, `src/services/runtime.ts`, `src/services/tauri-bridge.ts`
---
## 8. Security Model
### Trust Boundaries
```
Browser β Vercel Edge β Upstream APIs
Desktop β Sidecar β Cloud API / Upstream APIs
```
### Content Security Policy
Three CSP sources that must stay in sync:
1. `index.html` `<meta>` tag (development, Tauri fallback)
2. `vercel.json` HTTP header (production, overrides meta)
3. `src-tauri/tauri.conf.json` (desktop)
### Authentication
API keys are required for non-browser origins. Trusted browser origins (production domains, Vercel preview deployments, localhost) are exempt. Premium RPC paths always require a key.
### Bot Protection
`middleware.ts` filters automated traffic: blocks known crawler user-agents on API and asset paths, allows social preview bots (Twitter, Facebook, LinkedIn, Telegram, Discord) on story and OG endpoints.
### Rate Limiting
Per-IP sliding window via Upstash with per-endpoint overrides for high-traffic paths.
### Desktop Secret Storage
Secrets are stored in the platform keyring (never plaintext), injected into the sidecar via Tauri IPC, and scoped to an allowlist of environment variable keys.
**Source files**: `middleware.ts`, `vercel.json`, `index.html`, `src-tauri/tauri.conf.json`, `api/_api-key.js`, `server/_shared/rate-limit.ts`
---
## 9. Caching Architecture
### Four-Layer Hierarchy
```
Bootstrap seed (Railway writes to Redis on schedule)
β miss
In-memory cache (per Vercel instance, short TTL)
β miss
Redis (Upstash, cross-instance, cachedFetchJson coalesces concurrent misses)
β miss
Upstream API fetch (result cached back to Redis + seed-meta written)
```
### Cache Key Rules
Every RPC handler with shared cache MUST include request-varying parameters in the cache key. Failure to do so causes cross-request data leakage.
### ETag / Conditional Requests
`server/gateway.ts` computes an FNV-1a hash of each response body and returns it as an `ETag`. Clients send `If-None-Match` and receive `304 Not Modified` when content is unchanged.
### CDN Integration
`CDN-Cache-Control` headers give Cloudflare edge (when enabled) longer TTLs than `Cache-Control`, since CF can revalidate via ETag without full payload transfer.
### Seed Metadata
Every cache write also writes `seed-meta:<key>` with `{ fetchedAt, recordCount }`. The health endpoint reads these to determine data freshness and raise staleness alerts.
**Source files**: `server/_shared/redis.ts`, `server/gateway.ts`, `api/health.js`
---
## 10. Testing
### Unit and Integration
`node:test` runner. Test files in `tests/*.test.{mjs,mts}` cover: server handlers, cache keying, circuit breakers, edge function constraints, data validation, market quote dedup, health checks, panel config guardrails, and variant layer filtering.
### Sidecar and API Tests
`api/*.test.mjs` and `src-tauri/sidecar/*.test.mjs` test CORS handling, YouTube embed proxying, and local API server behavior.
### End-to-End
Playwright specs in `e2e/*.spec.ts` test theme toggling, circuit breaker persistence, keyword spike flows, mobile map interactions, runtime fetch patching, and visual regression via golden screenshot comparison per variant.
### Edge Function Guardrails
`tests/edge-functions.test.mjs` validates that all non-helper `api/*.js` files are self-contained: no `node:` built-in imports, no cross-directory `../server/` or `../src/` imports. The pre-push hook also runs an esbuild bundle check on each endpoint.
### Pre-Push Hook
Runs before every `git push`:
1. TypeScript check (`tsc --noEmit` for src and API)
2. CJS syntax validation
3. Edge function esbuild bundle check
4. Edge function import guardrail test
5. Markdown lint
6. MDX lint (Mintlify compatibility)
7. Version sync check
**Source files**: `tests/`, `e2e/`, `playwright.config.ts`, `.husky/pre-push`
---
## 11. CI/CD
| Workflow | Trigger | Checks |
|----------|---------|--------|
| `typecheck.yml` | PR, push to main | `tsc --noEmit` for src and API tsconfigs |
| `lint-code.yml` | PR, push to main | Biome lint + sebuf API-contract enforcement |
| `lint.yml` | PR (markdown changes) | markdownlint-cli2 |
| `test.yml` | PR, push to main | Unit/integration suite, docs-stats guardrail, plus conditional digest-image and resilience-validation smoke gates |
| `proto-check.yml` | PR (proto changes) | Generated code matches committed output |
| `pro-bundle-freshness.yml` | PR (pro bundle changes) | Committed pro data bundle artifacts are fresh |
| `feed-validation.yml` | PR (feed changes), daily cron | RSS feed reachability and validation |
| `mcp-live-smoke.yml` | 6-hourly cron, push to main (smoke paths), manual | Anonymous strict-client walk of the production MCP surface on apex + www (capability walk, auth wall, OAuth endpoint routing β #4937/#4938 regression net) |
| `live-api-cache-auth.yml` | 6-hourly cron, push to main (sweep paths), manual | Production cache/auth posture sweep: fake auth stays no-store and is never a cached 200, anonymous public surfaces stay cacheable, MCP/OAuth surfaces stay protocol-valid (#4497 regression net; suite was inert until #5379 wired the gate on, and the step fails if it executes 0 assertions) |
| `china-decision-parity-live.yml` | 6-hourly cron, push to main (audit paths), manual (optional staging URL) | Live half of the China decision-signal parity audit: probes the deployed composition RPC and the public `chinaDecisionSignals` bootstrap projection for the six-domain contract and a canonical snapshot under one hour old (#5643 β the probe existed but nothing invoked it, and `--require-live` keeps a lost `--url` from passing vacuously) |
| `security-audit.yml` | PR, push to main, daily cron, manual | Production dependency audits for every tracked `package-lock.json` workspace, failing on unbaselined high/critical advisories |
| `seed-freshness-monitor.yml` | 15-minute cron, manual | Enforces production ingestion acceptance after a green scheduled main gate; fails on every actionable compact-health problem except explicitly on-demand sources without grading production before Railway deploys or runs |
| `analytics-collector-monitor.yml` | 15-minute cron, manual | Probes the self-hosted Umami collector directly (heartbeat, tracker script, ingest route) and fails when events are being dropped β Railway reported a green deployment through the 4-day #5565 blackout, so deployment status is not trusted here |
| `contributor-trust.yml` | PR | Gates untrusted first-time-contributor runs |
| `deploy-gate.yml` | After Test/Typecheck/Security Audit complete | Aggregates required smoke-gate statuses onto the head SHA for branch protection |
| `indexnow-submit.yml` | Successful Production deployment, manual | Submits deployment-relevant canonical URLs to IndexNow only after their host-specific ownership keys are directly reachable |
| `convex-deploy.yml` | Push to main, manual | Deploys Convex backend functions |
| `deploy-worker.yml` | Push to main (worker paths), manual | Deploys the `api-cors-preflight` Cloudflare Worker |
| `build-desktop.yml` | Release tag, push, manual | Multi-platform Tauri build, code signing (macOS), AppImage library stripping (Linux), smoke test |
| `docker-publish.yml` | Release, manual | Multi-arch image (amd64, arm64) pushed to GHCR |
| `publish-cli.yml` | `cli-v*` tag, manual | Tests and publishes the `worldmonitor` npm CLI (`cli/`) via OIDC trusted publishing (no token) with provenance |
| `publish-python.yml` | `py-v*` tag, manual | Tests and publishes the `worldmonitor-sdk` PyPI package (`sdk/python/`) via OIDC trusted publishing (no token) with attestations |
| `publish-ruby.yml` | `gem-v*` tag, manual | Tests and publishes the `worldmonitor` gem (`sdk/ruby/`) via RubyGems OIDC trusted publishing (no token) |
| `publish-go.yml` | `sdk/go/v*` tag, manual | Vets/tests the Go SDK module (`sdk/go/`) at the tag and warms proxy.golang.org so the version is go-gettable and indexed on pkg.go.dev |
| `test-linux-app.yml` | Manual | Linux AppImage build + headless smoke test with screenshot verification |
**Source files**: `.github/workflows/`, `.husky/pre-push`. The workflow list is CI-checked against `.github/workflows/*.yml` by `npm run docs:check` β a new workflow file must be added to this table.
---
## 12. Directory Reference
```
.
βββ api/ Vercel Edge Functions (self-contained JS)
β βββ _*.js Shared helpers (CORS, rate-limit, API key, relay, Sentry, session)
β βββ <domain>/ Domain endpoints (aviation/, climate/, conflict/, ...)
βββ blog-site/ Static blog (built into public/blog/)
βββ cli/ Official `worldmonitor` npm CLI (zero-dep ESM, MCP-first; published via cli-v* tag)
βββ consumer-prices-core/ Consumer-price collection service (Playwright scrapers, per-country baskets; Railway/Docker)
βββ convex/ Convex backend (billing/entitlements, user state, broadcast, forms, intel history)
βββ data/ Static data (telegram channels, OREF threat translations, gamma irradiators)
βββ deploy/ Deployment configs (nginx)
βββ docker/ Dockerfile + nginx config for Railway
βββ docs/ Mintlify documentation site
βββ e2e/ Playwright E2E specs
βββ pro-test/ Standalone Pro QA app (separate package)
βββ proto/ Protobuf service definitions (sebuf framework)
βββ public/ Static assets served as-is (favicons, textures, .well-known agent-skills/MCP, llms.txt)
βββ scripts/ Seed scripts, build helpers, relay service
βββ server/ Server-side code (bundled into Edge Functions)
β βββ _shared/ Redis, rate-limit, LLM, caching utilities
β βββ gateway.ts Domain gateway factory
β βββ router.ts Route matching
β βββ worldmonitor/ Domain handlers (mirrors proto structure)
βββ shared/ Cross-platform JSON configs (markets, RSS domains)
βββ src/ Browser SPA (TypeScript)
β βββ app/ App orchestration managers
β βββ bootstrap/ Startup/recovery (chunk reload, deferred Sentry, SW update)
β βββ components/ Panel subclasses + map components
β βββ config/ Variant, panel, layer, market configurations
β βββ data/ Static JSON datasets (conservation, renewable, happiness)
β βββ e2e/ Map test harnesses (consumed by Playwright specs)
β βββ embed/ Embeddable widget loader
β βββ generated/ Proto-generated client/server stubs (DO NOT EDIT)
β βββ locales/ i18n translation files
β βββ services/ Business logic organized by domain
β βββ shared/ Cross-cutting helpers (premium paths, registries, staleness)
β βββ shims/ Runtime shims (child-process for sidecar)
β βββ styles/ Global CSS (layers, themes, panel styles)
β βββ types/ TypeScript type definitions
β βββ utils/ Shared utilities (circuit-breaker, theme, URL state)
β βββ workers/ Web Workers (analysis, ML, vector DB)
βββ src-tauri/ Tauri desktop shell (Rust)
β βββ sidecar/ Node.js sidecar API server
βββ tests/ Unit/integration tests (node:test)
βββ workers/ Cloudflare Workers (edge CORS preflight for api.worldmonitor.app)
```
|