* feat(proto): generate unified worldmonitor.openapi.yaml bundle Adds a third protoc-gen-openapiv3 invocation that merges every service into a single docs/api/worldmonitor.openapi.yaml spanning all 68 RPCs, using the new bundle support shipped in sebuf 0.11.0 (SebastienMelki/sebuf#158). Per-service YAML/JSON files are untouched and continue to back the Mintlify docs in docs/docs.json. The bundle runs with strategy: all and bundle_only=true so only the aggregate file is emitted, avoiding duplicate-output conflicts with the existing per-service generator. Requires protoc-gen-openapiv3 >= v0.11.0 locally: go install github.com/SebastienMelki/sebuf/cmd/protoc-gen-openapiv3@v0.11.0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(proto): bump sebuf to v0.11.0 and document unified OpenAPI bundle - Makefile: SEBUF_VERSION v0.7.0 → v0.11.0 (required for bundle support). - proto/buf.gen.yaml: point bundle_server at https://api.worldmonitor.app. - CONTRIBUTING.md: new "OpenAPI Output" section covering per-service specs vs the unified worldmonitor.openapi.yaml bundle, plus a note that all three sebuf plugins must be installed from the pinned version. - AGENTS.md: clarify that `make generate` also produces the unified spec and requires sebuf v0.11.0. - CHANGELOG.md: Unreleased entry announcing the bundle and version bump. Also regenerates the bundle with the updated server URL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(codegen): regenerate TS client/server with sebuf v0.11.0 Mechanical output of the bumped protoc-gen-ts-client and protoc-gen-ts-server. Two behavioral improvements roll in from sebuf: - Proto enum fields now use the proper `*_UNSPECIFIED` sentinel in default-value checks instead of the empty string, so generated query-string serializers correctly omit enum params only when they actually equal the proto default. - `repeated string` query params now serialize via `forEach(v => params.append(...))` instead of being coerced through `String(req.field)`, matching the existing `parseStringArray()` contract on the server side. All files also drop the `// @ts-nocheck` header that earlier sebuf versions emitted — 0.11.0 output type-checks cleanly under our tsconfig. No hand edits. Reproduce with `make install-plugins && make generate`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(proto): bump sebuf v0.11.0 → v0.11.1, realign tests with repeated-param wire format - Bump SEBUF_VERSION to v0.11.1, pulling in the OpenAPI fix for repeated scalar query params (SebastienMelki/sebuf#161). `repeated string` fields now emit `type: array` + `items.type: string` + `style: form` + `explode: true` instead of `type: string`, so SDK generators consuming the unified bundle produce correct array clients. - Regenerate all 12 OpenAPI specs (unified bundle + Aviation, Economic, Infrastructure, Market, Trade per-service). TS client/server codegen is byte-identical to v0.11.0 — only the OpenAPI emitter was out of sync. - Update three tests that asserted the pre-v0.11 comma-joined wire format (`symbols=AAPL,MSFT`) to match the current repeated-param form (`symbols=AAPL&symbols=MSFT`) produced by `params.append(...)`: - tests/market-service-symbol-casing.test.mjs (2 cases: getAll) - tests/stock-analysis-history.test.mts - tests/stock-backtest.test.mts Locally: test:data 6619/6619 pass, typecheck clean, lint exit 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Apply suggestions from code review Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
14 KiB
Contributing to World Monitor
Thank you for your interest in contributing to World Monitor! This project thrives on community contributions — whether it's code, data sources, documentation, or bug reports.
Table of Contents
- Architecture Overview
- Getting Started
- Development Setup
- How to Contribute
- Pull Request Process
- AI-Assisted Development
- Coding Standards
- Working with Sebuf (RPC Framework)
- Adding Data Sources
- Adding RSS Feeds
- Reporting Bugs
- Feature Requests
- Code of Conduct
Architecture Overview
World Monitor is a real-time OSINT dashboard built with Vanilla TypeScript (no UI framework), MapLibre GL + deck.gl for map rendering, and a custom Proto-first RPC framework called Sebuf for all API communication.
Key Technologies
| Technology | Purpose |
|---|---|
| TypeScript | All code — frontend, edge functions, and handlers |
| Vite | Build tool and dev server |
| Sebuf | Proto-first HTTP RPC framework for typed API contracts |
| Protobuf / Buf | Service and message definitions across 22 domains |
| MapLibre GL | Base map rendering (tiles, globe mode, camera) |
| deck.gl | WebGL overlay layers (scatterplot, geojson, arcs, heatmaps) |
| d3 | Charts, sparklines, and data visualization |
| Vercel Edge Functions | Serverless API gateway |
| Tauri v2 | Desktop app (Windows, macOS, Linux) |
| Convex | Minimal backend (beta interest registration only) |
| Playwright | End-to-end and visual regression testing |
Variant System
The codebase produces three app variants from the same source, each targeting a different audience:
| Variant | Command | Focus |
|---|---|---|
full |
npm run dev |
Geopolitics, military, conflicts, infrastructure |
tech |
npm run dev:tech |
Startups, AI/ML, cloud, cybersecurity |
finance |
npm run dev:finance |
Markets, trading, central banks, commodities |
Variants share all code but differ in default panels, map layers, and RSS feeds. Variant configs live in src/config/variants/.
Directory Structure
| Directory | Purpose |
|---|---|
src/components/ |
UI components — Panel subclasses, map, modals (~50 panels) |
src/services/ |
Data fetching modules — sebuf client wrappers, AI, signal analysis |
src/config/ |
Static data and variant configs (feeds, geo, military, pipelines, ports) |
src/generated/ |
Auto-generated sebuf client + server stubs (do not edit by hand) |
src/types/ |
TypeScript type definitions |
src/locales/ |
i18n JSON files (14 languages) |
src/workers/ |
Web Workers for analysis |
server/ |
Sebuf handler implementations for all 17 domain services |
api/ |
Vercel Edge Functions (sebuf gateway + legacy endpoints) |
proto/ |
Protobuf service and message definitions |
data/ |
Static JSON datasets |
docs/ |
Documentation + generated OpenAPI specs |
src-tauri/ |
Tauri v2 Rust app + Node.js sidecar for desktop builds |
e2e/ |
Playwright end-to-end tests |
scripts/ |
Build and packaging scripts |
Getting Started
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/<your-username>/worldmonitor.git cd worldmonitor - Create a branch for your work:
git checkout -b feature/your-feature-name
Development Setup
# Install everything (buf CLI, sebuf plugins, npm deps, Playwright browsers)
make install
# Start the development server (full variant, default)
npm run dev
# Start other variants
npm run dev:tech
npm run dev:finance
# Run type checking
npm run typecheck
# Run tests
npm run test:data # Data integrity tests
npm run test:e2e # Playwright end-to-end tests
# Production build (per variant)
npm run build # full
npm run build:tech
npm run build:finance
The dev server runs at http://localhost:3000. Run make help to see all available make targets.
Environment Variables (Optional)
For full functionality, copy .env.example to .env.local and fill in the API keys you need. The app runs without any API keys — external data sources will simply be unavailable.
See API Dependencies for the full list.
How to Contribute
Types of Contributions We Welcome
- Bug fixes — found something broken? Fix it!
- New data layers — add new geospatial data sources to the map
- RSS feeds — expand our 100+ feed collection with quality sources
- UI/UX improvements — make the dashboard more intuitive
- Performance optimizations — faster loading, better caching
- Documentation — improve docs, add examples, fix typos
- Accessibility — make the dashboard usable by everyone
- Internationalization — help make World Monitor available in more languages
- Tests — add unit or integration tests
What We're Especially Looking For
- New data layers (see Adding Data Sources)
- Feed quality improvements and new RSS sources
- Mobile responsiveness improvements
- Performance optimizations for the map rendering pipeline
- Better anomaly detection algorithms
Pull Request Process
- Update documentation if your change affects the public API or user-facing behavior
- Run type checking before submitting:
npm run typecheck - Test your changes locally with at least the
fullvariant, and any other variant your change affects - Keep PRs focused — one feature or fix per pull request
- Write a clear description explaining what your PR does and why
- Link related issues if applicable
PR Title Convention
Use a descriptive title that summarizes the change:
feat: add earthquake magnitude filtering to map layerfix: resolve RSS feed timeout for Al Jazeeradocs: update API dependencies sectionperf: optimize marker clustering at low zoom levelsrefactor: extract threat classifier into separate module
Review Process
- All PRs require review from a maintainer before merging
- Maintainers may request changes — this is normal and collaborative
- Once approved, a maintainer will merge your PR
AI-Assisted Development
We fully embrace AI-assisted development. Many of our own PRs are labeled with the LLM that helped produce them (e.g., claude, codex, cursor), and contributors are welcome to use any AI tools they find helpful.
That said, all code is held to the same quality bar regardless of how it was written. AI-generated code will be reviewed with the same scrutiny as human-written code. Contributors are responsible for understanding and being able to explain every line they submit. Blindly pasting LLM output without review is discouraged — treat AI as a collaborator, not a replacement for your own judgement.
Coding Standards
TypeScript
- Use TypeScript for all new code
- Avoid
anytypes — use proper typing orunknownwith type guards - Export interfaces/types for public APIs
- Use meaningful variable and function names
Code Style
- Follow the existing code style in the repository
- Use
constby default,letwhen reassignment is needed - Prefer functional patterns (map, filter, reduce) over imperative loops
- Keep functions focused — one responsibility per function
- Add JSDoc comments for exported functions and complex logic
File Organization
- Static layer/geo data and variant configs go in
src/config/ - Sebuf handler implementations go in
server/worldmonitor/{domain}/v1/ - Edge function gateway and legacy endpoints go in
api/ - UI components (panels, map, modals) go in
src/components/ - Service modules (data fetching, client wrappers) go in
src/services/ - Proto definitions go in
proto/worldmonitor/{domain}/v1/
Working with Sebuf (RPC Framework)
Sebuf is the project's custom Proto-first HTTP RPC framework — a lightweight alternative to gRPC-Web. All API communication between client and server uses Sebuf.
How It Works
- Proto definitions in
proto/worldmonitor/{domain}/v1/define services and messages - Code generation (
make generate) produces:- TypeScript clients in
src/generated/client/(e.g.,MarketServiceClient) - Server route factories in
src/generated/server/(e.g.,createMarketServiceRoutes)
- TypeScript clients in
- Handlers in
server/worldmonitor/{domain}/v1/handler.tsimplement the service interface - Gateway in
api/[domain]/v1/[rpc].tsregisters all handlers and routes requests - Clients in
src/services/{domain}/index.tswrap the generated client for app use
Adding a New RPC Method
- Add the method to the
.protoservice definition - Run
make generateto regenerate client/server stubs - Implement the handler method in the domain's
handler.ts - The client stub is auto-generated — use it from
src/services/{domain}/
Use make lint to lint proto files and make breaking to check for breaking changes against main.
Proto Conventions
- Time fields: Use
int64(Unix epoch milliseconds), notgoogle.protobuf.Timestamp - int64 encoding: Apply
[(sebuf.http.int64_encoding) = INT64_ENCODING_NUMBER]on time fields so TypeScript receivesnumberinstead ofstring - HTTP annotations: Every RPC method needs
option (sebuf.http.config) = { path: "...", method: POST }
Proto Codegen Requirements
Run make install to install everything automatically, or install individually:
make install-buf # Install buf CLI (requires Go)
make install-plugins # Install sebuf protoc-gen plugins (requires Go)
The pinned sebuf version is set by SEBUF_VERSION in the Makefile (currently v0.11.1). All three plugins — protoc-gen-ts-client, protoc-gen-ts-server, protoc-gen-openapiv3 — must be installed from the same sebuf release. If you see codegen drift after pulling, rerun make install-plugins to resync.
OpenAPI Output
make generate (i.e. cd proto && buf generate) produces:
| File | Purpose |
|---|---|
docs/api/{Service}.openapi.yaml / .json |
Per-service specs — referenced individually by Mintlify in docs/docs.json |
docs/api/worldmonitor.openapi.yaml |
Unified bundle spanning every service (sebuf ≥ v0.11.0) — use this for external consumers, API explorers, or anywhere you want a single spec covering all RPCs |
The unified bundle is emitted by a third protoc-gen-openapiv3 invocation in proto/buf.gen.yaml using bundle=true, bundle_only=true, and strategy: all. Regenerate alongside the per-service files; do not edit by hand.
Adding Data Sources
To add a new data layer to the map:
- Define the data source — identify the API or dataset you want to integrate
- Add the proto service (if the data needs a backend proxy) — define messages and RPC methods in
proto/worldmonitor/{domain}/v1/ - Generate stubs — run
make generate - Implement the handler in
server/worldmonitor/{domain}/v1/ - Register the handler in
api/[domain]/v1/[rpc].tsandvite.config.ts(for local dev) - Create the service module in
src/services/{domain}/wrapping the generated client - Add the layer config and implement the map renderer following existing layer patterns
- Add to layer toggles — make it toggleable in the UI
- Document the source — add it to
docs/DOCUMENTATION.md
For endpoints that deal with non-JSON payloads (XML feeds, binary data, HTML embeds), you can add a standalone Edge Function in api/ instead of Sebuf. For anything returning JSON, prefer Sebuf — the typed contracts are always worth it.
Data Source Requirements
- Must be freely accessible (no paid-only APIs for core functionality)
- Must have a permissive license or be public government data
- Should update at least daily for real-time relevance
- Must include geographic coordinates or be geo-locatable
Country boundary overrides
Country outlines are loaded from public/data/countries.geojson. Optional higher-resolution overrides (sourced from Natural Earth) are served from R2 CDN. The app loads overrides after the main file and replaces geometry for any country whose ISO3166-1-Alpha-2 (or ISO_A2) matches. To refresh boundary overrides from Natural Earth, run:
node scripts/fetch-country-boundary-overrides.mjs
rclone copy public/data/country-boundary-overrides.geojson r2:worldmonitor-maps/
Adding RSS Feeds
To add new RSS feeds:
- Verify the feed is reliable and actively maintained
- Assign a source tier (1-4) based on editorial reliability
- Flag any state affiliation or propaganda risk
- Categorize the feed (geopolitics, defense, energy, tech, etc.)
- Test that the feed parses correctly through the RSS proxy
Reporting Bugs
When filing a bug report, please include:
- Description — clear description of the issue
- Steps to reproduce — how to trigger the bug
- Expected behavior — what should happen
- Actual behavior — what actually happens
- Screenshots — if applicable
- Browser/OS — your environment details
- Console errors — any relevant browser console output
Use the Bug Report issue template when available.
Feature Requests
We welcome feature ideas! When suggesting a feature:
- Describe the problem it solves
- Propose a solution with as much detail as possible
- Consider alternatives you've thought about
- Provide context — who would benefit from this feature?
Use the Feature Request issue template when available.
Code of Conduct
This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior through GitHub issues or by contacting the repository owner.
Thank you for helping make World Monitor better! 🌍