File size: 14,928 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 | # AGENTS.md
Agent entry point for WorldMonitor. Read this first, then follow links for depth.
## What This Project Is
Real-time global intelligence dashboard. TypeScript SPA (Vite + Preact) with 179 top-level TypeScript component files, 80+ Vercel Edge API endpoint entries, a Tauri desktop app with Node.js sidecar, and a Railway relay service. Aggregates geopolitics, military, finance, climate, cyber, maritime, and aviation data across 35 freshness-tracked source groups.
## Repository Map
```
.
βββ src/ # Browser SPA (TypeScript, class-based components)
β βββ app/ # App orchestration (data-loader, refresh-scheduler, panel-layout)
β βββ bootstrap/ # Startup/recovery (chunk reload, deferred Sentry, SW update)
β βββ components/ # 179 top-level TypeScript component files
β βββ config/ # Variant configs, panel/layer definitions, market symbols
β βββ services/ # Business logic (218 service modules and domain directories)
β βββ shared/ # Cross-cutting helpers (premium paths, registries, staleness)
β βββ embed/ # Embeddable widget loader
β βββ styles/ # Global CSS (layers, themes, panel styles)
β βββ shims/ # Runtime shims (child-process for sidecar)
β βββ data/ # Static JSON datasets (conservation, renewable, happiness)
β βββ e2e/ # Map test harnesses (consumed by Playwright specs)
β βββ types/ # TypeScript type definitions
β βββ utils/ # Shared utilities (circuit-breaker, theme, URL state, DOM)
β βββ workers/ # Web Workers (analysis, ML/ONNX, vector DB)
β βββ generated/ # Proto-generated client/server stubs (DO NOT EDIT)
β βββ locales/ # i18n translation files
β βββ App.ts # Main application entry
βββ api/ # Vercel Edge Functions (plain JS, self-contained)
β βββ _*.js # Shared helpers (CORS, rate-limit, API key, relay)
β βββ health.js # Health check endpoint
β βββ bootstrap.js # Bulk data hydration endpoint
β βββ <domain>/ # Domain-specific endpoints (aviation/, climate/, etc.)
βββ server/ # Server-side shared code (used by Edge Functions)
β βββ _shared/ # Redis, rate-limit, LLM, caching, response headers
β βββ gateway.ts # Domain gateway factory (CORS, auth, cache tiers)
β βββ router.ts # Route matching
β βββ worldmonitor/ # Domain handlers (mirrors proto service structure)
βββ proto/ # Protobuf definitions (sebuf framework)
β βββ buf.yaml # Buf configuration
β βββ worldmonitor/ # Service definitions with HTTP annotations
βββ shared/ # Cross-platform data (JSON configs for markets, RSS domains)
βββ data/ # Static data (telegram channels, OREF threat translations, gamma irradiators)
βββ public/ # Static assets served as-is (favicons, textures, .well-known, llms.txt)
βββ scripts/ # Seed scripts, build helpers, data fetchers
βββ src-tauri/ # Tauri desktop shell (Rust + Node.js sidecar)
β βββ sidecar/ # Node.js sidecar API server
βββ consumer-prices-core/ # Consumer-price scrapers (Playwright, per-country baskets; Railway/Docker)
βββ workers/ # Cloudflare Workers (edge CORS preflight for api.worldmonitor.app)
βββ tests/ # Unit/integration tests (node:test runner)
βββ e2e/ # Playwright E2E specs
βββ pro-test/ # Standalone Pro QA app (separate package)
βββ docs/ # Mintlify documentation site
β βββ solutions/ # Documented solutions to past problems (bugs, patterns, practices) β YAML frontmatter (module, tags, problem_type)
βββ docker/ # Docker build for Railway services
βββ deploy/ # Deployment configs (nginx)
βββ CONCEPTS.md # Shared domain vocabulary (entities, named processes, status concepts)
βββ blog-site/ # Static blog (built into public/blog/)
```
## How to Run
```bash
npm ci # Deterministic install (also runs blog-site postinstall)
npm run dev # Start Vite dev server (full variant)
npm run dev:tech # Start tech-only variant
npm run dev:energy # Start energy-security variant
npm run typecheck # tsc --noEmit (strict mode)
npm run typecheck:api # Typecheck API layer separately
npm run test:data # Run unit/integration tests
npm run test:sidecar # Run sidecar + API handler tests
npm run test:e2e # Run all Playwright E2E tests
make generate # Regenerate proto stubs + per-service & unified OpenAPI specs (requires buf + sebuf v0.11.1 plugins)
npm run worktree:bootstrap # Fresh worktree: link local env files + npm ci with tmp cache
npm run worktree:bootstrap:test-only # Fresh docs/test worktree: same, but npm ci --ignore-scripts
npm run worktree:env # Link ignored local env files only
```
## Fresh Worktree Bootstrap
Worktrees usually start without ignored local state. When creating or entering one:
1. Start from `origin/main` or the requested base, not a dirty local branch.
2. Run `npm run worktree:bootstrap` before typecheck/tests. The helper links ignored `.env.local` / `.env` from the main worktree when Git can infer it, and installs deps with `npm ci --cache /tmp/worldmonitor-npm-cache`.
3. If only docs/test tooling is needed and native postinstall work is unnecessary, use `npm run worktree:bootstrap:test-only`.
4. If live credentials are unavailable, do not fabricate secrets. Run the non-credentialed checks you can and report the credential gate explicitly.
Env rules:
- Link only `.env.local` and `.env`. Never copy or link `.env.vercel-backup` or `.env.vercel-export`; the pre-push guard blocks those files even as symlinks.
- Override env source discovery with `WM_ENV_SOURCE=/path/to/worldmonitor npm run worktree:env` when the main worktree cannot be inferred.
- `.env*` files are ignored local state. Do not add, print, or summarize secret values.
Validation hygiene:
- Prefer `npm ci` over `npm install` in fresh worktrees. Use `npm_config_cache=/tmp/worldmonitor-npm-cache` for `npx` or install commands if cache ownership errors appear.
- After bootstrap or pre-push, run `git status --short`. If dependency bootstrap changed lockfiles you did not intend to edit, remove those incidental changes before finalizing.
- After install, prefer local tools such as `./node_modules/.bin/tsx --test ...` for focused TypeScript tests when `npx` is flaky.
## Architecture Rules
### Dependency Direction
```
types -> config -> services -> components -> app -> App.ts
```
- `types/` has zero internal imports
- `config/` imports only from `types/`
- `services/` imports from `types/` and `config/`
- `components/` imports from all above
- `app/` orchestrates components and services
### API Layer Constraints
- `api/*.js` are Vercel Edge Functions: **self-contained JS only**
- They CANNOT import from `../src/` or `../server/` (different runtime)
- Only same-directory `_*.js` helpers and npm packages
- Enforced by `tests/edge-functions.test.mjs` and pre-push hook esbuild check
### Server Layer
- `server/` code is bundled INTO Edge Functions at deploy time via gateway
- `server/_shared/` contains Redis client, rate limiting, LLM helpers
- `server/worldmonitor/<domain>/` has RPC handlers matching proto services
- All handlers use `cachedFetchJson()` for Redis caching with stampede protection
### Proto Contract Flow
```
proto/ definitions -> buf generate -> src/generated/{client,server}/ -> handlers wire up
```
- GET fields need `(sebuf.http.query)` annotation
- `repeated string` fields need `parseStringArray()` in handler
- `int64` maps to `string` in TypeScript
- CI checks proto freshness via `.github/workflows/proto-check.yml`
## Variant System
The app ships multiple variants with different panel/layer configurations:
- `full` (default): All features
- `tech`: Technology-focused subset
- `finance`: Financial markets focus
- `commodity`: Commodity markets focus
- `happy`: Positive news only
- `energy`: Energy security, chokepoints, oil/gas, and disruption timelines
Variant is set via `VITE_VARIANT` env var. Config lives in `src/config/variants/`.
## Key Patterns
### Adding a New API Endpoint
1. Define proto message in `proto/worldmonitor/<domain>/`
2. Add RPC with `(sebuf.http.config)` annotation
3. Run `make generate`
4. Create handler in `server/worldmonitor/<domain>/`
5. Wire handler in domain's `handler.ts`
6. Use `cachedFetchJson()` for caching, include request params in cache key
### Adding a New Panel
1. Create `src/components/MyPanel.ts` extending `Panel`
2. Register in `src/config/panels.ts`
3. Add to variant configs in `src/config/variants/`
4. Wire data loading in `src/app/data-loader.ts`
### Circuit Breakers
- `src/utils/circuit-breaker.ts` for client-side
- Used in data loaders to prevent cascade failures
- Separate breaker per data domain
### Caching
- Redis (Upstash) via `server/_shared/redis.ts`
- `cachedFetchJson()` coalesces concurrent cache misses
- Cache tiers: fast (5m), medium (10m), slow (30m), static (2h), daily (24h)
- Cache key MUST include request-varying params
## Testing
- **Unit/Integration**: `tests/*.test.{mjs,mts}` using `node:test` runner
- **Sidecar tests**: `api/*.test.mjs`, `src-tauri/sidecar/*.test.mjs`
- **E2E**: `e2e/*.spec.ts` using Playwright
- **Visual regression**: Golden screenshot comparison per variant
## CI Checks (GitHub Actions)
| Workflow | Trigger | What it checks |
|---|---|---|
| `typecheck.yml` | PR + push to main | `tsc --noEmit` for src and API |
| `lint.yml` | PR (markdown changes) | markdownlint-cli2 |
| `proto-check.yml` | PR (proto changes) | Generated code freshness |
| `build-desktop.yml` | Manual | Tauri desktop build |
| `test-linux-app.yml` | Manual | Linux AppImage smoke test |
## Pre-Push Hook
Runs automatically before `git push`. Two tiers:
**Always (state-dependent, fast β run even on a cache hit):** local Vercel env-dump guard, PR-state check (no pushes to merged/closed PR branches), branch-contamination guard (>20 commits ahead), `scripts/` lockfile sync.
**Tree-dependent (skipped entirely on a green-tree cache hit):** Unicode safety and version sync (always run for uncached trees), plus the diff-scoped checks: TypeScript (frontend tsc on `src/`-surface changes; `typecheck:api` on `api/|server/|scripts/|src/generated/`; Convex tsc on `convex/`), CJS syntax, boundary/safe-html/Sentry-coverage/rate-limit/premium-fetch lints (each also fires when its own guardrail script changes), edge esbuild check (`api/|server/|src/generated/` β edge entries bundle-import server code), markdown/MDX lint, proto + pro-test bundle freshness, change-scoped tests. `package.json`/`tsconfig` changes β or an unresolvable `origin/main` diff β force everything (an unresolvable diff also bypasses the green-tree cache: a blind run trusts nothing, including prior attestations).
**Green-tree cache:** a tree that passed the full gate is recorded (`$GIT_DIR/wm-prepush-green`); re-pushing the identical tree (remote failure, message-only amend) skips all tree-dependent checks β same tree, same result. Delete that file to force a full re-run.
Heavy checks (`test:data`, typechecks, edge-bundle) must run **sequentially** in worktrees β parallel runs OOM (exit 137).
## Shipping Velocity (Agent Workflow)
- **Before starting work on an issue:** check for parallel/duplicate work first β `gh pr list --search "<issue#>"` AND `git worktree list` (background codex/claude sessions ship PRs under the same account).
- **PR delivery authority:** a user request to implement, fix, or ship a scoped change authorizes creating and updating the ready PRs needed to deliver it, including corrective follow-up PRs discovered by review or CI, plus monitoring and repairing those PRs without additional per-PR confirmation. This authority is limited to the requested change and its delivery branches; review-only or diagnostic requests remain read-only.
- **Merge authority is explicit and non-delegable:** never merge a PR, enable auto-merge, queue a merge, or run any equivalent GitHub merge action unless the user has explicitly requested that specific action in the current conversation. A request to implement, ship, push, create a PR, or monitor CI does **not** authorize merging. Wait for clear approval and report the ready state instead.
- **After pushing a PR:** do not sleep-poll CI. Start `gh pr checks <n> --watch` as a background task, or report the current check state; never turn on auto-merge without the explicit approval above.
- **docs/plans/ is gitignored** β plan documents are local working state and do not travel between worktrees or ship in PRs.
- **PR-review verification:** never assert a finding is fixed/stale from memory β re-fetch the PR head SHA and diff the cited lines first.
## Deployment
- **Web**: Vercel (auto-deploy on push to main)
- **Relay/Seeds**: Railway (Docker, cron services)
- **Desktop**: Tauri builds via GitHub Actions
- **Docs**: Mintlify (proxied through Vercel at `/docs`)
## Critical Conventions
- `fetch.bind(globalThis)` is BANNED. Use `(...args) => globalThis.fetch(...args)` instead
- Edge Functions cannot use `node:http`, `node:https`, `node:zlib`
- Always include `User-Agent` header in server-side fetch calls
- Yahoo Finance requests must be staggered (150ms delays)
- New data sources MUST have bootstrap hydration wired in `api/bootstrap.js`
- Redis seed scripts MUST write `seed-meta:<key>` for health monitoring
- Seed credentials load only via `loadEnvFile()` (inert under test runtimes, resolves `.env.local` at the checkout root, `only:` narrows the keys) β never hand-roll a `.env` reader or resolve one from `$HOME` or an absolute literal. Note `worktree:bootstrap` symlinks the source checkout's `.env.local`, so a bootstrapped worktree shares real credentials when a seeder is actually run
## External References
- [Architecture (system reference)](ARCHITECTURE.md)
- [Design Philosophy (why decisions were made)](docs/architecture.mdx)
- [Contributing guide](CONTRIBUTING.md)
- [Data sources catalog](docs/data-sources.mdx)
- [Health endpoints](docs/health-endpoints.mdx)
- [Adding endpoints guide](docs/adding-endpoints.mdx)
- [API reference (OpenAPI)](docs/api/)
|