| # 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](#architecture-overview) |
| - [Getting Started](#getting-started) |
| - [Development Setup](#development-setup) |
| - [How to Contribute](#how-to-contribute) |
| - [Pull Request Process](#pull-request-process) |
| - [AI-Assisted Development](#ai-assisted-development) |
| - [Coding Standards](#coding-standards) |
| - [Working with Sebuf (RPC Framework)](#working-with-sebuf-rpc-framework) |
| - [Adding Data Sources](#adding-data-sources) |
| - [Adding RSS Feeds](#adding-rss-feeds) |
| - [Reporting Bugs](#reporting-bugs) |
| - [Feature Requests](#feature-requests) |
| - [Code of Conduct](#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 36 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 6 app variants from the same source, each targeting a different audience or use case: |
|
|
| | 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 | |
| | `commodity` | `npm run dev:commodity` | Commodities, mining, energy markets | |
| | `happy` | `npm run dev:happy` | Positive news and constructive signals | |
| | `energy` | `npm run dev:energy` | Energy security, chokepoints, oil/gas | |
|
|
| 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 β 179 top-level TypeScript component files | |
| | `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 (25 languages) | |
| | `src/workers/` | Web Workers for analysis | |
| | `server/` | Sebuf handler implementations for all 35 server handler domains | |
| | `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 |
|
|
| 1. **Fork** the repository on GitHub |
| 2. **Clone** your fork locally: |
| ```bash |
| git clone https://github.com/<your-username>/worldmonitor.git |
| cd worldmonitor |
| ``` |
| 3. **Create a branch** for your work: |
| ```bash |
| git checkout -b feature/your-feature-name |
| ``` |
|
|
| ## Development Setup |
|
|
| ```bash |
| # 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 |
| npm run dev:commodity |
| npm run dev:happy |
| npm run dev:energy |
| |
| # Run type checking |
| npm run typecheck |
| |
| # Run tests |
| npm run test:data # Data integrity tests |
| npm run test:e2e:full # Playwright end-to-end tests (full variant) |
| |
| # Production build (per variant) |
| npm run build # full |
| npm run build:tech |
| npm run build:finance |
| npm run build:commodity |
| npm run build:happy |
| npm run build:energy |
| ``` |
|
|
| The dev server runs at `http://localhost:3000` (override the port with `DEV_PORT` in `.env.local`). 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 the [API dependencies docs](https://www.worldmonitor.app/docs/getting-started#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 500+ 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](#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 |
|
|
| 1. **Update documentation** if your change affects the public API or user-facing behavior |
| 2. **Run type checking** before submitting: `npm run typecheck` |
| 3. **Test your changes** locally with at least the `full` variant, and any other variant your change affects |
| 4. **Keep PRs focused** β one feature or fix per pull request |
| 5. **Write a clear description** explaining what your PR does and why |
| 6. **Link related issues** if applicable |
|
|
| ### PR Title Convention |
|
|
| Use a descriptive title that summarizes the change: |
|
|
| - `feat: add earthquake magnitude filtering to map layer` |
| - `fix: resolve RSS feed timeout for Al Jazeera` |
| - `docs: update API dependencies section` |
| - `perf: optimize marker clustering at low zoom levels` |
| - `refactor: 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 `any` types β use proper typing or `unknown` with 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 `const` by default, `let` when 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 |
|
|
| 1. **Proto definitions** in `proto/worldmonitor/{domain}/v1/` define services and messages |
| 2. **Code generation** (`make generate`) produces: |
| - TypeScript clients in `src/generated/client/` (e.g., `MarketServiceClient`) |
| - Server route factories in `src/generated/server/` (e.g., `createMarketServiceRoutes`) |
| 3. **Handlers** in `server/worldmonitor/{domain}/v1/handler.ts` implement the service interface |
| 4. **Gateway** in `api/[domain]/v1/[rpc].ts` registers all handlers and routes requests |
| 5. **Clients** in `src/services/{domain}/index.ts` wrap the generated client for app use |
|
|
| ### Adding a New RPC Method |
|
|
| 1. Add the method to the `.proto` service definition |
| 2. Run `make generate` to regenerate client/server stubs |
| 3. Implement the handler method in the domain's `handler.ts` |
| 4. 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), not `google.protobuf.Timestamp` |
| - **int64 encoding**: Apply `[(sebuf.http.int64_encoding) = INT64_ENCODING_NUMBER]` on time fields so TypeScript receives `number` instead of `string` |
| - **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: |
|
|
| ```bash |
| 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: |
|
|
| 1. **Define the data source** β identify the API or dataset you want to integrate |
| 2. **Add the proto service** (if the data needs a backend proxy) β define messages and RPC methods in `proto/worldmonitor/{domain}/v1/` |
| 3. **Generate stubs** β run `make generate` |
| 4. **Implement the handler** in `server/worldmonitor/{domain}/v1/` |
| 5. **Register the handler** in `api/[domain]/v1/[rpc].ts` and `vite.config.ts` (for local dev) |
| 6. **Create the service module** in `src/services/{domain}/` wrapping the generated client |
| 7. **Add the layer config** and implement the map renderer following existing layer patterns |
| 8. **Add to layer toggles** β make it toggleable in the UI |
| 9. **Document the source** β add it to the [data sources docs](https://www.worldmonitor.app/docs/data-sources) |
|
|
| 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](https://www.naturalearthdata.com/)) 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: |
|
|
| ```bash |
| 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: |
|
|
| 1. Verify the feed is reliable and actively maintained |
| 2. Assign a **source tier** (1-4) based on editorial reliability |
| 3. Flag any **state affiliation** or **propaganda risk** |
| 4. Categorize the feed (geopolitics, defense, energy, tech, etc.) |
| 5. 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](https://github.com/koala73/worldmonitor/issues/new/choose) 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](https://github.com/koala73/worldmonitor/issues/new/choose) when available. |
|
|
| ## Code of Conduct |
|
|
| This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). 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! π |
|
|